xref: /haiku/src/kits/game/PushGameSound.cpp (revision 0044a8c39ab5721051b6279506d1a8c511e20453)
1 /*
2  * Copyright 2001-2007, Haiku Inc.
3  * Authors:
4  *		Christopher ML Zumwalt May (zummy@users.sf.net)
5  *		Jérôme Duval
6  *
7  * Distributed under the terms of the MIT License.
8  */
9 
10 #include <string.h>
11 
12 #include <List.h>
13 #include <PushGameSound.h>
14 
15 #include "GSUtility.h"
16 
17 
18 BPushGameSound::BPushGameSound(size_t inBufferFrameCount,
19 	const gs_audio_format *format, size_t inBufferCount,
20 	BGameSoundDevice *device)
21  	:
22 	BStreamingGameSound(inBufferFrameCount, format, inBufferCount, device),
23 	fLockPos(0),
24 	fPlayPos(0)
25 {
26 	fPageLocked = new BList;
27 
28 	size_t frameSize = get_sample_size(format->format) * format->channel_count;
29 
30 	fPageCount = inBufferCount;
31 	fPageSize = frameSize * inBufferFrameCount;
32 	fBufferSize = fPageSize * fPageCount;
33 
34 	fBuffer = new char[fBufferSize];
35 }
36 
37 
38 BPushGameSound::BPushGameSound(BGameSoundDevice * device)
39 		:	BStreamingGameSound(device),
40 			fLockPos(0),
41 			fPlayPos(0),
42 			fBuffer(NULL),
43 			fPageSize(0),
44 			fPageCount(0),
45 			fBufferSize(0)
46 {
47 	fPageLocked = new BList;
48 }
49 
50 
51 BPushGameSound::~BPushGameSound()
52 {
53 	delete [] fBuffer;
54 	delete fPageLocked;
55 }
56 
57 
58 BPushGameSound::lock_status
59 BPushGameSound::LockNextPage(void **out_pagePtr, size_t *out_pageSize)
60 {
61 	// the user can not lock every page
62 	if (fPageLocked->CountItems() > fPageCount - 3)
63 		return lock_failed;
64 
65 	// the user cann't lock a page being played
66 	if (fLockPos < fPlayPos
67 		&& fLockPos + fPageSize > fPlayPos)
68 		return lock_failed;
69 
70 	// lock the page
71 	char * lockPage = &fBuffer[fLockPos];
72 	fPageLocked->AddItem(lockPage);
73 
74 	// move the locker to the next page
75 	fLockPos += fPageSize;
76 	if (fLockPos > fBufferSize)
77 		fLockPos = 0;
78 
79 	*out_pagePtr = lockPage;
80 	*out_pageSize = fPageSize;
81 
82 	return lock_ok;
83 }
84 
85 
86 status_t
87 BPushGameSound::UnlockPage(void *in_pagePtr)
88 {
89 	return (fPageLocked->RemoveItem(in_pagePtr)) ? B_OK : B_ERROR;
90 }
91 
92 
93 BPushGameSound::lock_status
94 BPushGameSound::LockForCyclic(void **out_basePtr, size_t *out_size)
95 {
96 	*out_basePtr = fBuffer;
97 	*out_size = fBufferSize;
98 	return lock_ok;
99 }
100 
101 
102 status_t
103 BPushGameSound::UnlockCyclic()
104 {
105 	return B_OK;
106 }
107 
108 
109 size_t
110 BPushGameSound::CurrentPosition()
111 {
112 	return fPlayPos;
113 }
114 
115 
116 BGameSound *
117 BPushGameSound::Clone() const
118 {
119 	gs_audio_format format = Format();
120 	size_t frameSize = get_sample_size(format.format) * format.channel_count;
121 	size_t bufferFrameCount = fPageSize / frameSize;
122 
123 	return new BPushGameSound(bufferFrameCount, &format, fPageCount, Device());
124 }
125 
126 
127 status_t
128 BPushGameSound::Perform(int32 selector, void *data)
129 {
130 	return BStreamingGameSound::Perform(selector, data);
131 }
132 
133 
134 status_t
135 BPushGameSound::SetParameters(size_t inBufferFrameCount,
136 							  const gs_audio_format *format,
137 							  size_t inBufferCount)
138 {
139 	return B_UNSUPPORTED;
140 }
141 
142 
143 status_t
144 BPushGameSound::SetStreamHook(void (*hook)(void * inCookie, void * inBuffer,
145 	size_t inByteCount, BStreamingGameSound * me), void * cookie)
146 {
147 	return B_UNSUPPORTED;
148 }
149 
150 
151 void
152 BPushGameSound::FillBuffer(void *inBuffer, size_t inByteCount)
153 {
154 	size_t bytes = inByteCount;
155 
156 	if (!BytesReady(&bytes))
157 		return;
158 
159 	if (fPlayPos + bytes > fBufferSize) {
160 		size_t remainder = fBufferSize - fPlayPos;
161 			// Space left in buffer
162 		char * buffer = (char*)inBuffer;
163 
164 		// fill the buffer with the samples left at the end of our buffer
165 		memcpy(buffer, &fBuffer[fPlayPos], remainder);
166 		fPlayPos = 0;
167 
168 		// fill the remainder of the buffer by looping to the start
169 		// of the buffer if it isn't locked
170 		bytes -= remainder;
171 		if (BytesReady(&bytes)) {
172 			memcpy(&buffer[remainder], fBuffer, bytes);
173 			fPlayPos += bytes;
174 		}
175 	} else {
176 		memcpy(inBuffer, &fBuffer[fPlayPos], bytes);
177 		fPlayPos += bytes;
178 	}
179 
180 	BStreamingGameSound::FillBuffer(inBuffer, inByteCount);
181 }
182 
183 
184 bool
185 BPushGameSound::BytesReady(size_t * bytes)
186 {
187 	if (fPageLocked->CountItems() <= 0)
188 		return true;
189 
190 	size_t start = fPlayPos;
191 	size_t ready = fPlayPos;
192 	int32 page = int32(start / fPageSize);
193 
194 	// return if there is nothing to do
195 	if (fPageLocked->HasItem(&fBuffer[page * fPageSize]))
196 		return false;
197 
198 	while (ready < *bytes) {
199 		ready += fPageSize;
200 		page = int32(ready / fPageSize);
201 
202 		if (fPageLocked->HasItem(&fBuffer[page * fPageSize])) {
203 			// we have found a locked page
204 			*bytes = ready - start - (ready - page * fPageSize);
205 			return true;
206 		}
207 	}
208 
209 	// all of the bytes are ready
210 	return true;
211 }
212 
213 /* unimplemented for protection of the user:
214  *
215  * BPushGameSound::BPushGameSound()
216  * BPushGameSound::BPushGameSound(const BPushGameSound &)
217  * BPushGameSound &BPushGameSound::operator=(const BPushGameSound &)
218  */
219 
220 
221 status_t
222 BPushGameSound::_Reserved_BPushGameSound_0(int32 arg, ...)
223 {
224 	return B_ERROR;
225 }
226 
227 
228 status_t
229 BPushGameSound::_Reserved_BPushGameSound_1(int32 arg, ...)
230 {
231 	return B_ERROR;
232 }
233 
234 
235 status_t
236 BPushGameSound::_Reserved_BPushGameSound_2(int32 arg, ...)
237 {
238 	return B_ERROR;
239 }
240 
241 
242 status_t
243 BPushGameSound::_Reserved_BPushGameSound_3(int32 arg, ...)
244 {
245 	return B_ERROR;
246 }
247 
248 
249 status_t
250 BPushGameSound::_Reserved_BPushGameSound_4(int32 arg, ...)
251 {
252 	return B_ERROR;
253 }
254 
255 
256 status_t
257 BPushGameSound::_Reserved_BPushGameSound_5(int32 arg, ...)
258 {
259 	return B_ERROR;
260 }
261 
262 
263 status_t
264 BPushGameSound::_Reserved_BPushGameSound_6(int32 arg, ...)
265 {
266 	return B_ERROR;
267 }
268 
269 
270 status_t
271 BPushGameSound::_Reserved_BPushGameSound_7(int32 arg, ...)
272 {
273 	return B_ERROR;
274 }
275 
276 
277 status_t
278 BPushGameSound::_Reserved_BPushGameSound_8(int32 arg, ...)
279 {
280 	return B_ERROR;
281 }
282 
283 
284 status_t
285 BPushGameSound::_Reserved_BPushGameSound_9(int32 arg, ...)
286 {
287 	return B_ERROR;
288 }
289 
290 
291 status_t
292 BPushGameSound::_Reserved_BPushGameSound_10(int32 arg, ...)
293 {
294 	return B_ERROR;
295 }
296 
297 
298 status_t
299 BPushGameSound::_Reserved_BPushGameSound_11(int32 arg, ...)
300 {
301 	return B_ERROR;
302 }
303 
304 
305 status_t
306 BPushGameSound::_Reserved_BPushGameSound_12(int32 arg, ...)
307 {
308 	return B_ERROR;
309 }
310 
311 
312 status_t
313 BPushGameSound::_Reserved_BPushGameSound_13(int32 arg, ...)
314 {
315 	return B_ERROR;
316 }
317 
318 
319 status_t
320 BPushGameSound::_Reserved_BPushGameSound_14(int32 arg, ...)
321 {
322 	return B_ERROR;
323 }
324 
325 
326 status_t
327 BPushGameSound::_Reserved_BPushGameSound_15(int32 arg, ...)
328 {
329 	return B_ERROR;
330 }
331 
332 
333 status_t
334 BPushGameSound::_Reserved_BPushGameSound_16(int32 arg, ...)
335 {
336 	return B_ERROR;
337 }
338 
339 
340 status_t
341 BPushGameSound::_Reserved_BPushGameSound_17(int32 arg, ...)
342 {
343 	return B_ERROR;
344 }
345 
346 
347 status_t
348 BPushGameSound::_Reserved_BPushGameSound_18(int32 arg, ...)
349 {
350 	return B_ERROR;
351 }
352 
353 
354 status_t
355 BPushGameSound::_Reserved_BPushGameSound_19(int32 arg, ...)
356 {
357 	return B_ERROR;
358 }
359 
360 
361 status_t
362 BPushGameSound::_Reserved_BPushGameSound_20(int32 arg, ...)
363 {
364 	return B_ERROR;
365 }
366 
367 
368 status_t
369 BPushGameSound::_Reserved_BPushGameSound_21(int32 arg, ...)
370 {
371 	return B_ERROR;
372 }
373 
374 
375 status_t
376 BPushGameSound::_Reserved_BPushGameSound_22(int32 arg, ...)
377 {
378 	return B_ERROR;
379 }
380 
381 
382 status_t
383 BPushGameSound::_Reserved_BPushGameSound_23(int32 arg, ...)
384 {
385 	return B_ERROR;
386 }
387 
388 
389