1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * DirectSound sound driver.
12 *
13 * By Stefan Schimanski.
14 *
15 * Various bugfixes by Patrick Hogan.
16 *
17 * Custom loop points support added by Eric Botcazou.
18 *
19 * Backward playing support, bidirectional looping support
20 * and bugfixes by Javier Gonzalez.
21 *
22 * See readme.txt for copyright information.
23 */
24
25
26 #define DIRECTSOUND_VERSION 0x0300
27
28 #include "allegro.h"
29 #include "allegro/internal/aintern.h"
30 #include "allegro/platform/aintwin.h"
31
32 #ifndef SCAN_DEPEND
33 #ifdef ALLEGRO_MINGW32
34 #undef MAKEFOURCC
35 #endif
36
37 #include <mmsystem.h>
38 #include <dsound.h>
39 #include <math.h>
40
41 #ifdef ALLEGRO_MSVC
42 #include <mmreg.h>
43 #endif
44 #endif
45
46 #ifndef ALLEGRO_WINDOWS
47 #error something is wrong with the makefile
48 #endif
49
50 #define PREFIX_I "al-dsound INFO: "
51 #define PREFIX_W "al-dsound WARNING: "
52 #define PREFIX_E "al-dsound ERROR: "
53
54
55 static int digi_directsound_detect(int input);
56 static int digi_directsound_init(int input, int voices);
57 static void digi_directsound_exit(int input);
58 static int digi_directsound_set_mixer_volume(int volume);
59 static int digi_directsound_get_mixer_volume(void);
60
61 static void digi_directsound_init_voice(int voice, AL_CONST SAMPLE * sample);
62 static void digi_directsound_release_voice(int voice);
63 static void digi_directsound_start_voice(int voice);
64 static void digi_directsound_stop_voice(int voice);
65 static void digi_directsound_loop_voice(int voice, int playmode);
66
67 static void *digi_directsound_lock_voice(int voice, int start, int end);
68 static void digi_directsound_unlock_voice(int voice);
69
70 static int digi_directsound_get_position(int voice);
71 static void digi_directsound_set_position(int voice, int position);
72
73 static int digi_directsound_get_volume(int voice);
74 static void digi_directsound_set_volume(int voice, int volume);
75
76 static int digi_directsound_get_frequency(int voice);
77 static void digi_directsound_set_frequency(int voice, int frequency);
78
79 static int digi_directsound_get_pan(int voice);
80 static void digi_directsound_set_pan(int voice, int pan);
81
82
83 /* template driver: will be cloned for each device */
84 static DIGI_DRIVER digi_directsound =
85 {
86 0,
87 empty_string,
88 empty_string,
89 empty_string,
90 0, // available voices
91 0, // voice number offset
92 16, // maximum voices we can support
93 4, // default number of voices to use
94
95 /* setup routines */
96 digi_directsound_detect,
97 digi_directsound_init,
98 digi_directsound_exit,
99 digi_directsound_set_mixer_volume,
100 digi_directsound_get_mixer_volume,
101
102 /* audiostream locking functions */
103 digi_directsound_lock_voice,
104 digi_directsound_unlock_voice,
105 NULL, // AL_METHOD(int, buffer_size, (void));
106
107 /* voice control functions */
108 digi_directsound_init_voice,
109 digi_directsound_release_voice,
110 digi_directsound_start_voice,
111 digi_directsound_stop_voice,
112 digi_directsound_loop_voice,
113
114 /* position control functions */
115 digi_directsound_get_position,
116 digi_directsound_set_position,
117
118 /* volume control functions */
119 digi_directsound_get_volume,
120 digi_directsound_set_volume,
121 NULL, // AL_METHOD(void, ramp_volume, (int voice, int time, int endvol));
122 NULL, // AL_METHOD(void, stop_volume_ramp, (int voice));
123
124 /* pitch control functions */
125 digi_directsound_get_frequency,
126 digi_directsound_set_frequency,
127 NULL, // AL_METHOD(void, sweep_frequency, (int voice, int time, int endfreq));
128 NULL, // AL_METHOD(void, stop_frequency_sweep, (int voice));
129
130 /* pan control functions */
131 digi_directsound_get_pan,
132 digi_directsound_set_pan,
133 NULL, // AL_METHOD(void, sweep_pan, (int voice, int time, int endpan));
134 NULL, // AL_METHOD(void, stop_pan_sweep, (int voice));
135
136 /* effect control functions */
137 NULL, // AL_METHOD(void, set_echo, (int voice, int strength, int delay));
138 NULL, // AL_METHOD(void, set_tremolo, (int voice, int rate, int depth));
139 NULL, // AL_METHOD(void, set_vibrato, (int voice, int rate, int depth));
140
141 /* input functions */
142 0, /* int rec_cap_bits; */
143 0, /* int rec_cap_stereo; */
144 digi_directsound_rec_cap_rate,
145 digi_directsound_rec_cap_param,
146 digi_directsound_rec_source,
147 digi_directsound_rec_start,
148 digi_directsound_rec_stop,
149 digi_directsound_rec_read
150 };
151
152
153 /* sound driver globals */
154 static LPDIRECTSOUND directsound = NULL;
155 static LPDIRECTSOUNDBUFFER prim_buf = NULL;
156 static long int initial_volume;
157 static int _freq, _bits, _stereo;
158 static int alleg_to_dsound_volume[256];
159 static int alleg_to_dsound_pan[256];
160
161
162 /* internal driver representation of a voice */
163 struct DIRECTSOUND_VOICE {
164 int bits;
165 int bytes_per_sample;
166 int freq, pan, vol;
167 int stereo;
168 int reversed;
169 int bidir;
170 int len;
171 unsigned char *data;
172 int loop_offset;
173 int loop_len;
174 int looping;
175 void *lock_buf_a;
176 long lock_size_a;
177 LPDIRECTSOUNDBUFFER ds_buffer;
178 LPDIRECTSOUNDBUFFER ds_loop_buffer;
179 LPDIRECTSOUNDBUFFER ds_locked_buffer;
180 };
181
182 static struct DIRECTSOUND_VOICE *ds_voices;
183
184
185 /* dynamically generated driver list */
186 static _DRIVER_INFO *driver_list = NULL;
187
188 #define MAX_DRIVERS 16
189 static int num_drivers = 0;
190 static char *driver_names[MAX_DRIVERS];
191 static LPGUID driver_guids[MAX_DRIVERS];
192
193
194
195 /* DSEnumCallback:
196 * Callback function for enumerating the available DirectSound drivers.
197 */
DSEnumCallback(LPGUID lpGuid,LPCSTR lpcstrDescription,LPCSTR lpcstrModule,LPVOID lpContext)198 static BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
199 {
200 if (lpGuid) {
201 driver_guids[num_drivers] = lpGuid;
202 driver_names[num_drivers] = _AL_MALLOC_ATOMIC(strlen(lpcstrDescription)+1);
203 if(driver_names[num_drivers])
204 {
205 _al_sane_strncpy(driver_names[num_drivers], lpcstrDescription, strlen(lpcstrDescription)+1);
206 num_drivers++;
207 }
208 }
209
210 return (num_drivers < MAX_DRIVERS);
211 }
212
213
214
215 /* _get_win_digi_driver_list:
216 * System driver hook for listing the available sound drivers. This
217 * generates the device list at runtime, to match whatever DirectSound
218 * devices are available.
219 */
_get_win_digi_driver_list(void)220 _DRIVER_INFO *_get_win_digi_driver_list(void)
221 {
222 DIGI_DRIVER *driver;
223 HRESULT hr;
224 int i;
225
226 if (!driver_list) {
227 driver_list = _create_driver_list();
228
229 /* enumerate the DirectSound drivers */
230 hr = DirectSoundEnumerate(DSEnumCallback, NULL);
231
232 if (hr == DS_OK) {
233 /* Allegro mixer to DirectSound drivers */
234 for (i=0; i<num_drivers; i++) {
235 driver = _get_dsalmix_driver(driver_names[i], driver_guids[i], i);
236
237 _driver_list_append_driver(&driver_list, driver->id, driver, TRUE);
238 }
239
240 /* pure DirectSound drivers */
241 for (i=0; i<num_drivers; i++) {
242 driver = _AL_MALLOC(sizeof(DIGI_DRIVER));
243 memcpy(driver, &digi_directsound, sizeof(DIGI_DRIVER));
244 driver->id = DIGI_DIRECTX(i);
245 driver->ascii_name = driver_names[i];
246
247 _driver_list_append_driver(&driver_list, driver->id, driver, TRUE);
248 }
249 }
250
251 /* Allegro mixer to WaveOut drivers */
252 for (i=0; i<2; i++) {
253 driver = _get_woalmix_driver(i);
254
255 _driver_list_append_driver(&driver_list, driver->id, driver, TRUE);
256 }
257 }
258
259 return driver_list;
260 }
261
262
263
264 /* _free_win_digi_driver_list:
265 * Helper function for freeing the dynamically generated driver list.
266 */
_free_win_digi_driver_list(void)267 void _free_win_digi_driver_list(void)
268 {
269 int i = 0;
270
271 if (driver_list) {
272 while (driver_list[i].driver) {
273 _AL_FREE(driver_list[i].driver);
274 i++;
275 }
276
277 _destroy_driver_list(driver_list);
278 driver_list = NULL;
279 }
280
281 for (i = 0; i < num_drivers; i++) {
282 _AL_FREE(driver_names[i]);
283 }
284
285 _free_win_dsalmix_name_list();
286 }
287
288
289
290 /* ds_err:
291 * Returns a DirectSound error string.
292 */
293 #ifdef DEBUGMODE
ds_err(long err)294 static char *ds_err(long err)
295 {
296 static char err_str[64];
297
298 switch (err) {
299
300 case DS_OK:
301 _al_sane_strncpy(err_str, "DS_OK", sizeof(err_str));
302 break;
303
304 case DSERR_ALLOCATED:
305 _al_sane_strncpy(err_str, "DSERR_ALLOCATED", sizeof(err_str));
306 break;
307
308 case DSERR_BADFORMAT:
309 _al_sane_strncpy(err_str, "DSERR_BADFORMAT", sizeof(err_str));
310 break;
311
312 case DSERR_INVALIDPARAM:
313 _al_sane_strncpy(err_str, "DSERR_INVALIDPARAM", sizeof(err_str));
314 break;
315
316 case DSERR_NOAGGREGATION:
317 _al_sane_strncpy(err_str, "DSERR_NOAGGREGATION", sizeof(err_str));
318 break;
319
320 case DSERR_OUTOFMEMORY:
321 _al_sane_strncpy(err_str, "DSERR_OUTOFMEMORY", sizeof(err_str));
322 break;
323
324 case DSERR_UNINITIALIZED:
325 _al_sane_strncpy(err_str, "DSERR_UNINITIALIZED", sizeof(err_str));
326 break;
327
328 case DSERR_UNSUPPORTED:
329 _al_sane_strncpy(err_str, "DSERR_UNSUPPORTED", sizeof(err_str));
330 break;
331
332 default:
333 _al_sane_strncpy(err_str, "DSERR_UNKNOWN", sizeof(err_str));
334 break;
335 }
336
337 return err_str;
338 }
339 #else
340 #define ds_err(hr) "\0"
341 #endif
342
343
344
345 /* digi_directsound_detect:
346 */
digi_directsound_detect(int input)347 static int digi_directsound_detect(int input)
348 {
349 HRESULT hr;
350 int id;
351
352 /* deduce our device number from the driver ID code */
353 id = ((digi_driver->id >> 8) & 0xFF) - 'A';
354
355 if (input)
356 return digi_directsound_capture_detect(driver_guids[id]);
357
358 if (!directsound) {
359 /* initialize DirectSound interface */
360 hr = DirectSoundCreate(driver_guids[id], &directsound, NULL);
361 if (FAILED(hr)) {
362 _TRACE(PREFIX_E "DirectSound interface creation failed during detect (%s).\n", ds_err(hr));
363 return 0;
364 }
365
366 _TRACE(PREFIX_I "DirectSound interface successfully created.\n");
367
368 /* release DirectSound interface */
369 IDirectSound_Release(directsound);
370 directsound = NULL;
371 }
372
373 return 1;
374 }
375
376
377
378 /* digi_directsound_init:
379 */
digi_directsound_init(int input,int voices)380 static int digi_directsound_init(int input, int voices)
381 {
382 HRESULT hr;
383 DSCAPS dscaps;
384 DSBUFFERDESC desc;
385 WAVEFORMATEX format;
386 int v, id;
387 HWND allegro_wnd = win_get_window();
388
389 /* deduce our device number from the driver ID code */
390 id = ((digi_driver->id >> 8) & 0xFF) - 'A';
391
392 if (input)
393 return digi_directsound_capture_init(driver_guids[id]);
394
395 digi_driver->voices = voices;
396
397 /* initialize DirectSound interface */
398 hr = DirectSoundCreate(driver_guids[id], &directsound, NULL);
399 if (FAILED(hr)) {
400 _TRACE(PREFIX_E "Can't create DirectSound interface (%s).\n", ds_err(hr));
401 goto Error;
402 }
403
404 /* set cooperative level */
405 hr = IDirectSound_SetCooperativeLevel(directsound, allegro_wnd, DSSCL_PRIORITY);
406 if (FAILED(hr))
407 _TRACE(PREFIX_W "Can't set DirectSound cooperative level (%s).\n", ds_err(hr));
408 else
409 _TRACE(PREFIX_I "DirectSound cooperation level set to PRIORITY.\n");
410
411 /* get hardware capabilities */
412 dscaps.dwSize = sizeof(DSCAPS);
413 hr = IDirectSound_GetCaps(directsound, &dscaps);
414 if (FAILED(hr)) {
415 _TRACE(PREFIX_E "Can't get DirectSound caps (%s).\n", ds_err(hr));
416 goto Error;
417 }
418
419 /* For some reason the audio driver on my machine doesn't seem to set either
420 * PRIMARY16BIT or PRIMARY8BIT; of course it actually does support 16-bit
421 * sound.
422 */
423 if (((dscaps.dwFlags & DSCAPS_PRIMARY16BIT) || !(dscaps.dwFlags & DSCAPS_PRIMARY8BIT))
424 && ((_sound_bits >= 16) || (_sound_bits <= 0)))
425 _bits = 16;
426 else
427 _bits = 8;
428
429 if ((dscaps.dwFlags & DSCAPS_PRIMARYSTEREO) && _sound_stereo)
430 _stereo = 1;
431 else
432 _stereo = 0;
433
434 if ((dscaps.dwMaxSecondarySampleRate > (DWORD)_sound_freq) && (_sound_freq > 0))
435 _freq = _sound_freq;
436 else
437 _freq = dscaps.dwMaxSecondarySampleRate;
438
439 _TRACE(PREFIX_I "DirectSound caps: %u bits, %s, %uHz\n", _bits, _stereo ? "stereo" : "mono", _freq);
440
441 /* create primary buffer */
442 memset(&desc, 0, sizeof(DSBUFFERDESC));
443 desc.dwSize = sizeof(DSBUFFERDESC);
444 desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
445
446 hr = IDirectSound_CreateSoundBuffer(directsound, &desc, &prim_buf, NULL);
447 if (hr != DS_OK) {
448 _TRACE(PREFIX_W "Can't create primary buffer (%s)\nGlobal volume control won't be available.\n", ds_err(hr));
449 }
450
451 /* get current format */
452 if (prim_buf) {
453 hr = IDirectSoundBuffer_GetFormat(prim_buf, &format, sizeof(format), NULL);
454 if (FAILED(hr)) {
455 _TRACE(PREFIX_W "Can't get primary buffer format (%s).\n", ds_err(hr));
456 }
457 else {
458 format.nChannels = _stereo ? 2 : 1;
459 format.nSamplesPerSec = _freq;
460 format.wBitsPerSample = _bits;
461 format.nBlockAlign = (format.wBitsPerSample * format.nChannels) >> 3;
462 format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
463
464 hr = IDirectSoundBuffer_SetFormat(prim_buf, &format);
465 if (FAILED(hr)) {
466 _TRACE(PREFIX_W "Can't set primary buffer format (%s).\n", ds_err(hr));
467 }
468
469 /* output primary format */
470 hr = IDirectSoundBuffer_GetFormat(prim_buf, &format, sizeof(format), NULL);
471 if (FAILED(hr)) {
472 _TRACE(PREFIX_W "Can't get primary buffer format (%s).\n", ds_err(hr));
473 }
474 else {
475 _TRACE(PREFIX_I "primary format:\n");
476 _TRACE(PREFIX_I " %u channels\n %u Hz\n %u AvgBytesPerSec\n %u BlockAlign\n %u bits\n %u size\n",
477 format.nChannels, format.nSamplesPerSec, format.nAvgBytesPerSec,
478 format.nBlockAlign, format.wBitsPerSample, format.cbSize);
479 }
480 }
481
482 /* get primary buffer (global) volume */
483 IDirectSoundBuffer_GetVolume(prim_buf, &initial_volume);
484 }
485
486 /* initialize physical voices */
487 ds_voices = (struct DIRECTSOUND_VOICE *)_AL_MALLOC(sizeof(struct DIRECTSOUND_VOICE) * voices);
488 for (v = 0; v < digi_driver->voices; v++) {
489 ds_voices[v].ds_buffer = NULL;
490 ds_voices[v].ds_loop_buffer = NULL;
491 ds_voices[v].ds_locked_buffer = NULL;
492 }
493
494 /* setup volume lookup table */
495 alleg_to_dsound_volume[0] = DSBVOLUME_MIN;
496 for (v = 1; v < 256; v++)
497 alleg_to_dsound_volume[v] = MAX(DSBVOLUME_MIN, DSBVOLUME_MAX + 2000.0*log10(v/255.0));
498
499 /* setup pan lookup table */
500 alleg_to_dsound_pan[0] = DSBPAN_LEFT;
501 for (v = 1; v < 128; v++)
502 alleg_to_dsound_pan[v] = MAX(DSBPAN_LEFT, DSBPAN_CENTER + 2000.0*log10(v/127.0));
503
504 alleg_to_dsound_pan[255] = DSBPAN_RIGHT;
505 for (v = 128; v < 255; v++)
506 alleg_to_dsound_pan[v] = MIN(DSBPAN_RIGHT, DSBPAN_CENTER - 2000.0*log10((255.0-v)/127.0));
507
508 return 0;
509
510 Error:
511 _TRACE(PREFIX_E "digi_directsound_init() failed.\n");
512 digi_directsound_exit(FALSE);
513 return -1;
514 }
515
516
517
518 /* digi_directsound_exit:
519 */
digi_directsound_exit(int input)520 static void digi_directsound_exit(int input)
521 {
522 int v;
523
524 if (input) {
525 digi_directsound_capture_exit();
526 return;
527 }
528
529 /* destroy physical voices */
530 for (v = 0; v < digi_driver->voices; v++)
531 digi_directsound_release_voice(v);
532
533 _AL_FREE(ds_voices);
534 ds_voices = NULL;
535
536 /* destroy primary buffer */
537 if (prim_buf) {
538 /* restore primary buffer initial volume */
539 IDirectSoundBuffer_SetVolume(prim_buf, initial_volume);
540
541 IDirectSoundBuffer_Release(prim_buf);
542 prim_buf = NULL;
543 }
544
545 /* shutdown DirectSound */
546 if (directsound) {
547 IDirectSound_Release(directsound);
548 directsound = NULL;
549 }
550 }
551
552
553
554 /* digi_directsound_set_mixer_volume:
555 */
digi_directsound_set_mixer_volume(int volume)556 static int digi_directsound_set_mixer_volume(int volume)
557 {
558 int ds_vol;
559
560 if (prim_buf) {
561 ds_vol = alleg_to_dsound_volume[CLAMP(0, volume, 255)];
562 IDirectSoundBuffer_SetVolume(prim_buf, ds_vol);
563 }
564
565 return 0;
566 }
567
568
569
570 /* digi_directsound_get_mixer_volume:
571 */
digi_directsound_get_mixer_volume(void)572 static int digi_directsound_get_mixer_volume(void)
573 {
574 LONG vol;
575
576 if (!prim_buf)
577 return -1;
578
579 IDirectSoundBuffer_GetVolume(prim_buf, &vol);
580 vol = CLAMP(0, pow(10, (vol/2000.0))*255.0 - DSBVOLUME_MAX, 255);
581
582 return vol;
583 }
584
585
586
587 /********************************************************/
588 /*********** voice management functions *****************/
589 /********************************************************/
590
591
592 /* create_dsound_buffer:
593 * Worker function for creating a DirectSound buffer.
594 */
create_dsound_buffer(int len,int freq,int bits,int stereo,int vol,int pan)595 static LPDIRECTSOUNDBUFFER create_dsound_buffer(int len, int freq, int bits, int stereo, int vol, int pan)
596 {
597 LPDIRECTSOUNDBUFFER snd_buf;
598 WAVEFORMATEX wf;
599 DSBUFFERDESC dsbdesc;
600 HRESULT hr;
601 int switch_mode;
602
603 /* setup wave format structure */
604 memset(&wf, 0, sizeof(WAVEFORMATEX));
605 wf.wFormatTag = WAVE_FORMAT_PCM;
606 wf.nChannels = stereo ? 2 : 1;
607 wf.nSamplesPerSec = freq;
608 wf.wBitsPerSample = bits;
609 wf.nBlockAlign = bits * (stereo ? 2 : 1) / 8;
610 wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
611
612 /* setup DSBUFFERDESC structure */
613 memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
614 dsbdesc.dwSize = sizeof(DSBUFFERDESC);
615
616 /* need default controls (pan, volume, frequency) */
617 dsbdesc.dwFlags = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
618
619 switch_mode = get_display_switch_mode();
620 if ((switch_mode == SWITCH_BACKAMNESIA) || (switch_mode == SWITCH_BACKGROUND))
621 dsbdesc.dwFlags |= DSBCAPS_GLOBALFOCUS;
622
623 dsbdesc.dwBufferBytes = len * (bits / 8) * (stereo ? 2 : 1);
624 dsbdesc.lpwfxFormat = &wf;
625
626 /* create buffer */
627 hr = IDirectSound_CreateSoundBuffer(directsound, &dsbdesc, &snd_buf, NULL);
628 if (FAILED(hr)) {
629 _TRACE(PREFIX_E "create_directsound_buffer() failed (%s).\n", ds_err(hr));
630 _TRACE(PREFIX_E " - %d Hz, %s, %d bits\n", freq, stereo ? "stereo" : "mono", bits);
631 return NULL;
632 }
633
634 /* set volume */
635 IDirectSoundBuffer_SetVolume(snd_buf, alleg_to_dsound_volume[CLAMP(0, vol, 255)]);
636
637 /* set pan */
638 IDirectSoundBuffer_SetPan(snd_buf, alleg_to_dsound_pan[CLAMP(0, pan, 255)]);
639
640 return snd_buf;
641 }
642
643
644
645 /* fill_dsound_buffer:
646 * Worker function for copying data to a DirectSound buffer.
647 */
fill_dsound_buffer(LPDIRECTSOUNDBUFFER snd_buf,int offset,int len,int bits,int stereo,int reversed,unsigned char * data)648 static int fill_dsound_buffer(LPDIRECTSOUNDBUFFER snd_buf, int offset, int len, int bits, int stereo, int reversed, unsigned char *data)
649 {
650 void *buf_a;
651 unsigned long int size, size_a;
652 HRESULT hr;
653
654 /* transform from samples to bytes */
655 size = len * (bits / 8) * (stereo ? 2 : 1);
656 offset = offset * (bits / 8) * (stereo ? 2 : 1);
657
658 /* lock the buffer portion */
659 hr = IDirectSoundBuffer_Lock(snd_buf, offset, size, &buf_a, &size_a, NULL, NULL, 0);
660
661 /* if buffer lost, restore and retry lock */
662 if (hr == DSERR_BUFFERLOST) {
663 IDirectSoundBuffer_Restore(snd_buf);
664
665 hr = IDirectSoundBuffer_Lock(snd_buf, offset, size, &buf_a, &size_a, NULL, NULL, 0);
666 if (FAILED(hr)) {
667 _TRACE(PREFIX_E "fill_dsound_buffer() failed (%s).\n", ds_err(hr));
668 return -1;
669 }
670 }
671
672 if (reversed) {
673 if (stereo) {
674 if (bits == 8) {
675 /* 8-bit stereo */
676 unsigned short *read_p = (unsigned short *)data + len - 1;
677 unsigned short *write_p = (unsigned short *)buf_a;
678
679 while (len--)
680 *write_p++ = *read_p--;
681 }
682 else if (bits == 16) {
683 /* 16-bit stereo (conversion needed) */
684 unsigned long *read_p = (unsigned long *)data + len - 1;
685 unsigned long *write_p = (unsigned long *)buf_a;
686
687 while (len--)
688 *write_p++ = *read_p-- ^ 0x80008000;
689 }
690 }
691 else {
692 if (bits == 8) {
693 /* 8-bit mono */
694 unsigned char *read_p = (unsigned char *)data + len - 1;
695 unsigned char *write_p = (unsigned char *)buf_a;
696
697 while (len--)
698 *write_p++ = *read_p--;
699 }
700 else {
701 /* 16-bit mono (conversion needed) */
702 unsigned short *read_p = (unsigned short *)data + len - 1;
703 unsigned short *write_p = (unsigned short *)buf_a;
704
705 while (len--)
706 *write_p++ = *read_p-- ^ 0x8000;
707 }
708 }
709 }
710 else {
711 if (bits == 8) {
712 /* 8-bit mono and stereo */
713 memcpy(buf_a, data, size);
714 }
715 else if (bits == 16) {
716 /* 16-bit mono and stereo (conversion needed) */
717 unsigned short *read_p = (unsigned short *)data;
718 unsigned short *write_p = (unsigned short *)buf_a;
719
720 size >>= 1;
721
722 while (size--)
723 *write_p++ = *read_p++ ^ 0x8000;
724 }
725 }
726
727 /* unlock the buffer */
728 IDirectSoundBuffer_Unlock(snd_buf, buf_a, size_a, NULL, 0);
729
730 return 0;
731 }
732
733
734
735 /* digi_directsound_init_voice:
736 */
digi_directsound_init_voice(int voice,AL_CONST SAMPLE * sample)737 static void digi_directsound_init_voice(int voice, AL_CONST SAMPLE *sample)
738 {
739 ds_voices[voice].bits = sample->bits;
740 ds_voices[voice].bytes_per_sample = (sample->bits/8) * (sample->stereo ? 2 : 1);
741 ds_voices[voice].freq = sample->freq;
742 ds_voices[voice].pan = 128;
743 ds_voices[voice].vol = 255;
744 ds_voices[voice].stereo = sample->stereo;
745 ds_voices[voice].reversed = FALSE;
746 ds_voices[voice].bidir = FALSE;
747 ds_voices[voice].len = sample->len;
748 ds_voices[voice].data = (unsigned char *)sample->data;
749 ds_voices[voice].loop_offset = sample->loop_start;
750 ds_voices[voice].loop_len = sample->loop_end - sample->loop_start;
751 ds_voices[voice].looping = FALSE;
752 ds_voices[voice].lock_buf_a = NULL;
753 ds_voices[voice].lock_size_a = 0;
754 ds_voices[voice].ds_locked_buffer = NULL;
755 ds_voices[voice].ds_loop_buffer = NULL;
756 ds_voices[voice].ds_buffer = create_dsound_buffer(ds_voices[voice].len,
757 ds_voices[voice].freq,
758 ds_voices[voice].bits,
759 ds_voices[voice].stereo,
760 ds_voices[voice].vol,
761 ds_voices[voice].pan);
762 if (!ds_voices[voice].ds_buffer)
763 return;
764
765 fill_dsound_buffer(ds_voices[voice].ds_buffer,
766 0, /* offset */
767 ds_voices[voice].len,
768 ds_voices[voice].bits,
769 ds_voices[voice].stereo,
770 ds_voices[voice].reversed,
771 ds_voices[voice].data);
772 }
773
774
775
776 /* digi_directsound_release_voice:
777 */
digi_directsound_release_voice(int voice)778 static void digi_directsound_release_voice(int voice)
779 {
780 /* just in case */
781 digi_directsound_unlock_voice(voice);
782
783 if (ds_voices[voice].ds_buffer) {
784 IDirectSoundBuffer_Release(ds_voices[voice].ds_buffer);
785 ds_voices[voice].ds_buffer = NULL;
786 }
787
788 if (ds_voices[voice].ds_loop_buffer) {
789 IDirectSoundBuffer_Release(ds_voices[voice].ds_loop_buffer);
790 ds_voices[voice].ds_loop_buffer = NULL;
791 }
792 }
793
794
795
796 /* digi_directsound_start_voice:
797 */
digi_directsound_start_voice(int voice)798 static void digi_directsound_start_voice(int voice)
799 {
800 if (ds_voices[voice].looping && ds_voices[voice].ds_loop_buffer) {
801 IDirectSoundBuffer_Play(ds_voices[voice].ds_loop_buffer, 0, 0, DSBPLAY_LOOPING);
802 }
803 else if (ds_voices[voice].ds_buffer) {
804 IDirectSoundBuffer_Play(ds_voices[voice].ds_buffer, 0, 0,
805 ds_voices[voice].looping ? DSBPLAY_LOOPING : 0);
806 }
807 }
808
809
810
811 /* digi_directsound_stop_voice:
812 */
digi_directsound_stop_voice(int voice)813 static void digi_directsound_stop_voice(int voice)
814 {
815 if (ds_voices[voice].looping && ds_voices[voice].ds_loop_buffer) {
816 IDirectSoundBuffer_Stop(ds_voices[voice].ds_loop_buffer);
817 }
818 else if (ds_voices[voice].ds_buffer) {
819 IDirectSoundBuffer_Stop(ds_voices[voice].ds_buffer);
820 }
821 }
822
823
824
825 /* update_voice_buffers:
826 * Worker function for updating the voice buffers with the current
827 * parameters.
828 */
update_voice_buffers(int voice,int reversed,int bidir,int loop)829 static void update_voice_buffers(int voice, int reversed, int bidir, int loop)
830 {
831 int update_main_buffer = FALSE;
832 int update_loop_buffer = FALSE;
833 int update_reversed = (ds_voices[voice].reversed != reversed);
834 int update_loop = (ds_voices[voice].looping != loop);
835 int update_bidir = (ds_voices[voice].bidir != bidir);
836
837 /* no work to do? */
838 if (!update_reversed && !update_bidir && !update_loop)
839 return;
840
841 /* we need to change looping or bidir? */
842 if (update_loop || update_bidir) {
843 ds_voices[voice].looping = loop;
844 ds_voices[voice].bidir = bidir;
845
846 if (!loop && ds_voices[voice].ds_loop_buffer) {
847 /* we don't need a loop buffer anymore, destroy it */
848 if (ds_voices[voice].ds_locked_buffer == ds_voices[voice].ds_loop_buffer)
849 digi_directsound_unlock_voice(voice);
850 IDirectSoundBuffer_Release(ds_voices[voice].ds_loop_buffer);
851 ds_voices[voice].ds_loop_buffer = NULL;
852 }
853 else if (loop && !ds_voices[voice].ds_loop_buffer) {
854 /* we haven't got one, create it */
855 ds_voices[voice].ds_loop_buffer = create_dsound_buffer(ds_voices[voice].loop_len * (bidir ? 2 : 1),
856 ds_voices[voice].freq,
857 ds_voices[voice].bits,
858 ds_voices[voice].stereo,
859 ds_voices[voice].vol,
860 ds_voices[voice].pan);
861 update_loop_buffer = TRUE;
862 }
863 else if (update_bidir) {
864 /* we need to resize the loop buffer */
865 if (ds_voices[voice].ds_locked_buffer == ds_voices[voice].ds_loop_buffer)
866 digi_directsound_unlock_voice(voice);
867 IDirectSoundBuffer_Release(ds_voices[voice].ds_loop_buffer);
868 ds_voices[voice].ds_loop_buffer = create_dsound_buffer(ds_voices[voice].loop_len * (bidir ? 2 : 1),
869 ds_voices[voice].freq,
870 ds_voices[voice].bits,
871 ds_voices[voice].stereo,
872 ds_voices[voice].vol,
873 ds_voices[voice].pan);
874 update_loop_buffer = TRUE;
875 }
876 }
877
878 /* we need to change the order? */
879 if (update_reversed) {
880 ds_voices[voice].reversed = reversed;
881
882 update_main_buffer = TRUE;
883 update_loop_buffer = TRUE;
884 }
885
886 /* we need to update the main buffer? */
887 if (update_main_buffer) {
888 fill_dsound_buffer(ds_voices[voice].ds_buffer,
889 0, /* offset */
890 ds_voices[voice].len,
891 ds_voices[voice].bits,
892 ds_voices[voice].stereo,
893 ds_voices[voice].reversed,
894 ds_voices[voice].data);
895 }
896
897 /* we need to update the loop buffer? */
898 if (update_loop_buffer && ds_voices[voice].ds_loop_buffer) {
899 fill_dsound_buffer(ds_voices[voice].ds_loop_buffer,
900 0, /* offset */
901 ds_voices[voice].loop_len,
902 ds_voices[voice].bits,
903 ds_voices[voice].stereo,
904 ds_voices[voice].reversed,
905 ds_voices[voice].data + ds_voices[voice].loop_offset * ds_voices[voice].bytes_per_sample);
906
907 if (ds_voices[voice].bidir)
908 fill_dsound_buffer(ds_voices[voice].ds_loop_buffer,
909 ds_voices[voice].loop_len,
910 ds_voices[voice].loop_len,
911 ds_voices[voice].bits,
912 ds_voices[voice].stereo,
913 !ds_voices[voice].reversed,
914 ds_voices[voice].data + ds_voices[voice].loop_offset * ds_voices[voice].bytes_per_sample);
915
916 /* rewind the buffer */
917 IDirectSoundBuffer_SetCurrentPosition(ds_voices[voice].ds_loop_buffer, 0);
918 }
919 }
920
921
922
923 /* digi_directsound_loop_voice:
924 */
digi_directsound_loop_voice(int voice,int playmode)925 static void digi_directsound_loop_voice(int voice, int playmode)
926 {
927 int reversed = (playmode & PLAYMODE_BACKWARD ? TRUE : FALSE);
928 int bidir = (playmode & PLAYMODE_BIDIR ? TRUE : FALSE);
929 int loop = (playmode & PLAYMODE_LOOP ? TRUE : FALSE);
930
931 /* update the voice buffers */
932 update_voice_buffers(voice, reversed, bidir, loop);
933 }
934
935
936
937 /* digi_directsound_lock_voice:
938 */
digi_directsound_lock_voice(int voice,int start,int end)939 static void *digi_directsound_lock_voice(int voice, int start, int end)
940 {
941 LPDIRECTSOUNDBUFFER ds_locked_buffer;
942 unsigned long size_a;
943 void *buf_a;
944 HRESULT hr;
945
946 /* just in case */
947 digi_directsound_unlock_voice(voice);
948
949 if (ds_voices[voice].looping && ds_voices[voice].ds_loop_buffer)
950 ds_locked_buffer = ds_voices[voice].ds_loop_buffer;
951 else
952 ds_locked_buffer = ds_voices[voice].ds_buffer;
953
954 start = start * ds_voices[voice].bytes_per_sample;
955 end = end * ds_voices[voice].bytes_per_sample;
956
957 hr = IDirectSoundBuffer_Lock(ds_locked_buffer, start, end - start, &buf_a, &size_a, NULL, NULL, 0);
958
959 /* if buffer lost, restore and retry lock */
960 if (hr == DSERR_BUFFERLOST) {
961 IDirectSoundBuffer_Restore(ds_locked_buffer);
962
963 hr = IDirectSoundBuffer_Lock(ds_locked_buffer, start, end - start, &buf_a, &size_a, NULL, NULL, 0);
964 if (FAILED(hr)) {
965 _TRACE(PREFIX_E "digi_directsound_lock_voice() failed (%s).\n", ds_err(hr));
966 return NULL;
967 }
968 }
969
970 ds_voices[voice].ds_locked_buffer = ds_locked_buffer;
971 ds_voices[voice].lock_buf_a = buf_a;
972 ds_voices[voice].lock_size_a = size_a;
973
974 return buf_a;
975 }
976
977
978
979 /* digi_directsound_unlock_voice:
980 */
digi_directsound_unlock_voice(int voice)981 static void digi_directsound_unlock_voice(int voice)
982 {
983 HRESULT hr;
984 int lock_bytes;
985
986 if (ds_voices[voice].ds_locked_buffer && ds_voices[voice].lock_buf_a) {
987
988 if (ds_voices[voice].bits == 16) {
989 unsigned short *p = (unsigned short *)ds_voices[voice].lock_buf_a;
990
991 lock_bytes = ds_voices[voice].lock_size_a >> 1;
992
993 while (lock_bytes--)
994 *p++ ^= 0x8000;
995 }
996
997 hr = IDirectSoundBuffer_Unlock(ds_voices[voice].ds_locked_buffer,
998 ds_voices[voice].lock_buf_a,
999 ds_voices[voice].lock_size_a,
1000 NULL,
1001 0);
1002
1003 if (FAILED(hr)) {
1004 _TRACE(PREFIX_E "digi_directsound_unlock_voice() failed (%s).\n", ds_err(hr));
1005 }
1006
1007 ds_voices[voice].ds_locked_buffer = NULL;
1008 ds_voices[voice].lock_buf_a = NULL;
1009 ds_voices[voice].lock_size_a = 0;
1010 }
1011 }
1012
1013
1014
1015 /* digi_directsound_get_position:
1016 */
digi_directsound_get_position(int voice)1017 static int digi_directsound_get_position(int voice)
1018 {
1019 HRESULT hr;
1020 unsigned long int play_cursor;
1021 unsigned long int write_cursor;
1022 unsigned long int status;
1023 int pos;
1024
1025 if (ds_voices[voice].looping && ds_voices[voice].ds_loop_buffer) {
1026 /* is buffer playing? */
1027 hr = IDirectSoundBuffer_GetStatus(ds_voices[voice].ds_loop_buffer, &status);
1028 if (FAILED(hr) || !(status & DSBSTATUS_PLAYING))
1029 return -1;
1030
1031 hr = IDirectSoundBuffer_GetCurrentPosition(ds_voices[voice].ds_loop_buffer,
1032 &play_cursor, &write_cursor);
1033 if (FAILED(hr)) {
1034 _TRACE(PREFIX_E "digi_directsound_get_position() failed (%s).\n", ds_err(hr));
1035 return -1;
1036 }
1037
1038 pos = play_cursor / ds_voices[voice].bytes_per_sample;
1039
1040 /* handle bidir data */
1041 if (ds_voices[voice].bidir && (pos >= ds_voices[voice].loop_len))
1042 pos = (ds_voices[voice].loop_len - 1) - (pos - ds_voices[voice].loop_len);
1043
1044 /* handle reversed data */
1045 if (ds_voices[voice].reversed)
1046 pos = ds_voices[voice].loop_len - 1 - pos;
1047
1048 return ds_voices[voice].loop_offset + pos;
1049 }
1050 else if (ds_voices[voice].ds_buffer) {
1051 /* is buffer playing? */
1052 hr = IDirectSoundBuffer_GetStatus(ds_voices[voice].ds_buffer, &status);
1053 if (FAILED(hr) || !(status & DSBSTATUS_PLAYING))
1054 return -1;
1055
1056 hr = IDirectSoundBuffer_GetCurrentPosition(ds_voices[voice].ds_buffer,
1057 &play_cursor, &write_cursor);
1058 if (FAILED(hr)) {
1059 _TRACE(PREFIX_E "digi_directsound_get_position() failed (%s).\n", ds_err(hr));
1060 return -1;
1061 }
1062
1063 pos = play_cursor / ds_voices[voice].bytes_per_sample;
1064
1065 /* handle reversed data */
1066 if (ds_voices[voice].reversed)
1067 pos = ds_voices[voice].len - 1 - pos;
1068
1069 return pos;
1070 }
1071 else
1072 return -1;
1073 }
1074
1075
1076
1077 /* digi_directsound_set_position:
1078 */
digi_directsound_set_position(int voice,int position)1079 static void digi_directsound_set_position(int voice, int position)
1080 {
1081 HRESULT hr;
1082 int pos;
1083
1084 if (ds_voices[voice].ds_loop_buffer) {
1085 pos = CLAMP(0, position - ds_voices[voice].loop_offset, ds_voices[voice].loop_len-1);
1086
1087 /* handle bidir data: todo? */
1088
1089 /* handle reversed data */
1090 if (ds_voices[voice].reversed)
1091 pos = ds_voices[voice].loop_len - 1 - pos;
1092
1093 hr = IDirectSoundBuffer_SetCurrentPosition(ds_voices[voice].ds_loop_buffer,
1094 pos * ds_voices[voice].bytes_per_sample);
1095 if (FAILED(hr)) {
1096 _TRACE(PREFIX_E "digi_directsound_set_position() failed (%s).\n", ds_err(hr));
1097 }
1098 }
1099
1100 if (ds_voices[voice].ds_buffer) {
1101 pos = position;
1102
1103 /* handle reversed data */
1104 if (ds_voices[voice].reversed)
1105 pos = ds_voices[voice].len - 1 - pos;
1106
1107 hr = IDirectSoundBuffer_SetCurrentPosition(ds_voices[voice].ds_buffer,
1108 pos * ds_voices[voice].bytes_per_sample);
1109 if (FAILED(hr)) {
1110 _TRACE(PREFIX_E "digi_directsound_set_position() failed (%s).\n", ds_err(hr));
1111 }
1112 }
1113 }
1114
1115
1116
1117 /* digi_directsound_get_volume:
1118 */
digi_directsound_get_volume(int voice)1119 static int digi_directsound_get_volume(int voice)
1120 {
1121 return ds_voices[voice].vol;
1122 }
1123
1124
1125
1126 /* digi_directsound_set_volume:
1127 */
digi_directsound_set_volume(int voice,int volume)1128 static void digi_directsound_set_volume(int voice, int volume)
1129 {
1130 int ds_vol;
1131
1132 ds_voices[voice].vol = volume;
1133
1134 if (ds_voices[voice].ds_buffer) {
1135 ds_vol = alleg_to_dsound_volume[CLAMP(0, volume, 255)];
1136 IDirectSoundBuffer_SetVolume(ds_voices[voice].ds_buffer, ds_vol);
1137
1138 if (ds_voices[voice].ds_loop_buffer)
1139 IDirectSoundBuffer_SetVolume(ds_voices[voice].ds_loop_buffer, ds_vol);
1140 }
1141 }
1142
1143
1144
1145 /* digi_directsound_get_frequency:
1146 */
digi_directsound_get_frequency(int voice)1147 static int digi_directsound_get_frequency(int voice)
1148 {
1149 return ds_voices[voice].freq;
1150 }
1151
1152
1153
1154 /* digi_directsound_set_frequency:
1155 */
digi_directsound_set_frequency(int voice,int frequency)1156 static void digi_directsound_set_frequency(int voice, int frequency)
1157 {
1158 ds_voices[voice].freq = frequency;
1159
1160 if (ds_voices[voice].ds_buffer) {
1161 IDirectSoundBuffer_SetFrequency(ds_voices[voice].ds_buffer, frequency);
1162
1163 if (ds_voices[voice].ds_loop_buffer)
1164 IDirectSoundBuffer_SetFrequency(ds_voices[voice].ds_loop_buffer, frequency);
1165 }
1166 }
1167
1168
1169
1170 /* digi_directsound_get_pan:
1171 */
digi_directsound_get_pan(int voice)1172 static int digi_directsound_get_pan(int voice)
1173 {
1174 return ds_voices[voice].pan;
1175 }
1176
1177
1178
1179 /* digi_directsound_set_pan:
1180 */
digi_directsound_set_pan(int voice,int pan)1181 static void digi_directsound_set_pan(int voice, int pan)
1182 {
1183 int ds_pan;
1184
1185 ds_voices[voice].pan = pan;
1186
1187 if (ds_voices[voice].ds_buffer) {
1188 ds_pan = alleg_to_dsound_pan[CLAMP(0, pan, 255)];
1189 IDirectSoundBuffer_SetPan(ds_voices[voice].ds_buffer, ds_pan);
1190
1191 if (ds_voices[voice].ds_loop_buffer)
1192 IDirectSoundBuffer_SetPan(ds_voices[voice].ds_loop_buffer, ds_pan);
1193 }
1194 }
1195
1196