static void sndboard_rethink(void);
static uae_u8 *sndboard_get_buffer(int *frames);
static void sndboard_release_buffer(uae_u8 *buffer, int frames);
-static void sndboard_free_capture(void);
-static bool sndboard_init_capture(int freq);
+static void sndboard_free_capture(int owner);
+static bool sndboard_init_capture(int freq, int owner);
static void uaesndboard_reset(int hardreset);
static void sndboard_reset(int hardreset);
#define MAX_UAE_CHANNELS 8
#define MAX_UAE_STREAMS 8
+#define UAESND_CAP_24_32BIT 1
+#define UAESND_CAP_MONO_HPAN 2
+#define UAESND_CAP_DIAGNOSTICS 4
+#define UAESND_CAP_CAPTURE 8
+#define UAESND_CAP_CAPTURE_BLOCK 16
+#define UAESND_DIAG_VERSION 1
+#define UAESND_ERR_NONE 0
+#define UAESND_ERR_INVALID_SET 1
+#define UAESND_ERR_STREAM_ALLOC 2
+#define UAESND_ERR_CAPTURE_BLOCK_ADDRESS 3
+#define SNDBOARD_CAPTURE_OWNER_NONE 0
+#define SNDBOARD_CAPTURE_OWNER_TOCCATA 1
+#define SNDBOARD_CAPTURE_OWNER_UAESND 2
+#define UAESND_CAPTURE_REG_DATA 0xc0
+#define UAESND_CAPTURE_REG_OVERRUNS 0xc4
+#define UAESND_CAPTURE_REG_INTREQ 0xc8
+#define UAESND_CAPTURE_REG_THRESHOLD 0xcc
+#define UAESND_CAPTURE_REG_CONTROL 0xd0
+#define UAESND_CAPTURE_REG_STATUS 0xd4
+#define UAESND_CAPTURE_REG_FREQUENCY 0xd8
+#define UAESND_CAPTURE_REG_AVAILABLE 0xdc
+#define UAESND_CAPTURE_CONTROL_ENABLE 1
+#define UAESND_CAPTURE_CONTROL_IRQ_ENABLE 2
+#define UAESND_CAPTURE_BLOCK_REG_ADDRESS 0x900
+#define UAESND_CAPTURE_BLOCK_REG_FRAMES 0x904
+#define UAESND_CAPTURE_BLOCK_REG_DONE 0x908
+#define UAESND_CAPTURE_BLOCK_REG_COMMAND 0x90c
+#define UAESND_CAPTURE_BLOCK_COMMAND_COPY 1
+#define UAESND_CAPTURE_STATUS_UNAVAILABLE 1
+#define UAESND_CAPTURE_STATUS_ACTIVE 2
+#define UAESND_CAPTURE_STATUS_OVERRUN 4
+
struct uaesndboard_stream
{
int streamid;
int timer_event_time;
int sample[MAX_UAE_CHANNELS];
};
+
+struct uaesnd_capture_state
+{
+ uae_u32 control;
+ uae_u32 status;
+ uae_u32 frequency;
+ uae_u32 available;
+ uae_u32 overrun_count;
+ uae_u32 intreq;
+ uae_u32 threshold;
+ uae_u32 frame_count;
+ uae_u32 dropped_byte_count;
+ uae_u32 block_address;
+ uae_u32 block_frames;
+ uae_u32 block_done;
+ int buffer_size;
+ int read_index;
+ int write_index;
+ uae_u8 *buffer;
+};
+
struct uaesndboard_data
{
bool enabled;
int volume[MAX_UAE_CHANNELS];
struct uaesndboard_stream stream[MAX_UAE_STREAMS];
uae_u8 info[256];
+ uae_u32 invalid_set_count;
+ uae_u32 stream_alloc_failure_count;
+ uae_u32 stream_start_count;
+ uae_u32 stream_stop_count;
+ uae_u32 stream_irq_count;
+ uae_u32 timer_irq_count;
+ uae_u32 last_error_code;
+ struct uaesnd_capture_state capture;
};
static struct uaesndboard_data uaesndboard[MAX_DUPLICATE_SOUND_BOARDS];
+static int capture_owner = SNDBOARD_CAPTURE_OWNER_NONE;
+
+static void uaesnd_update_info(struct uaesndboard_data *data)
+{
+ put_long_host(data->info + 24, UAESND_CAP_24_32BIT | UAESND_CAP_MONO_HPAN | UAESND_CAP_DIAGNOSTICS | UAESND_CAP_CAPTURE | UAESND_CAP_CAPTURE_BLOCK);
+ put_long_host(data->info + 28, UAESND_DIAG_VERSION);
+ put_long_host(data->info + 32, data->invalid_set_count);
+ put_long_host(data->info + 36, data->stream_alloc_failure_count);
+ put_long_host(data->info + 40, data->stream_start_count);
+ put_long_host(data->info + 44, data->stream_stop_count);
+ put_long_host(data->info + 48, data->stream_irq_count);
+ put_long_host(data->info + 52, data->timer_irq_count);
+ put_long_host(data->info + 56, data->last_error_code);
+ put_long_host(data->info + 60, data->capture.frame_count);
+ put_long_host(data->info + 64, data->capture.dropped_byte_count);
+}
+
+static void uaesnd_set_error(struct uaesndboard_data *data, uae_u32 error_code)
+{
+ data->last_error_code = error_code;
+}
+
+static bool uaesnd_capture_addr(uaecptr addr)
+{
+ addr &= 65535;
+ return addr >= UAESND_CAPTURE_REG_DATA && addr < 0xe0;
+}
+
+static bool uaesnd_capture_block_addr(uaecptr addr)
+{
+ addr &= 65535;
+ return addr >= UAESND_CAPTURE_BLOCK_REG_ADDRESS && addr < UAESND_CAPTURE_BLOCK_REG_COMMAND + 4;
+}
+
+static uae_u32 uaesnd_capture_available(struct uaesnd_capture_state *capture)
+{
+ if (!capture->buffer || capture->buffer_size <= 0)
+ return 0;
+ if (capture->write_index >= capture->read_index)
+ return capture->write_index - capture->read_index;
+ return capture->buffer_size - capture->read_index + capture->write_index;
+}
+
+static void uaesnd_capture_reset_buffer(struct uaesnd_capture_state *capture)
+{
+ capture->read_index = 0;
+ capture->write_index = 0;
+ capture->available = 0;
+}
+
+static void uaesnd_capture_start(struct uaesndboard_data *data)
+{
+ if (data->capture.status & UAESND_CAPTURE_STATUS_ACTIVE)
+ return;
+ if (data->capture.frequency == 0)
+ data->capture.frequency = currprefs.sound_freq;
+ data->capture.buffer_size = data->capture.frequency * 2 * 2;
+ if (data->capture.buffer_size < 4096)
+ data->capture.buffer_size = 4096;
+ data->capture.buffer = xcalloc(uae_u8, data->capture.buffer_size);
+ uaesnd_capture_reset_buffer(&data->capture);
+ data->capture.control |= UAESND_CAPTURE_CONTROL_ENABLE;
+ if (!sndboard_init_capture(data->capture.frequency, SNDBOARD_CAPTURE_OWNER_UAESND)) {
+ xfree(data->capture.buffer);
+ data->capture.buffer = NULL;
+ data->capture.buffer_size = 0;
+ data->capture.status = UAESND_CAPTURE_STATUS_UNAVAILABLE;
+ return;
+ }
+ data->capture.status = UAESND_CAPTURE_STATUS_ACTIVE;
+}
+
+static void uaesnd_capture_stop(struct uaesndboard_data *data)
+{
+ if (data->capture.status & UAESND_CAPTURE_STATUS_ACTIVE)
+ sndboard_free_capture(SNDBOARD_CAPTURE_OWNER_UAESND);
+ xfree(data->capture.buffer);
+ data->capture.buffer = NULL;
+ data->capture.buffer_size = 0;
+ data->capture.control &= ~UAESND_CAPTURE_CONTROL_ENABLE;
+ data->capture.status = 0;
+ data->capture.intreq = 0;
+ uaesnd_capture_reset_buffer(&data->capture);
+}
+
+static void uaesnd_capture_write_byte(struct uaesnd_capture_state *capture, uae_u8 value)
+{
+ if (!capture->buffer || capture->buffer_size <= 1)
+ return;
+ int next = (capture->write_index + 1) % capture->buffer_size;
+ if (next == capture->read_index) {
+ capture->read_index = (capture->read_index + 1) % capture->buffer_size;
+ capture->overrun_count++;
+ capture->dropped_byte_count++;
+ capture->status |= UAESND_CAPTURE_STATUS_OVERRUN;
+ }
+ capture->buffer[capture->write_index] = value;
+ capture->write_index = next;
+ capture->available = uaesnd_capture_available(capture);
+}
+
+static void uaesnd_capture_write_s16be(struct uaesnd_capture_state *capture, int sample)
+{
+ uaesnd_capture_write_byte(capture, sample >> 8);
+ uaesnd_capture_write_byte(capture, sample);
+}
+
+static void uaesnd_capture_process(struct uaesndboard_data *data)
+{
+ if (!(data->capture.status & UAESND_CAPTURE_STATUS_ACTIVE))
+ return;
+ int frames = 0;
+ uae_u8 *buffer = sndboard_get_buffer(&frames);
+ if (buffer && frames > 0) {
+ data->capture.frame_count += frames;
+ int samples = frames * 2;
+ for (int i = 0; i < samples; i++) {
+ int sample = (uae_s16)(buffer[i * 2 + 0] | (buffer[i * 2 + 1] << 8));
+ uaesnd_capture_write_s16be(&data->capture, sample);
+ }
+ if ((data->capture.control & UAESND_CAPTURE_CONTROL_IRQ_ENABLE) && data->capture.threshold > 0 && data->capture.available >= data->capture.threshold)
+ data->capture.intreq = 1;
+ }
+ sndboard_release_buffer(buffer, frames);
+}
+
+static bool uaesnd_capture_rethink(struct uaesndboard_data *data)
+{
+ uaesnd_capture_process(data);
+ return (data->capture.control & UAESND_CAPTURE_CONTROL_IRQ_ENABLE) && data->capture.intreq != 0;
+}
+
+static void uaesnd_capture_refresh_if_empty(struct uaesndboard_data *data)
+{
+ struct uaesnd_capture_state *capture = &data->capture;
+ if (!capture->buffer || capture->read_index == capture->write_index)
+ uaesnd_capture_process(data);
+}
+
+static uae_u8 uaesnd_capture_read_byte(struct uaesndboard_data *data)
+{
+ struct uaesnd_capture_state *capture = &data->capture;
+ uaesnd_capture_refresh_if_empty(data);
+ if (!capture->buffer || capture->read_index == capture->write_index) {
+ capture->available = 0;
+ return 0;
+ }
+ uae_u8 value = capture->buffer[capture->read_index];
+ capture->read_index = (capture->read_index + 1) % capture->buffer_size;
+ capture->available = uaesnd_capture_available(capture);
+ return value;
+}
+
+static void uaesnd_capture_block_copy(struct uaesndboard_data *data)
+{
+ uaesnd_capture_process(data);
+ data->capture.block_done = 0;
+ uae_u32 frames = data->capture.block_frames;
+ uae_u32 available_frames = data->capture.available / 4;
+ if (frames > available_frames)
+ frames = available_frames;
+ uae_u32 bytes = frames * 4;
+ if (bytes == 0)
+ return;
+ if (!valid_address(data->capture.block_address, bytes)) {
+ uaesnd_set_error(data, UAESND_ERR_CAPTURE_BLOCK_ADDRESS);
+ return;
+ }
+ for (uae_u32 i = 0; i < bytes; i++) {
+ put_byte(data->capture.block_address + i, uaesnd_capture_read_byte(data));
+ }
+ data->capture.block_done = frames;
+}
+
+static void uaesnd_capture_fill_regs(struct uaesndboard_data *data, uae_u8 *regs)
+{
+ uaesnd_capture_process(data);
+ put_long_host(regs + (UAESND_CAPTURE_REG_OVERRUNS - UAESND_CAPTURE_REG_DATA), data->capture.overrun_count);
+ put_long_host(regs + (UAESND_CAPTURE_REG_INTREQ - UAESND_CAPTURE_REG_DATA), data->capture.intreq);
+ put_long_host(regs + (UAESND_CAPTURE_REG_THRESHOLD - UAESND_CAPTURE_REG_DATA), data->capture.threshold);
+ put_long_host(regs + (UAESND_CAPTURE_REG_CONTROL - UAESND_CAPTURE_REG_DATA), data->capture.control);
+ put_long_host(regs + (UAESND_CAPTURE_REG_STATUS - UAESND_CAPTURE_REG_DATA), data->capture.status);
+ put_long_host(regs + (UAESND_CAPTURE_REG_FREQUENCY - UAESND_CAPTURE_REG_DATA), data->capture.frequency);
+ put_long_host(regs + (UAESND_CAPTURE_REG_AVAILABLE - UAESND_CAPTURE_REG_DATA), data->capture.available);
+}
+
+static uae_u8 uaesnd_capture_bget(struct uaesndboard_data *data, uaecptr addr)
+{
+ if ((addr & ~3) == UAESND_CAPTURE_REG_DATA)
+ return uaesnd_capture_read_byte(data);
+ uae_u8 regs[32] = {};
+ uaesnd_capture_fill_regs(data, regs);
+ return regs[(addr - UAESND_CAPTURE_REG_DATA) & 31];
+}
+
+static uae_u16 uaesnd_capture_wget(struct uaesndboard_data *data, uaecptr addr)
+{
+ return (uaesnd_capture_bget(data, addr) << 8) | uaesnd_capture_bget(data, addr + 1);
+}
+
+static uae_u32 uaesnd_capture_lget(struct uaesndboard_data *data, uaecptr addr)
+{
+ return (uaesnd_capture_wget(data, addr) << 16) | uaesnd_capture_wget(data, addr + 2);
+}
+
+static void uaesnd_capture_apply_reg(struct uaesndboard_data *data, int reg, uae_u32 value)
+{
+ if (reg == UAESND_CAPTURE_REG_CONTROL) {
+ data->capture.control = value;
+ if (value & UAESND_CAPTURE_CONTROL_ENABLE)
+ uaesnd_capture_start(data);
+ else
+ uaesnd_capture_stop(data);
+ } else if (reg == UAESND_CAPTURE_REG_FREQUENCY) {
+ data->capture.frequency = value;
+ } else if (reg == UAESND_CAPTURE_REG_INTREQ) {
+ data->capture.intreq &= value;
+ } else if (reg == UAESND_CAPTURE_REG_THRESHOLD) {
+ data->capture.threshold = value;
+ } else if (reg == UAESND_CAPTURE_REG_STATUS) {
+ data->capture.status &= value;
+ }
+}
+
+static void uaesnd_capture_put(struct uaesndboard_data *data, uaecptr addr, uae_u32 value, int size)
+{
+ uae_u8 regs[32] = {};
+ int offset = (addr - UAESND_CAPTURE_REG_DATA) & 31;
+ int reg = (addr & ~3) & 65535;
+ uaesnd_capture_fill_regs(data, regs);
+ if (size == 4) {
+ put_long_host(regs + offset, value);
+ } else if (size == 2) {
+ put_word_host(regs + offset, value);
+ } else {
+ regs[offset] = value;
+ }
+ uaesnd_capture_apply_reg(data, reg, get_long_host(regs + (reg - UAESND_CAPTURE_REG_DATA)));
+}
+
+static void uaesnd_capture_block_fill_regs(struct uaesndboard_data *data, uae_u8 *regs)
+{
+ put_long_host(regs + (UAESND_CAPTURE_BLOCK_REG_ADDRESS - UAESND_CAPTURE_BLOCK_REG_ADDRESS), data->capture.block_address);
+ put_long_host(regs + (UAESND_CAPTURE_BLOCK_REG_FRAMES - UAESND_CAPTURE_BLOCK_REG_ADDRESS), data->capture.block_frames);
+ put_long_host(regs + (UAESND_CAPTURE_BLOCK_REG_DONE - UAESND_CAPTURE_BLOCK_REG_ADDRESS), data->capture.block_done);
+ put_long_host(regs + (UAESND_CAPTURE_BLOCK_REG_COMMAND - UAESND_CAPTURE_BLOCK_REG_ADDRESS), 0);
+}
+
+static uae_u8 uaesnd_capture_block_bget(struct uaesndboard_data *data, uaecptr addr)
+{
+ uae_u8 regs[16] = {};
+ uaesnd_capture_block_fill_regs(data, regs);
+ return regs[(addr - UAESND_CAPTURE_BLOCK_REG_ADDRESS) & 15];
+}
+
+static uae_u16 uaesnd_capture_block_wget(struct uaesndboard_data *data, uaecptr addr)
+{
+ return (uaesnd_capture_block_bget(data, addr) << 8) | uaesnd_capture_block_bget(data, addr + 1);
+}
+
+static uae_u32 uaesnd_capture_block_lget(struct uaesndboard_data *data, uaecptr addr)
+{
+ return (uaesnd_capture_block_wget(data, addr) << 16) | uaesnd_capture_block_wget(data, addr + 2);
+}
+
+static void uaesnd_capture_block_apply_reg(struct uaesndboard_data *data, int reg, uae_u32 value)
+{
+ if (reg == UAESND_CAPTURE_BLOCK_REG_ADDRESS) {
+ data->capture.block_address = value;
+ } else if (reg == UAESND_CAPTURE_BLOCK_REG_FRAMES) {
+ data->capture.block_frames = value;
+ } else if (reg == UAESND_CAPTURE_BLOCK_REG_DONE) {
+ data->capture.block_done = value;
+ } else if (reg == UAESND_CAPTURE_BLOCK_REG_COMMAND && (value & UAESND_CAPTURE_BLOCK_COMMAND_COPY)) {
+ uaesnd_capture_block_copy(data);
+ }
+}
+
+static void uaesnd_capture_block_put(struct uaesndboard_data *data, uaecptr addr, uae_u32 value, int size)
+{
+ uae_u8 regs[16] = {};
+ int offset = (addr - UAESND_CAPTURE_BLOCK_REG_ADDRESS) & 15;
+ int reg = (addr & ~3) & 65535;
+ uaesnd_capture_block_fill_regs(data, regs);
+ if (size == 4) {
+ put_long_host(regs + offset, value);
+ } else if (size == 2) {
+ put_word_host(regs + offset, value);
+ } else {
+ regs[offset] = value;
+ }
+ uaesnd_capture_block_apply_reg(data, reg, get_long_host(regs + (reg - UAESND_CAPTURE_BLOCK_REG_ADDRESS)));
+}
/*
autoconfig data:
static bool uaesnd_rethink(void)
{
- bool irq = false;
+ bool any_irq = false;
for (int j = 0; j < MAX_DUPLICATE_SOUND_BOARDS; j++) {
struct uaesndboard_data *data = &uaesndboard[j];
if (data->enabled) {
+ bool capture_irq = uaesnd_capture_rethink(data);
+ bool stream_irq = false;
for (int i = 0; i < MAX_UAE_STREAMS; i++) {
if (data->streamintenamask & (1 << i)) {
struct uaesndboard_stream *s = &uaesndboard[j].stream[i];
if (s->intreqmask & 0x80) {
data->streamintreqmask |= 1 << i;
- irq = true;
- break;
+ stream_irq = true;
+ continue;
}
}
- if (!irq) {
- data->streamintreqmask &= ~(1 << i);
- }
+ data->streamintreqmask &= ~(1 << i);
}
+ if (capture_irq || stream_irq)
+ any_irq = true;
}
}
- return irq;
+ return any_irq;
}
static void uaesndboard_stop(struct uaesndboard_data *data, struct uaesndboard_stream *s)
write_log("UAESND %d: STOP\n", s - data->stream);
#endif
+ data->stream_stop_count++;
s->play = 0;
s->next = 0;
data->streammask &= ~(1 << (s - data->stream));
#endif
if (!s->streamid) {
+ data->stream_alloc_failure_count++;
+ uaesnd_set_error(data, UAESND_ERR_STREAM_ALLOC);
uaesndboard_stop(data, s);
}
}
#endif
s->play = 1;
+ data->stream_start_count++;
for (int i = 0; i < MAX_UAE_CHANNELS; i++) {
s->sample[i] = 0;
}
s->panx = get_word_host(s->io + 36);
s->pany = get_word_host(s->io + 38);
}
- return uaesnd_validate(data, s);
+ if (!uaesnd_validate(data, s)) {
+ data->invalid_set_count++;
+ uaesnd_set_error(data, UAESND_ERR_INVALID_SET);
+ return false;
+ }
+ return true;
}
static bool uaesnd_next(struct uaesndboard_data *data, struct uaesndboard_stream *s, uaecptr addr)
{
if ((addr & 3) || !valid_address(addr, STREAM_STRUCT_SIZE) || addr < 0x100) {
write_log(_T("UAESND: invalid sample set pointer %08x\n"), addr);
+ data->invalid_set_count++;
+ uaesnd_set_error(data, UAESND_ERR_INVALID_SET);
return false;
}
s->first = 10;
s->repeating = false;
- return uaesnd_validate(data, s);
+ if (!uaesnd_validate(data, s)) {
+ data->invalid_set_count++;
+ uaesnd_set_error(data, UAESND_ERR_INVALID_SET);
+ return false;
+ }
+ return true;
}
static void uaesnd_stream_start(struct uaesndboard_data *data, struct uaesndboard_stream *s, bool always)
static void uaesnd_irq(struct uaesndboard_stream *s, uae_u8 mask)
{
+ struct uaesndboard_data *data = &uaesndboard[0];
uae_u8 enablemask = s->masterintenamask;
uae_u8 intenamask = s->intenamask | 0x10 | 0x20 | 0x40;
+ data->stream_irq_count++;
+ if (mask & 0x10)
+ data->timer_irq_count++;
s->intreqmask |= mask;
if ((intenamask & mask) && (enablemask & mask)) {
s->intreqmask |= 0x80;
s->intreqmask = 0;
s->io[0x93] = (s->play ? 1 : 0) | (s->streamid > 0 ? 2 : 0) | (s->repeating ? 4 : 0);
v = get_byte_host(s->io + reg);
+ } else if (uaesnd_capture_addr(addr)) {
+ v = uaesnd_capture_bget(data, addr);
} else if (addr >= 0x80 && addr < 0xe0) {
+ uaesnd_update_info(data);
v = get_byte_host(data->info + (addr & 0x7f));
+ } else if (uaesnd_capture_block_addr(addr)) {
+ v = uaesnd_capture_block_bget(data, addr);
} else if (addr >= 0xe0 && addr <= 0xe3) {
v = data->streamallocmask >> (8 * (3 - (addr - 0xe0)));
} else if (addr >= 0xf0 && addr <= 0xf3) {
s->intreqmask = 0;
}
v = get_word_host(s->io + reg);
+ } else if (uaesnd_capture_addr(addr)) {
+ v = uaesnd_capture_wget(data, addr);
} else if (addr >= 0x80 && addr < 0xe0 - 1) {
+ uaesnd_update_info(data);
v = get_word_host(data->info + (addr & 0x7f));
+ } else if (uaesnd_capture_block_addr(addr)) {
+ v = uaesnd_capture_block_wget(data, addr);
} else if (addr == 0xe0) {
v = data->streamallocmask >> 16;
} else if (addr == 0xe2) {
if (reg == 0x84)
s->intreqmask = 0;
v = get_long_host(s->io + reg);
+ } else if (uaesnd_capture_addr(addr)) {
+ v = uaesnd_capture_lget(data, addr);
} else if (addr >= 0x80 && addr < 0xe0 - 3) {
+ uaesnd_update_info(data);
v = get_long_host(data->info + (addr & 0x7f));
+ } else if (uaesnd_capture_block_addr(addr)) {
+ v = uaesnd_capture_block_lget(data, addr);
} else if (addr == 0xe0) {
v = data->streamallocmask;
} else if (addr == 0xf0) {
int reg = addr & 255;
put_byte_host(s->io + reg, b);
uaesnd_put(data, s, reg);
+ } else if (uaesnd_capture_addr(addr)) {
+ uaesnd_capture_put(data, addr, b, 1);
+ } else if (uaesnd_capture_block_addr(addr)) {
+ uaesnd_capture_block_put(data, addr, b, 1);
} else if (addr >= 0xe0 && addr <= 0xe3) {
uae_u32 v = data->streamallocmask;
int shift = 8 * (3 - (addr - 0xe0));
int reg = addr & 255;
put_word_host(s->io + reg, b);
uaesnd_put(data, s, reg);
+ } else if (uaesnd_capture_addr(addr)) {
+ uaesnd_capture_put(data, addr, b, 2);
+ } else if (uaesnd_capture_block_addr(addr)) {
+ uaesnd_capture_block_put(data, addr, b, 2);
} else if (addr == 0xe4 + 2) {
uaesnd_latch_mask(data, b);
} else if (addr == 0xe8 + 2) {
int reg = addr & 255;
put_long_host(s->io + reg, b);
uaesnd_put(data, s, reg);
+ } else if (uaesnd_capture_addr(addr)) {
+ uaesnd_capture_put(data, addr, b, 4);
+ } else if (uaesnd_capture_block_addr(addr)) {
+ uaesnd_capture_block_put(data, addr, b, 4);
} else if (addr == 0xe0) {
uaesnd_streammask(data, data->streammask & b);
data->streamallocmask = b;
if (!ert)
return false;
data->streammask = 0;
+ data->invalid_set_count = 0;
+ data->stream_alloc_failure_count = 0;
+ data->stream_start_count = 0;
+ data->stream_stop_count = 0;
+ data->stream_irq_count = 0;
+ data->timer_irq_count = 0;
+ data->last_error_code = UAESND_ERR_NONE;
+ memset(&data->capture, 0, sizeof data->capture);
for (int i = 0; i < MAX_UAE_CHANNELS; i++) {
data->volume[i] = 32768;
}
put_byte_host(data->info + 14, MAX_UAE_STREAMS);
put_long_host(data->info + 16, data->z3 ? 8 * 1024 * 1024 : 0x8000);
put_long_host(data->info + 20, data->z3 ? 8 * 1024 * 1024 : 0x8000);
+ uaesnd_update_info(data);
for (int i = 0; i < 16; i++) {
uae_u8 b = ert->autoconfig[i];
ew(data->acmemory, i * 4, b);
{
for (int j = 0; j < MAX_DUPLICATE_SOUND_BOARDS; j++) {
struct uaesndboard_data *data = &uaesndboard[j];
+ uaesnd_capture_stop(data);
data->enabled = false;
}
mapped_free(&uaesndboard_ram_bank);
}
}
data->streammask = 0;
+ uaesnd_capture_stop(data);
}
mapped_free(&uaesndboard_ram_bank);
sndboard_rethink();
if (data->snddev_active & STATUS_FIFO_RECORD) {
data->capture_buffer_size = 48000 * 2 * 2; // 1s at 48000/stereo/16bit
data->capture_buffer = xcalloc(uae_u8, data->capture_buffer_size);
- if (!sndboard_init_capture(data->freq_adjusted)) {
+ if (!sndboard_init_capture(data->freq_adjusted, SNDBOARD_CAPTURE_OWNER_TOCCATA)) {
write_log(_T("SNDDEV capture unavailable, recording disabled\n"));
data->snddev_active &= ~STATUS_FIFO_RECORD;
xfree(data->capture_buffer);
return;
write_log(_T("CODEC stop\n"));
data->snddev_active = 0;
- sndboard_free_capture();
+ sndboard_free_capture(SNDBOARD_CAPTURE_OWNER_TOCCATA);
int streamid = data->streamid;
data->streamid = 0;
audio_enable_stream(false, streamid, 0, NULL, NULL);
}
}
-static void sndboard_free_capture(void)
+static void sndboard_free_capture(int owner)
{
+ if (capture_owner != owner)
+ return;
if (capture_started)
pAudioClient->Stop();
capture_started = false;
+ capture_owner = SNDBOARD_CAPTURE_OWNER_NONE;
SAFE_RELEASE(pEnumerator)
SAFE_RELEASE(pDevice)
SAFE_RELEASE(pAudioClient)
SAFE_RELEASE(pCaptureClient)
}
-static bool sndboard_init_capture(int freq)
+static bool sndboard_init_capture(int freq, int owner)
{
HRESULT hr;
WAVEFORMATEX wavfmtsrc;
WAVEFORMATEX *wavfmt;
bool init = false;
+ if (capture_started)
+ return capture_owner == owner;
+
wavfmt2 = NULL;
hr = CoCreateInstance(
if (hr == S_FALSE && wavfmt2) {
wavfmt = wavfmt2;
- hr = pAudioClient->Initialize(exc, 0, time, 0, wavfmt, NULL);
- if (SUCCEEDED(hr)) {
- init = true;
- break;
+ if (wavfmt->wFormatTag == WAVE_FORMAT_PCM && wavfmt->nChannels == 2 && wavfmt->wBitsPerSample == 16) {
+ hr = pAudioClient->Initialize(exc, 0, time, 0, wavfmt, NULL);
+ if (SUCCEEDED(hr)) {
+ init = true;
+ break;
+ }
}
}
}
hr = pAudioClient->Start();
EXIT_ON_ERROR(hr)
capture_started = true;
+ capture_owner = owner;
CoTaskMemFree(wavfmt2);
Exit:;
CoTaskMemFree(wavfmt2);
write_log(_T("sndboard capture init failed %08x\n"), hr);
- sndboard_free_capture();
+ sndboard_free_capture(owner);
return false;
}
unix_sndboard_release_buffer(buffer, frames);
}
-static void sndboard_free_capture(void)
+static void sndboard_free_capture(int owner)
{
+ if (capture_owner != owner)
+ return;
unix_sndboard_free_capture();
+ capture_owner = SNDBOARD_CAPTURE_OWNER_NONE;
}
-static bool sndboard_init_capture(int freq)
+static bool sndboard_init_capture(int freq, int owner)
{
- return unix_sndboard_init_capture(freq);
+ if (capture_owner != SNDBOARD_CAPTURE_OWNER_NONE)
+ return capture_owner == owner;
+ if (!unix_sndboard_init_capture(freq))
+ return false;
+ capture_owner = owner;
+ return true;
}
#endif