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