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