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