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