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
BSound(void * data,size_t size,const media_raw_audio_format & format,bool freeWhenDone)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
BSound(const entry_ref * soundFile,bool loadIntoMemory)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
BSound(const media_raw_audio_format & format)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
~BSound()89 BSound::~BSound()
90 {
91 delete fTrackReader;
92 delete fFile;
93
94 if (fFreeWhenDone)
95 free(fData);
96 }
97
98
99 status_t
InitCheck()100 BSound::InitCheck()
101 {
102 return fStatus;
103 }
104
105
106 BSound*
AcquireRef()107 BSound::AcquireRef()
108 {
109 atomic_add(&fRefCount, 1);
110 return this;
111 }
112
113
114 bool
ReleaseRef()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
RefCount() const128 BSound::RefCount() const
129 {
130 return fRefCount;
131 }
132
133
134 bigtime_t
Duration() const135 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&
Format() const151 BSound::Format() const
152 {
153 return fFormat;
154 }
155
156
157 const void*
Data() const158 BSound::Data() const
159 {
160 return fData;
161 }
162
163
164 off_t
Size() const165 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
GetDataAt(off_t offset,void * intoBuffer,size_t bufferSize,size_t * outUsed)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
BindTo(BSoundPlayer * player,const media_raw_audio_format & format)243 BSound::BindTo(BSoundPlayer* player, const media_raw_audio_format& format)
244 {
245 UNIMPLEMENTED();
246 return B_ERROR;
247 }
248
249
250 status_t
UnbindFrom(BSoundPlayer * player)251 BSound::UnbindFrom(BSoundPlayer* player)
252 {
253 UNIMPLEMENTED();
254 return B_ERROR;
255 }
256
257
258 status_t
Perform(int32 code,...)259 BSound::Perform(int32 code, ...)
260 {
261 UNIMPLEMENTED();
262 return B_ERROR;
263 }
264
265
_Reserved_Sound_0(void *)266 status_t BSound::_Reserved_Sound_0(void*) { return B_ERROR; }
_Reserved_Sound_1(void *)267 status_t BSound::_Reserved_Sound_1(void*) { return B_ERROR; }
_Reserved_Sound_2(void *)268 status_t BSound::_Reserved_Sound_2(void*) { return B_ERROR; }
_Reserved_Sound_3(void *)269 status_t BSound::_Reserved_Sound_3(void*) { return B_ERROR; }
_Reserved_Sound_4(void *)270 status_t BSound::_Reserved_Sound_4(void*) { return B_ERROR; }
_Reserved_Sound_5(void *)271 status_t BSound::_Reserved_Sound_5(void*) { return B_ERROR; }
272