* SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
*/
-#include "vl.h"
+#include "qemu-common.h"
+#include "audio.h"
#define AUDIO_CAP "dsound"
#include "audio_int.h"
#include <windows.h>
+#include <mmsystem.h>
#include <objbase.h>
#include <dsound.h>
-/* #define DEBUG_DSOUND */
+#include "audio_win_int.h"
-struct full_fmt {
- int freq;
- int nchannels;
- audfmt_e fmt;
-};
+/* #define DEBUG_DSOUND */
static struct {
int lock_retries;
int set_primary;
int bufsize_in;
int bufsize_out;
- struct full_fmt full_fmt;
+ struct audsettings settings;
int latency_millis;
} conf = {
- 1,
- 1,
- 1,
- 0,
- 16384,
- 16384,
- {
- 44100,
- 2,
- AUD_FMT_S16
- },
- 10
+ .lock_retries = 1,
+ .restore_retries = 1,
+ .getstatus_retries = 1,
+ .set_primary = 0,
+ .bufsize_in = 16384,
+ .bufsize_out = 16384,
+ .settings.freq = 44100,
+ .settings.nchannels = 2,
+ .settings.fmt = AUD_FMT_S16,
+ .latency_millis = 10
};
typedef struct {
LPDIRECTSOUND dsound;
LPDIRECTSOUNDCAPTURE dsound_capture;
LPDIRECTSOUNDBUFFER dsound_primary_buffer;
- struct full_fmt fmt;
+ struct audsettings settings;
} dsound;
static dsound glob_dsound;
{
va_list ap;
- AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ);
+ AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
continue;
default:
- dsound_logerr (hr, "Can not restore playback buffer\n");
+ dsound_logerr (hr, "Could not restore playback buffer\n");
return -1;
}
}
return -1;
}
-static int waveformat_from_full_fmt (WAVEFORMATEX *wfx,
- struct full_fmt *full_fmt)
-{
- memset (wfx, 0, sizeof (*wfx));
-
- wfx->wFormatTag = WAVE_FORMAT_PCM;
- wfx->nChannels = full_fmt->nchannels;
- wfx->nSamplesPerSec = full_fmt->freq;
- wfx->nAvgBytesPerSec = full_fmt->freq << (full_fmt->nchannels == 2);
- wfx->nBlockAlign = 1 << (full_fmt->nchannels == 2);
- wfx->cbSize = 0;
-
- switch (full_fmt->fmt) {
- case AUD_FMT_S8:
- wfx->wBitsPerSample = 8;
- break;
-
- case AUD_FMT_U8:
- wfx->wBitsPerSample = 8;
- break;
-
- case AUD_FMT_S16:
- wfx->wBitsPerSample = 16;
- wfx->nAvgBytesPerSec <<= 1;
- wfx->nBlockAlign <<= 1;
- break;
-
- case AUD_FMT_U16:
- wfx->wBitsPerSample = 16;
- wfx->nAvgBytesPerSec <<= 1;
- wfx->nBlockAlign <<= 1;
- break;
-
- default:
- dolog ("Internal logic error: Bad audio format %d\n",
- full_fmt->freq);
- return -1;
- }
-
- return 0;
-}
-
-static int waveformat_to_full_fmt (WAVEFORMATEX *wfx,
- struct full_fmt *full_fmt)
-{
- if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
- dolog ("Invalid wave format, tag is not PCM, but %d\n",
- wfx->wFormatTag);
- return -1;
- }
-
- if (!wfx->nSamplesPerSec) {
- dolog ("Invalid wave format, frequency is zero\n");
- return -1;
- }
- full_fmt->freq = wfx->nSamplesPerSec;
-
- switch (wfx->nChannels) {
- case 1:
- full_fmt->nchannels = 1;
- break;
-
- case 2:
- full_fmt->nchannels = 2;
- break;
-
- default:
- dolog (
- "Invalid wave format, number of channels is not 1 or 2, but %d\n",
- wfx->nChannels
- );
- return -1;
- }
-
- switch (wfx->wBitsPerSample) {
- case 8:
- full_fmt->fmt = AUD_FMT_U8;
- break;
-
- case 16:
- full_fmt->fmt = AUD_FMT_S16;
- break;
-
- default:
- dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n",
- wfx->wBitsPerSample);
- return -1;
- }
-
- return 0;
-}
-
#include "dsound_template.h"
#define DSBTYPE_IN
#include "dsound_template.h"
for (i = 0; i < conf.getstatus_retries; ++i) {
hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not get playback buffer status\n");
+ dsound_logerr (hr, "Could not get playback buffer status\n");
return -1;
}
hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not get capture buffer status\n");
+ dsound_logerr (hr, "Could not get capture buffer status\n");
return -1;
}
int src_len1 = dst_len;
int src_len2 = 0;
int pos = hw->rpos + dst_len;
- st_sample_t *src1 = hw->mix_buf + hw->rpos;
- st_sample_t *src2 = NULL;
+ struct st_sample *src1 = hw->mix_buf + hw->rpos;
+ struct st_sample *src2 = NULL;
if (pos > hw->samples) {
src_len1 = hw->samples - hw->rpos;
if (src_len1) {
hw->clip (dst, src1, src_len1);
- mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
- mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
if (s->dsound_primary_buffer) {
hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not release primary buffer\n");
+ dsound_logerr (hr, "Could not release primary buffer\n");
}
s->dsound_primary_buffer = NULL;
}
);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not set cooperative level for window %p\n",
+ dsound_logerr (hr, "Could not set cooperative level for window %p\n",
hwnd);
return -1;
}
return 0;
}
- err = waveformat_from_full_fmt (&wfx, &conf.full_fmt);
+ err = waveformat_from_audio_settings (&wfx, &conf.settings);
if (err) {
return -1;
}
NULL
);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not create primary playback buffer\n");
+ dsound_logerr (hr, "Could not create primary playback buffer\n");
return -1;
}
hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not set primary playback buffer format\n");
+ dsound_logerr (hr, "Could not set primary playback buffer format\n");
}
hr = IDirectSoundBuffer_GetFormat (
NULL
);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not get primary playback buffer format\n");
+ dsound_logerr (hr, "Could not get primary playback buffer format\n");
goto fail0;
}
print_wave_format (&wfx);
#endif
- err = waveformat_to_full_fmt (&wfx, &s->fmt);
+ err = waveformat_to_audio_settings (&wfx, &s->settings);
if (err) {
goto fail0;
}
}
if (status & DSBSTATUS_PLAYING) {
- dolog ("warning: voice is already playing\n");
+ dolog ("warning: Voice is already playing\n");
return 0;
}
hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not start playing buffer\n");
+ dsound_logerr (hr, "Could not start playing buffer\n");
return -1;
}
break;
if (status & DSBSTATUS_PLAYING) {
hr = IDirectSoundBuffer_Stop (dsb);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not stop playing buffer\n");
+ dsound_logerr (hr, "Could not stop playing buffer\n");
return -1;
}
}
else {
- dolog ("warning: voice is not playing\n");
+ dolog ("warning: Voice is not playing\n");
}
break;
}
return audio_pcm_sw_write (sw, buf, len);
}
-static int dsound_run_out (HWVoiceOut *hw)
+static int dsound_run_out (HWVoiceOut *hw, int live)
{
int err;
HRESULT hr;
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
- int live, len, hwshift;
+ int len, hwshift;
DWORD blen1, blen2;
DWORD len1, len2;
DWORD decr;
DWORD wpos, ppos, old_pos;
LPVOID p1, p2;
+ int bufsize;
if (!dsb) {
dolog ("Attempt to run empty with playback buffer\n");
}
hwshift = hw->info.shift;
-
- live = audio_pcm_hw_get_live_out (hw);
+ bufsize = hw->samples << hwshift;
hr = IDirectSoundBuffer_GetCurrentPosition (
dsb,
ds->first_time ? &wpos : NULL
);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not get playback buffer position\n");
+ dsound_logerr (hr, "Could not get playback buffer position\n");
return 0;
}
if (ds->first_time) {
if (conf.latency_millis) {
- DWORD cur_blat = audio_ring_dist (wpos, ppos, hw->bufsize);
+ DWORD cur_blat;
+ cur_blat = audio_ring_dist (wpos, ppos, bufsize);
ds->first_time = 0;
old_pos = wpos;
old_pos +=
millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat;
- old_pos %= hw->bufsize;
+ old_pos %= bufsize;
old_pos &= ~hw->info.align;
}
else {
len = ppos - old_pos;
}
else {
- if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->bufsize))) {
- len = hw->bufsize - old_pos + ppos;
+ if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) {
+ len = bufsize - old_pos + ppos;
}
}
- if (audio_bug (AUDIO_FUNC, len < 0 || len > hw->bufsize)) {
- dolog ("len=%d hw->bufsize=%d old_pos=%ld ppos=%ld\n",
- len, hw->bufsize, old_pos, ppos);
+ if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) {
+ dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
+ len, bufsize, old_pos, ppos);
return 0;
}
}
dsound_unlock_out (dsb, p1, p2, blen1, blen2);
- ds->old_pos = (old_pos + (decr << hwshift)) % hw->bufsize;
+ ds->old_pos = (old_pos + (decr << hwshift)) % bufsize;
#ifdef DEBUG_DSOUND
ds->mixed += decr << hwshift;
}
if (status & DSCBSTATUS_CAPTURING) {
- dolog ("warning: voice is already capturing\n");
+ dolog ("warning: Voice is already capturing\n");
return 0;
}
hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not start capturing\n");
+ dsound_logerr (hr, "Could not start capturing\n");
return -1;
}
break;
if (status & DSCBSTATUS_CAPTURING) {
hr = IDirectSoundCaptureBuffer_Stop (dscb);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not stop capturing\n");
+ dsound_logerr (hr, "Could not stop capturing\n");
return -1;
}
}
else {
- dolog ("warning: voice is not capturing\n");
+ dolog ("warning: Voice is not capturing\n");
}
break;
}
ds->first_time ? &rpos : NULL
);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not get capture buffer position\n");
+ dsound_logerr (hr, "Could not get capture buffer position\n");
return 0;
}
if (ds->first_time) {
ds->first_time = 0;
if (rpos & hw->info.align) {
- ldebug ("warning: misaligned capture read position %ld(%d)\n",
+ ldebug ("warning: Misaligned capture read position %ld(%d)\n",
rpos, hw->info.align);
}
hw->wpos = rpos >> hwshift;
}
if (cpos & hw->info.align) {
- ldebug ("warning: misaligned capture position %ld(%d)\n",
+ ldebug ("warning: Misaligned capture position %ld(%d)\n",
cpos, hw->info.align);
}
cpos >>= hwshift;
decr = len1 + len2;
if (p1 && len1) {
- hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
+ hw->conv (hw->conv_buf + hw->wpos, p1, len1);
}
if (p2 && len2) {
- hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
+ hw->conv (hw->conv_buf, p2, len2);
}
dsound_unlock_in (dscb, p1, p2, blen1, blen2);
hr = IDirectSound_Release (s->dsound);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not release DirectSound\n");
+ dsound_logerr (hr, "Could not release DirectSound\n");
}
s->dsound = NULL;
hr = IDirectSoundCapture_Release (s->dsound_capture);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not release DirectSoundCapture\n");
+ dsound_logerr (hr, "Could not release DirectSoundCapture\n");
}
s->dsound_capture = NULL;
}
hr = CoInitialize (NULL);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not initialize COM\n");
+ dsound_logerr (hr, "Could not initialize COM\n");
return NULL;
}
(void **) &s->dsound
);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not create DirectSound instance\n");
+ dsound_logerr (hr, "Could not create DirectSound instance\n");
return NULL;
}
hr = IDirectSound_Initialize (s->dsound, NULL);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not initialize DirectSound\n");
+ dsound_logerr (hr, "Could not initialize DirectSound\n");
+
+ hr = IDirectSound_Release (s->dsound);
+ if (FAILED (hr)) {
+ dsound_logerr (hr, "Could not release DirectSound\n");
+ }
+ s->dsound = NULL;
return NULL;
}
(void **) &s->dsound_capture
);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not create DirectSoundCapture instance\n");
+ dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
}
else {
hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not initialize DirectSoundCapture\n");
+ dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
hr = IDirectSoundCapture_Release (s->dsound_capture);
if (FAILED (hr)) {
- dsound_logerr (hr, "Can not release DirectSoundCapture\n");
+ dsound_logerr (hr, "Could not release DirectSoundCapture\n");
}
s->dsound_capture = NULL;
}
}
static struct audio_option dsound_options[] = {
- {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries,
- "Number of times to attempt locking the buffer", NULL, 0},
- {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries,
- "Number of times to attempt restoring the buffer", NULL, 0},
- {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries,
- "Number of times to attempt getting status of the buffer", NULL, 0},
- {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary,
- "Set the parameters of primary buffer", NULL, 0},
- {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis,
- "(undocumented)", NULL, 0},
- {"PRIMARY_FREQ", AUD_OPT_INT, &conf.full_fmt.freq,
- "Primary buffer frequency", NULL, 0},
- {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.full_fmt.nchannels,
- "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0},
- {"PRIMARY_FMT", AUD_OPT_FMT, &conf.full_fmt.fmt,
- "Primary buffer format", NULL, 0},
- {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out,
- "(undocumented)", NULL, 0},
- {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in,
- "(undocumented)", NULL, 0},
- {NULL, 0, NULL, NULL, NULL, 0}
+ {
+ .name = "LOCK_RETRIES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.lock_retries,
+ .descr = "Number of times to attempt locking the buffer"
+ },
+ {
+ .name = "RESTOURE_RETRIES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.restore_retries,
+ .descr = "Number of times to attempt restoring the buffer"
+ },
+ {
+ .name = "GETSTATUS_RETRIES",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.getstatus_retries,
+ .descr = "Number of times to attempt getting status of the buffer"
+ },
+ {
+ .name = "SET_PRIMARY",
+ .tag = AUD_OPT_BOOL,
+ .valp = &conf.set_primary,
+ .descr = "Set the parameters of primary buffer"
+ },
+ {
+ .name = "LATENCY_MILLIS",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.latency_millis,
+ .descr = "(undocumented)"
+ },
+ {
+ .name = "PRIMARY_FREQ",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.settings.freq,
+ .descr = "Primary buffer frequency"
+ },
+ {
+ .name = "PRIMARY_CHANNELS",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.settings.nchannels,
+ .descr = "Primary buffer number of channels (1 - mono, 2 - stereo)"
+ },
+ {
+ .name = "PRIMARY_FMT",
+ .tag = AUD_OPT_FMT,
+ .valp = &conf.settings.fmt,
+ .descr = "Primary buffer format"
+ },
+ {
+ .name = "BUFSIZE_OUT",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.bufsize_out,
+ .descr = "(undocumented)"
+ },
+ {
+ .name = "BUFSIZE_IN",
+ .tag = AUD_OPT_INT,
+ .valp = &conf.bufsize_in,
+ .descr = "(undocumented)"
+ },
+ { /* End of list */ }
};
static struct audio_pcm_ops dsound_pcm_ops = {
- dsound_init_out,
- dsound_fini_out,
- dsound_run_out,
- dsound_write,
- dsound_ctl_out,
-
- dsound_init_in,
- dsound_fini_in,
- dsound_run_in,
- dsound_read,
- dsound_ctl_in
+ .init_out = dsound_init_out,
+ .fini_out = dsound_fini_out,
+ .run_out = dsound_run_out,
+ .write = dsound_write,
+ .ctl_out = dsound_ctl_out,
+
+ .init_in = dsound_init_in,
+ .fini_in = dsound_fini_in,
+ .run_in = dsound_run_in,
+ .read = dsound_read,
+ .ctl_in = dsound_ctl_in
};
struct audio_driver dsound_audio_driver = {
- INIT_FIELD (name = ) "dsound",
- INIT_FIELD (descr = )
- "DirectSound http://wikipedia.org/wiki/DirectSound",
- INIT_FIELD (options = ) dsound_options,
- INIT_FIELD (init = ) dsound_audio_init,
- INIT_FIELD (fini = ) dsound_audio_fini,
- INIT_FIELD (pcm_ops = ) &dsound_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) INT_MAX,
- INIT_FIELD (max_voices_in = ) 1,
- INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut),
- INIT_FIELD (voice_size_in = ) sizeof (DSoundVoiceIn)
+ .name = "dsound",
+ .descr = "DirectSound http://wikipedia.org/wiki/DirectSound",
+ .options = dsound_options,
+ .init = dsound_audio_init,
+ .fini = dsound_audio_fini,
+ .pcm_ops = &dsound_pcm_ops,
+ .can_be_default = 1,
+ .max_voices_out = INT_MAX,
+ .max_voices_in = 1,
+ .voice_size_out = sizeof (DSoundVoiceOut),
+ .voice_size_in = sizeof (DSoundVoiceIn)
};