1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      BeOS sound driver implementation.
12  *
13  *      Originally by Peter Wang, rewritten to use the BSoundPlayer
14  *      class by Angelo Mottola.
15  *
16  *      See readme.txt for copyright information.
17  */
18 
19 #include "bealleg.h"
20 #include "allegro/internal/aintern.h"
21 #include "allegro/platform/aintbeos.h"
22 
23 #if !defined ALLEGRO_BEOS && !defined ALLEGRO_HAIKU
24 #error something is wrong with the makefile
25 #endif
26 
27 #ifndef SCAN_DEPEND
28 #include <media/SoundPlayer.h>
29 #endif
30 
31 
32 #ifdef ALLEGRO_BIG_ENDIAN
33    #define BE_SOUND_ENDIAN	 B_MEDIA_BIG_ENDIAN
34 #else
35    #define BE_SOUND_ENDIAN	 B_MEDIA_LITTLE_ENDIAN
36 #endif
37 
38 
39 sem_id _be_sound_stream_lock = -1;
40 
41 static bool be_sound_active = false;
42 static bool be_sound_stream_locked = false;
43 
44 static BLocker *locker = NULL;
45 static BSoundPlayer *be_sound = NULL;
46 
47 static int be_sound_bufsize;
48 static int be_sound_signed;
49 
50 static char be_sound_desc[256] = EMPTY_STRING;
51 
52 
53 
54 /* be_sound_handler:
55  *  Update data.
56  */
be_sound_handler(void * cookie,void * buffer,size_t size,const media_raw_audio_format & format)57 static void be_sound_handler(void *cookie, void *buffer, size_t size, const media_raw_audio_format &format)
58 {
59    locker->Lock();
60    acquire_sem(_be_sound_stream_lock);
61    if (be_sound_active) {
62       _mix_some_samples((unsigned long)buffer, 0, be_sound_signed);
63    }
64    else {
65       memset(buffer, 0, size);
66    }
67    release_sem(_be_sound_stream_lock);
68    locker->Unlock();
69 }
70 
71 
72 
73 /* be_sound_detect.
74  *  Return TRUE if sound available.
75  */
be_sound_detect(int input)76 extern "C" int be_sound_detect(int input)
77 {
78    BSoundPlayer *sound;
79    media_raw_audio_format format;
80    status_t status;
81 
82    if (input) {
83       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported"));
84       return FALSE;
85    }
86 
87    format.frame_rate = 11025;
88    format.channel_count = 1;
89    format.format = media_raw_audio_format::B_AUDIO_UCHAR;
90    format.byte_order = BE_SOUND_ENDIAN;
91    format.buffer_size = 0;
92 
93    sound = new BSoundPlayer(&format);
94    status = sound->InitCheck();
95    delete sound;
96 
97    return (status == B_OK) ? TRUE : FALSE;
98 }
99 
100 
101 
102 /* be_sound_init:
103  *  Init sound driver.
104  */
be_sound_init(int input,int voices)105 extern "C" int be_sound_init(int input, int voices)
106 {
107    media_raw_audio_format format;
108    char tmp1[128], tmp2[128];
109 
110    if (input) {
111       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported"));
112       return -1;
113    }
114 
115    be_sound_active = false;
116 
117    /* create BPushGameSound instance */
118    format.frame_rate    = (_sound_freq > 0) ? _sound_freq : 44100;
119    format.channel_count = (_sound_stereo) ? 2 : 1;
120    format.format	    = (_sound_bits == 8) ? (media_raw_audio_format::B_AUDIO_UCHAR) : (media_raw_audio_format::B_AUDIO_SHORT);
121    format.byte_order    = BE_SOUND_ENDIAN;
122    format.buffer_size   = 0;
123 
124    be_sound = new BSoundPlayer(&format, "Sound player", be_sound_handler);
125 
126    if (be_sound->InitCheck() != B_OK) {
127       goto cleanup;
128    }
129 
130    /* read the sound format back */
131    format = be_sound->Format();
132 
133    switch (format.format) {
134 
135       case media_raw_audio_format::B_AUDIO_UCHAR:
136 	 _sound_bits = 8;
137 	 be_sound_signed = FALSE;
138 	 break;
139 
140       case media_raw_audio_format::B_AUDIO_SHORT:
141 	 _sound_bits = 16;
142 	 be_sound_signed = TRUE;
143 	 break;
144 
145       default:
146 	 goto cleanup;
147    }
148 
149    _sound_stereo = (format.channel_count == 2) ? 1 : 0;
150    _sound_freq = (int)format.frame_rate;
151 
152    /* start internal mixer */
153    be_sound_bufsize = format.buffer_size;
154    digi_beos.voices = voices;
155 
156    if (_mixer_init(be_sound_bufsize / (_sound_bits / 8), _sound_freq,
157 		   _sound_stereo, ((_sound_bits == 16) ? 1 : 0),
158 		   &digi_beos.voices) != 0) {
159       goto cleanup;
160    }
161 
162    /* start audio output */
163    locker = new BLocker();
164    if (!locker)
165       goto cleanup;
166 
167    be_sound->Start();
168    be_sound->SetHasData(true);
169 
170    uszprintf(be_sound_desc, sizeof(be_sound_desc), get_config_text("%d bits, %s, %d bps, %s"),
171 	     _sound_bits, uconvert_ascii(be_sound_signed ? "signed" : "unsigned", tmp1),
172 	     _sound_freq, uconvert_ascii(_sound_stereo ? "stereo" : "mono", tmp2));
173 
174    digi_driver->desc = be_sound_desc;
175    be_sound_active = true;
176 
177    return 0;
178 
179    cleanup: {
180       be_sound_exit(input);
181       return -1;
182    }
183 }
184 
185 
186 
187 /* be_sound_exit:
188  *  Shutdown sound driver.
189  */
be_sound_exit(int input)190 extern "C" void be_sound_exit(int input)
191 {
192    if (input) {
193       return;
194    }
195    be_sound_active = false;
196    be_sound->Stop();
197 
198    acquire_sem(_be_sound_stream_lock);
199    _mixer_exit();
200    release_sem(_be_sound_stream_lock);
201 
202    delete be_sound;
203    delete locker;
204 
205    be_sound = NULL;
206    locker = NULL;
207 }
208 
209 
210 
211 /* be_sound_lock_voice:
212  *  Locks audio stream for exclusive access.
213  */
be_sound_lock_voice(int voice,int start,int end)214 extern "C" void *be_sound_lock_voice(int voice, int start, int end)
215 {
216    if (!be_sound_stream_locked) {
217       be_sound_stream_locked = true;
218       acquire_sem(_be_sound_stream_lock);
219    }
220    return NULL;
221 }
222 
223 
224 
225 /* be_sound_unlock_voice:
226  *  Unlocks audio stream.
227  */
be_sound_unlock_voice(int voice)228 void be_sound_unlock_voice(int voice)
229 {
230    if (be_sound_stream_locked) {
231       be_sound_stream_locked = false;
232       release_sem(_be_sound_stream_lock);
233    }
234 }
235 
236 
237 
238 /* be_sound_buffer_size:
239  *  Returns the current buffer size, for use by the audiostream code.
240  */
be_sound_buffer_size()241 extern "C" int be_sound_buffer_size()
242 {
243    return be_sound_bufsize / (_sound_bits / 8) / (_sound_stereo ? 2 : 1);
244 }
245 
246 
247 
248 /* be_sound_set_mixer_volume:
249  *  Set mixer volume.
250  */
be_sound_set_mixer_volume(int volume)251 extern "C" int be_sound_set_mixer_volume(int volume)
252 {
253    if (!be_sound)
254       return -1;
255 
256    be_sound->SetVolume((float)volume / 255.0);
257 
258    return 0;
259 }
260 
261 
262 
263 /* be_sound_get_mixer_volume:
264  *  Set mixer volume.
265  */
be_sound_get_mixer_volume(void)266 extern "C" int be_sound_get_mixer_volume(void)
267 {
268    if (!be_sound)
269       return -1;
270 
271    return (int)(be_sound->Volume() * 255.0);
272 }
273 
274 
275 /* be_sound_suspend:
276  *  Pauses the sound output.
277  */
be_sound_suspend(void)278 extern "C" void be_sound_suspend(void)
279 {
280    if (!be_sound)
281       return;
282    locker->Lock();
283    be_sound_active = false;
284    locker->Unlock();
285 }
286 
287 
288 
289 /* be_sound_resume:
290  *  Resumes the sound output.
291  */
be_sound_resume(void)292 extern "C" void be_sound_resume(void)
293 {
294    if (!be_sound)
295       return;
296    locker->Lock();
297    be_sound_active = true;
298    locker->Unlock();
299 }
300