diff options
-rw-r--r-- | Makefile.target | 4 | ||||
-rw-r--r-- | audio/alsaaudio.c | 86 | ||||
-rw-r--r-- | audio/audio.c | 550 | ||||
-rw-r--r-- | audio/audio.h | 78 | ||||
-rw-r--r-- | audio/audio_int.h | 107 | ||||
-rw-r--r-- | audio/audio_template.h | 251 | ||||
-rw-r--r-- | audio/coreaudio.c | 52 | ||||
-rw-r--r-- | audio/dsound_template.h | 66 | ||||
-rw-r--r-- | audio/dsoundaudio.c | 126 | ||||
-rw-r--r-- | audio/fmodaudio.c | 26 | ||||
-rw-r--r-- | audio/mixeng.c | 7 | ||||
-rw-r--r-- | audio/noaudio.c | 14 | ||||
-rw-r--r-- | audio/ossaudio.c | 108 | ||||
-rw-r--r-- | audio/rate_template.h | 2 | ||||
-rw-r--r-- | audio/sdlaudio.c | 26 | ||||
-rw-r--r-- | audio/wavaudio.c | 57 | ||||
-rw-r--r-- | hw/adlib.c | 40 | ||||
-rw-r--r-- | hw/es1370.c | 49 | ||||
-rw-r--r-- | hw/pc.c | 22 | ||||
-rw-r--r-- | hw/sb16.c | 78 | ||||
-rw-r--r-- | qemu-doc.texi | 11 | ||||
-rw-r--r-- | vl.c | 11 | ||||
-rw-r--r-- | vl.h | 8 |
23 files changed, 981 insertions, 798 deletions
diff --git a/Makefile.target b/Makefile.target index cefad74..a22b2e0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -453,8 +453,8 @@ ifneq ($(wildcard .depend),) include .depend endif -ifeq (0, 1) +ifeq (1, 0) audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \ -fmodaudio.o alsaaudio.o mixeng.o: \ +fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \ CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare endif diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 1336905..65a0a0d 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -98,7 +98,7 @@ struct alsa_params_obt { audfmt_e fmt; int nchannels; int can_pause; - snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t samples; }; static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...) @@ -121,7 +121,7 @@ static void GCC_FMT_ATTR (3, 4) alsa_logerr2 ( { 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); @@ -209,7 +209,7 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness) return 0; } -#ifdef DEBUG_MISMATCHES +#if defined DEBUG_MISMATCHES || defined DEBUG static void alsa_dump_info (struct alsa_params_req *req, struct alsa_params_obt *obt) { @@ -221,7 +221,7 @@ static void alsa_dump_info (struct alsa_params_req *req, dolog ("============================================\n"); dolog ("requested: buffer size %d period size %d\n", req->buffer_size, req->period_size); - dolog ("obtained: buffer size %ld\n", obt->buffer_size); + dolog ("obtained: samples %ld\n", obt->samples); } #endif @@ -234,14 +234,14 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) err = snd_pcm_sw_params_current (handle, sw_params); if (err < 0) { - dolog ("Can not fully initialize DAC\n"); + dolog ("Could not fully initialize DAC\n"); alsa_logerr (err, "Failed to get current software parameters\n"); return; } err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold); if (err < 0) { - dolog ("Can not fully initialize DAC\n"); + dolog ("Could not fully initialize DAC\n"); alsa_logerr (err, "Failed to set software threshold to %ld\n", threshold); return; @@ -249,7 +249,7 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) err = snd_pcm_sw_params (handle, sw_params); if (err < 0) { - dolog ("Can not fully initialize DAC\n"); + dolog ("Could not fully initialize DAC\n"); alsa_logerr (err, "Failed to set software parameters\n"); return; } @@ -344,7 +344,8 @@ static int alsa_open (int in, struct alsa_params_req *req, handle, hw_params, &period_size, - 0); + 0 + ); if (err < 0) { alsa_logerr2 (err, typ, "Failed to set period time %d\n", @@ -357,7 +358,8 @@ static int alsa_open (int in, struct alsa_params_req *req, handle, hw_params, &buffer_size, - 0); + 0 + ); if (err < 0) { alsa_logerr2 (err, typ, @@ -382,7 +384,7 @@ static int alsa_open (int in, struct alsa_params_req *req, if (err < 0) { alsa_logerr ( err, - "Can not get minmal period size for %s\n", + "Could not get minmal period size for %s\n", typ ); } @@ -419,7 +421,7 @@ static int alsa_open (int in, struct alsa_params_req *req, &minval ); if (err < 0) { - alsa_logerr (err, "Can not get minmal buffer size for %s\n", + alsa_logerr (err, "Could not get minmal buffer size for %s\n", typ); } else { @@ -451,7 +453,7 @@ static int alsa_open (int in, struct alsa_params_req *req, } } else { - dolog ("warning: buffer size is not set\n"); + dolog ("warning: Buffer size is not set\n"); } err = snd_pcm_hw_params (handle, hw_params); @@ -468,13 +470,13 @@ static int alsa_open (int in, struct alsa_params_req *req, err = snd_pcm_prepare (handle); if (err < 0) { - alsa_logerr2 (err, typ, "Can not prepare handle %p\n", handle); + alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle); goto err; } obt->can_pause = snd_pcm_hw_params_can_pause (hw_params); if (obt->can_pause < 0) { - alsa_logerr (err, "Can not get pause capability for %s\n", typ); + alsa_logerr (err, "Could not get pause capability for %s\n", typ); obt->can_pause = 0; } @@ -493,17 +495,17 @@ static int alsa_open (int in, struct alsa_params_req *req, obt->fmt = req->fmt; obt->nchannels = nchannels; obt->freq = freq; - obt->buffer_size = snd_pcm_frames_to_bytes (handle, obt_buffer_size); + obt->samples = obt_buffer_size; *handlep = handle; +#if defined DEBUG_MISMATCHES || defined DEBUG if (obt->fmt != req->fmt || obt->nchannels != req->nchannels || obt->freq != req->freq) { -#ifdef DEBUG_MISMATCHES dolog ("Audio paramters mismatch for %s\n", typ); alsa_dump_info (req, obt); -#endif } +#endif #ifdef DEBUG alsa_dump_info (req, obt); @@ -550,7 +552,7 @@ static int alsa_run_out (HWVoiceOut *hw) } } - alsa_logerr (avail, "Can not get amount free space\n"); + alsa_logerr (avail, "Could not get amount free space\n"); return 0; } @@ -618,7 +620,7 @@ static void alsa_fini_out (HWVoiceOut *hw) } } -static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as) { ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; struct alsa_params_req req; @@ -627,10 +629,11 @@ static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) int endianness; int err; snd_pcm_t *handle; + audsettings_t obt_as; - req.fmt = aud_to_alsafmt (fmt); - req.freq = freq; - req.nchannels = nchannels; + req.fmt = aud_to_alsafmt (as->fmt); + req.freq = as->freq; + req.nchannels = as->nchannels; req.period_size = conf.period_size_out; req.buffer_size = conf.buffer_size_out; @@ -644,18 +647,22 @@ static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.nchannels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.nchannels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianness) ); alsa->can_pause = obt.can_pause; - hw->bufsize = obt.buffer_size; + hw->samples = obt.samples; - alsa->pcm_buf = qemu_mallocz (hw->bufsize); + alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift); if (!alsa->pcm_buf) { + dolog ("Could not allocate DAC buffer (%d bytes)\n", + hw->samples << hw->info.shift); alsa_anal_close (&handle); return -1; } @@ -703,8 +710,7 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...) return 0; } -static int alsa_init_in (HWVoiceIn *hw, - int freq, int nchannels, audfmt_e fmt) +static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) { ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; struct alsa_params_req req; @@ -713,10 +719,11 @@ static int alsa_init_in (HWVoiceIn *hw, int err; audfmt_e effective_fmt; snd_pcm_t *handle; + audsettings_t obt_as; - req.fmt = aud_to_alsafmt (fmt); - req.freq = freq; - req.nchannels = nchannels; + req.fmt = aud_to_alsafmt (as->fmt); + req.freq = as->freq; + req.nchannels = as->nchannels; req.period_size = conf.period_size_in; req.buffer_size = conf.buffer_size_in; @@ -730,17 +737,22 @@ static int alsa_init_in (HWVoiceIn *hw, return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.nchannels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.nchannels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianness) ); alsa->can_pause = obt.can_pause; - hw->bufsize = obt.buffer_size; - alsa->pcm_buf = qemu_mallocz (hw->bufsize); + hw->samples = obt.samples; + + alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!alsa->pcm_buf) { + dolog ("Could not allocate ADC buffer (%d bytes)\n", + hw->samples << hw->info.shift); alsa_anal_close (&handle); return -1; } diff --git a/audio/audio.c b/audio/audio.c index 1a3925d..961654b 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -26,16 +26,12 @@ #define AUDIO_CAP "audio" #include "audio_int.h" -static void audio_pcm_hw_fini_in (HWVoiceIn *hw); -static void audio_pcm_hw_fini_out (HWVoiceOut *hw); - -static LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; -static LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; - /* #define DEBUG_PLIVE */ /* #define DEBUG_LIVE */ /* #define DEBUG_OUT */ +#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" + static struct audio_driver *drvtab[] = { #ifdef CONFIG_OSS &oss_audio_driver, @@ -59,31 +55,50 @@ static struct audio_driver *drvtab[] = { &wav_audio_driver }; -AudioState audio_state = { - /* Out */ - 1, /* use fixed settings */ - 44100, /* fixed frequency */ - 2, /* fixed channels */ - AUD_FMT_S16, /* fixed format */ - 1, /* number of hw voices */ - 1, /* greedy */ - - /* In */ - 1, /* use fixed settings */ - 44100, /* fixed frequency */ - 2, /* fixed channels */ - AUD_FMT_S16, /* fixed format */ - 1, /* number of hw voices */ - 1, /* greedy */ - - NULL, /* driver opaque */ - NULL, /* driver */ - - NULL, /* timer handle */ +struct fixed_settings { + int enabled; + int nb_voices; + int greedy; + audsettings_t settings; +}; + +static struct { + struct fixed_settings fixed_out; + struct fixed_settings fixed_in; + union { + int hz; + int64_t ticks; + } period; + int plive; +} conf = { + { /* DAC fixed settings */ + 1, /* enabled */ + 1, /* nb_voices */ + 1, /* greedy */ + { + 44100, /* freq */ + 2, /* nchannels */ + AUD_FMT_S16 /* fmt */ + } + }, + + { /* ADC fixed settings */ + 1, /* enabled */ + 1, /* nb_voices */ + 1, /* greedy */ + { + 44100, /* freq */ + 2, /* nchannels */ + AUD_FMT_S16 /* fmt */ + } + }, + { 0 }, /* period */ 0 /* plive */ }; +static AudioState glob_audio_state; + volume_t nominal_volume = { 0, #ifdef FLOAT_MIXENG @@ -148,6 +163,26 @@ int audio_bug (const char *funcname, int cond) } #endif +void *audio_calloc (const char *funcname, int nmemb, size_t size) +{ + int cond; + size_t len; + + len = nmemb * size; + cond = !nmemb || !size; + cond |= nmemb < 0; + cond |= len < size; + + if (audio_bug ("audio_calloc", cond)) { + AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n", + funcname); + AUD_log (NULL, "nmemb=%d size=%d (len=%d)\n", nmemb, size, len); + return NULL; + } + + return qemu_mallocz (len); +} + static char *audio_alloc_prefix (const char *s) { const char qemu_prefix[] = "QEMU_"; @@ -386,14 +421,19 @@ static void audio_process_options (const char *prefix, } len = strlen (opt->name); + /* len of opt->name + len of prefix + size of qemu_prefix + * (includes trailing zero) + zero + underscore (on behalf of + * sizeof) */ optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1); if (!optname) { - dolog ("Can not allocate memory for option name `%s'\n", + dolog ("Could not allocate memory for option name `%s'\n", opt->name); continue; } strcpy (optname, qemu_prefix); + + /* copy while upper-casing, including trailing zero */ for (i = 0; i <= preflen; ++i) { optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]); } @@ -438,12 +478,60 @@ static void audio_process_options (const char *prefix, } } -static int audio_pcm_info_eq (struct audio_pcm_info *info, int freq, - int nchannels, audfmt_e fmt) +static void audio_print_settings (audsettings_t *as) +{ + dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels); + + switch (as->fmt) { + case AUD_FMT_S8: + AUD_log (NULL, "S8"); + break; + case AUD_FMT_U8: + AUD_log (NULL, "U8"); + break; + case AUD_FMT_S16: + AUD_log (NULL, "S16"); + break; + case AUD_FMT_U16: + AUD_log (NULL, "U16"); + break; + default: + AUD_log (NULL, "invalid(%d)", as->fmt); + break; + } + AUD_log (NULL, "\n"); +} + +static int audio_validate_settigs (audsettings_t *as) +{ + int invalid; + + invalid = as->nchannels != 1 && as->nchannels != 2; + + switch (as->fmt) { + case AUD_FMT_S8: + case AUD_FMT_U8: + case AUD_FMT_S16: + case AUD_FMT_U16: + break; + default: + invalid = 1; + break; + } + + invalid |= as->freq <= 0; + + if (invalid) { + return -1; + } + return 0; +} + +static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) { int bits = 8, sign = 0; - switch (fmt) { + switch (as->fmt) { case AUD_FMT_S8: sign = 1; case AUD_FMT_U8: @@ -455,18 +543,21 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, int freq, bits = 16; break; } - return info->freq == freq - && info->nchannels == nchannels + return info->freq == as->freq + && info->nchannels == as->nchannels && info->sign == sign && info->bits == bits; } -void audio_pcm_init_info (struct audio_pcm_info *info, int freq, - int nchannels, audfmt_e fmt, int swap_endian) +void audio_pcm_init_info ( + struct audio_pcm_info *info, + audsettings_t *as, + int swap_endian + ) { int bits = 8, sign = 0; - switch (fmt) { + switch (as->fmt) { case AUD_FMT_S8: sign = 1; case AUD_FMT_U8: @@ -479,11 +570,11 @@ void audio_pcm_init_info (struct audio_pcm_info *info, int freq, break; } - info->freq = freq; + info->freq = as->freq; info->bits = bits; info->sign = sign; - info->nchannels = nchannels; - info->shift = (nchannels == 2) + (bits == 16); + info->nchannels = as->nchannels; + info->shift = (as->nchannels == 2) + (bits == 16); info->align = (1 << info->shift) - 1; info->bytes_per_second = info->freq << info->shift; info->swap_endian = swap_endian; @@ -532,38 +623,16 @@ static void audio_pcm_hw_free_resources_in (HWVoiceIn *hw) static int audio_pcm_hw_alloc_resources_in (HWVoiceIn *hw) { - hw->conv_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); + hw->conv_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); if (!hw->conv_buf) { + dolog ("Could not allocate ADC conversion buffer (%d bytes)\n", + hw->samples * sizeof (st_sample_t)); return -1; } return 0; } -static int audio_pcm_hw_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) -{ - audio_pcm_hw_fini_in (hw); - - if (hw->pcm_ops->init_in (hw, freq, nchannels, fmt)) { - memset (hw, 0, audio_state.drv->voice_size_in); - return -1; - } - LIST_INIT (&hw->sw_head); - hw->active = 1; - hw->samples = hw->bufsize >> hw->info.shift; - hw->conv = - mixeng_conv - [nchannels == 2] - [hw->info.sign] - [hw->info.swap_endian] - [hw->info.bits == 16]; - if (audio_pcm_hw_alloc_resources_in (hw)) { - audio_pcm_hw_free_resources_in (hw); - return -1; - } - return 0; -} - -static uint64_t audio_pcm_hw_find_min_in (HWVoiceIn *hw) +static int audio_pcm_hw_find_min_in (HWVoiceIn *hw) { SWVoiceIn *sw; int m = hw->total_samples_captured; @@ -606,8 +675,10 @@ static void audio_pcm_sw_free_resources_in (SWVoiceIn *sw) static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw) { int samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; - sw->conv_buf = qemu_mallocz (samples * sizeof (st_sample_t)); + sw->conv_buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t)); if (!sw->conv_buf) { + dolog ("Could not allocate buffer for `%s' (%d bytes)\n", + SW_NAME (sw), samples * sizeof (st_sample_t)); return -1; } @@ -620,19 +691,22 @@ static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw) return 0; } -static int audio_pcm_sw_init_in (SWVoiceIn *sw, HWVoiceIn *hw, const char *name, - int freq, int nchannels, audfmt_e fmt) +static int audio_pcm_sw_init_in ( + SWVoiceIn *sw, + HWVoiceIn *hw, + const char *name, + audsettings_t *as + ) { - audio_pcm_init_info (&sw->info, freq, nchannels, fmt, - /* None of the cards emulated by QEMU are big-endian - hence following shortcut */ - audio_need_to_swap_endian (0)); + /* None of the cards emulated by QEMU are big-endian + hence following shortcut */ + audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0)); sw->hw = hw; sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq; sw->clip = mixeng_clip - [nchannels == 2] + [sw->info.nchannels == 2] [sw->info.sign] [sw->info.swap_endian] [sw->info.bits == 16]; @@ -699,6 +773,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) if (audio_bug (AUDIO_FUNC, osamp < 0)) { dolog ("osamp=%d\n", osamp); + return 0; } st_rate_flow (sw->rate, src, dst, &isamp, &osamp); @@ -717,23 +792,6 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) /* * Hard voice (playback) */ -static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) -{ - SWVoiceOut *sw; - int m = INT_MAX; - int nb_live = 0; - - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - if (sw->active || !sw->empty) { - m = audio_MIN (m, sw->total_hw_samples_mixed); - nb_live += 1; - } - } - - *nb_livep = nb_live; - return m; -} - static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw) { if (hw->mix_buf) { @@ -745,37 +803,31 @@ static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw) static int audio_pcm_hw_alloc_resources_out (HWVoiceOut *hw) { - hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); + hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); if (!hw->mix_buf) { + dolog ("Could not allocate DAC mixing buffer (%d bytes)\n", + hw->samples * sizeof (st_sample_t)); return -1; } return 0; } -static int audio_pcm_hw_init_out (HWVoiceOut *hw, int freq, - int nchannels, audfmt_e fmt) +static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) { - audio_pcm_hw_fini_out (hw); - if (hw->pcm_ops->init_out (hw, freq, nchannels, fmt)) { - memset (hw, 0, audio_state.drv->voice_size_out); - return -1; - } + SWVoiceOut *sw; + int m = INT_MAX; + int nb_live = 0; - LIST_INIT (&hw->sw_head); - hw->active = 1; - hw->samples = hw->bufsize >> hw->info.shift; - hw->clip = - mixeng_clip - [nchannels == 2] - [hw->info.sign] - [hw->info.swap_endian] - [hw->info.bits == 16]; - if (audio_pcm_hw_alloc_resources_out (hw)) { - audio_pcm_hw_fini_out (hw); - return -1; + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (sw->active || !sw->empty) { + m = audio_MIN (m, sw->total_hw_samples_mixed); + nb_live += 1; + } } - return 0; + + *nb_livep = nb_live; + return m; } int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live) @@ -830,8 +882,10 @@ static void audio_pcm_sw_free_resources_out (SWVoiceOut *sw) static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw) { - sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t)); + sw->buf = audio_calloc (AUDIO_FUNC, sw->hw->samples, sizeof (st_sample_t)); if (!sw->buf) { + dolog ("Could not allocate buffer for `%s' (%d bytes)\n", + SW_NAME (sw), sw->hw->samples * sizeof (st_sample_t)); return -1; } @@ -844,14 +898,16 @@ static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw) return 0; } -static int audio_pcm_sw_init_out (SWVoiceOut *sw, HWVoiceOut *hw, - const char *name, int freq, - int nchannels, audfmt_e fmt) +static int audio_pcm_sw_init_out ( + SWVoiceOut *sw, + HWVoiceOut *hw, + const char *name, + audsettings_t *as + ) { - audio_pcm_init_info (&sw->info, freq, nchannels, fmt, - /* None of the cards emulated by QEMU are big-endian - hence following shortcut */ - audio_need_to_swap_endian (0)); + /* None of the cards emulated by QEMU are big-endian + hence following shortcut */ + audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0)); sw->hw = hw; sw->empty = 1; sw->active = 0; @@ -860,7 +916,7 @@ static int audio_pcm_sw_init_out (SWVoiceOut *sw, HWVoiceOut *hw, sw->conv = mixeng_conv - [nchannels == 2] + [sw->info.nchannels == 2] [sw->info.sign] [sw->info.swap_endian] [sw->info.bits == 16]; @@ -930,12 +986,11 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) #ifdef DEBUG_OUT dolog ( - "%s: write size %d ret %d total sw %d, hw %d\n", - sw->name, + "%s: write size %d ret %d total sw %d\n", + SW_NAME (sw), size >> sw->info.shift, ret, - sw->total_hw_samples_mixed, - sw->hw->total_samples_played + sw->total_hw_samples_mixed ); #endif @@ -965,7 +1020,7 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size) } if (!sw->hw->enabled) { - dolog ("Writing to disabled voice %s\n", sw->name); + dolog ("Writing to disabled voice %s\n", SW_NAME (sw)); return 0; } @@ -983,7 +1038,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size) } if (!sw->hw->enabled) { - dolog ("Reading from disabled voice %s\n", sw->name); + dolog ("Reading from disabled voice %s\n", SW_NAME (sw)); return 0; } @@ -993,7 +1048,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size) int AUD_get_buffer_size_out (SWVoiceOut *sw) { - return sw->hw->bufsize; + return sw->hw->samples << sw->hw->info.shift; } void AUD_set_active_out (SWVoiceOut *sw, int on) @@ -1091,7 +1146,7 @@ static int audio_get_avail (SWVoiceIn *sw) ldebug ( "%s: get_avail live %d ret %lld\n", - sw->name, + SW_NAME (sw), live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift ); @@ -1110,34 +1165,37 @@ static int audio_get_free (SWVoiceOut *sw) if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); + return 0; } dead = sw->hw->samples - live; #ifdef DEBUG_OUT dolog ("%s: get_free live %d dead %d ret %lld\n", - sw->name, + SW_NAME (sw), live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); #endif return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; } -static void audio_run_out (void) +static void audio_run_out (AudioState *s) { HWVoiceOut *hw = NULL; SWVoiceOut *sw; - while ((hw = audio_pcm_hw_find_any_active_enabled_out (hw))) { + while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) { int played; - int live, free, nb_live; + int live, free, nb_live, cleanup_required; live = audio_pcm_hw_get_live_out2 (hw, &nb_live); if (!nb_live) { live = 0; } + if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); + continue; } if (hw->pending_disable && !nb_live) { @@ -1170,15 +1228,15 @@ static void audio_run_out (void) } #ifdef DEBUG_OUT - dolog ("played = %d total %d\n", played, hw->total_samples_played); + dolog ("played=%d\n", played); #endif if (played) { hw->ts_helper += played; } + cleanup_required = 0; for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - again: if (!sw->active && sw->empty) { continue; } @@ -1193,22 +1251,7 @@ static void audio_run_out (void) if (!sw->total_hw_samples_mixed) { sw->empty = 1; - - if (!sw->active && !sw->callback.fn) { - SWVoiceOut *temp = sw->entries.le_next; - -#ifdef DEBUG_PLIVE - dolog ("Finishing with old voice\n"); -#endif - AUD_close_out (sw); - sw = temp; - if (sw) { - goto again; - } - else { - break; - } - } + cleanup_required |= !sw->active && !sw->callback.fn; } if (sw->active) { @@ -1218,14 +1261,27 @@ static void audio_run_out (void) } } } + + if (cleanup_required) { + restart: + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (!sw->active && !sw->callback.fn) { +#ifdef DEBUG_PLIVE + dolog ("Finishing with old voice\n"); +#endif + audio_close_out (s, sw); + goto restart; /* play it safe */ + } + } + } } } -static void audio_run_in (void) +static void audio_run_in (AudioState *s) { HWVoiceIn *hw = NULL; - while ((hw = audio_pcm_hw_find_any_active_enabled_in (hw))) { + while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) { SWVoiceIn *sw; int captured, min; @@ -1252,42 +1308,42 @@ static void audio_run_in (void) static struct audio_option audio_options[] = { /* DAC */ - {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out, + {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled, "Use fixed settings for host DAC", NULL, 0}, - {"DAC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out, + {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq, "Frequency for fixed host DAC", NULL, 0}, - {"DAC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out, + {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt, "Format for fixed host DAC", NULL, 0}, - {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_out, + {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels, "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0}, - {"DAC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out, + {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices, "Number of voices for DAC", NULL, 0}, /* ADC */ - {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out, + {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled, "Use fixed settings for host ADC", NULL, 0}, - {"ADC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out, - "Frequency for fixed ADC", NULL, 0}, + {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq, + "Frequency for fixed host ADC", NULL, 0}, - {"ADC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out, - "Format for fixed ADC", NULL, 0}, + {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt, + "Format for fixed host ADC", NULL, 0}, - {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_in, + {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels, "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0}, - {"ADC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out, + {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices, "Number of voices for ADC", NULL, 0}, /* Misc */ - {"TIMER_PERIOD", AUD_OPT_INT, &audio_state.period.usec, - "Timer period in microseconds (0 - try lowest possible)", NULL, 0}, + {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz, + "Timer period in HZ (0 - use lowest possible)", NULL, 0}, - {"PLIVE", AUD_OPT_BOOL, &audio_state.plive, + {"PLIVE", AUD_OPT_BOOL, &conf.plive, "(undocumented)", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} @@ -1378,25 +1434,21 @@ void audio_timer (void *opaque) { AudioState *s = opaque; - audio_run_out (); - audio_run_in (); + audio_run_out (s); + audio_run_in (s); - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); } -static int audio_driver_init (struct audio_driver *drv) +static int audio_driver_init (AudioState *s, struct audio_driver *drv) { if (drv->options) { audio_process_options (drv->name, drv->options); } - audio_state.opaque = drv->init (); + s->drv_opaque = drv->init (); - if (audio_state.opaque) { - int i; - HWVoiceOut *hwo; - HWVoiceIn *hwi; - - if (audio_state.nb_hw_voices_out > drv->max_voices_out) { + if (s->drv_opaque) { + if (s->nb_hw_voices_out > drv->max_voices_out) { if (!drv->max_voices_out) { dolog ("`%s' does not support DAC\n", drv->name); } @@ -1405,30 +1457,13 @@ static int audio_driver_init (struct audio_driver *drv) "`%s' does not support %d multiple DAC voicess\n" "Resetting to %d\n", drv->name, - audio_state.nb_hw_voices_out, + s->nb_hw_voices_out, drv->max_voices_out ); } - audio_state.nb_hw_voices_out = drv->max_voices_out; - } - - LIST_INIT (&hw_head_out); - hwo = qemu_mallocz (audio_state.nb_hw_voices_out * drv->voice_size_out); - if (!hwo) { - dolog ( - "Not enough memory for %d `%s' DAC voices (each %d bytes)\n", - audio_state.nb_hw_voices_out, - drv->name, - drv->voice_size_out - ); - drv->fini (audio_state.opaque); - return -1; + s->nb_hw_voices_out = drv->max_voices_out; } - for (i = 0; i < audio_state.nb_hw_voices_out; ++i) { - LIST_INSERT_HEAD (&hw_head_out, hwo, entries); - hwo = advance (hwo, drv->voice_size_out); - } if (!drv->voice_size_in && drv->max_voices_in) { ldebug ("warning: No ADC voice size defined for `%s'\n", @@ -1442,16 +1477,16 @@ static int audio_driver_init (struct audio_driver *drv) } if (drv->voice_size_in && !drv->max_voices_in) { - ldebug ("warning: ADC voice size is %d for ADC less driver `%s'\n", - drv->voice_size_out, drv->name); + ldebug ("warning: `%s' ADC voice size %d, zero voices \n", + drv->name, drv->voice_size_out); } if (drv->voice_size_out && !drv->max_voices_out) { - ldebug ("warning: DAC voice size is %d for DAC less driver `%s'\n", - drv->voice_size_in, drv->name); + ldebug ("warning: `%s' DAC voice size %d, zero voices \n", + drv->name, drv->voice_size_in); } - if (audio_state.nb_hw_voices_in > drv->max_voices_in) { + if (s->nb_hw_voices_in > drv->max_voices_in) { if (!drv->max_voices_in) { ldebug ("`%s' does not support ADC\n", drv->name); } @@ -1460,33 +1495,16 @@ static int audio_driver_init (struct audio_driver *drv) "`%s' does not support %d multiple ADC voices\n" "Resetting to %d\n", drv->name, - audio_state.nb_hw_voices_in, + s->nb_hw_voices_in, drv->max_voices_in ); } - audio_state.nb_hw_voices_in = drv->max_voices_in; + s->nb_hw_voices_in = drv->max_voices_in; } - LIST_INIT (&hw_head_in); - hwi = qemu_mallocz (audio_state.nb_hw_voices_in * drv->voice_size_in); - if (!hwi) { - dolog ( - "Not enough memory for %d `%s' ADC voices (each %d bytes)\n", - audio_state.nb_hw_voices_in, - drv->name, - drv->voice_size_in - ); - qemu_free (hwo); - drv->fini (audio_state.opaque); - return -1; - } - - for (i = 0; i < audio_state.nb_hw_voices_in; ++i) { - LIST_INSERT_HEAD (&hw_head_in, hwi, entries); - hwi = advance (hwi, drv->voice_size_in); - } - - audio_state.drv = drv; + LIST_INIT (&s->hw_head_out); + LIST_INIT (&s->hw_head_in); + s->drv = drv; return 0; } else { @@ -1497,12 +1515,12 @@ static int audio_driver_init (struct audio_driver *drv) static void audio_vm_stop_handler (void *opaque, int reason) { + AudioState *s = opaque; HWVoiceOut *hwo = NULL; HWVoiceIn *hwi = NULL; int op = reason ? VOICE_ENABLE : VOICE_DISABLE; - (void) opaque; - while ((hwo = audio_pcm_hw_find_any_out (hwo))) { + while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) { if (!hwo->pcm_ops) { continue; } @@ -1512,7 +1530,7 @@ static void audio_vm_stop_handler (void *opaque, int reason) } } - while ((hwi = audio_pcm_hw_find_any_in (hwi))) { + while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) { if (!hwi->pcm_ops) { continue; } @@ -1525,10 +1543,11 @@ static void audio_vm_stop_handler (void *opaque, int reason) static void audio_atexit (void) { + AudioState *s = &glob_audio_state; HWVoiceOut *hwo = NULL; HWVoiceIn *hwi = NULL; - while ((hwo = audio_pcm_hw_find_any_out (hwo))) { + while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) { if (!hwo->pcm_ops) { continue; } @@ -1539,7 +1558,7 @@ static void audio_atexit (void) hwo->pcm_ops->fini_out (hwo); } - while ((hwi = audio_pcm_hw_find_any_in (hwi))) { + while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) { if (!hwi->pcm_ops) { continue; } @@ -1549,7 +1568,10 @@ static void audio_atexit (void) } hwi->pcm_ops->fini_in (hwi); } - audio_state.drv->fini (audio_state.opaque); + + if (s->drv) { + s->drv->fini (s->drv_opaque); + } } static void audio_save (QEMUFile *f, void *opaque) @@ -1570,15 +1592,33 @@ static int audio_load (QEMUFile *f, void *opaque, int version_id) return 0; } -void AUD_init (void) +void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card) +{ + card->audio = s; + card->name = qemu_strdup (name); + memset (&card->entries, 0, sizeof (card->entries)); + LIST_INSERT_HEAD (&s->card_head, card, entries); +} + +void AUD_remove_card (QEMUSoundCard *card) +{ + LIST_REMOVE (card, entries); + card->audio = NULL; + qemu_free (card->name); +} + +AudioState *AUD_init (void) { size_t i; int done = 0; const char *drvname; - AudioState *s = &audio_state; + AudioState *s = &glob_audio_state; audio_process_options ("AUDIO", audio_options); + s->nb_hw_voices_out = conf.fixed_out.nb_voices; + s->nb_hw_voices_in = conf.fixed_in.nb_voices; + if (s->nb_hw_voices_out <= 0) { dolog ("Bogus number of DAC voices %d\n", s->nb_hw_voices_out); @@ -1598,8 +1638,8 @@ void AUD_init (void) s->ts = qemu_new_timer (vm_clock, audio_timer, s); if (!s->ts) { - dolog ("Can not create audio timer\n"); - return; + dolog ("Could not create audio timer\n"); + return NULL; } if (drvname) { @@ -1607,7 +1647,7 @@ void AUD_init (void) for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { if (!strcmp (drvname, drvtab[i]->name)) { - done = !audio_driver_init (drvtab[i]); + done = !audio_driver_init (s, drvtab[i]); found = 1; break; } @@ -1619,37 +1659,47 @@ void AUD_init (void) } } - qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); - atexit (audio_atexit); - if (!done) { for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { if (drvtab[i]->can_be_default) { - done = !audio_driver_init (drvtab[i]); + done = !audio_driver_init (s, drvtab[i]); } } } - register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); if (!done) { - if (audio_driver_init (&no_audio_driver)) { - dolog ("Can not initialize audio subsystem\n"); + done = !audio_driver_init (s, &no_audio_driver); + if (!done) { + dolog ("Could not initialize audio subsystem\n"); } else { - dolog ("warning: using timer based audio emulation\n"); + dolog ("warning: Using timer based audio emulation\n"); } } - if (s->period.usec <= 0) { - if (s->period.usec < 0) { - dolog ("warning: timer period is negative - %d treating as zero\n", - s->period.usec); + if (done) { + if (conf.period.hz <= 0) { + if (conf.period.hz < 0) { + dolog ("warning: Timer period is negative - %d " + "treating as zero\n", + conf.period.hz); + } + conf.period.ticks = 1; } - s->period.ticks = 1; + else { + conf.period.ticks = ticks_per_sec / conf.period.hz; + } + + qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); } else { - s->period.ticks = (ticks_per_sec * s->period.usec) / 1000000; + qemu_del_timer (s->ts); + return NULL; } - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks); + LIST_INIT (&s->card_head); + register_savevm ("audio", 0, 1, audio_save, audio_load, s); + atexit (audio_atexit); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); + return s; } diff --git a/audio/audio.h b/audio/audio.h index 6dd2fd2..682d0e0 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -24,18 +24,33 @@ #ifndef QEMU_AUDIO_H #define QEMU_AUDIO_H +#include "sys-queue.h" + typedef void (*audio_callback_fn_t) (void *opaque, int avail); typedef enum { - AUD_FMT_U8, - AUD_FMT_S8, - AUD_FMT_U16, - AUD_FMT_S16 + AUD_FMT_U8, + AUD_FMT_S8, + AUD_FMT_U16, + AUD_FMT_S16 } audfmt_e; +typedef struct { + int freq; + int nchannels; + audfmt_e fmt; +} audsettings_t; + +typedef struct AudioState AudioState; typedef struct SWVoiceOut SWVoiceOut; typedef struct SWVoiceIn SWVoiceIn; +typedef struct QEMUSoundCard { + AudioState *audio; + char *name; + LIST_ENTRY (QEMUSoundCard) entries; +} QEMUSoundCard; + typedef struct QEMUAudioTimeStamp { uint64_t old_ts; } QEMUAudioTimeStamp; @@ -47,46 +62,45 @@ void AUD_log (const char *cap, const char *fmt, ...) #endif ; -void AUD_init (void); +AudioState *AUD_init (void); void AUD_help (void); +void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card); +void AUD_remove_card (QEMUSoundCard *card); -SWVoiceOut *AUD_open_out ( +SWVoiceOut *AUD_open_out ( + QEMUSoundCard *card, SWVoiceOut *sw, const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - int freq, - int nchannels, - audfmt_e fmt + audsettings_t *settings ); -void AUD_close_out (SWVoiceOut *sw); -int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size); -int AUD_get_buffer_size_out (SWVoiceOut *sw); -void AUD_set_active_out (SWVoiceOut *sw, int on); -int AUD_is_active_out (SWVoiceOut *sw); -void AUD_init_time_stamp_out (SWVoiceOut *sw, - QEMUAudioTimeStamp *ts); -uint64_t AUD_time_stamp_get_elapsed_usec_out (SWVoiceOut *sw, - QEMUAudioTimeStamp *ts); - -SWVoiceIn *AUD_open_in ( + +void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw); +int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size); +int AUD_get_buffer_size_out (SWVoiceOut *sw); +void AUD_set_active_out (SWVoiceOut *sw, int on); +int AUD_is_active_out (SWVoiceOut *sw); + +void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); +uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); + +SWVoiceIn *AUD_open_in ( + QEMUSoundCard *card, SWVoiceIn *sw, const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - int freq, - int nchannels, - audfmt_e fmt + audsettings_t *settings ); -void AUD_close_in (SWVoiceIn *sw); -int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size); -void AUD_adjust_in (SWVoiceIn *sw, int leftover); -void AUD_set_active_in (SWVoiceIn *sw, int on); -int AUD_is_active_in (SWVoiceIn *sw); -void AUD_init_time_stamp_in (SWVoiceIn *sw, - QEMUAudioTimeStamp *ts); -uint64_t AUD_time_stamp_get_elapsed_usec_in (SWVoiceIn *sw, - QEMUAudioTimeStamp *ts); + +void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw); +int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size); +void AUD_set_active_in (SWVoiceIn *sw, int on); +int AUD_is_active_in (SWVoiceIn *sw); + +void AUD_init_time_stamp_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts); +uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts); static inline void *advance (void *p, int incr) { diff --git a/audio/audio_int.h b/audio/audio_int.h index 9d28829..6d4c32b 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -24,16 +24,12 @@ #ifndef QEMU_AUDIO_INT_H #define QEMU_AUDIO_INT_H -#include "sys-queue.h" - #ifdef CONFIG_COREAUDIO #define FLOAT_MIXENG /* #define RECIPROCAL */ #endif #include "mixeng.h" -int audio_bug (const char *funcname, int cond); - struct audio_pcm_ops; typedef enum { @@ -69,7 +65,6 @@ struct audio_pcm_info { }; typedef struct HWVoiceOut { - int active; int enabled; int pending_disable; int valid; @@ -78,7 +73,6 @@ typedef struct HWVoiceOut { f_sample *clip; int rpos; - int bufsize; uint64_t ts_helper; st_sample_t *mix_buf; @@ -91,13 +85,11 @@ typedef struct HWVoiceOut { typedef struct HWVoiceIn { int enabled; - int active; struct audio_pcm_info info; t_sample *conv; int wpos; - int bufsize; int total_samples_captured; uint64_t ts_helper; @@ -109,58 +101,6 @@ typedef struct HWVoiceIn { LIST_ENTRY (HWVoiceIn) entries; } HWVoiceIn; -extern struct audio_driver no_audio_driver; -extern struct audio_driver oss_audio_driver; -extern struct audio_driver sdl_audio_driver; -extern struct audio_driver wav_audio_driver; -extern struct audio_driver fmod_audio_driver; -extern struct audio_driver alsa_audio_driver; -extern struct audio_driver coreaudio_audio_driver; -extern struct audio_driver dsound_audio_driver; -extern volume_t nominal_volume; - -struct audio_driver { - const char *name; - const char *descr; - struct audio_option *options; - void *(*init) (void); - void (*fini) (void *); - struct audio_pcm_ops *pcm_ops; - int can_be_default; - int max_voices_out; - int max_voices_in; - int voice_size_out; - int voice_size_in; -}; - -typedef struct AudioState { - int fixed_settings_out; - int fixed_freq_out; - int fixed_channels_out; - int fixed_fmt_out; - int nb_hw_voices_out; - int greedy_out; - - int fixed_settings_in; - int fixed_freq_in; - int fixed_channels_in; - int fixed_fmt_in; - int nb_hw_voices_in; - int greedy_in; - - void *opaque; - struct audio_driver *drv; - - QEMUTimer *ts; - union { - int usec; - int64_t ticks; - } period; - - int plive; -} AudioState; -extern AudioState audio_state; - struct SWVoiceOut { struct audio_pcm_info info; t_sample *conv; @@ -192,22 +132,58 @@ struct SWVoiceIn { LIST_ENTRY (SWVoiceIn) entries; }; +struct audio_driver { + const char *name; + const char *descr; + struct audio_option *options; + void *(*init) (void); + void (*fini) (void *); + struct audio_pcm_ops *pcm_ops; + int can_be_default; + int max_voices_out; + int max_voices_in; + int voice_size_out; + int voice_size_in; +}; + struct audio_pcm_ops { - int (*init_out)(HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt); + int (*init_out)(HWVoiceOut *hw, audsettings_t *as); void (*fini_out)(HWVoiceOut *hw); int (*run_out) (HWVoiceOut *hw); int (*write) (SWVoiceOut *sw, void *buf, int size); int (*ctl_out) (HWVoiceOut *hw, int cmd, ...); - int (*init_in) (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt); + int (*init_in) (HWVoiceIn *hw, audsettings_t *as); void (*fini_in) (HWVoiceIn *hw); int (*run_in) (HWVoiceIn *hw); int (*read) (SWVoiceIn *sw, void *buf, int size); int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); }; -void audio_pcm_init_info (struct audio_pcm_info *info, int freq, - int nchannels, audfmt_e fmt, int swap_endian); +struct AudioState { + struct audio_driver *drv; + void *drv_opaque; + + QEMUTimer *ts; + LIST_HEAD (card_head, QEMUSoundCard) card_head; + LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; + LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; + int nb_hw_voices_out; + int nb_hw_voices_in; +}; + +extern struct audio_driver no_audio_driver; +extern struct audio_driver oss_audio_driver; +extern struct audio_driver sdl_audio_driver; +extern struct audio_driver wav_audio_driver; +extern struct audio_driver fmod_audio_driver; +extern struct audio_driver alsa_audio_driver; +extern struct audio_driver coreaudio_audio_driver; +extern struct audio_driver dsound_audio_driver; +extern volume_t nominal_volume; + +void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as, + int swap_endian); void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len); @@ -217,6 +193,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len); int audio_pcm_hw_get_live_out (HWVoiceOut *hw); int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live); +int audio_bug (const char *funcname, int cond); +void *audio_calloc (const char *funcname, int nmemb, size_t size); + #define VOICE_ENABLE 1 #define VOICE_DISABLE 2 diff --git a/audio/audio_template.h b/audio/audio_template.h index 25ea72f..d985c2e 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -32,6 +32,43 @@ #define SW glue (SWVoice, In) #endif +static int glue (audio_pcm_hw_init_, TYPE) ( + HW *hw, + audsettings_t *as + ) +{ + glue (audio_pcm_hw_free_resources_, TYPE) (hw); + + if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { + return -1; + } + + if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { + dolog ("hw->samples=%d\n", hw->samples); + return -1; + } + + LIST_INIT (&hw->sw_head); +#ifdef DAC + hw->clip = + mixeng_clip +#else + hw->conv = + mixeng_conv +#endif + [hw->info.nchannels == 2] + [hw->info.sign] + [hw->info.swap_endian] + [hw->info.bits == 16]; + + if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { + glue (hw->pcm_ops->fini_, TYPE) (hw); + return -1; + } + + return 0; +} + static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) { glue (audio_pcm_sw_free_resources_, TYPE) (sw); @@ -51,89 +88,86 @@ static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) LIST_REMOVE (sw, entries); } -static void glue (audio_pcm_hw_fini_, TYPE) (HW *hw) +static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp) { - if (hw->active) { - glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); - glue (hw->pcm_ops->fini_, TYPE) (hw); - memset (hw, 0, glue (audio_state.drv->voice_size_, TYPE)); - } -} + HW *hw = *hwp; -static void glue (audio_pcm_hw_gc_, TYPE) (HW *hw) -{ if (!hw->sw_head.lh_first) { - glue (audio_pcm_hw_fini_, TYPE) (hw); + LIST_REMOVE (hw, entries); + glue (s->nb_hw_voices_, TYPE) += 1; + glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); + glue (hw->pcm_ops->fini_, TYPE) (hw); + qemu_free (hw); + *hwp = NULL; } } -static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw) +static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw) { - return hw ? hw->entries.le_next : glue (hw_head_, TYPE).lh_first; + return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first; } -static HW *glue (audio_pcm_hw_find_any_active_, TYPE) (HW *hw) +static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw) { - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { - if (hw->active) { + while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) { + if (hw->enabled) { return hw; } } return NULL; } -static HW *glue (audio_pcm_hw_find_any_active_enabled_, TYPE) (HW *hw) +static HW *glue (audio_pcm_hw_find_any_passive_, TYPE) (AudioState *s) { - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { - if (hw->active && hw->enabled) { - return hw; + if (glue (s->nb_hw_voices_, TYPE)) { + struct audio_driver *drv = s->drv; + + if (audio_bug (AUDIO_FUNC, !drv)) { + dolog ("No host audio driver\n"); + return NULL; } - } - return NULL; -} -static HW *glue (audio_pcm_hw_find_any_passive_, TYPE) (HW *hw) -{ - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { - if (!hw->active) { - return hw; + HW *hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE)); + if (!hw) { + dolog ("Can not allocate voice `%s' size %d\n", + drv->name, glue (drv->voice_size_, TYPE)); } + + LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); + glue (s->nb_hw_voices_, TYPE) -= 1; + return hw; } + return NULL; } static HW *glue (audio_pcm_hw_find_specific_, TYPE) ( + AudioState *s, HW *hw, - int freq, - int nchannels, - audfmt_e fmt + audsettings_t *as ) { - while ((hw = glue (audio_pcm_hw_find_any_active_, TYPE) (hw))) { - if (audio_pcm_info_eq (&hw->info, freq, nchannels, fmt)) { + while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) { + if (audio_pcm_info_eq (&hw->info, as)) { return hw; } } return NULL; } -static HW *glue (audio_pcm_hw_add_new_, TYPE) ( - int freq, - int nchannels, - audfmt_e fmt - ) +static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) { HW *hw; - hw = glue (audio_pcm_hw_find_any_passive_, TYPE) (NULL); + hw = glue (audio_pcm_hw_find_any_passive_, TYPE) (s); if (hw) { - hw->pcm_ops = audio_state.drv->pcm_ops; + hw->pcm_ops = s->drv->pcm_ops; if (!hw->pcm_ops) { return NULL; } - if (glue (audio_pcm_hw_init_, TYPE) (hw, freq, nchannels, fmt)) { - glue (audio_pcm_hw_gc_, TYPE) (hw); + if (glue (audio_pcm_hw_init_, TYPE) (hw, as)) { + glue (audio_pcm_hw_gc_, TYPE) (s, &hw); return NULL; } else { @@ -144,66 +178,62 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) ( return NULL; } -static HW *glue (audio_pcm_hw_add_, TYPE) ( - int freq, - int nchannels, - audfmt_e fmt - ) +static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as) { HW *hw; - if (glue (audio_state.greedy_, TYPE)) { - hw = glue (audio_pcm_hw_add_new_, TYPE) (freq, nchannels, fmt); + if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) { + hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); if (hw) { return hw; } } - hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, freq, nchannels, fmt); + hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as); if (hw) { return hw; } - hw = glue (audio_pcm_hw_add_new_, TYPE) (freq, nchannels, fmt); + hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); if (hw) { return hw; } - return glue (audio_pcm_hw_find_any_active_, TYPE) (NULL); + return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL); } static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( - const char *name, - int freq, - int nchannels, - audfmt_e fmt + AudioState *s, + const char *sw_name, + audsettings_t *as ) { SW *sw; HW *hw; - int hw_freq = freq; - int hw_nchannels = nchannels; - int hw_fmt = fmt; + audsettings_t hw_as; - if (glue (audio_state.fixed_settings_, TYPE)) { - hw_freq = glue (audio_state.fixed_freq_, TYPE); - hw_nchannels = glue (audio_state.fixed_channels_, TYPE); - hw_fmt = glue (audio_state.fixed_fmt_, TYPE); + if (glue (conf.fixed_, TYPE).enabled) { + hw_as = glue (conf.fixed_, TYPE).settings; + } + else { + hw_as = *as; } - sw = qemu_mallocz (sizeof (*sw)); + sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); if (!sw) { + dolog ("Could not allocate soft voice `%s' (%d bytes)\n", + sw_name ? sw_name : "unknown", sizeof (*sw)); goto err1; } - hw = glue (audio_pcm_hw_add_, TYPE) (hw_freq, hw_nchannels, hw_fmt); + hw = glue (audio_pcm_hw_add_, TYPE) (s, &hw_as); if (!hw) { goto err2; } glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, freq, nchannels, fmt)) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) { goto err3; } @@ -211,67 +241,86 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( err3: glue (audio_pcm_hw_del_sw_, TYPE) (sw); - glue (audio_pcm_hw_gc_, TYPE) (hw); + glue (audio_pcm_hw_gc_, TYPE) (s, &hw); err2: qemu_free (sw); err1: return NULL; } -void glue (AUD_close_, TYPE) (SW *sw) +static void glue (audio_close_, TYPE) (AudioState *s, SW *sw) +{ + glue (audio_pcm_sw_fini_, TYPE) (sw); + glue (audio_pcm_hw_del_sw_, TYPE) (sw); + glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw); + qemu_free (sw); +} +void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw) { if (sw) { - glue (audio_pcm_sw_fini_, TYPE) (sw); - glue (audio_pcm_hw_del_sw_, TYPE) (sw); - glue (audio_pcm_hw_gc_, TYPE) (sw->hw); - qemu_free (sw); + if (audio_bug (AUDIO_FUNC, !card || !card->audio)) { + dolog ("card=%p card->audio=%p\n", + card, card ? card->audio : NULL); + return; + } + + glue (audio_close_, TYPE) (card->audio, sw); } } SW *glue (AUD_open_, TYPE) ( + QEMUSoundCard *card, SW *sw, const char *name, void *callback_opaque , audio_callback_fn_t callback_fn, - int freq, - int nchannels, - audfmt_e fmt + audsettings_t *as ) { + AudioState *s; #ifdef DAC int live = 0; SW *old_sw = NULL; #endif - if (!callback_fn) { - dolog ("No callback specifed for voice `%s'\n", name); + ldebug ("open %s, freq %d, nchannels %d, fmt %d\n", + name, as->freq, as->nchannels, as->fmt); + + if (audio_bug (AUDIO_FUNC, + !card || !card->audio || !name || !callback_fn || !as)) { + dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n", + card, card ? card->audio : NULL, name, callback_fn, as); goto fail; } - if (nchannels != 1 && nchannels != 2) { - dolog ("Bogus channel count %d for voice `%s'\n", nchannels, name); + s = card->audio; + + if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) { + audio_print_settings (as); goto fail; } - if (!audio_state.drv) { - dolog ("No audio driver defined\n"); + if (audio_bug (AUDIO_FUNC, !s->drv)) { + dolog ("Can not open `%s' (no host audio driver)\n", name); goto fail; } - if (sw && audio_pcm_info_eq (&sw->info, freq, nchannels, fmt)) { + if (sw && audio_pcm_info_eq (&sw->info, as)) { return sw; } #ifdef DAC - if (audio_state.plive && sw && (!sw->active && !sw->empty)) { + if (conf.plive && sw && (!sw->active && !sw->empty)) { live = sw->total_hw_samples_mixed; #ifdef DEBUG_PLIVE - dolog ("Replacing voice %s with %d live samples\n", sw->name, live); + dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live); dolog ("Old %s freq %d, bits %d, channels %d\n", - sw->name, sw->info.freq, sw->info.bits, sw->info.nchannels); + SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); dolog ("New %s freq %d, bits %d, channels %d\n", - name, freq, (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, + name, + freq, + (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, nchannels); #endif @@ -283,8 +332,8 @@ SW *glue (AUD_open_, TYPE) ( } #endif - if (!glue (audio_state.fixed_settings_, TYPE) && sw) { - glue (AUD_close_, TYPE) (sw); + if (!glue (conf.fixed_, TYPE).enabled && sw) { + glue (AUD_close_, TYPE) (card, sw); sw = NULL; } @@ -292,30 +341,19 @@ SW *glue (AUD_open_, TYPE) ( HW *hw = sw->hw; if (!hw) { - dolog ("Internal logic error voice %s has no hardware store\n", - name); + dolog ("Internal logic error voice `%s' has no hardware store\n", + SW_NAME (sw)); goto fail; } - if (glue (audio_pcm_sw_init_, TYPE) ( - sw, - hw, - name, - freq, - nchannels, - fmt - )) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) { goto fail; } } else { - sw = glue (audio_pcm_create_voice_pair_, TYPE) ( - name, - freq, - nchannels, - fmt); + sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as); if (!sw) { - dolog ("Failed to create voice %s\n", name); + dolog ("Failed to create voice `%s'\n", name); goto fail; } } @@ -349,7 +387,7 @@ SW *glue (AUD_open_, TYPE) ( return sw; fail: - glue (AUD_close_, TYPE) (sw); + glue (AUD_close_, TYPE) (card, sw); return NULL; } @@ -367,10 +405,7 @@ void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) ts->old_ts = sw->hw->ts_helper; } -uint64_t glue (AUD_time_stamp_get_elapsed_usec_, TYPE) ( - SW *sw, - QEMUAudioTimeStamp *ts - ) +uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) { uint64_t delta, cur_ts, old_ts; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index eee1238..8551938 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -31,8 +31,6 @@ #define AUDIO_CAP "coreaudio" #include "audio_int.h" -#define DEVICE_BUFFER_FRAMES (512) - struct { int buffer_frames; } conf = { @@ -132,7 +130,7 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 ( { 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); @@ -147,7 +145,7 @@ static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name) err = pthread_mutex_lock (&core->mutex); if (err) { - dolog ("Can not lock voice for %s\nReason: %s\n", + dolog ("Could not lock voice for %s\nReason: %s\n", fn_name, strerror (err)); return -1; } @@ -160,7 +158,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name) err = pthread_mutex_unlock (&core->mutex); if (err) { - dolog ("Can not unlock voice for %s\nReason: %s\n", + dolog ("Could not unlock voice for %s\nReason: %s\n", fn_name, strerror (err)); return -1; } @@ -268,8 +266,7 @@ static int coreaudio_write (SWVoiceOut *sw, void *buf, int len) return audio_pcm_sw_write (sw, buf, len); } -static int coreaudio_init_out (HWVoiceOut *hw, int freq, - int nchannels, audfmt_e fmt) +static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) { OSStatus status; coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; @@ -282,25 +279,22 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, /* create mutex */ err = pthread_mutex_init(&core->mutex, NULL); if (err) { - dolog("Can not create mutex\nReason: %s\n", strerror (err)); + dolog("Could not create mutex\nReason: %s\n", strerror (err)); return -1; } - if (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) { + if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { bits = 16; endianess = 1; } audio_pcm_init_info ( &hw->info, - freq, - nchannels, - fmt, + as, /* Following is irrelevant actually since we do not use mixengs clipping routines */ audio_need_to_swap_endian (endianess) ); - hw->bufsize = 4 * conf.buffer_frames * nchannels * bits; /* open default output device */ propertySize = sizeof(core->outputDeviceID); @@ -310,18 +304,18 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, &core->outputDeviceID); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, - "Can not get default output Device\n"); + "Could not get default output Device\n"); return -1; } if (core->outputDeviceID == kAudioDeviceUnknown) { - dolog ("Can not initialize %s - Unknown Audiodevice\n", typ); + dolog ("Could not initialize %s - Unknown Audiodevice\n", typ); return -1; } /* set Buffersize to conf.buffer_frames frames */ propertySize = sizeof(core->audioDevicePropertyBufferSize); core->audioDevicePropertyBufferSize = - conf.buffer_frames * sizeof(float) * 2; + conf.buffer_frames * sizeof(float) << (as->nchannels == 2); status = AudioDeviceSetProperty( core->outputDeviceID, NULL, @@ -332,7 +326,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, &core->audioDevicePropertyBufferSize); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, - "Can not set device buffer size %d\n", + "Could not set device buffer size %d\n", kAudioDevicePropertyBufferSize); return -1; } @@ -347,9 +341,11 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, &propertySize, &core->audioDevicePropertyBufferSize); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Can not get device buffer size\n"); + coreaudio_logerr2 (status, typ, "Could not get device buffer size\n"); return -1; } + hw->samples = (core->audioDevicePropertyBufferSize / sizeof (float)) + >> (as->nchannels == 2); /* get StreamFormat */ propertySize = sizeof(core->outputStreamBasicDescription); @@ -362,13 +358,13 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, &core->outputStreamBasicDescription); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, - "Can not get Device Stream properties\n"); + "Could not get Device Stream properties\n"); core->outputDeviceID = kAudioDeviceUnknown; return -1; } /* set Samplerate */ - core->outputStreamBasicDescription.mSampleRate = (Float64)freq; + core->outputStreamBasicDescription.mSampleRate = (Float64)as->freq; propertySize = sizeof(core->outputStreamBasicDescription); status = AudioDeviceSetProperty( core->outputDeviceID, @@ -379,7 +375,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, propertySize, &core->outputStreamBasicDescription); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Can not set samplerate %d\n", freq); + coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", freq); core->outputDeviceID = kAudioDeviceUnknown; return -1; } @@ -387,7 +383,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, /* set Callback */ status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Can not set IOProc\n"); + coreaudio_logerr2 (status, typ, "Could not set IOProc\n"); core->outputDeviceID = kAudioDeviceUnknown; return -1; } @@ -396,7 +392,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, if (!core->isPlaying) { status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Can not start playback\n"); + coreaudio_logerr2 (status, typ, "Could not start playback\n"); AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); core->outputDeviceID = kAudioDeviceUnknown; return -1; @@ -417,7 +413,7 @@ static void coreaudio_fini_out (HWVoiceOut *hw) if (core->isPlaying) { status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Can not stop playback\n"); + coreaudio_logerr (status, "Could not stop playback\n"); } core->isPlaying = 0; } @@ -425,14 +421,14 @@ static void coreaudio_fini_out (HWVoiceOut *hw) /* remove callback */ status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Can not remove IOProc\n"); + coreaudio_logerr (status, "Could not remove IOProc\n"); } core->outputDeviceID = kAudioDeviceUnknown; /* destroy mutex */ err = pthread_mutex_destroy(&core->mutex); if (err) { - dolog("Can not destroy mutex\nReason: %s\n", strerror (err)); + dolog("Could not destroy mutex\nReason: %s\n", strerror (err)); } } @@ -447,7 +443,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) if (!core->isPlaying) { status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Can not unpause playback\n"); + coreaudio_logerr (status, "Could not unpause playback\n"); } core->isPlaying = 1; } @@ -458,7 +454,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) if (core->isPlaying) { status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Can not pause playback\n"); + coreaudio_logerr (status, "Could not pause playback\n"); } core->isPlaying = 0; } diff --git a/audio/dsound_template.h b/audio/dsound_template.h index a04806e..38ba5b9 100644 --- a/audio/dsound_template.h +++ b/audio/dsound_template.h @@ -47,7 +47,7 @@ static int glue (dsound_unlock_, TYPE) ( hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); if (FAILED (hr)) { - dsound_logerr (hr, "Can not unlock " NAME "\n"); + dsound_logerr (hr, "Could not unlock " NAME "\n"); return -1; } @@ -93,13 +93,13 @@ static int glue (dsound_lock_, TYPE) ( #ifndef DSBTYPE_IN if (hr == DSERR_BUFFERLOST) { if (glue (dsound_restore_, TYPE) (buf)) { - dsound_logerr (hr, "Can not lock " NAME "\n"); + dsound_logerr (hr, "Could not lock " NAME "\n"); goto fail; } continue; } #endif - dsound_logerr (hr, "Can not lock " NAME "\n"); + dsound_logerr (hr, "Could not lock " NAME "\n"); goto fail; } @@ -158,38 +158,28 @@ static void dsound_fini_out (HWVoiceOut *hw) if (ds->FIELD) { hr = glue (IFACE, _Stop) (ds->FIELD); if (FAILED (hr)) { - dsound_logerr (hr, "Can not stop " NAME "\n"); + dsound_logerr (hr, "Could not stop " NAME "\n"); } hr = glue (IFACE, _Release) (ds->FIELD); if (FAILED (hr)) { - dsound_logerr (hr, "Can not release " NAME "\n"); + dsound_logerr (hr, "Could not release " NAME "\n"); } ds->FIELD = NULL; } } #ifdef DSBTYPE_IN -static int dsound_init_in ( - HWVoiceIn *hw, - int freq, - int nchannels, - audfmt_e fmt - ) +static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as) #else -static int dsound_init_out ( - HWVoiceOut *hw, - int freq, - int nchannels, - audfmt_e fmt - ) +static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as) #endif { int err; HRESULT hr; dsound *s = &glob_dsound; WAVEFORMATEX wfx; - struct full_fmt full_fmt; + audsettings_t obt_as; #ifdef DSBTYPE_IN const char *typ = "ADC"; DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; @@ -202,10 +192,7 @@ static int dsound_init_out ( DSBCAPS bc; #endif - full_fmt.freq = freq; - full_fmt.nchannels = nchannels; - full_fmt.fmt = fmt; - err = waveformat_from_full_fmt (&wfx, &full_fmt); + err = waveformat_from_audio_settings (&wfx, as); if (err) { return -1; } @@ -233,18 +220,13 @@ static int dsound_init_out ( #endif if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Can not create " NAME "\n"); + dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); return -1; } - hr = glue (IFACE, _GetFormat) ( - ds->FIELD, - &wfx, - sizeof (wfx), - NULL - ); + hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Can not get " NAME " format\n"); + dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); goto fail0; } @@ -258,31 +240,33 @@ static int dsound_init_out ( hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Can not get " NAME " format\n"); + dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); goto fail0; } - err = waveformat_to_full_fmt (&wfx, &full_fmt); + err = waveformat_to_audio_settings (&wfx, &obt_as); if (err) { goto fail0; } ds->first_time = 1; - hw->bufsize = bc.dwBufferBytes; - audio_pcm_init_info ( - &hw->info, - full_fmt.freq, - full_fmt.nchannels, - full_fmt.fmt, - audio_need_to_swap_endian (0) - ); + + audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0)); + + if (bc.dwBufferBytes & hw->info.align) { + dolog ( + "GetCaps returned misaligned buffer size %ld, alignment %d\n", + bc.dwBufferBytes, hw->info.align + 1 + ); + } + hw->samples = bc.dwBufferBytes >> hw->info.shift; #ifdef DEBUG_DSOUND dolog ("caps %ld, desc %ld\n", bc.dwBufferBytes, bd.dwBufferBytes); dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", - hw->bufsize, full_fmt.freq, full_fmt.nchannels, full_fmt.fmt); + hw->bufsize, settings.freq, settings.nchannels, settings.fmt); #endif return 0; diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index 64b8417..63c5a50 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -37,12 +37,6 @@ /* #define DEBUG_DSOUND */ -struct full_fmt { - int freq; - int nchannels; - audfmt_e fmt; -}; - static struct { int lock_retries; int restore_retries; @@ -50,7 +44,7 @@ static struct { int set_primary; int bufsize_in; int bufsize_out; - struct full_fmt full_fmt; + audsettings_t settings; int latency_millis; } conf = { 1, @@ -71,7 +65,7 @@ typedef struct { LPDIRECTSOUND dsound; LPDIRECTSOUNDCAPTURE dsound_capture; LPDIRECTSOUNDBUFFER dsound_primary_buffer; - struct full_fmt fmt; + audsettings_t settings; } dsound; static dsound glob_dsound; @@ -259,7 +253,7 @@ static void GCC_FMT_ATTR (3, 4) dsound_logerr2 ( { 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); @@ -301,7 +295,7 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb) continue; default: - dsound_logerr (hr, "Can not restore playback buffer\n"); + dsound_logerr (hr, "Could not restore playback buffer\n"); return -1; } } @@ -310,19 +304,18 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb) return -1; } -static int waveformat_from_full_fmt (WAVEFORMATEX *wfx, - struct full_fmt *full_fmt) +static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as) { 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->nChannels = as->nchannels; + wfx->nSamplesPerSec = as->freq; + wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2); + wfx->nBlockAlign = 1 << (as->nchannels == 2); wfx->cbSize = 0; - switch (full_fmt->fmt) { + switch (as->fmt) { case AUD_FMT_S8: wfx->wBitsPerSample = 8; break; @@ -344,16 +337,14 @@ static int waveformat_from_full_fmt (WAVEFORMATEX *wfx, break; default: - dolog ("Internal logic error: Bad audio format %d\n", - full_fmt->freq); + dolog ("Internal logic error: Bad audio format %d\n", as->freq); return -1; } return 0; } -static int waveformat_to_full_fmt (WAVEFORMATEX *wfx, - struct full_fmt *full_fmt) +static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as) { if (wfx->wFormatTag != WAVE_FORMAT_PCM) { dolog ("Invalid wave format, tag is not PCM, but %d\n", @@ -365,15 +356,15 @@ static int waveformat_to_full_fmt (WAVEFORMATEX *wfx, dolog ("Invalid wave format, frequency is zero\n"); return -1; } - full_fmt->freq = wfx->nSamplesPerSec; + as->freq = wfx->nSamplesPerSec; switch (wfx->nChannels) { case 1: - full_fmt->nchannels = 1; + as->nchannels = 1; break; case 2: - full_fmt->nchannels = 2; + as->nchannels = 2; break; default: @@ -386,11 +377,11 @@ static int waveformat_to_full_fmt (WAVEFORMATEX *wfx, switch (wfx->wBitsPerSample) { case 8: - full_fmt->fmt = AUD_FMT_U8; + as->fmt = AUD_FMT_U8; break; case 16: - full_fmt->fmt = AUD_FMT_S16; + as->fmt = AUD_FMT_S16; break; default: @@ -415,7 +406,7 @@ static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp) 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; } @@ -438,7 +429,7 @@ static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb, 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; } @@ -520,7 +511,7 @@ static void dsound_close (dsound *s) 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; } @@ -542,7 +533,7 @@ static int dsound_open (dsound *s) ); 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; } @@ -551,7 +542,7 @@ static int dsound_open (dsound *s) return 0; } - err = waveformat_from_full_fmt (&wfx, &conf.full_fmt); + err = waveformat_from_audio_settings (&wfx, &conf.settings); if (err) { return -1; } @@ -569,13 +560,13 @@ static int dsound_open (dsound *s) 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 ( @@ -585,7 +576,7 @@ static int dsound_open (dsound *s) 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; } @@ -594,7 +585,7 @@ static int dsound_open (dsound *s) 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; } @@ -625,7 +616,7 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) } if (status & DSBSTATUS_PLAYING) { - dolog ("warning: voice is already playing\n"); + dolog ("warning: Voice is already playing\n"); return 0; } @@ -633,7 +624,7 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) 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; @@ -646,12 +637,12 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) 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; } @@ -675,6 +666,7 @@ static int dsound_run_out (HWVoiceOut *hw) DWORD decr; DWORD wpos, ppos, old_pos; LPVOID p1, p2; + int bufsize; if (!dsb) { dolog ("Attempt to run empty with playback buffer\n"); @@ -682,6 +674,7 @@ static int dsound_run_out (HWVoiceOut *hw) } hwshift = hw->info.shift; + bufsize = hw->samples << hwshift; live = audio_pcm_hw_get_live_out (hw); @@ -691,7 +684,7 @@ static int dsound_run_out (HWVoiceOut *hw) 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; } @@ -699,13 +692,14 @@ static int dsound_run_out (HWVoiceOut *hw) 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 { @@ -734,14 +728,14 @@ static int dsound_run_out (HWVoiceOut *hw) 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; } @@ -779,7 +773,7 @@ static int dsound_run_out (HWVoiceOut *hw) } 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; @@ -812,7 +806,7 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) } if (status & DSCBSTATUS_CAPTURING) { - dolog ("warning: voice is already capturing\n"); + dolog ("warning: Voice is already capturing\n"); return 0; } @@ -820,7 +814,7 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) 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; @@ -833,12 +827,12 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) 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; } @@ -883,21 +877,21 @@ static int dsound_run_in (HWVoiceIn *hw) 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; @@ -951,7 +945,7 @@ static void dsound_audio_fini (void *opaque) 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; @@ -961,7 +955,7 @@ static void dsound_audio_fini (void *opaque) 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; } @@ -974,7 +968,7 @@ static void *dsound_audio_init (void) hr = CoInitialize (NULL); if (FAILED (hr)) { - dsound_logerr (hr, "Can not initialize COM\n"); + dsound_logerr (hr, "Could not initialize COM\n"); return NULL; } @@ -986,13 +980,13 @@ static void *dsound_audio_init (void) (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"); return NULL; } @@ -1004,16 +998,16 @@ static void *dsound_audio_init (void) (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; } @@ -1039,11 +1033,11 @@ static struct audio_option dsound_options[] = { "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_FREQ", AUD_OPT_INT, &conf.settings.freq, "Primary buffer frequency", NULL, 0}, - {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.full_fmt.nchannels, + {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels, "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0}, - {"PRIMARY_FMT", AUD_OPT_FMT, &conf.full_fmt.fmt, + {"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt, "Primary buffer format", NULL, 0}, {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out, "(undocumented)", NULL, 0}, diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index 36b8d47..072d8a8 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -78,7 +78,7 @@ static void GCC_FMT_ATTR (2, 3) fmod_logerr2 ( { 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); @@ -356,17 +356,17 @@ static void fmod_fini_out (HWVoiceOut *hw) } } -static int fmod_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as) { int bits16, mode, channel; FMODVoiceOut *fmd = (FMODVoiceOut *) hw; - mode = aud_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0); + mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); fmd->fmod_sample = FSOUND_Sample_Alloc ( FSOUND_FREE, /* index */ conf.nb_samples, /* length */ mode, /* mode */ - freq, /* freq */ + as->freq, /* freq */ 255, /* volume */ 128, /* pan */ 255 /* priority */ @@ -386,10 +386,9 @@ static int fmod_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) fmd->channel = channel; /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, freq, nchannels, fmt, - audio_need_to_swap_endian (0)); + audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); bits16 = (mode & FSOUND_16BITS) != 0; - hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16; + hw->samples = conf.nb_samples; return 0; } @@ -417,7 +416,7 @@ static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...) return 0; } -static int fmod_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) +static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as) { int bits16, mode; FMODVoiceIn *fmd = (FMODVoiceIn *) hw; @@ -426,12 +425,12 @@ static int fmod_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) return -1; } - mode = aud_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0); + mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); fmd->fmod_sample = FSOUND_Sample_Alloc ( FSOUND_FREE, /* index */ conf.nb_samples, /* length */ mode, /* mode */ - freq, /* freq */ + as->freq, /* freq */ 255, /* volume */ 128, /* pan */ 255 /* priority */ @@ -443,10 +442,9 @@ static int fmod_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) } /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, freq, nchannels, fmt, - audio_need_to_swap_endian (0)); + audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); bits16 = (mode & FSOUND_16BITS) != 0; - hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16; + hw->samples = conf.nb_samples; return 0; } @@ -479,7 +477,7 @@ static int fmod_run_in (HWVoiceIn *hw) new_pos = FSOUND_Record_GetPosition (); if (new_pos < 0) { - fmod_logerr ("Can not get recording position\n"); + fmod_logerr ("Could not get recording position\n"); return 0; } diff --git a/audio/mixeng.c b/audio/mixeng.c index d43c5e5..14e37ae 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -228,21 +228,22 @@ f_sample *mixeng_clip[2][2][2][2] = { */ /* Private data */ -typedef struct ratestuff { +struct rate { uint64_t opos; uint64_t opos_inc; uint32_t ipos; /* position in the input stream (integer) */ st_sample_t ilast; /* last sample in the input stream */ -} *rate_t; +}; /* * Prepare processing. */ void *st_rate_start (int inrate, int outrate) { - rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff)); + struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate)); if (!rate) { + dolog ("Could not allocate resampler (%d bytes)\n", sizeof (*rate)); return NULL; } diff --git a/audio/noaudio.c b/audio/noaudio.c index e7936cc..aa35811 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -67,11 +67,10 @@ static int no_write (SWVoiceOut *sw, void *buf, int len) return audio_pcm_sw_write (sw, buf, len); } -static int no_init_out (HWVoiceOut *hw, int freq, - int nchannels, audfmt_e fmt) +static int no_init_out (HWVoiceOut *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, freq, nchannels, fmt, 0); - hw->bufsize = 4096; + audio_pcm_init_info (&hw->info, as, 0); + hw->samples = 1024; return 0; } @@ -87,11 +86,10 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...) return 0; } -static int no_init_in (HWVoiceIn *hw, int freq, - int nchannels, audfmt_e fmt) +static int no_init_in (HWVoiceIn *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, freq, nchannels, fmt, 0); - hw->bufsize = 4096; + audio_pcm_init_info (&hw->info, as, 0); + hw->samples = 1024; return 0; } diff --git a/audio/ossaudio.c b/audio/ossaudio.c index ff1a034..5072742 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -91,7 +91,7 @@ static void GCC_FMT_ATTR (3, 4) oss_logerr2 ( { 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); @@ -179,7 +179,7 @@ static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness) return 0; } -#ifdef DEBUG_MISMATCHES +#if defined DEBUG_MISMATCHES || defined DEBUG static void oss_dump_info (struct oss_params *req, struct oss_params *obt) { dolog ("parameter | requested value | obtained value\n"); @@ -253,16 +253,16 @@ static int oss_open (int in, struct oss_params *req, obt->fragsize = abinfo.fragsize; *pfd = fd; +#ifdef DEBUG_MISMATCHES if ((req->fmt != obt->fmt) || (req->nchannels != obt->nchannels) || (req->freq != obt->freq) || (req->fragsize != obt->fragsize) || (req->nfrags != obt->nfrags)) { -#ifdef DEBUG_MISMATCHES dolog ("Audio parameters mismatch\n"); oss_dump_info (req, obt); -#endif } +#endif #ifdef DEBUG oss_dump_info (req, obt); @@ -283,12 +283,15 @@ static int oss_run_out (HWVoiceOut *hw) st_sample_t *src; struct audio_buf_info abinfo; struct count_info cntinfo; + int bufsize; live = audio_pcm_hw_get_live_out (hw); if (!live) { return 0; } + bufsize = hw->samples << hw->info.shift; + if (oss->mmapped) { int bytes; @@ -300,7 +303,7 @@ static int oss_run_out (HWVoiceOut *hw) if (cntinfo.ptr == oss->old_optr) { if (abs (hw->samples - live) < 64) { - dolog ("warning: overrun\n"); + dolog ("warning: Overrun\n"); } return 0; } @@ -309,7 +312,7 @@ static int oss_run_out (HWVoiceOut *hw) bytes = cntinfo.ptr - oss->old_optr; } else { - bytes = hw->bufsize + cntinfo.ptr - oss->old_optr; + bytes = bufsize + cntinfo.ptr - oss->old_optr; } decr = audio_MIN (bytes >> hw->info.shift, live); @@ -321,9 +324,9 @@ static int oss_run_out (HWVoiceOut *hw) return 0; } - if (abinfo.bytes < 0 || abinfo.bytes > hw->bufsize) { - ldebug ("warning: invalid available size, size=%d bufsize=%d\n", - abinfo.bytes, hw->bufsize); + if (abinfo.bytes < 0 || abinfo.bytes > bufsize) { + ldebug ("warning: Invalid available size, size=%d bufsize=%d\n", + abinfo.bytes, bufsize); return 0; } @@ -362,7 +365,7 @@ static int oss_run_out (HWVoiceOut *hw) int wsamples = written >> hw->info.shift; int wbytes = wsamples << hw->info.shift; if (wbytes != written) { - dolog ("warning: misaligned write %d (requested %d), " + dolog ("warning: Misaligned write %d (requested %d), " "alignment %d\n", wbytes, written, hw->info.align + 1); } @@ -396,10 +399,10 @@ static void oss_fini_out (HWVoiceOut *hw) if (oss->pcm_buf) { if (oss->mmapped) { - err = munmap (oss->pcm_buf, hw->bufsize); + err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); if (err) { oss_logerr (errno, "Failed to unmap buffer %p, size %d\n", - oss->pcm_buf, hw->bufsize); + oss->pcm_buf, hw->samples << hw->info.shift); } } else { @@ -409,7 +412,7 @@ static void oss_fini_out (HWVoiceOut *hw) } } -static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int oss_init_out (HWVoiceOut *hw, audsettings_t *as) { OSSVoiceOut *oss = (OSSVoiceOut *) hw; struct oss_params req, obt; @@ -417,10 +420,11 @@ static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) int err; int fd; audfmt_e effective_fmt; + audsettings_t obt_as; - req.fmt = aud_to_ossfmt (fmt); - req.freq = freq; - req.nchannels = nchannels; + req.fmt = aud_to_ossfmt (as->fmt); + req.freq = as->freq; + req.nchannels = as->nchannels; req.fragsize = conf.fragsize; req.nfrags = conf.nfrags; @@ -434,24 +438,38 @@ static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.nchannels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.nchannels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianness) ); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; - hw->bufsize = obt.nfrags * obt.fragsize; + + if (obt.nfrags * obt.fragsize & hw->info.align) { + dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", + obt.nfrags * obt.fragsize, hw->info.align + 1); + } + + hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; oss->mmapped = 0; if (conf.try_mmap) { - oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); + oss->pcm_buf = mmap ( + 0, + hw->samples << hw->info.shift, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0 + ); if (oss->pcm_buf == MAP_FAILED) { oss_logerr (errno, "Failed to map %d bytes of DAC\n", - hw->bufsize); + hw->samples << hw->info.shift); } else { int err; int trig = 0; @@ -472,18 +490,24 @@ static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) } if (!oss->mmapped) { - err = munmap (oss->pcm_buf, hw->bufsize); + err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); if (err) { oss_logerr (errno, "Failed to unmap buffer %p size %d\n", - oss->pcm_buf, hw->bufsize); + oss->pcm_buf, hw->samples << hw->info.shift); } } } } if (!oss->mmapped) { - oss->pcm_buf = qemu_mallocz (hw->bufsize); + oss->pcm_buf = audio_calloc ( + AUDIO_FUNC, + hw->samples, + 1 << hw->info.shift + ); if (!oss->pcm_buf) { + dolog ("Could not allocate DAC buffer (%d bytes)\n", + hw->samples << hw->info.shift); oss_anal_close (&fd); return -1; } @@ -528,8 +552,7 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) return 0; } -static int oss_init_in (HWVoiceIn *hw, - int freq, int nchannels, audfmt_e fmt) +static int oss_init_in (HWVoiceIn *hw, audsettings_t *as) { OSSVoiceIn *oss = (OSSVoiceIn *) hw; struct oss_params req, obt; @@ -537,10 +560,11 @@ static int oss_init_in (HWVoiceIn *hw, int err; int fd; audfmt_e effective_fmt; + audsettings_t obt_as; - req.fmt = aud_to_ossfmt (fmt); - req.freq = freq; - req.nchannels = nchannels; + req.fmt = aud_to_ossfmt (as->fmt); + req.freq = as->freq; + req.nchannels = as->nchannels; req.fragsize = conf.fragsize; req.nfrags = conf.nfrags; if (oss_open (1, &req, &obt, &fd)) { @@ -553,18 +577,28 @@ static int oss_init_in (HWVoiceIn *hw, return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.nchannels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.nchannels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianness) ); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; - hw->bufsize = obt.nfrags * obt.fragsize; - oss->pcm_buf = qemu_mallocz (hw->bufsize); + + if (obt.nfrags * obt.fragsize & hw->info.align) { + dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", + obt.nfrags * obt.fragsize, hw->info.align + 1); + } + + hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; + oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!oss->pcm_buf) { + dolog ("Could not allocate ADC buffer (%d bytes)\n", + hw->samples << hw->info.shift); oss_anal_close (&fd); return -1; } @@ -623,7 +657,7 @@ static int oss_run_in (HWVoiceIn *hw) if (nread > 0) { if (nread & hw->info.align) { - dolog ("warning: misaligned read %d (requested %d), " + dolog ("warning: Misaligned read %d (requested %d), " "alignment %d\n", nread, bufs[i].add << hwshift, hw->info.align + 1); } diff --git a/audio/rate_template.h b/audio/rate_template.h index 5cc95c8..3e0e77c 100644 --- a/audio/rate_template.h +++ b/audio/rate_template.h @@ -30,7 +30,7 @@ void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, int *isamp, int *osamp) { - rate_t rate = (rate_t) opaque; + struct rate *rate = opaque; st_sample_t *istart, *iend; st_sample_t *ostart, *oend; st_sample_t ilast, icur, out; diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 673e2a1..713c784 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -303,7 +303,7 @@ static void sdl_fini_out (HWVoiceOut *hw) sdl_close (&glob_sdl); } -static int sdl_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as) { SDLVoiceOut *sdl = (SDLVoiceOut *) hw; SDLAudioState *s = &glob_sdl; @@ -312,18 +312,14 @@ static int sdl_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) int endianess; int err; audfmt_e effective_fmt; + audsettings_t obt_as; - if (nchannels != 2) { - dolog ("Can not init DAC. Bogus channel count %d\n", nchannels); - return -1; - } + shift <<= as->nchannels == 2; - req.freq = freq; - req.format = aud_to_sdlfmt (fmt, &shift); - req.channels = nchannels; + req.freq = as->freq; + req.format = aud_to_sdlfmt (as->fmt, &shift); + req.channels = as->nchannels; req.samples = conf.nb_samples; - shift <<= nchannels == 2; - req.callback = sdl_callback; req.userdata = sdl; @@ -337,14 +333,16 @@ static int sdl_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.channels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.channels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianess) ); - hw->bufsize = obt.samples << shift; + hw->samples = obt.samples; s->initialized = 1; s->exit = 0; diff --git a/audio/wavaudio.c b/audio/wavaudio.c index e9bd878..4cc9ca7 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -35,9 +35,15 @@ typedef struct WAVVoiceOut { } WAVVoiceOut; static struct { + audsettings_t settings; const char *wav_path; } conf = { - .wav_path = "qemu.wav" + { + 44100, + 2, + AUD_FMT_S16 + }, + "qemu.wav" }; static int wav_run_out (HWVoiceOut *hw) @@ -101,22 +107,22 @@ static void le_store (uint8_t *buf, uint32_t val, int len) } } -static int wav_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) { WAVVoiceOut *wav = (WAVVoiceOut *) hw; - int bits16; + int bits16 = 0, stereo = 0; uint8_t hdr[] = { 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 }; + audsettings_t wav_as = conf.settings; - freq = audio_state.fixed_freq_out; - fmt = audio_state.fixed_fmt_out; - nchannels = audio_state.fixed_channels_out; + (void) as; - switch (fmt) { + stereo = wav_as.nchannels == 2; + switch (wav_as.fmt) { case AUD_FMT_S8: case AUD_FMT_U8: bits16 = 0; @@ -126,32 +132,24 @@ static int wav_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) case AUD_FMT_U16: bits16 = 1; break; - - default: - dolog ("Internal logic error bad format %d\n", fmt); - return -1; } hdr[34] = bits16 ? 0x10 : 0x08; - audio_pcm_init_info ( - &hw->info, - freq, - nchannels, - bits16 ? AUD_FMT_S16 : AUD_FMT_U8, - audio_need_to_swap_endian (0) - ); - hw->bufsize = 4096; - wav->pcm_buf = qemu_mallocz (hw->bufsize); + + audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0)); + + hw->samples = 1024; + wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!wav->pcm_buf) { - dolog ("Can not initialize WAV buffer of %d bytes\n", - hw->bufsize); + dolog ("Could not allocate buffer (%d bytes)\n", + hw->samples << hw->info.shift); return -1; } le_store (hdr + 22, hw->info.nchannels, 2); le_store (hdr + 24, hw->info.freq, 4); - le_store (hdr + 28, hw->info.freq << (bits16 + (nchannels == 2)), 4); - le_store (hdr + 32, 1 << (bits16 + (nchannels == 2)), 2); + le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); + le_store (hdr + 32, 1 << (bits16 + stereo), 2); wav->f = fopen (conf.wav_path, "wb"); if (!wav->f) { @@ -175,7 +173,7 @@ static void wav_fini_out (HWVoiceOut *hw) uint32_t rifflen = (wav->total_samples << stereo) + 36; uint32_t datalen = wav->total_samples << stereo; - if (!wav->f || !hw->active) { + if (!wav->f) { return; } @@ -214,6 +212,15 @@ static void wav_audio_fini (void *opaque) } struct audio_option wav_options[] = { + {"FREQUENCY", AUD_OPT_INT, &conf.settings.freq, + "Frequency", NULL, 0}, + + {"FORMAT", AUD_OPT_FMT, &conf.settings.fmt, + "Format", NULL, 0}, + + {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels, + "Number of channels (1 - mono, 2 - stereo)", NULL, 0}, + {"PATH", AUD_OPT_STR, &conf.wav_path, "Path to wave file", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} @@ -53,6 +53,7 @@ static struct { } conf = {0x220, 44100}; typedef struct { + QEMUSoundCard card; int ticking[2]; int enabled; int active; @@ -70,7 +71,7 @@ typedef struct { #endif } AdlibState; -static AdlibState adlib; +static AdlibState glob_adlib; static void adlib_stop_opl_timer (AdlibState *s, size_t n) { @@ -90,7 +91,7 @@ static void adlib_kill_timers (AdlibState *s) if (s->ticking[i]) { uint64_t delta; - delta = AUD_time_stamp_get_elapsed_usec_out (s->voice, &s->ats); + delta = AUD_get_elapsed_usec_out (s->voice, &s->ats); ldebug ( "delta = %f dexp = %f expired => %d\n", delta / 1000000.0, @@ -141,10 +142,11 @@ static IO_READ_PROTO(adlib_read) static void timer_handler (int c, double interval_Sec) { - AdlibState *s = &adlib; + AdlibState *s = &glob_adlib; unsigned n = c & 1; #ifdef DEBUG double interval; + int64_t exp; #endif if (interval_Sec == 0.0) { @@ -262,16 +264,23 @@ static void Adlib_fini (AdlibState *s) s->active = 0; s->enabled = 0; + AUD_remove_card (&s->card); } -void Adlib_init (void) +int Adlib_init (AudioState *audio) { - AdlibState *s = &adlib; + AdlibState *s = &glob_adlib; + audsettings_t as; + + if (!audio) { + dolog ("No audio state\n"); + return -1; + } #ifdef HAS_YMF262 if (YMF262Init (1, 14318180, conf.freq)) { dolog ("YMF262Init %d failed\n", conf.freq); - return; + return -1; } else { YMF262SetTimerHandler (0, timer_handler, 0); @@ -281,7 +290,7 @@ void Adlib_init (void) s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq); if (!s->opl) { dolog ("OPLCreate %d failed\n", conf.freq); - return; + return -1; } else { OPLSetTimerHandler (s->opl, timer_handler, 0); @@ -289,18 +298,23 @@ void Adlib_init (void) } #endif + as.freq = conf.freq; + as.nchannels = SHIFT; + as.fmt = AUD_FMT_S16; + + AUD_register_card (audio, "adlib", &s->card); + s->voice = AUD_open_out ( + &s->card, s->voice, "adlib", s, adlib_callback, - conf.freq, - SHIFT, - AUD_FMT_S16 + &as ); if (!s->voice) { Adlib_fini (s); - return; + return -1; } s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT; @@ -310,7 +324,7 @@ void Adlib_init (void) dolog ("not enough memory for adlib mixing buffer (%d)\n", s->samples << SHIFT); Adlib_fini (s); - return; + return -1; } register_ioport_read (0x388, 4, 1, adlib_read, s); @@ -321,4 +335,6 @@ void Adlib_init (void) register_ioport_read (conf.port + 8, 2, 1, adlib_read, s); register_ioport_write (conf.port + 8, 2, 1, adlib_write, s); + + return 0; } diff --git a/hw/es1370.c b/hw/es1370.c index 0191f5f..fc7ac0a 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -265,6 +265,7 @@ struct chan { typedef struct ES1370State { PCIDevice *pci_dev; + QEMUSoundCard card; struct chan chan[NB_CHANNELS]; SWVoiceOut *dac_voice[2]; SWVoiceIn *adc_voice; @@ -341,11 +342,11 @@ static void es1370_reset (ES1370State *s) d->scount = 0; d->leftover = 0; if (i == ADC_CHANNEL) { - AUD_close_in (s->adc_voice); + AUD_close_in (&s->card, s->adc_voice); s->adc_voice = NULL; } else { - AUD_close_out (s->dac_voice[i]); + AUD_close_out (&s->card, s->dac_voice[i]); s->dac_voice[i] = NULL; } } @@ -417,28 +418,32 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8, d->shift); if (new_freq) { + audsettings_t as; + + as.freq = new_freq; + as.nchannels = 1 << (new_fmt & 1); + as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8; + if (i == ADC_CHANNEL) { s->adc_voice = AUD_open_in ( + &s->card, s->adc_voice, "es1370.adc", s, es1370_adc_callback, - new_freq, - 1 << (new_fmt & 1), - (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8 + &as ); } else { s->dac_voice[i] = AUD_open_out ( + &s->card, s->dac_voice[i], i ? "es1370.dac2" : "es1370.dac1", s, i ? es1370_dac2_callback : es1370_dac1_callback, - new_freq, - 1 << (new_fmt & 1), - (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8 + &as ); } } @@ -761,7 +766,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, while (temp) { int acquired, to_copy; - to_copy = audio_MIN (temp, sizeof (tmpbuf)); + to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); acquired = AUD_read (s->adc_voice, tmpbuf, to_copy); if (!acquired) break; @@ -779,7 +784,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, while (temp) { int copied, to_copy; - to_copy = audio_MIN (temp, sizeof (tmpbuf)); + to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); cpu_physical_memory_read (addr, tmpbuf, to_copy); copied = AUD_write (voice, tmpbuf, to_copy); if (!copied) @@ -812,7 +817,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, else { d->frame_cnt = size; - if (cnt <= d->frame_cnt) + if ((uint32_t) cnt <= d->frame_cnt) d->frame_cnt |= cnt << 16; } @@ -876,6 +881,10 @@ static void es1370_map (PCIDevice *pci_dev, int region_num, PCIES1370State *d = (PCIES1370State *) pci_dev; ES1370State *s = &d->es1370; + (void) region_num; + (void) size; + (void) type; + register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s); register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s); register_ioport_write (addr, 0x40, 4, es1370_writel, s); @@ -923,13 +932,13 @@ static int es1370_load (QEMUFile *f, void *opaque, int version_id) qemu_get_be32s (f, &d->frame_cnt); if (i == ADC_CHANNEL) { if (s->adc_voice) { - AUD_close_in (s->adc_voice); + AUD_close_in (&s->card, s->adc_voice); s->adc_voice = NULL; } } else { if (s->dac_voice[i]) { - AUD_close_out (s->dac_voice[i]); + AUD_close_out (&s->card, s->dac_voice[i]); s->dac_voice[i] = NULL; } } @@ -953,12 +962,22 @@ static void es1370_on_reset (void *opaque) es1370_reset (s); } -int es1370_init (PCIBus *bus) +int es1370_init (PCIBus *bus, AudioState *audio) { PCIES1370State *d; ES1370State *s; uint8_t *c; + if (!bus) { + dolog ("No PCI bus\n"); + return -1; + } + + if (!audio) { + dolog ("No audio state\n"); + return -1; + } + d = (PCIES1370State *) pci_register_device (bus, "ES1370", sizeof (PCIES1370State), -1, NULL, NULL); @@ -1002,6 +1021,8 @@ int es1370_init (PCIBus *bus) pci_register_io_region (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map); register_savevm ("es1370", 0, 1, es1370_save, es1370_load, s); qemu_register_reset (es1370_on_reset, s); + + AUD_register_card (audio, "es1370", &s->card); es1370_reset (s); return 0; } @@ -601,19 +601,23 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, DMA_init(0); if (audio_enabled) { - AUD_init(); - if (sb16_enabled) - SB16_init (); + AudioState *audio; + + audio = AUD_init(); + if (audio) { + if (sb16_enabled) + SB16_init (audio); #ifdef CONFIG_ADLIB - if (adlib_enabled) - Adlib_init (); + if (adlib_enabled) + Adlib_init (audio); #endif #ifdef CONFIG_GUS - if (gus_enabled) - GUS_init (); + if (gus_enabled) + GUS_init (audio); #endif - if (pci_enabled && es1370_enabled) - es1370_init (pci_bus); + if (pci_enabled && es1370_enabled) + es1370_init (pci_bus, audio); + } } floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); @@ -53,6 +53,7 @@ static struct { } conf = {5, 4, 5, 1, 5, 0x220}; typedef struct SB16State { + QEMUSoundCard card; int irq; int dma; int hdma; @@ -108,9 +109,6 @@ typedef struct SB16State { uint8_t mixer_regs[256]; } SB16State; -/* XXX: suppress that and use a context */ -static struct SB16State dsp; - static void SB_audio_callback (void *opaque, int free); static int magic_of_irq (int irq) @@ -242,15 +240,21 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->block_size, s->dma_auto, s->fifo, s->highspeed); if (s->freq) { + audsettings_t as; + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + s->voice = AUD_open_out ( + &s->card, s->voice, "sb16", s, SB_audio_callback, - s->freq, - 1 << s->fmt_stereo, - s->fmt + &as ); } @@ -330,15 +334,21 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) } if (s->freq) { + audsettings_t as; + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + s->voice = AUD_open_out ( + &s->card, s->voice, "sb16", s, SB_audio_callback, - s->freq, - 1 << s->fmt_stereo, - s->fmt + &as ); } @@ -349,7 +359,7 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) static inline void dsp_out_data (SB16State *s, uint8_t val) { ldebug ("outdata %#x\n", val); - if (s->out_data_len < sizeof (s->out_data)) { + if ((size_t) s->out_data_len < sizeof (s->out_data)) { s->out_data[s->out_data_len++] = val; } } @@ -1018,6 +1028,7 @@ static void reset_mixer (SB16State *s) static IO_WRITE_PROTO(mixer_write_indexb) { SB16State *s = opaque; + (void) nport; s->mixer_nreg = val; } @@ -1025,10 +1036,8 @@ static IO_WRITE_PROTO(mixer_write_datab) { SB16State *s = opaque; + (void) nport; ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); - if (s->mixer_nreg > sizeof (s->mixer_regs)) { - return; - } switch (s->mixer_nreg) { case 0x00: @@ -1088,6 +1097,8 @@ static IO_WRITE_PROTO(mixer_write_indexw) static IO_READ_PROTO(mixer_read) { SB16State *s = opaque; + + (void) nport; #ifndef DEBUG_SB16_MOST if (s->mixer_nreg != 0x82) { ldebug ("mixer_read[%#x] -> %#x\n", @@ -1111,11 +1122,12 @@ static int write_audio (SB16State *s, int nchan, int dma_pos, while (temp) { int left = dma_len - dma_pos; - int to_copy, copied; + int copied; + size_t to_copy; to_copy = audio_MIN (temp, left); - if (to_copy > sizeof(tmpbuf)) { - to_copy = sizeof(tmpbuf); + if (to_copy > sizeof (tmpbuf)) { + to_copy = sizeof (tmpbuf); } copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); @@ -1308,21 +1320,27 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) qemu_get_buffer (f, s->mixer_regs, 256); if (s->voice) { - AUD_close_out (s->voice); + AUD_close_out (&s->card, s->voice); s->voice = NULL; } if (s->dma_running) { if (s->freq) { + audsettings_t as; + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + s->voice = AUD_open_out ( + &s->card, s->voice, "sb16", s, SB_audio_callback, - s->freq, - 1 << s->fmt_stereo, - s->fmt + &as ); } @@ -1332,13 +1350,25 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) return 0; } -void SB16_init (void) +int SB16_init (AudioState *audio) { - SB16State *s = &dsp; + SB16State *s; int i; static const uint8_t dsp_write_ports[] = {0x6, 0xc}; static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; + if (!audio) { + dolog ("No audio state\n"); + return -1; + } + + s = qemu_mallocz (sizeof (*s)); + if (!s) { + dolog ("Could not allocate memory for SB16 (%d bytes)\n", + sizeof (*s)); + return -1; + } + s->cmd = -1; s->irq = conf.irq; s->dma = conf.dma; @@ -1356,7 +1386,7 @@ void SB16_init (void) reset_mixer (s); s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s); if (!s->aux_ts) { - dolog ("Can not create auxiliary timer\n"); + dolog ("warning: Could not create auxiliary timer\n"); } for (i = 0; i < LENOFA (dsp_write_ports); i++) { @@ -1377,4 +1407,6 @@ void SB16_init (void) s->can_write = 1; register_savevm ("sb16", 0, 1, SB_save, SB_load, s); + AUD_register_card (audio, "sb16", &s->card); + return 0; } diff --git a/qemu-doc.texi b/qemu-doc.texi index 51875d7..1c5b5b7 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -95,12 +95,21 @@ NE2000 PCI network adapters @item Serial ports @item -Soundblaster 16 card +Creative SoundBlaster 16 sound card +@item +ENSONIQ AudioPCI ES1370 sound card +@item +Adlib(OPL2) - Yamaha YM3812 compatible chip @end itemize +Note that adlib is only available when QEMU was configured with +-enable-adlib + QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL VGA BIOS. +QEMU uses YM3812 emulation by Tatsuyuki Satoh. + @c man end @section Quick Start @@ -2842,10 +2842,11 @@ void help(void) "-k language use keyboard layout (for example \"fr\" for French)\n" #endif #ifdef HAS_AUDIO - "-enable-audio enable audio support\n" + "-enable-audio enable audio support, and all the sound cars\n" "-audio-help print list of audio drivers and their options\n" - "-soundhw c1,... comma separated list of sound card names\n" - " use -soundhw ? to get the list of supported sound cards\n" + "-soundhw c1,... enable audio support\n" + " and only specified sound cards (comma separated list)\n" + " use -soundhw ? to get the list of supported cards\n" #endif "-localtime set the real time clock to local time [default=utc]\n" "-full-screen start in full screen\n" @@ -3145,9 +3146,9 @@ static void select_soundhw (const char *optarg) printf ("sb16 Creative Sound Blaster 16\n"); #ifdef CONFIG_ADLIB #ifdef HAS_YMF262 - printf ("adlib Ymaha YMF262 (OPL3)\n"); + printf ("adlib Yamaha YMF262 (OPL3)\n"); #else - printf ("adlib Ymaha YM3812 (OPL2)\n"); + printf ("adlib Yamaha YM3812 (OPL2)\n"); #endif #endif #ifdef CONFIG_GUS @@ -631,16 +631,16 @@ int pmac_ide_init (BlockDriverState **hd_table, SetIRQFunc *set_irq, void *irq_opaque, int irq); /* es1370.c */ -int es1370_init (PCIBus *bus); +int es1370_init (PCIBus *bus, AudioState *s); /* sb16.c */ -void SB16_init (void); +int SB16_init (AudioState *s); /* adlib.c */ -void Adlib_init (void); +int Adlib_init (AudioState *s); /* gus.c */ -void GUS_init (void); +int GUS_init (AudioState *s); /* dma.c */ typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); |