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 */
8
9
10#include <SimpleGameSound.h>
11
12#include <Entry.h>
13#include <MediaFile.h>
14#include <MediaTrack.h>
15#include <stdlib.h>
16#include <string.h>
17
18#include "GameSoundBuffer.h"
19#include "GameSoundDefs.h"
20#include "GameSoundDevice.h"
21#include "GSUtility.h"
22
23
24BSimpleGameSound::BSimpleGameSound(const entry_ref *inFile,
25	BGameSoundDevice *device)
26	:
27	BGameSound(device)
28{
29	if (InitCheck() == B_OK)
30		SetInitError(Init(inFile));
31}
32
33
34BSimpleGameSound::BSimpleGameSound(const char *inFile, BGameSoundDevice *device)
35	:
36	BGameSound(device)
37{
38	if (InitCheck() == B_OK) {
39		entry_ref file;
40
41		if (get_ref_for_path(inFile, &file) != B_OK)
42			SetInitError(B_ENTRY_NOT_FOUND);
43		else
44			SetInitError(Init(&file));
45	}
46}
47
48
49BSimpleGameSound::BSimpleGameSound(const void *inData, size_t inFrameCount,
50	const gs_audio_format *format, BGameSoundDevice *device)
51	:
52	BGameSound(device)
53{
54	if (InitCheck() != B_OK)
55		return;
56
57	gs_audio_format actual = *format;
58	if (actual.byte_order == 0)
59		actual.byte_order = B_MEDIA_HOST_ENDIAN;
60
61	size_t frameSize
62		= get_sample_size(format->format) * format->channel_count;
63	uchar * data = new uchar[inFrameCount * frameSize];
64	memcpy(data, inData, inFrameCount * frameSize);
65
66	SetInitError(Init(data, inFrameCount, &actual));
67}
68
69
70BSimpleGameSound::BSimpleGameSound(const BSimpleGameSound &other)
71	:
72	BGameSound(other)
73{
74	gs_audio_format format;
75	void *data = NULL;
76
77	status_t error = other.Device()->Buffer(other.ID(), &format, data);
78	if (error != B_OK)
79		SetInitError(error);
80
81	Init(data, 0, &format);
82	free(data);
83}
84
85
86BSimpleGameSound::~BSimpleGameSound()
87{
88}
89
90
91BGameSound *
92BSimpleGameSound::Clone() const
93{
94	gs_audio_format format;
95	void *data = NULL;
96
97	status_t error = Device()->Buffer(ID(), &format, data);
98	if (error != B_OK)
99		return NULL;
100
101	BSimpleGameSound *clone = new BSimpleGameSound(data, 0, &format, Device());
102	free(data);
103
104	return clone;
105}
106
107
108/* virtual */ status_t
109BSimpleGameSound::Perform(int32 selector, void * data)
110{
111	return B_ERROR;
112}
113
114
115status_t
116BSimpleGameSound::SetIsLooping(bool looping)
117{
118	gs_attribute attribute;
119
120	attribute.attribute = B_GS_LOOPING;
121	attribute.value = (looping) ? -1.0 : 0.0;
122	attribute.duration = bigtime_t(0);
123	attribute.flags = 0;
124
125	return Device()->SetAttributes(ID(), &attribute, 1);
126}
127
128
129bool
130BSimpleGameSound::IsLooping() const
131{
132	gs_attribute attribute;
133
134	attribute.attribute = B_GS_LOOPING;
135	attribute.flags = 0;
136
137	if (Device()->GetAttributes(ID(), &attribute, 1) != B_OK)
138		return false;
139
140	return bool(attribute.value);
141}
142
143
144status_t
145BSimpleGameSound::Init(const entry_ref* inFile)
146{
147	BMediaFile file(inFile);
148	gs_audio_format gsformat;
149	media_format mformat;
150	int64 framesRead, framesTotal = 0;
151
152	if (file.InitCheck() != B_OK)
153		return file.InitCheck();
154
155	BMediaTrack* audioStream = file.TrackAt(0);
156	audioStream->EncodedFormat(&mformat);
157	if (!mformat.IsAudio())
158		return B_ERROR;
159
160	int64 frames = audioStream->CountFrames();
161
162	mformat.Clear();
163	mformat.type = B_MEDIA_RAW_AUDIO;
164//	mformat.u.raw_audio.byte_order
165//		= (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
166	status_t error = audioStream->DecodedFormat(&mformat);
167	if (error != B_OK)
168		return error;
169
170	memset(&gsformat, 0, sizeof(gs_audio_format));
171	media_to_gs_format(&gsformat, &mformat.u.raw_audio);
172
173	if (mformat.u.raw_audio.format == media_raw_audio_format::B_AUDIO_CHAR) {
174		// The GameKit doesnt support this format so we will have to reformat
175		// the data into something the GameKit does support.
176		char * buffer = new char[gsformat.buffer_size];
177		uchar * data = new uchar[frames * gsformat.channel_count];
178
179		while (framesTotal < frames) {
180			// read the next chunck from the stream
181			memset(buffer, 0, gsformat.buffer_size);
182			audioStream->ReadFrames(buffer, &framesRead);
183
184			// refomat the buffer from
185			int64 position = framesTotal * gsformat.channel_count;
186			for (int32 i = 0; i < (int32)gsformat.buffer_size; i++)
187				data[i + position] = buffer[i] + 128;
188
189			framesTotal += framesRead;
190		}
191		delete [] buffer;
192
193		gsformat.format = gs_audio_format::B_GS_U8;
194
195		error = Init(data, frames, &gsformat);
196
197		// free the buffers we no longer need
198	} else {
199		// We need to determine the size, in bytes, of a single sample.
200		// At the same time, we will store the format of the audio buffer
201		size_t frameSize
202			= get_sample_size(gsformat.format) * gsformat.channel_count;
203		char * data = new char[frames * frameSize];
204		gsformat.buffer_size = frames * frameSize;
205
206		while (framesTotal < frames) {
207			char * position = &data[framesTotal * frameSize];
208			audioStream->ReadFrames(position, &framesRead);
209
210			framesTotal += framesRead;
211		}
212
213		error = Init(data, frames, &gsformat);
214	}
215
216	file.ReleaseTrack(audioStream);
217	return error;
218}
219
220
221status_t
222BSimpleGameSound::Init(const void* inData, int64 inFrameCount,
223	const gs_audio_format* format)
224{
225	gs_id sound;
226
227	status_t error
228		= Device()->CreateBuffer(&sound, format, inData, inFrameCount);
229	if (error != B_OK)
230		return error;
231
232	BGameSound::Init(sound);
233
234	return B_OK;
235}
236
237
238/* unimplemented for protection of the user:
239 *
240 * BSimpleGameSound::BSimpleGameSound()
241 * BSimpleGameSound &BSimpleGameSound::operator=(const BSimpleGameSound &)
242 */
243
244
245status_t
246BSimpleGameSound::_Reserved_BSimpleGameSound_0(int32 arg, ...)
247{
248	return B_ERROR;
249}
250
251
252status_t
253BSimpleGameSound::_Reserved_BSimpleGameSound_1(int32 arg, ...)
254{
255	return B_ERROR;
256}
257
258
259status_t
260BSimpleGameSound::_Reserved_BSimpleGameSound_2(int32 arg, ...)
261{
262	return B_ERROR;
263}
264
265
266status_t
267BSimpleGameSound::_Reserved_BSimpleGameSound_3(int32 arg, ...)
268{
269	return B_ERROR;
270}
271
272
273status_t
274BSimpleGameSound::_Reserved_BSimpleGameSound_4(int32 arg, ...)
275{
276	return B_ERROR;
277}
278
279
280status_t
281BSimpleGameSound::_Reserved_BSimpleGameSound_5(int32 arg, ...)
282{
283	return B_ERROR;
284}
285
286
287status_t
288BSimpleGameSound::_Reserved_BSimpleGameSound_6(int32 arg, ...)
289{
290	return B_ERROR;
291}
292
293
294status_t
295BSimpleGameSound::_Reserved_BSimpleGameSound_7(int32 arg, ...)
296{
297	return B_ERROR;
298}
299
300
301status_t
302BSimpleGameSound::_Reserved_BSimpleGameSound_8(int32 arg, ...)
303{
304	return B_ERROR;
305}
306
307
308status_t
309BSimpleGameSound::_Reserved_BSimpleGameSound_9(int32 arg, ...)
310{
311	return B_ERROR;
312}
313
314
315status_t
316BSimpleGameSound::_Reserved_BSimpleGameSound_10(int32 arg, ...)
317{
318	return B_ERROR;
319}
320
321
322status_t
323BSimpleGameSound::_Reserved_BSimpleGameSound_11(int32 arg, ...)
324{
325	return B_ERROR;
326}
327
328
329status_t
330BSimpleGameSound::_Reserved_BSimpleGameSound_12(int32 arg, ...)
331{
332	return B_ERROR;
333}
334
335
336status_t
337BSimpleGameSound::_Reserved_BSimpleGameSound_13(int32 arg, ...)
338{
339	return B_ERROR;
340}
341
342
343status_t
344BSimpleGameSound::_Reserved_BSimpleGameSound_14(int32 arg, ...)
345{
346	return B_ERROR;
347}
348
349
350status_t
351BSimpleGameSound::_Reserved_BSimpleGameSound_15(int32 arg, ...)
352{
353	return B_ERROR;
354}
355
356
357status_t
358BSimpleGameSound::_Reserved_BSimpleGameSound_16(int32 arg, ...)
359{
360	return B_ERROR;
361}
362
363
364status_t
365BSimpleGameSound::_Reserved_BSimpleGameSound_17(int32 arg, ...)
366{
367	return B_ERROR;
368}
369
370
371status_t
372BSimpleGameSound::_Reserved_BSimpleGameSound_18(int32 arg, ...)
373{
374	return B_ERROR;
375}
376
377
378status_t
379BSimpleGameSound::_Reserved_BSimpleGameSound_19(int32 arg, ...)
380{
381	return B_ERROR;
382}
383
384
385status_t
386BSimpleGameSound::_Reserved_BSimpleGameSound_20(int32 arg, ...)
387{
388	return B_ERROR;
389}
390
391
392status_t
393BSimpleGameSound::_Reserved_BSimpleGameSound_21(int32 arg, ...)
394{
395	return B_ERROR;
396}
397
398
399status_t
400BSimpleGameSound::_Reserved_BSimpleGameSound_22(int32 arg, ...)
401{
402	return B_ERROR;
403}
404
405
406status_t
407BSimpleGameSound::_Reserved_BSimpleGameSound_23(int32 arg, ...)
408{
409	return B_ERROR;
410}
411