xref: /haiku/src/kits/media/Sound.cpp (revision 12dba4e70f831d6d27a7f769cc9dab19c19a155d)
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 <MediaDebug.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 
112 bool
113 BSound::ReleaseRef()
114 {
115 	if (atomic_add(&fRefCount, -1) == 1) {
116 		delete this;
117 		return false;
118 	}
119 
120 	// TODO: verify those returns
121 	return true;
122 }
123 
124 
125 int32
126 BSound::RefCount() const
127 {
128 	return fRefCount;
129 }
130 
131 
132 bigtime_t
133 BSound::Duration() const
134 {
135 	UNIMPLEMENTED();
136 	return 0;
137 }
138 
139 
140 const media_raw_audio_format&
141 BSound::Format() const
142 {
143 	return fFormat;
144 }
145 
146 
147 const void*
148 BSound::Data() const
149 {
150 	return fData;
151 }
152 
153 
154 off_t
155 BSound::Size() const
156 {
157 	if (fFile != NULL) {
158 		off_t result = 0;
159 		fFile->GetSize(&result);
160 		return result;
161 	}
162 
163 	return fDataSize;
164 }
165 
166 
167 bool
168 BSound::GetDataAt(off_t offset, void* intoBuffer, size_t bufferSize,
169 	size_t* outUsed)
170 {
171 	if (intoBuffer == NULL)
172 		return false;
173 
174 	if (fData != NULL) {
175 		size_t copySize = MIN(bufferSize, fDataSize - offset);
176 		memcpy(intoBuffer, (uint8*)fData + offset, copySize);
177 		if (outUsed != NULL)
178 			*outUsed = copySize;
179 		return true;
180 	}
181 
182 	if (fTrackReader != NULL) {
183 		int32 frameSize = fTrackReader->FrameSize();
184 		int64 frameCount = fTrackReader->CountFrames();
185 		int64 startFrame = offset / frameSize;
186 		if (startFrame > frameCount)
187 			return false;
188 
189 		if (fTrackReader->SeekToFrame(&startFrame) != B_OK)
190 			return false;
191 
192 		off_t bufferOffset = offset - startFrame * frameSize;
193 		int64 directStartFrame = (offset + frameSize - 1) / frameSize;
194 		int64 directFrameCount = (offset + bufferSize - directStartFrame
195 			* frameSize) / frameSize;
196 
197 		if (bufferOffset != 0) {
198 			int64 indirectFrameCount = directStartFrame - startFrame;
199 			size_t indirectSize = indirectFrameCount * frameSize;
200 			void* buffer = malloc(indirectSize);
201 			if (buffer == NULL)
202 				return false;
203 
204 			if (fTrackReader->ReadFrames(buffer, indirectFrameCount) != B_OK) {
205 				free(buffer);
206 				return false;
207 			}
208 
209 			memcpy(intoBuffer, (uint8*)buffer + bufferOffset,
210 				indirectSize - bufferOffset);
211 			if (outUsed != NULL)
212 				*outUsed = indirectSize - bufferOffset;
213 
214 			free(buffer);
215 		} else if (outUsed != NULL)
216 			*outUsed = 0;
217 
218 		if (fTrackReader->ReadFrames((uint8*)intoBuffer + bufferOffset,
219 			directFrameCount) != B_OK)
220 			return false;
221 
222 		if (outUsed != NULL)
223 			*outUsed += directFrameCount * frameSize;
224 
225 		return true;
226 	}
227 
228 	return false;
229 }
230 
231 
232 status_t
233 BSound::BindTo(BSoundPlayer* player, const media_raw_audio_format& format)
234 {
235 	UNIMPLEMENTED();
236 	return B_ERROR;
237 }
238 
239 
240 status_t
241 BSound::UnbindFrom(BSoundPlayer* player)
242 {
243 	UNIMPLEMENTED();
244 	return B_ERROR;
245 }
246 
247 
248 status_t
249 BSound::Perform(int32 code, ...)
250 {
251 	UNIMPLEMENTED();
252 	return B_ERROR;
253 }
254 
255 
256 status_t BSound::_Reserved_Sound_0(void*) { return B_ERROR; }
257 status_t BSound::_Reserved_Sound_1(void*) { return B_ERROR; }
258 status_t BSound::_Reserved_Sound_2(void*) { return B_ERROR; }
259 status_t BSound::_Reserved_Sound_3(void*) { return B_ERROR; }
260 status_t BSound::_Reserved_Sound_4(void*) { return B_ERROR; }
261 status_t BSound::_Reserved_Sound_5(void*) { return B_ERROR; }
262