xref: /haiku/src/kits/media/Sound.cpp (revision 5b189b0e1e2f51f367bfcb126b2f00a3702f352d)
1 /*
2  * Copyright 2009-2019, Haiku Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Jacob Secunda
7  *		Marcus Overhagen
8  *		Michael Lotz <mmlr@mlotz.ch>
9  */
10 
11 #include <Sound.h>
12 
13 #include <new>
14 #include <string.h>
15 
16 #include <File.h>
17 #include <MediaDebug.h>
18 
19 #include "TrackReader.h"
20 
21 
22 BSound::BSound(void* data, size_t size, const media_raw_audio_format& format,
23 	bool freeWhenDone)
24 	:	fData(data),
25 		fDataSize(size),
26 		fFile(NULL),
27 		fRefCount(1),
28 		fStatus(B_NO_INIT),
29 		fFormat(format),
30 		fFreeWhenDone(freeWhenDone),
31 		fTrackReader(NULL)
32 {
33 	if (fData == NULL)
34 		return;
35 
36 	fStatus = B_OK;
37 }
38 
39 
40 BSound::BSound(const entry_ref* soundFile, bool loadIntoMemory)
41 	:	fData(NULL),
42 		fDataSize(0),
43 		fFile(new(std::nothrow) BFile(soundFile, B_READ_ONLY)),
44 		fRefCount(1),
45 		fStatus(B_NO_INIT),
46 		fFreeWhenDone(false),
47 		fTrackReader(NULL)
48 {
49 	if (fFile == NULL) {
50 		fStatus = B_NO_MEMORY;
51 		return;
52 	}
53 
54 	fStatus = fFile->InitCheck();
55 	if (fStatus != B_OK)
56 		return;
57 
58 	memset(&fFormat, 0, sizeof(fFormat));
59 	fTrackReader = new(std::nothrow) BPrivate::BTrackReader(fFile, fFormat);
60 	if (fTrackReader == NULL) {
61 		fStatus = B_NO_MEMORY;
62 		return;
63 	}
64 
65 	fStatus = fTrackReader->InitCheck();
66 	if (fStatus != B_OK)
67 		return;
68 
69 	fFormat = fTrackReader->Format();
70 	fStatus = B_OK;
71 }
72 
73 
74 BSound::BSound(const media_raw_audio_format& format)
75 	:	fData(NULL),
76 		fDataSize(0),
77 		fFile(NULL),
78 		fRefCount(1),
79 		fStatus(B_ERROR),
80 		fFormat(format),
81 		fFreeWhenDone(false),
82 		fTrackReader(NULL)
83 {
84 	// unimplemented protected constructor
85 	UNIMPLEMENTED();
86 }
87 
88 
89 BSound::~BSound()
90 {
91 	delete fTrackReader;
92 	delete fFile;
93 
94 	if (fFreeWhenDone)
95 		free(fData);
96 }
97 
98 
99 status_t
100 BSound::InitCheck()
101 {
102 	return fStatus;
103 }
104 
105 
106 BSound*
107 BSound::AcquireRef()
108 {
109 	atomic_add(&fRefCount, 1);
110 	return this;
111 }
112 
113 
114 bool
115 BSound::ReleaseRef()
116 {
117 	if (atomic_add(&fRefCount, -1) == 1) {
118 		delete this;
119 		return false;
120 	}
121 
122 	// TODO: verify those returns
123 	return true;
124 }
125 
126 
127 int32
128 BSound::RefCount() const
129 {
130 	return fRefCount;
131 }
132 
133 
134 bigtime_t
135 BSound::Duration() const
136 {
137 	float frameRate = fFormat.frame_rate;
138 
139 	if (frameRate == 0.0)
140 		return 0;
141 
142 	uint32 bytesPerSample = fFormat.format &
143 		media_raw_audio_format::B_AUDIO_SIZE_MASK;
144 	int64 frameCount = Size() / (fFormat.channel_count * bytesPerSample);
145 
146 	return (bigtime_t)ceil((1000000LL * frameCount) / frameRate);
147 }
148 
149 
150 const media_raw_audio_format&
151 BSound::Format() const
152 {
153 	return fFormat;
154 }
155 
156 
157 const void*
158 BSound::Data() const
159 {
160 	return fData;
161 }
162 
163 
164 off_t
165 BSound::Size() const
166 {
167 	if (fFile != NULL) {
168 		off_t result = 0;
169 		fFile->GetSize(&result);
170 		return result;
171 	}
172 
173 	return fDataSize;
174 }
175 
176 
177 bool
178 BSound::GetDataAt(off_t offset, void* intoBuffer, size_t bufferSize,
179 	size_t* outUsed)
180 {
181 	if (intoBuffer == NULL)
182 		return false;
183 
184 	if (fData != NULL) {
185 		size_t copySize = MIN(bufferSize, fDataSize - offset);
186 		memcpy(intoBuffer, (uint8*)fData + offset, copySize);
187 		if (outUsed != NULL)
188 			*outUsed = copySize;
189 		return true;
190 	}
191 
192 	if (fTrackReader != NULL) {
193 		int32 frameSize = fTrackReader->FrameSize();
194 		int64 frameCount = fTrackReader->CountFrames();
195 		int64 startFrame = offset / frameSize;
196 		if (startFrame > frameCount)
197 			return false;
198 
199 		if (fTrackReader->SeekToFrame(&startFrame) != B_OK)
200 			return false;
201 
202 		off_t bufferOffset = offset - startFrame * frameSize;
203 		int64 directStartFrame = (offset + frameSize - 1) / frameSize;
204 		int64 directFrameCount = (offset + bufferSize - directStartFrame
205 			* frameSize) / frameSize;
206 
207 		if (bufferOffset != 0) {
208 			int64 indirectFrameCount = directStartFrame - startFrame;
209 			size_t indirectSize = indirectFrameCount * frameSize;
210 			void* buffer = malloc(indirectSize);
211 			if (buffer == NULL)
212 				return false;
213 
214 			if (fTrackReader->ReadFrames(buffer, indirectFrameCount) != B_OK) {
215 				free(buffer);
216 				return false;
217 			}
218 
219 			memcpy(intoBuffer, (uint8*)buffer + bufferOffset,
220 				indirectSize - bufferOffset);
221 			if (outUsed != NULL)
222 				*outUsed = indirectSize - bufferOffset;
223 
224 			free(buffer);
225 		} else if (outUsed != NULL)
226 			*outUsed = 0;
227 
228 		if (fTrackReader->ReadFrames((uint8*)intoBuffer + bufferOffset,
229 			directFrameCount) != B_OK)
230 			return false;
231 
232 		if (outUsed != NULL)
233 			*outUsed += directFrameCount * frameSize;
234 
235 		return true;
236 	}
237 
238 	return false;
239 }
240 
241 
242 status_t
243 BSound::BindTo(BSoundPlayer* player, const media_raw_audio_format& format)
244 {
245 	UNIMPLEMENTED();
246 	return B_ERROR;
247 }
248 
249 
250 status_t
251 BSound::UnbindFrom(BSoundPlayer* player)
252 {
253 	UNIMPLEMENTED();
254 	return B_ERROR;
255 }
256 
257 
258 status_t
259 BSound::Perform(int32 code, ...)
260 {
261 	UNIMPLEMENTED();
262 	return B_ERROR;
263 }
264 
265 
266 status_t BSound::_Reserved_Sound_0(void*) { return B_ERROR; }
267 status_t BSound::_Reserved_Sound_1(void*) { return B_ERROR; }
268 status_t BSound::_Reserved_Sound_2(void*) { return B_ERROR; }
269 status_t BSound::_Reserved_Sound_3(void*) { return B_ERROR; }
270 status_t BSound::_Reserved_Sound_4(void*) { return B_ERROR; }
271 status_t BSound::_Reserved_Sound_5(void*) { return B_ERROR; }
272