1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Allegro mixer to DirectSound driver.
12 *
13 * By Robin Burrows.
14 *
15 * Based on original src/win/wdsound.c by Stefan Schimanski
16 * and src/unix/oss.c by Joshua Heyer.
17 *
18 * Bugfixes by Javier Gonzalez.
19 *
20 * See readme.txt for copyright information.
21 */
22
23
24 #define DIRECTSOUND_VERSION 0x0300
25
26 #include "allegro.h"
27 #include "allegro/internal/aintern.h"
28 #include "allegro/platform/aintwin.h"
29
30 #ifndef SCAN_DEPEND
31 #ifdef ALLEGRO_MINGW32
32 #undef MAKEFOURCC
33 #endif
34
35 #include <mmsystem.h>
36 #include <dsound.h>
37 #include <math.h>
38
39 #ifdef ALLEGRO_MSVC
40 #include <mmreg.h>
41 #endif
42 #endif
43
44 #ifndef ALLEGRO_WINDOWS
45 #error something is wrong with the makefile
46 #endif
47
48 #define PREFIX_I "al-dsndmix INFO: "
49 #define PREFIX_W "al-dsndmix WARNING: "
50 #define PREFIX_E "al-dsndmix ERROR: "
51
52
53 static int digi_dsoundmix_detect(int input);
54 static int digi_dsoundmix_init(int input, int voices);
55 static void digi_dsoundmix_exit(int input);
56 static int digi_dsoundmix_set_mixer_volume(int volume);
57 static int digi_dsoundmix_get_mixer_volume(void);
58 static int digi_dsoundmix_buffer_size(void);
59
60
61 /* template driver: will be cloned for each device */
62 static DIGI_DRIVER digi_dsoundmix =
63 {
64 0,
65 empty_string,
66 empty_string,
67 empty_string,
68 0, // available voices
69 0, // voice number offset
70 MIXER_MAX_SFX, // maximum voices we can support
71 MIXER_DEF_SFX, // default number of voices to use
72
73 /* setup routines */
74 digi_dsoundmix_detect,
75 digi_dsoundmix_init,
76 digi_dsoundmix_exit,
77 digi_dsoundmix_set_mixer_volume,
78 digi_dsoundmix_get_mixer_volume,
79
80 /* audiostream locking functions */
81 NULL, // AL_METHOD(void *, lock_voice, (int voice, int start, int end));
82 NULL, // AL_METHOD(void, unlock_voice, (int voice));
83 digi_dsoundmix_buffer_size,
84
85 /* voice control functions */
86 _mixer_init_voice,
87 _mixer_release_voice,
88 _mixer_start_voice,
89 _mixer_stop_voice,
90 _mixer_loop_voice,
91
92 /* position control functions */
93 _mixer_get_position,
94 _mixer_set_position,
95
96 /* volume control functions */
97 _mixer_get_volume,
98 _mixer_set_volume,
99 _mixer_ramp_volume,
100 _mixer_stop_volume_ramp,
101
102 /* pitch control functions */
103 _mixer_get_frequency,
104 _mixer_set_frequency,
105 _mixer_sweep_frequency,
106 _mixer_stop_frequency_sweep,
107
108 /* pan control functions */
109 _mixer_get_pan,
110 _mixer_set_pan,
111 _mixer_sweep_pan,
112 _mixer_stop_pan_sweep,
113
114 /* effect control functions */
115 _mixer_set_echo,
116 _mixer_set_tremolo,
117 _mixer_set_vibrato,
118
119 /* input functions */
120 0, // int rec_cap_bits;
121 0, // int rec_cap_stereo;
122 digi_directsound_rec_cap_rate,
123 digi_directsound_rec_cap_param,
124 digi_directsound_rec_source,
125 digi_directsound_rec_start,
126 digi_directsound_rec_stop,
127 digi_directsound_rec_read
128 };
129
130
131 #define MAX_DRIVERS 16
132 static char *driver_names[MAX_DRIVERS];
133 static LPGUID driver_guids[MAX_DRIVERS];
134
135
136 #define USE_NEW_CODE 0
137
138 /* sound driver globals */
139 static LPDIRECTSOUND directsound = NULL;
140 static LPDIRECTSOUNDBUFFER prim_buf = NULL;
141 static LPDIRECTSOUNDBUFFER alleg_buf = NULL;
142 static long int initial_volume;
143 static int _freq, _bits, _stereo;
144 static int alleg_to_dsound_volume[256];
145 static unsigned int digidsbufsize;
146 static unsigned char *digidsbufdata;
147 #if !USE_NEW_CODE
148 static unsigned int bufdivs = 16, digidsbufpos;
149 #else
150 static int digidsbufdirty;
151 #endif
152 static int alleg_buf_paused = FALSE;
153 static int alleg_buf_vol;
154
155
156
157 /* ds_err:
158 * Returns a DirectSound error string.
159 */
160 #ifdef DEBUGMODE
ds_err(long err)161 static char *ds_err(long err)
162 {
163 static char err_str[64];
164
165 switch (err) {
166
167 case DS_OK:
168 _al_sane_strncpy(err_str, "DS_OK", sizeof(err_str));
169 break;
170
171 case DSERR_ALLOCATED:
172 _al_sane_strncpy(err_str, "DSERR_ALLOCATED", sizeof(err_str));
173 break;
174
175 case DSERR_BADFORMAT:
176 _al_sane_strncpy(err_str, "DSERR_BADFORMAT", sizeof(err_str));
177 break;
178
179 case DSERR_INVALIDPARAM:
180 _al_sane_strncpy(err_str, "DSERR_INVALIDPARAM", sizeof(err_str));
181 break;
182
183 case DSERR_NOAGGREGATION:
184 _al_sane_strncpy(err_str, "DSERR_NOAGGREGATION", sizeof(err_str));
185 break;
186
187 case DSERR_OUTOFMEMORY:
188 _al_sane_strncpy(err_str, "DSERR_OUTOFMEMORY", sizeof(err_str));
189 break;
190
191 case DSERR_UNINITIALIZED:
192 _al_sane_strncpy(err_str, "DSERR_UNINITIALIZED", sizeof(err_str));
193 break;
194
195 case DSERR_UNSUPPORTED:
196 _al_sane_strncpy(err_str, "DSERR_UNSUPPORTED", sizeof(err_str));
197 break;
198
199 default:
200 _al_sane_strncpy(err_str, "DSERR_UNKNOWN", sizeof(err_str));
201 break;
202 }
203
204 return err_str;
205 }
206 #else
207 #define ds_err(hr) "\0"
208 #endif
209
210
211
212 /* _get_dsalmix_driver:
213 * System driver hook for listing the available sound drivers. This
214 * generates the device list at runtime, to match whatever DirectSound
215 * devices are available.
216 */
_get_dsalmix_driver(char * name,LPGUID guid,int num)217 DIGI_DRIVER *_get_dsalmix_driver(char *name, LPGUID guid, int num)
218 {
219 DIGI_DRIVER *driver;
220
221 driver = _AL_MALLOC(sizeof(DIGI_DRIVER));
222 if (!driver)
223 return NULL;
224
225 memcpy(driver, &digi_dsoundmix, sizeof(DIGI_DRIVER));
226
227 driver->id = DIGI_DIRECTAMX(num);
228
229 driver_names[num] = _AL_MALLOC_ATOMIC(strlen(name)+10);
230 if (driver_names[num]) {
231 _al_sane_strncpy(driver_names[num], "Allegmix ", strlen(name)+10);
232 _al_sane_strncpy(driver_names[num]+9, name, strlen(name)+1);
233 driver->ascii_name = driver_names[num];
234 }
235
236 driver_guids[num] = guid;
237
238 return driver;
239 }
240
241
242
243 /* _free_win_dsalmix_name_list
244 * Helper function for freeing dynamically generated driver names.
245 */
_free_win_dsalmix_name_list(void)246 void _free_win_dsalmix_name_list(void)
247 {
248 int i = 0;
249 for (i = 0; i < MAX_DRIVERS; i++) {
250 if (driver_names[i]) _AL_FREE(driver_names[i]);
251 }
252 }
253
254
255
256 /* create_dsound_buffer:
257 * Worker function for creating a DirectSound buffer.
258 */
create_dsound_buffer(int len,int freq,int bits,int stereo,int vol)259 static LPDIRECTSOUNDBUFFER create_dsound_buffer(int len, int freq, int bits, int stereo, int vol)
260 {
261 LPDIRECTSOUNDBUFFER snd_buf;
262 WAVEFORMATEX wf;
263 DSBUFFERDESC dsbdesc;
264 HRESULT hr;
265
266 /* setup wave format structure */
267 memset(&wf, 0, sizeof(WAVEFORMATEX));
268 wf.wFormatTag = WAVE_FORMAT_PCM;
269 wf.nChannels = stereo ? 2 : 1;
270 wf.nSamplesPerSec = freq;
271 wf.wBitsPerSample = bits;
272 wf.nBlockAlign = bits * (stereo ? 2 : 1) / 8;
273 wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
274
275 /* setup DSBUFFERDESC structure */
276 memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
277 dsbdesc.dwSize = sizeof(DSBUFFERDESC);
278
279 /* need volume control and global focus */
280 dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS |
281 DSBCAPS_GETCURRENTPOSITION2;
282
283 dsbdesc.dwBufferBytes = len * (bits / 8) * (stereo ? 2 : 1);
284 dsbdesc.lpwfxFormat = &wf;
285
286 /* create buffer */
287 hr = IDirectSound_CreateSoundBuffer(directsound, &dsbdesc, &snd_buf, NULL);
288 if (FAILED(hr)) {
289 _TRACE(PREFIX_E "create_directsound_buffer() failed (%s).\n", ds_err(hr));
290 _TRACE(PREFIX_E " - %d Hz, %s, %d bits\n", freq, stereo ? "stereo" : "mono", bits);
291 return NULL;
292 }
293
294 /* set volume */
295 IDirectSoundBuffer_SetVolume(snd_buf, alleg_to_dsound_volume[CLAMP(0, vol, 255)]);
296
297 return snd_buf;
298 }
299
300
301
302 /* digi_dsoundmix_mixer_callback:
303 * Callback function to update sound in the DS buffer.
304 */
digi_dsoundmix_mixer_callback(void)305 static void digi_dsoundmix_mixer_callback(void)
306 {
307 LPVOID lpvPtr1, lpvPtr2;
308 DWORD dwBytes1, dwBytes2;
309 DWORD playcurs, writecurs;
310 HRESULT hr;
311 int switch_mode;
312
313 /* handle display switchs */
314 switch_mode = get_display_switch_mode();
315
316 if (alleg_buf_paused) {
317 if (_win_app_foreground ||
318 (switch_mode == SWITCH_BACKGROUND) || (switch_mode == SWITCH_BACKAMNESIA)) {
319 /* get current state of the sound buffer */
320 hr = IDirectSoundBuffer_GetStatus(alleg_buf, &dwBytes1);
321 if ((hr == DS_OK) && (dwBytes1 & DSBSTATUS_BUFFERLOST)) {
322 if(IDirectSoundBuffer_Restore(alleg_buf) != DS_OK)
323 return;
324 IDirectSoundBuffer_SetVolume(alleg_buf, alleg_buf_vol);
325 }
326
327 alleg_buf_paused = FALSE;
328 IDirectSoundBuffer_Play(alleg_buf, 0, 0, DSBPLAY_LOOPING);
329 }
330 else
331 return;
332 }
333 else {
334 if (!_win_app_foreground &&
335 ((switch_mode == SWITCH_PAUSE) || (switch_mode == SWITCH_AMNESIA))) {
336 alleg_buf_paused = TRUE;
337 IDirectSoundBuffer_Stop(alleg_buf);
338 return;
339 }
340 }
341
342 #if USE_NEW_CODE /* this should work, dammit */
343 /* write data into the buffer */
344 if (digidsbufdirty) {
345 _mix_some_samples((uintptr_t)digidsbufdata, 0, TRUE);
346 digidsbufdirty = FALSE;
347 }
348
349 hr = IDirectSoundBuffer_GetCurrentPosition(alleg_buf, &playcurs, &writecurs);
350 if (FAILED(hr))
351 return;
352
353 if (((playcurs-writecurs)%(digidsbufsize*2)) < digidsbufsize)
354 return;
355
356 /* Consider the buffer used. Even if the buffer was lost, mark the data as old
357 so the mixer doesn't stall */
358 digidsbufdirty = TRUE;
359
360 hr = IDirectSoundBuffer_Lock(alleg_buf, 0, digidsbufsize,
361 &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2,
362 DSBLOCK_FROMWRITECURSOR);
363
364 /* only try to restore the buffer once. don't wait around forever */
365 if (hr == DSERR_BUFFERLOST) {
366 if(IDirectSoundBuffer_Restore(alleg_buf) != DS_OK)
367 return;
368
369 IDirectSoundBuffer_Play(alleg_buf, 0, 0, DSBPLAY_LOOPING);
370 IDirectSoundBuffer_SetVolume(alleg_buf, alleg_buf_vol);
371 hr = IDirectSoundBuffer_Lock(alleg_buf, 0, digidsbufsize,
372 &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2,
373 DSBLOCK_FROMWRITECURSOR);
374 }
375
376 if (FAILED(hr))
377 return;
378
379 /* if the first buffer has enough room, put it all there */
380 if(dwBytes1 >= digidsbufsize) {
381 dwBytes1 = digidsbufsize;
382 memcpy(lpvPtr1, digidsbufdata, dwBytes1);
383 dwBytes2 = 0;
384 }
385 /* else, sput the first part into the first buffer, and the rest into the
386 second */
387 else {
388 memcpy(lpvPtr1, digidsbufdata, dwBytes1);
389 dwBytes2 = digidsbufsize-dwBytes1;
390 memcpy(lpvPtr2, digidsbufdata+dwBytes1, dwBytes2);
391 }
392
393 IDirectSoundBuffer_Unlock(alleg_buf, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
394 #else
395 hr = IDirectSoundBuffer_GetCurrentPosition(alleg_buf, &playcurs, &writecurs);
396 if (FAILED(hr))
397 return;
398
399 writecurs /= (digidsbufsize/bufdivs);
400 writecurs += 8;
401
402 while (writecurs > (bufdivs-1))
403 writecurs -= bufdivs;
404
405 /* avoid locking the buffer if no data to write */
406 if (writecurs == digidsbufpos)
407 return;
408
409 hr = IDirectSoundBuffer_Lock(alleg_buf, 0, 0,
410 &lpvPtr1, &dwBytes1,
411 &lpvPtr2, &dwBytes2,
412 DSBLOCK_FROMWRITECURSOR | DSBLOCK_ENTIREBUFFER);
413
414 if (FAILED(hr))
415 return;
416
417 /* write data into the buffer */
418 while (writecurs != digidsbufpos) {
419 if (lpvPtr2) {
420 memcpy((char*)lpvPtr2 + (((dwBytes1+dwBytes2)/bufdivs)*digidsbufpos),
421 digidsbufdata + (((dwBytes1+dwBytes2)/bufdivs)*digidsbufpos),
422 (dwBytes1+dwBytes2)/bufdivs);
423 }
424 else {
425 memcpy((char*)lpvPtr1 + (((dwBytes1)/bufdivs)*digidsbufpos),
426 digidsbufdata + (((dwBytes1)/bufdivs)*digidsbufpos),
427 (dwBytes1)/bufdivs);
428 }
429
430 if (++digidsbufpos > (bufdivs-1))
431 digidsbufpos = 0;
432
433 _mix_some_samples((uintptr_t) (digidsbufdata+(((dwBytes1+dwBytes2)/bufdivs)*digidsbufpos)), 0, TRUE);
434 }
435
436 IDirectSoundBuffer_Unlock(alleg_buf, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
437 #endif
438 }
439
440
441
442 /* digi_dsoundmix_detect:
443 */
digi_dsoundmix_detect(int input)444 static int digi_dsoundmix_detect(int input)
445 {
446 HRESULT hr;
447 int id;
448
449 /* deduce our device number from the driver ID code */
450 id = ((digi_driver->id >> 8) & 0xFF) - 'A';
451
452 if (input)
453 return digi_directsound_capture_detect(driver_guids[id]);
454
455 if (!directsound) {
456 /* initialize DirectSound interface */
457 hr = DirectSoundCreate(driver_guids[id], &directsound, NULL);
458 if (FAILED(hr)) {
459 _TRACE(PREFIX_E "DirectSound interface creation failed during detect (%s)\n", ds_err(hr));
460 return 0;
461 }
462
463 _TRACE(PREFIX_I "DirectSound interface successfully created\n");
464
465 /* release DirectSound */
466 IDirectSound_Release(directsound);
467 directsound = NULL;
468 }
469
470 return 1;
471 }
472
473
474
475 /* digi_dsoundmix_init:
476 */
digi_dsoundmix_init(int input,int voices)477 static int digi_dsoundmix_init(int input, int voices)
478 {
479 LPVOID lpvPtr1, lpvPtr2;
480 DWORD dwBytes1, dwBytes2;
481 HRESULT hr;
482 DSCAPS dscaps;
483 DSBUFFERDESC desc;
484 WAVEFORMATEX format;
485 HWND allegro_wnd = win_get_window();
486 char tmp1[128], tmp2[128];
487 int v, id;
488
489 /* deduce our device number from the driver ID code */
490 id = ((digi_driver->id >> 8) & 0xFF) - 'A';
491
492 if (input)
493 return digi_directsound_capture_init(driver_guids[id]);
494
495 digi_driver->voices = voices;
496
497 /* initialize DirectSound interface */
498 hr = DirectSoundCreate(driver_guids[id], &directsound, NULL);
499 if (FAILED(hr)) {
500 _TRACE(PREFIX_E "Can't create DirectSound interface (%s)\n", ds_err(hr));
501 goto Error;
502 }
503
504 /* set cooperative level */
505 hr = IDirectSound_SetCooperativeLevel(directsound, allegro_wnd, DSSCL_PRIORITY);
506 if (FAILED(hr))
507 _TRACE(PREFIX_W "Can't set DirectSound cooperative level (%s)\n", ds_err(hr));
508 else
509 _TRACE(PREFIX_I "DirectSound cooperation level set to DSSCL_PRIORITY\n");
510
511 /* get hardware capabilities */
512 dscaps.dwSize = sizeof(DSCAPS);
513 hr = IDirectSound_GetCaps(directsound, &dscaps);
514 if (FAILED(hr)) {
515 _TRACE(PREFIX_E "Can't get DirectSound caps (%s)\n", ds_err(hr));
516 goto Error;
517 }
518
519 /* For some reason the audio driver on my machine doesn't seem to set either
520 * PRIMARY16BIT or PRIMARY8BIT; of course it actually does support 16-bit
521 * sound.
522 */
523 if (((dscaps.dwFlags & DSCAPS_PRIMARY16BIT) || !(dscaps.dwFlags & DSCAPS_PRIMARY8BIT))
524 && ((_sound_bits >= 16) || (_sound_bits <= 0)))
525 _bits = 16;
526 else
527 _bits = 8;
528
529 if ((dscaps.dwFlags & DSCAPS_PRIMARYSTEREO) && _sound_stereo)
530 _stereo = 1;
531 else
532 _stereo = 0;
533
534 /* Try to set the requested frequency */
535 if ((dscaps.dwMaxSecondarySampleRate > (DWORD)_sound_freq) && (_sound_freq > 0))
536 _freq = _sound_freq;
537 /* If no frequency is specified, make sure it's clamped to a reasonable value
538 by default */
539 else if ((_sound_freq <= 0) && (dscaps.dwMaxSecondarySampleRate > 44100))
540 _freq = 44100;
541 else
542 _freq = dscaps.dwMaxSecondarySampleRate;
543
544 _TRACE(PREFIX_I "DirectSound caps: %u bits, %s, %uHz\n", _bits, _stereo ? "stereo" : "mono", _freq);
545
546 memset(&desc, 0, sizeof(DSBUFFERDESC));
547 desc.dwSize = sizeof(DSBUFFERDESC);
548 desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GLOBALFOCUS;// | DSBCAPS_CTRLVOLUME | DSBCAPS_STICKYFOCUS;
549
550 hr = IDirectSound_CreateSoundBuffer(directsound, &desc, &prim_buf, NULL);
551 if (FAILED(hr))
552 _TRACE(PREFIX_W "Can't create primary buffer (%s)\nGlobal volume control won't be available\n", ds_err(hr));
553
554 if (prim_buf) {
555 hr = IDirectSoundBuffer_GetFormat(prim_buf, &format, sizeof(format), NULL);
556 if (FAILED(hr)) {
557 _TRACE(PREFIX_W "Can't get primary buffer format (%s)\n", ds_err(hr));
558 }
559 else {
560 format.nChannels = (_stereo ? 2 : 1);
561 format.nSamplesPerSec = _freq;
562 format.wBitsPerSample = _bits;
563 format.nBlockAlign = (format.wBitsPerSample * format.nChannels) >> 3;
564 format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
565
566 hr = IDirectSoundBuffer_SetFormat(prim_buf, &format);
567 if (FAILED(hr))
568 _TRACE(PREFIX_W "Can't set primary buffer format (%s)\n", ds_err(hr));
569
570 hr = IDirectSoundBuffer_GetFormat(prim_buf, &format, sizeof(format), NULL);
571 if (FAILED(hr)) {
572 _TRACE(PREFIX_W "Can't get primary buffer format (%s)\n", ds_err(hr));
573 }
574 else {
575 _TRACE(PREFIX_I "primary format:\n");
576 _TRACE(PREFIX_I " %u channels\n %u Hz\n %u AvgBytesPerSec\n %u BlockAlign\n %u bits\n %u size\n",
577 format.nChannels, format.nSamplesPerSec, format.nAvgBytesPerSec,
578 format.nBlockAlign, format.wBitsPerSample, format.cbSize);
579 }
580 }
581 }
582
583 /* setup volume lookup table */
584 alleg_to_dsound_volume[0] = DSBVOLUME_MIN;
585 for (v = 1; v < 256; v++) {
586 int dB = DSBVOLUME_MAX + 2000.0*log10(v/255.0);
587 alleg_to_dsound_volume[v] = MAX(DSBVOLUME_MIN, dB);
588 }
589
590 /* create the sound buffer to mix into */
591 alleg_buf = create_dsound_buffer(get_config_int(uconvert_ascii("sound", tmp1),
592 uconvert_ascii("dsound_numfrags", tmp2),
593 6) * 1024,
594 _freq, _bits, _stereo, 255);
595 if(!alleg_buf) {
596 _TRACE(PREFIX_E "Can't create mixing buffer\n");
597 return -1;
598 }
599
600 /* fill the sound buffer with zeros */
601 hr = IDirectSoundBuffer_Lock(alleg_buf, 0, 0, &lpvPtr1, &dwBytes1,
602 &lpvPtr2, &dwBytes2, DSBLOCK_ENTIREBUFFER);
603
604 if (FAILED(hr)) {
605 _TRACE(PREFIX_E "Can't lock sound buffer (%s)\n", ds_err(hr));
606 return -1;
607 }
608
609 memset(lpvPtr1, 0, dwBytes1);
610 digidsbufsize = dwBytes1;
611
612 if (lpvPtr2) {
613 _TRACE(PREFIX_E "Second buffer set when locking buffer. Error?\n");
614 memset(lpvPtr2, 0, dwBytes2);
615 digidsbufsize += dwBytes2;
616 }
617
618 IDirectSoundBuffer_Unlock(alleg_buf, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
619
620 _TRACE(PREFIX_I "Sound buffer length is %u\n", digidsbufsize);
621
622 /* shouldn't ever happen */
623 if (digidsbufsize&1023) {
624 _TRACE(PREFIX_E "Sound buffer is not multiple of 1024, failed\n");
625 return -1;
626 }
627
628 #if USE_NEW_CODE
629 digidsbufsize /= 2;
630 #endif
631 digidsbufdata = _AL_MALLOC_ATOMIC(digidsbufsize);
632 if (!digidsbufdata) {
633 _TRACE(PREFIX_E "Can't create temp buffer\n");
634 return -1;
635 }
636
637 #if USE_NEW_CODE
638 if (_mixer_init(digidsbufsize / (_bits /8), _freq, _stereo,
639 ((_bits == 16) ? 1 : 0), &digi_driver->voices) != 0) {
640 _TRACE(PREFIX_E "Can't init software mixer\n");
641 return -1;
642 }
643 #else
644 bufdivs = digidsbufsize/1024;
645 if (_mixer_init((digidsbufsize / (_bits /8)) / bufdivs, _freq,
646 _stereo, ((_bits == 16) ? 1 : 0), &digi_driver->voices) != 0) {
647 _TRACE(PREFIX_E "Can't init software mixer\n");
648 return -1;
649 }
650
651 _mix_some_samples((uintptr_t)digidsbufdata, 0, TRUE);
652 #endif
653
654 /* get primary buffer volume */
655 IDirectSoundBuffer_GetVolume(alleg_buf, &initial_volume);
656 alleg_buf_vol = initial_volume;
657
658 /* mark the buffer as paused, so the mixer callback will start it */
659 alleg_buf_paused = TRUE;
660 #if USE_NEW_CODE
661 digidsbufdirty = TRUE;
662 #endif
663 install_int(digi_dsoundmix_mixer_callback, 20); /* 50 Hz */
664
665 return 0;
666
667 Error:
668 _TRACE(PREFIX_E "digi_directsound_init() failed\n");
669 digi_dsoundmix_exit(0);
670 return -1;
671 }
672
673
674
675 /* digi_dsoundmix_exit:
676 */
digi_dsoundmix_exit(int input)677 static void digi_dsoundmix_exit(int input)
678 {
679 if (input) {
680 digi_directsound_capture_exit();
681 return;
682 }
683
684 /* stop playing */
685 remove_int(digi_dsoundmix_mixer_callback);
686
687 if (digidsbufdata) {
688 _AL_FREE(digidsbufdata);
689 digidsbufdata = NULL;
690 }
691
692 /* destroy mixer buffer */
693 if (alleg_buf) {
694 IDirectSoundBuffer_Release(alleg_buf);
695 alleg_buf = NULL;
696 }
697
698 /* destroy primary buffer */
699 if (prim_buf) {
700 /* restore primary buffer initial volume */
701 IDirectSoundBuffer_SetVolume(prim_buf, initial_volume);
702
703 IDirectSoundBuffer_Release(prim_buf);
704 prim_buf = NULL;
705 }
706
707 /* shutdown DirectSound */
708 if (directsound) {
709 IDirectSound_Release(directsound);
710 directsound = NULL;
711 }
712 }
713
714
715
716 /* digi_dsoundmix_set_mixer_volume:
717 */
digi_dsoundmix_set_mixer_volume(int volume)718 static int digi_dsoundmix_set_mixer_volume(int volume)
719 {
720 if (prim_buf) {
721 alleg_buf_vol = alleg_to_dsound_volume[CLAMP(0, volume, 255)];
722 IDirectSoundBuffer_SetVolume(alleg_buf, alleg_buf_vol);
723 }
724
725 return 0;
726 }
727
728
729
730 /* digi_dsoundmix_get_mixer_volume:
731 */
digi_dsoundmix_get_mixer_volume(void)732 static int digi_dsoundmix_get_mixer_volume(void)
733 {
734 LONG vol;
735
736 if (!prim_buf)
737 return -1;
738
739 IDirectSoundBuffer_GetVolume(alleg_buf, &vol);
740 vol = CLAMP(0, pow(10, (vol/2000.0))*255.0 - DSBVOLUME_MAX, 255);
741
742 return vol;
743 }
744
745
746
747 /* digi_dsoundmix_buffer_size:
748 */
digi_dsoundmix_buffer_size(void)749 static int digi_dsoundmix_buffer_size(void)
750 {
751 return digidsbufsize / (_bits / 8) / (_stereo ? 2 : 1);
752 }
753