[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v4 08/20] asc: generate silence if FIFO empty but engine still ru
|
From: |
Mark Cave-Ayland |
|
Subject: |
[PATCH v4 08/20] asc: generate silence if FIFO empty but engine still running |
|
Date: |
Wed, 4 Oct 2023 09:37:54 +0100 |
MacOS (un)helpfully leaves the FIFO engine running even when all the samples
have
been written to the hardware, and expects the FIFO status flags and IRQ to be
updated continuously.
There is an additional problem in that not all audio backends guarantee an
all-zero output when there is no FIFO data available, in particular the Windows
dsound backend which re-uses its internal circular buffer causing the last
played
sound to loop indefinitely.
Whilst this is effectively a bug in the Windows dsound backend, work around it
for now using a simple heuristic: if the FIFO remains empty for half a cycle
(~23ms) then continuously fill the generated buffer with empty silence.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
---
hw/audio/asc.c | 19 +++++++++++++++++++
include/hw/audio/asc.h | 2 ++
2 files changed, 21 insertions(+)
diff --git a/hw/audio/asc.c b/hw/audio/asc.c
index 9084708eaf..0f36b4ce9b 100644
--- a/hw/audio/asc.c
+++ b/hw/audio/asc.c
@@ -341,6 +341,21 @@ static void asc_out_cb(void *opaque, int free_b)
}
if (!generated) {
+ /* Workaround for audio underflow bug on Windows dsound backend */
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ int silent_samples = muldiv64(now - s->fifo_empty_ns,
+ NANOSECONDS_PER_SECOND, ASC_FREQ);
+
+ if (silent_samples > ASC_FIFO_CYCLE_TIME / 2) {
+ /*
+ * No new FIFO data within half a cycle time (~23ms) so fill the
+ * entire available buffer with silence. This prevents an issue
+ * with the Windows dsound backend whereby the sound appears to
+ * loop because the FIFO has run out of data, and the driver
+ * reuses the stale content in its circular audio buffer.
+ */
+ AUD_write(s->voice, s->silentbuf, samples << s->shift);
+ }
return;
}
@@ -618,6 +633,7 @@ static void asc_unrealize(DeviceState *dev)
ASCState *s = ASC(dev);
g_free(s->mixbuf);
+ g_free(s->silentbuf);
AUD_remove_card(&s->card);
}
@@ -642,6 +658,9 @@ static void asc_realize(DeviceState *dev, Error **errp)
s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift;
s->mixbuf = g_malloc0(s->samples << s->shift);
+ s->silentbuf = g_malloc0(s->samples << s->shift);
+ memset(s->silentbuf, 0x80, s->samples << s->shift);
+
/* Add easc registers if required */
if (s->type == ASC_TYPE_EASC) {
memory_region_add_subregion(&s->asc, ASC_EXTREG_OFFSET,
diff --git a/include/hw/audio/asc.h b/include/hw/audio/asc.h
index d9412815c3..4741f92c46 100644
--- a/include/hw/audio/asc.h
+++ b/include/hw/audio/asc.h
@@ -68,6 +68,8 @@ struct ASCState {
int samples;
int shift;
+ uint8_t *silentbuf;
+
/* Time when we were last able to generate samples */
int64_t fifo_empty_ns;
--
2.39.2
- [PATCH v4 00/20] q800: add support for booting MacOS Classic - part 2, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 02/20] q800: add djMEMC memory controller, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 01/20] q800-glue.c: convert to Resettable interface, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 03/20] q800: add machine id register, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 04/20] q800: implement additional machine id bits on VIA1 port A, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 05/20] q800: add IOSB subsystem, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 06/20] q800: allow accesses to RAM area even if less memory is available, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 07/20] audio: add Apple Sound Chip (ASC) emulation, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 08/20] asc: generate silence if FIFO empty but engine still running,
Mark Cave-Ayland <=
- [PATCH v4 09/20] q800: add Apple Sound Chip (ASC) audio to machine, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 10/20] q800: add easc bool machine class property to switch between ASC and EASC, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 11/20] swim: add trace events for IWM and ISM registers, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 12/20] swim: split into separate IWM and ISM register blocks, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 13/20] swim: update IWM/ISM register block decoding, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 14/20] mac_via: work around underflow in TimeDBRA timing loop in SETUPTIMEK, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 15/20] mac_via: workaround NetBSD ADB bus enumeration issue, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 16/20] mac_via: implement ADB_STATE_IDLE state if shift register in input mode, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 17/20] mac_via: always clear ADB interrupt when switching to A/UX mode, Mark Cave-Ayland, 2023/10/04
- [PATCH v4 18/20] q800: add ESCC alias at 0xc000, Mark Cave-Ayland, 2023/10/04