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