Commit ec36b695 authored by bellard's avatar bellard

audio capture to wab files (malc)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2059 c046a42c-6fe2-441c-8c8c-71466251a162
parent 63301264
......@@ -321,6 +321,7 @@ endif
ifdef CONFIG_ADLIB
SOUND_HW += fmopl.o adlib.o
endif
AUDIODRV+= wavcapture.o
# SCSI layer
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
......
This diff is collapsed.
......@@ -49,13 +49,31 @@ typedef struct {
int endianness;
} audsettings_t;
typedef enum {
AUD_CNOTIFY_ENABLE,
AUD_CNOTIFY_DISABLE
} audcnotification_e;
struct audio_capture_ops {
void (*state) (void *opaque, int enabled);
void (*notify) (void *opaque, audcnotification_e cmd);
void (*capture) (void *opaque, void *buf, int size);
void (*destroy) (void *opaque);
};
struct capture_ops {
void (*info) (void *opaque);
void (*destroy) (void *opaque);
};
typedef struct CaptureState {
void *opaque;
struct capture_ops ops;
LIST_ENTRY (CaptureState) entries;
} CaptureState;
typedef struct AudioState AudioState;
typedef struct SWVoiceOut SWVoiceOut;
typedef struct CaptureVoiceOut CaptureVoiceOut;
typedef struct SWVoiceIn SWVoiceIn;
typedef struct QEMUSoundCard {
......@@ -79,12 +97,13 @@ AudioState *AUD_init (void);
void AUD_help (void);
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card);
int AUD_add_capture (
CaptureVoiceOut *AUD_add_capture (
AudioState *s,
audsettings_t *as,
struct audio_capture_ops *ops,
void *opaque
);
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
SWVoiceOut *AUD_open_out (
QEMUSoundCard *card,
......
......@@ -64,10 +64,11 @@ struct audio_pcm_info {
int swap_endianness;
};
typedef struct SWVoiceCap SWVoiceCap;
typedef struct HWVoiceOut {
int enabled;
int pending_disable;
int valid;
struct audio_pcm_info info;
f_sample *clip;
......@@ -79,7 +80,7 @@ typedef struct HWVoiceOut {
int samples;
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
LIST_HEAD (sw_cap_listhead, SWVoiceOut) sw_cap_head;
LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
......@@ -116,7 +117,6 @@ struct SWVoiceOut {
volume_t vol;
struct audio_callback callback;
LIST_ENTRY (SWVoiceOut) entries;
LIST_ENTRY (SWVoiceOut) cap_entries;
};
struct SWVoiceIn {
......@@ -168,12 +168,18 @@ struct capture_callback {
LIST_ENTRY (capture_callback) entries;
};
typedef struct CaptureVoiceOut {
struct CaptureVoiceOut {
HWVoiceOut hw;
void *buf;
LIST_HEAD (cb_listhead, capture_callback) cb_head;
LIST_ENTRY (CaptureVoiceOut) entries;
} CaptureVoiceOut;
};
struct SWVoiceCap {
SWVoiceOut sw;
CaptureVoiceOut *cap;
LIST_ENTRY (SWVoiceCap) entries;
};
struct AudioState {
struct audio_driver *drv;
......
......@@ -269,7 +269,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
hw->pcm_ops = drv->pcm_ops;
LIST_INIT (&hw->sw_head);
#ifdef DAC
LIST_INIT (&hw->sw_cap_head);
LIST_INIT (&hw->cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
goto err0;
......@@ -426,7 +426,7 @@ SW *glue (AUD_open_, TYPE) (
s = card->audio;
if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) {
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
audio_print_settings (as);
goto fail;
}
......
......@@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw)
NoVoiceIn *no = (NoVoiceIn *) hw;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int samples;
int samples = 0;
if (dead) {
int64_t now = qemu_get_clock (vm_clock);
......
......@@ -3,6 +3,11 @@
typedef struct {
QEMUFile *f;
int bytes;
char *path;
int freq;
int bits;
int nchannels;
CaptureVoiceOut *cap;
} WAVState;
/* VICE code: Store number as little endian. */
......@@ -15,35 +20,39 @@ static void le_store (uint8_t *buf, uint32_t val, int len)
}
}
static void wav_state_cb (void *opaque, int enabled)
static void wav_notify (void *opaque, audcnotification_e cmd)
{
WAVState *wav = opaque;
(void) opaque;
(void) cmd;
}
if (!enabled) {
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t datalen = wav->bytes;
uint32_t rifflen = datalen + 36;
static void wav_destroy (void *opaque)
{
WAVState *wav = opaque;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t datalen = wav->bytes;
uint32_t rifflen = datalen + 36;
if (!wav->f) {
return;
}
if (!wav->f) {
return;
}
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
}
else {
qemu_fseek (wav->f, 0, SEEK_END);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
fclose (wav->f);
if (wav->path) {
qemu_free (wav->path);
}
}
static void wav_capture_cb (void *opaque, void *buf, int size)
static void wav_capture (void *opaque, void *buf, int size)
{
WAVState *wav = opaque;
......@@ -51,7 +60,30 @@ static void wav_capture_cb (void *opaque, void *buf, int size)
wav->bytes += size;
}
void wav_capture (const char *path, int freq, int bits16, int stereo)
static void wav_capture_destroy (void *opaque)
{
WAVState *wav = opaque;
AUD_del_capture (wav->cap, wav);
}
static void wav_capture_info (void *opaque)
{
WAVState *wav = opaque;
char *path = wav->path;
term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
wav->freq, wav->bits, wav->nchannels,
path ? path : "<not available>", wav->bytes);
}
static struct capture_ops wav_capture_ops = {
.destroy = wav_capture_destroy,
.info = wav_capture_info
};
int wav_start_capture (CaptureState *s, const char *path, int freq,
int bits, int nchannels)
{
WAVState *wav;
uint8_t hdr[] = {
......@@ -62,23 +94,35 @@ void wav_capture (const char *path, int freq, int bits16, int stereo)
};
audsettings_t as;
struct audio_capture_ops ops;
int shift;
int stereo, bits16, shift;
CaptureVoiceOut *cap;
if (bits != 8 && bits != 16) {
term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
return -1;
}
if (nchannels != 1 && nchannels != 2) {
term_printf ("incorrect channel count %d, must be 1 or 2\n", bits);
return -1;
}
stereo = !!stereo;
bits16 = !!bits16;
stereo = nchannels == 2;
bits16 = bits == 16;
as.freq = freq;
as.nchannels = 1 << stereo;
as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
as.endianness = 0;
ops.state = wav_state_cb;
ops.capture = wav_capture_cb;
ops.notify = wav_notify;
ops.capture = wav_capture;
ops.destroy = wav_destroy;
wav = qemu_mallocz (sizeof (*wav));
if (!wav) {
AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav));
return;
return -1;
}
shift = bits16 + stereo;
......@@ -91,12 +135,28 @@ void wav_capture (const char *path, int freq, int bits16, int stereo)
wav->f = fopen (path, "wb");
if (!wav->f) {
AUD_log ("wav", "Failed to open wave file `%s'\nReason: %s\n",
path, strerror (errno));
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
path, strerror (errno));
qemu_free (wav);
return;
return -1;
}
wav->path = qemu_strdup (path);
wav->bits = bits;
wav->nchannels = nchannels;
wav->freq = freq;
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
AUD_add_capture (NULL, &as, &ops, wav);
cap = AUD_add_capture (NULL, &as, &ops, wav);
if (!cap) {
term_printf ("Failed to add audio capture\n");
qemu_free (wav);
return -1;
}
wav->cap = cap;
s->opaque = wav;
s->ops = wav_capture_ops;
return 0;
}
......@@ -1077,6 +1077,64 @@ static void do_info_profile(void)
}
#endif
/* Capture support */
static LIST_HEAD (capture_list_head, CaptureState) capture_head;
static void do_info_capture (void)
{
int i;
CaptureState *s;
for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
term_printf ("[%d]: ", i);
s->ops.info (s->opaque);
}
}
static void do_stop_capture (int n)
{
int i;
CaptureState *s;
for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
if (i == n) {
s->ops.destroy (s->opaque);
LIST_REMOVE (s, entries);
qemu_free (s);
return;
}
}
}
#ifdef HAS_AUDIO
int wav_start_capture (CaptureState *s, const char *path, int freq,
int bits, int nchannels);
static void do_wav_capture (const char *path,
int has_freq, int freq,
int has_bits, int bits,
int has_channels, int nchannels)
{
CaptureState *s;
s = qemu_mallocz (sizeof (*s));
if (!s) {
term_printf ("Not enough memory to add wave capture\n");
return;
}
freq = has_freq ? freq : 44100;
bits = has_bits ? bits : 16;
nchannels = has_channels ? nchannels : 2;
if (wav_start_capture (s, path, freq, bits, nchannels)) {
term_printf ("Faied to add wave capture\n");
qemu_free (s);
}
LIST_INSERT_HEAD (&capture_head, s, entries);
}
#endif
static term_cmd_t term_cmds[] = {
{ "help|?", "s?", do_help,
"[cmd]", "show the help" },
......@@ -1133,6 +1191,13 @@ static term_cmd_t term_cmds[] = {
"dx dy [dz]", "send mouse move events" },
{ "mouse_button", "i", do_mouse_button,
"state", "change mouse button state (1=L, 2=M, 4=R)" },
#ifdef HAS_AUDIO
{ "wavcapture", "si?i?i?", do_wav_capture,
"path [frequency bits channels]",
"capture audio to a wave file (default frequency=44100 bits=16 channels=2)" },
#endif
{ "stopcapture", "i", do_stop_capture,
"capture index", "stop capture" },
{ NULL, NULL, },
};
......@@ -1171,6 +1236,8 @@ static term_cmd_t info_cmds[] = {
"", "show host USB devices", },
{ "profile", "", do_info_profile,
"", "show profiling information", },
{ "capture", "", do_info_capture,
"show capture information" },
{ NULL, NULL, },
};
......@@ -2081,6 +2148,9 @@ static void monitor_handle_command(const char *cmdline)
case 6:
cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]);
break;
case 7:
cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
break;
default:
term_printf("unsupported number of arguments: %d\n", nb_args);
goto fail;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment