qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
@ 2019-12-29  2:45 John Arbuckle
  0 siblings, 0 replies; 9+ messages in thread
From: John Arbuckle @ 2019-12-29  2:45 UTC (permalink / raw)
  To: mark.cave-ayland, qemu-ppc, qemu-devel; +Cc: John Arbuckle

This patch enables the playback of audio on a Mac OS 9 or Mac OS X guest.

Signed-off-by: John Arbuckle <programmingkidx@gmail.com>
---
v2 changes:
- Fixed a bug that prevented the sampling rate from being changed.

 hw/audio/Kconfig              |   3 +
 hw/audio/Makefile.objs        |   2 +
 hw/audio/screamer.c           | 993 ++++++++++++++++++++++++++++++++++++++++++
 hw/misc/macio/macio.c         |  35 +-
 hw/ppc/Kconfig                |   1 +
 hw/ppc/mac.h                  |   5 +
 include/hw/audio/screamer.h   |  42 ++
 include/hw/misc/macio/macio.h |   2 +
 8 files changed, 1082 insertions(+), 1 deletion(-)
 create mode 100644 hw/audio/screamer.c
 create mode 100644 include/hw/audio/screamer.h

diff --git a/hw/audio/Kconfig b/hw/audio/Kconfig
index e9c6fed826..196da6c3fe 100644
--- a/hw/audio/Kconfig
+++ b/hw/audio/Kconfig
@@ -50,3 +50,6 @@ config CS4231
 
 config MARVELL_88W8618
     bool
+
+config SCREAMER
+    bool
diff --git a/hw/audio/Makefile.objs b/hw/audio/Makefile.objs
index 63db383709..55906886bc 100644
--- a/hw/audio/Makefile.objs
+++ b/hw/audio/Makefile.objs
@@ -15,4 +15,6 @@ common-obj-$(CONFIG_CS4231) += cs4231.o
 common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o
 common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o
 
+common-obj-$(CONFIG_SCREAMER) += screamer.o
+
 common-obj-y += soundhw.o
diff --git a/hw/audio/screamer.c b/hw/audio/screamer.c
new file mode 100644
index 0000000000..d3a86d2e67
--- /dev/null
+++ b/hw/audio/screamer.c
@@ -0,0 +1,993 @@
+/*
+ * File: Screamer.c
+ * Description: Implement the Screamer sound chip used in Apple Macintoshes.
+ * It works by filling a buffer, then playing the buffer.
+ */
+
+#include "qemu/osdep.h"
+#include "audio/audio.h"
+#include "hw/hw.h"
+#include "hw/irq.h"
+#include <inttypes.h>
+#include "hw/ppc/mac.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "include/hw/audio/screamer.h"
+
+#define DEBUG_SCREAMER 0
+#define DPRINTF(fmt, ...) \
+do { if (DEBUG_SCREAMER) { printf(fmt , ## __VA_ARGS__); } } while (0)
+
+#define SOUND_CONTROL_REG  0
+#define CODEC_CONTROL_REG  1
+#define CODEC_STATUS_REG   2
+#define CLIP_COUNT_REG     3
+#define BYTE_SWAP_REG      4
+#define FRAME_COUNT_REG    5
+
+#define AWACS_BUSY         0x01000000
+
+/* Used with AWACS register 1 */
+#define RECALIBRATE         0x004
+#define LOOPTHRU            0x040
+#define SPEAKER_MUTE        0x080
+#define HEADPHONE_MUTE      0x200
+#define OUTPUT_ZERO         0x400
+#define OUTPUT_ONE          0x800
+#define PARALLEL_OUTPUT     0xc00
+
+/* Function prototypes */
+static uint32_t set_busy_bit(uint32_t value, int bit);
+static uint32_t set_part_ready_bit(uint32_t value, int bit_value);
+static uint32_t set_revision(uint32_t input_value);
+static uint32_t set_manufacturer(uint32_t input_value);
+static int get_sampling_rate(ScreamerState *s);
+static uint32_t get_frame_count_reg(ScreamerState *s);
+static void add_to_speaker_buffer(DBDMA_io *io);
+static void dma_request(DBDMA_io *io);
+
+
+/**************************** Getters *************************/
+
+/* Returns the codec control register's encoded AWACS address */
+static uint8_t get_codec_control_address(uint32_t value)
+{
+    uint8_t return_value;
+    return_value = (value >> 12) & 0x00000fff;
+    return return_value;
+}
+
+
+static uint32_t get_sound_control_reg(ScreamerState *s)
+{
+    DPRINTF("%s() called - returned 0x%x\n", __func__, s->sound_control);
+    return s->sound_control;
+}
+
+/* The AWACS registers are accessed thru this register */
+static uint32_t get_codec_control_reg(ScreamerState *s)
+{
+    int awacs_register = get_codec_control_address(s->codec_control);
+    uint32_t return_value = s->awacs[awacs_register];
+    return_value = set_busy_bit(return_value, 0); /* Tell CPU we are ready */
+    DPRINTF("%s() called - returned 0x%x\tAWACS register: %d\n", __func__,
+            return_value, awacs_register);
+    return return_value;
+}
+
+/*
+ * Determines if the readback bit is set.
+ * It is used by the Codec Control register.
+ */
+static bool readback_enabled(ScreamerState *s)
+{
+/* Note: bit zero is the readback enabled bit */
+    if (s->awacs[7] & 1) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static uint32_t get_codec_status_reg(ScreamerState *s)
+{
+    uint32_t return_value;
+
+    /* if in readback mode - return AWACS register value */
+    if (readback_enabled(s)) {
+        int awacs_register = (s->awacs[7] & 0xe) >> 1;
+        s->awacs[7] = s->awacs[7] & 0xfffffffe; /* turn off readback mode */
+        return_value = s->awacs[awacs_register] << 4;
+        DPRINTF("readback enable bit is set, returning AWACS register %d\t"
+                "value:0x%x\n", awacs_register, return_value);
+
+        return return_value;
+    }
+
+    /* Tell CPU we are ready */
+    return_value = set_part_ready_bit(s->codec_status, 1);
+
+    /* Set Revision to Screamer */
+    return_value = set_revision(return_value);
+
+    /* Set the Manufacturer to Crystal */
+    return_value = set_manufacturer(return_value);
+    DPRINTF("%s() called - returned 0x%x\n", __func__, return_value);
+
+    return return_value;
+}
+
+static uint32_t get_clip_count_reg(ScreamerState *s)
+{
+    DPRINTF("%s() called - returned 0x%x\n", __func__, s->clip_count);
+    uint32_t return_value;
+    return_value = s->clip_count;
+    /* This is reset everytime it is read */
+    s->clip_count = 0;
+    return return_value;
+}
+
+static uint32_t get_byte_swap_reg(ScreamerState *s)
+{
+    DPRINTF("%s() called - returned 0x%x\n", __func__, s->byte_swap);
+    /*
+     * If all you hear is noise, it could be this register reporting the
+     * wrong value.
+     */
+    return s->byte_swap ? 0 : 1;
+}
+
+/*
+ * Returns the frame (sample) count
+ */
+static uint32_t get_frame_count_reg(ScreamerState *s)
+{
+    DPRINTF("%s() called - returned 0x%x\n", __func__, s->frame_count);
+    return s->frame_count;
+}
+
+static uint8_t get_left_vol(uint32_t value)
+{
+    return value & 0xf;
+}
+
+static uint8_t get_right_vol(uint32_t value)
+{
+    return value & 0x3c0 >> 6;
+}
+
+/*
+ * Returns the sampling rate.
+ * If the audio is playing back too fast or too slow, this function may be the
+ * cause.
+ */
+static int get_sampling_rate(ScreamerState *s)
+{
+    uint32_t screamer_rate = s->sound_control & 0x700;
+    int return_value;
+
+    /* All return values are in Hertz */
+    switch (screamer_rate) {
+    case 0x0:
+        return_value = 44100;
+        break;
+    case 0x100:
+        return_value = 29400;
+        break;
+    case 0x200:
+        return_value = 22050;
+        break;
+    case 0x300:
+        return_value = 17640;
+        break;
+    case 0x400:
+        return_value = 14700;
+        break;
+    case 0x500:
+        return_value = 11025;
+        break;
+    case 0x600:
+        return_value = 8820;
+        break;
+    case 0x700:
+        return_value = 7350;
+        break;
+    default:
+        DPRINTF("get_sampling_rate() unknown value: 0x%x\nDefaulting to"
+                " 44100 Hz.\n", screamer_rate);
+        return 44100;
+}
+    DPRINTF("%s() called - returning %dHz\n", __func__, return_value);
+    return return_value;
+}
+
+/**************************** End of getters *************************/
+
+/***************************** Speaker call back *************************/
+
+/* resets the play and buffer position markers */
+static void reset_markers(ScreamerState *s)
+{
+    s->spk_play_position = 0;
+    s->spk_buffer_position = 0;
+}
+
+
+/* Sends the samples to the host for playing */
+static void send_samples_to_host(ScreamerState *s, int max_samples)
+{
+    int write_length, requested_length;
+    requested_length = MIN(max_samples, (s->spk_buffer_position -
+                                         s->spk_play_position));
+    write_length = AUD_write(s->speaker_voice,
+                             &s->spk_buffer[s->spk_play_position],
+                             requested_length);
+    DPRINTF("requested length: %d\twrite length: %d\t",
+            requested_length, write_length);
+    s->spk_play_position += write_length;
+    DPRINTF("AUD_write %d/%d\n", s->spk_play_position, s->spk_buffer_position);
+    s->frame_count += write_length;
+}
+
+
+/*
+ * Called by QEMU's audio system to tell the output backend to send samples
+ * from the buffer to the host sound system.
+ * opaque: a pointer to the ScreamerState instance.
+ * max_samples: the number of samples that can be sent to the hardware buffer.
+ */
+static void speaker_callback(void *opaque, int max_samples)
+{
+    ScreamerState *s = (ScreamerState *) opaque;
+
+    /* if we have more samples to play */
+    if (s->spk_buffer_position > 0) {
+        if (s->spk_buffer_position > s->spk_play_position) {
+            DPRINTF("%s() called - max_samples: %d\n", __func__, max_samples);
+            send_samples_to_host(s, max_samples);
+        }
+        if (s->spk_play_position >= s->spk_buffer_position) {
+            DPRINTF("done playing buffer\n");
+            DPRINTF("pp: %d\tbp: %d\n", s->spk_play_position,
+                    s->spk_buffer_position);
+            if (s->spk_play_position > s->spk_buffer_position) {
+                DPRINTF("Error detected! - pp > bp\n\a");
+            }
+            reset_markers(s);
+            /* play postponed samples */
+            if (s->dma_io.len > 0) {
+                DPRINTF("playing postponed samples\n");
+                add_to_speaker_buffer(&s->dma_io);
+                return;
+            }
+        }
+    }
+}
+
+/************************* End of speaker call back *************************/
+
+
+/* Opens the speaker's voice */
+static void open_speaker_voice(ScreamerState *s)
+{
+    DPRINTF("%s() called\n", __func__);
+
+    /* if voice is already open return from function */
+    if (s->speaker_voice != NULL) {
+        DPRINTF("closing speaker voice\n");
+        AUD_close_out(&s->card, s->speaker_voice);
+        s->speaker_voice = NULL;
+    }
+    struct audsettings audio_settings;
+    audio_settings.freq = get_sampling_rate(s);  /* in hertz */
+    audio_settings.nchannels = 2;                /* stereo output */
+    audio_settings.fmt = AUDIO_FORMAT_S16;       /* signed 16 bit */
+    audio_settings.endianness = get_byte_swap_reg(s); /* endianness */
+    s->speaker_voice = AUD_open_out(&s->card, s->speaker_voice, SOUND_CHIP_NAME
+                                    " speaker", s, speaker_callback,
+                                    &audio_settings);
+    if (!s->speaker_voice) {
+        AUD_log(SOUND_CHIP_NAME, "Out voice could not be opened\n");
+    } else {
+        AUD_set_active_out(s->speaker_voice, true);
+    }
+}
+
+
+/******************************* Setters *************************************/
+
+
+/* Updates QEMU's audio backend settings */
+static void set_QEMU_audio_settings(ScreamerState *s)
+{
+    DPRINTF("%s() called\n", __func__);
+    open_speaker_voice(s);
+}
+
+
+/* Return value: 1 = muted  0 = not muted */
+static int is_muted(ScreamerState *s)
+{
+    int mute_state = s->awacs[1] & SPEAKER_MUTE ? 1 : 0;
+    if (s->awacs[1] & SPEAKER_MUTE) {
+        DPRINTF("speaker is muted\n");
+    } else {
+        DPRINTF("speaker is unmuted\n");
+    }
+
+    if (s->awacs[1] & HEADPHONE_MUTE) {
+        DPRINTF("headphone is muted\n");
+    } else {
+        DPRINTF("headphone is unmuted\n");
+    }
+    return mute_state;
+}
+
+
+/* Converts Screamer's volume system to QEMU's system */
+static int screamer_to_qemu_volume(int x)
+{
+    return -16 * x + 240;
+}
+
+
+/* Sets QEMU's volume. */
+static void set_volume(ScreamerState *s)
+{
+    int should_mute = is_muted(s);
+
+    /* Get Screamer volume values */
+    uint8_t left_vol = get_left_vol(s->awacs[4]);
+    uint8_t right_vol = get_right_vol(s->awacs[4]);
+    DPRINTF("set_volume() called - M:%d\tL:%d\tR:%d\n", should_mute, left_vol,
+            right_vol);
+
+    /* Convert Screamer to QEMU volume values */
+    left_vol = screamer_to_qemu_volume(left_vol);
+    right_vol = screamer_to_qemu_volume(right_vol);
+    DPRINTF("QEMU volume: L:%d\tR:%d\n", left_vol, right_vol);
+    AUD_set_volume_out(s->speaker_voice, should_mute, left_vol, right_vol);
+}
+
+
+/* Sets the sound control register */
+static void set_sound_control_reg(ScreamerState *s, uint32_t value)
+{
+    DPRINTF("set_sound_control_reg() called - value: 0x%x\n", value);
+    s->sound_control = value;
+    set_QEMU_audio_settings(s);
+}
+
+
+/* Used for input gain only - can be ignored for now. */
+static void set_awacs_0_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("Settings AWACS register 0 to 0x%x\n", s->awacs[0]);
+    s->awacs[0] = new_value;
+}
+
+
+static void set_awacs_1_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("Settings AWACS register 1 to 0x%x\n", new_value);
+
+    s->awacs[1] = new_value;
+
+    /* If recalibration requested */
+    if (new_value & RECALIBRATE) {
+        DPRINTF("Recalibration requested - unimplemented\n");
+        new_value = new_value ^ RECALIBRATE; /* Turn off recalibrate bit */
+    }
+
+    /* If loop thru set - what does this mean? */
+    if (new_value & LOOPTHRU) {
+        DPRINTF("Loopthru enabled - doing nothing\n");
+    }
+
+    /* Set headphone jack mute state */
+    if (new_value & HEADPHONE_MUTE) {
+        DPRINTF("Headphone muted\n");
+    }
+
+    else {
+        DPRINTF("Headphone unmuted\n");
+    }
+
+    if (new_value & SPEAKER_MUTE) {
+        DPRINTF("Speaker muted\n");
+    }
+
+    else {
+        DPRINTF("Speaker unmuted\n");
+    }
+
+    if (new_value & OUTPUT_ZERO) {
+        DPRINTF("output zero set - not sure what this means\n");
+    }
+
+    if (new_value & OUTPUT_ONE) {
+        DPRINTF("output one set - not sure what this means\n");
+    }
+
+    if (new_value & PARALLEL_OUTPUT) {
+        DPRINTF("parallel port enabled - but no parallel port here\n");
+    }
+
+    set_volume(s);
+}
+
+
+/* This is used for headphone volume - not needed */
+static void set_awacs_2_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("Settings AWACS register 2 to 0x%x\n"
+            "Ignoring change in headphone volume.\n", s->awacs[2]);
+    s->awacs[2] = new_value;
+}
+
+
+/* Unknown register purpose */
+static void set_awacs_3_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("Settings AWACS register 3 to 0x%x\n"
+            "This register has an unknown purpose and does not do anything\n",
+            s->awacs[3]);
+    s->awacs[3] = new_value;
+}
+
+
+/* Mostly deals with speaker volume */
+static void set_awacs_4_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("AWACS register 4 write: 0x%x\n", new_value);
+    s->awacs[4] = new_value;
+    set_volume(s);
+}
+
+
+/* This register is about loop thru stuff I don't understand */
+static void set_awacs_5_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("Settings AWACS register 5 to 0x%x\n"
+            "Loop thru update ignored.\n", s->awacs[5]);
+    s->awacs[5] = new_value;
+}
+
+
+/* Prints the states of the AWACS power register */
+static void print_power_reg_values(uint32_t value)
+{
+    if ((value & 0x3) == 0) {
+        printf("Screamer run state set\n");
+    }
+    if ((value & 0x3) == 1) {
+        printf("Screamer doze state set\n");
+    }
+    if ((value & 0x3) == 2) {
+        printf("Screamer idle state set\n");
+    }
+}
+
+
+/* Power Magement register */
+static void set_awacs_6_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("Settings AWACS register 6 to 0x%x\n"
+            "Power management update ignored.\n", s->awacs[6]);
+    if (DEBUG_SCREAMER) {
+        print_power_reg_values(new_value);
+    }
+    s->awacs[6] = new_value;
+}
+
+
+/* Read Back - repeating something that was sent to this chip? */
+static void set_awacs_7_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("Settings AWACS register 7 to 0x%x\n", new_value);
+    s->awacs[7] = new_value;
+}
+
+
+/* Sets the AWACs registers - a.k.a. shadow registers */
+static void set_awacs_register(ScreamerState *s, uint32_t value)
+{
+    int the_register = get_codec_control_address(value);
+
+    switch (the_register) {
+    case 0:
+        set_awacs_0_reg(s, value);
+        break;
+    case 1:
+        set_awacs_1_reg(s, value);
+        break;
+    case 2:
+        set_awacs_2_reg(s, value);
+        break;
+    case 3:
+        set_awacs_3_reg(s, value);
+        break;
+    case 4:
+        set_awacs_4_reg(s, value);
+        break;
+    case 5:
+        set_awacs_5_reg(s, value);
+        break;
+    case 6:
+        set_awacs_6_reg(s, value);
+        break;
+    case 7:
+        set_awacs_7_reg(s, value);
+        break;
+    default:
+        DPRINTF("Unhandled awacs registers %d\n", the_register);
+    }
+}
+
+
+/* Used to set the AWACS registers */
+static void set_codec_control_reg(ScreamerState *s, uint32_t value)
+{
+    DPRINTF("set_codec_control_reg() called - value: 0x%x\n", value);
+    s->codec_control = value;
+    set_awacs_register(s, value);
+}
+
+static void set_codec_status_reg(ScreamerState *s, uint32_t value)
+{
+    DPRINTF("set_codec_status_reg() called - value: 0x%x\n", value);
+    s->codec_status = value;
+}
+
+static void set_clip_count_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("set_clip_count_reg() called - value: 0x%x\n", new_value);
+    s->clip_count = new_value;
+}
+
+static void set_byte_swap_reg(ScreamerState *s, uint32_t value)
+{
+    DPRINTF("set_byte_swap_reg() called - value: 0x%x\n", value);
+    s->byte_swap = value;
+}
+
+static void set_frame_count_reg(ScreamerState *s, uint32_t new_value)
+{
+    DPRINTF("%s() called - value: 0x%x\n", __func__, new_value);
+    s->frame_count = new_value;
+}
+
+/*
+ * Sets the busy bit of codec control register.
+ * It is used to tell the CPU to wait.
+ * value: the codec control register's value
+ * bit_value: used to set or disable the busy bit
+ */
+static uint32_t set_busy_bit(uint32_t value, int bit_value)
+{
+    const int busy_bit = 0x01000000;
+    uint32_t return_value;
+    if (bit_value == 1)  /* Set this bit */
+        return_value = (value | busy_bit);
+    else /* bit_value == 0  Disable this bit */
+        return_value = (value & ~busy_bit);
+    return return_value;
+}
+
+
+/*
+ * Sets the part ready bit of the codec status register
+ * value: the codec status register's value
+ * bit_value: used to set or disable the part ready bit
+ */
+static uint32_t set_part_ready_bit(uint32_t value, int bit_value)
+{
+    const int part_ready_bit = 0x00400000;
+    uint32_t return_value;
+    if (bit_value == 1)  /* Set this bit */
+        return_value = (value | part_ready_bit);
+    else /* bit_value == 0  Disable this bit */
+        return_value = (value & ~part_ready_bit);
+    return return_value;
+}
+
+/* Sets bits 12 and 13 to 1 to indicate the Screamer revision */
+static uint32_t set_revision(uint32_t input_value)
+{
+    uint32_t return_value;
+    return_value = input_value | 0x3000;
+    return return_value;
+}
+
+/* Sets bit 8 to indicate Crystal as the manufacturer */
+static uint32_t set_manufacturer(uint32_t input_value)
+{
+    uint32_t return_value;
+    return_value = input_value | 0x100;
+    return return_value;
+}
+
+
+/************************** End of Setters *********************************/
+
+
+/*************************** DMA functions *********************************/
+
+/*
+ * Sends audio samples from a microphone or line-in to memory.
+ * Used for sound input.
+ * Currently only prevents a deadlock condition with Mac OS 9.
+ */
+static void screamer_to_dma(DBDMA_io *io)
+{
+    DPRINTF("%s() called\n", __func__);
+    ScreamerState *s = (ScreamerState *)io->opaque;
+    DBDMAState *dbs = s->dbdma;
+    DBDMA_channel *ch = &dbs->channels[0x12];
+    ch->regs[DBDMA_STATUS] |= DEAD;
+    ch->regs[DBDMA_STATUS] &= ~ACTIVE;
+    io->dma_end(io);
+    return;
+}
+
+
+static void print_dma_info(DBDMA_io *io)
+{
+    #define RUN        0x8000
+    #define PAUSE      0x4000
+    #define FLUSH      0x2000
+    #define WAKE       0x1000
+    #define DEAD       0x0800
+    #define ACTIVE     0x0400
+    #define BT         0x0100
+    #define DEVSTAT    0x00ff
+
+    /*
+     * RUN and PAUSE are bits under software control only.
+     * FLUSH and WAKE are set by SW and cleared by hardware.
+     * DEAD, ACTIVE and BT are only under hardware control.
+     */
+
+    DBDMA_channel *ch = io->channel;
+    printf("DMA FLAGS: ");
+
+    if (ch->regs[DBDMA_STATUS] & RUN) {
+        printf("RUN ");
+    }
+
+    if (ch->regs[DBDMA_STATUS] & ACTIVE) {
+        printf("ACTIVE ");
+    }
+
+    if (ch->regs[DBDMA_STATUS] & PAUSE) {
+        printf("PAUSE ");
+    }
+
+    if (ch->regs[DBDMA_STATUS] & DEAD) {
+        printf("DEAD ");
+    }
+
+    if (ch->regs[DBDMA_STATUS] & WAKE) {
+        printf("WAKE ");
+    }
+
+    if (ch->regs[DBDMA_STATUS] & BT) {
+        printf("BT ");
+    }
+
+    if (ch->regs[DBDMA_STATUS] & DEVSTAT) {
+        printf("DEVSTAT ");
+    }
+
+    if (ch->regs[DBDMA_STATUS] & FLUSH) {
+        printf("FLUSH ");
+    }
+
+    if (ch->io.processing == true) {
+        printf("processing  ");
+    }
+
+    printf("\n");
+}
+
+/* Tell the DMA controller we request more samples */
+static void dma_request(DBDMA_io *io)
+{
+    DPRINTF("%s() called\n", __func__);
+    if (DEBUG_SCREAMER) {
+        print_dma_info(io);
+    }
+    io->len = 0;
+    io->dma_end(io);
+}
+
+
+/* Adds sample data to the buffer */
+static void add_to_speaker_buffer(DBDMA_io *io)
+{
+    ScreamerState *s = (ScreamerState *) io->opaque;
+
+    if (s->spk_buffer_position + io->len > MAX_BUFFER_SIZE) {
+        /* postpone calling these samples until the buffer has been emptied */
+        memcpy(&s->dma_io, io, sizeof(DBDMA_io));
+        return;
+    }
+    dma_memory_read(&address_space_memory, io->addr,
+                    &s->spk_buffer[s->spk_buffer_position], io->len);
+    s->spk_buffer_position += io->len;
+    DPRINTF("%s() called - len: %d pos: %d/%d\n", __func__, io->len,
+            s->spk_buffer_position, MAX_BUFFER_SIZE);
+
+    dma_request(io);
+}
+
+/*
+ * Called by the DMA chip to transfer samples from memory to the
+ * Screamer chip.
+ * Used for sound output.
+ */
+static void dma_to_screamer(DBDMA_io *io)
+{
+    add_to_speaker_buffer(io);
+}
+
+
+/*
+ * This will flush the audio buffer of previous audio - eliminating previous
+ * audio playback.
+ */
+static void send_silence_to_speaker(ScreamerState *s)
+{
+    DPRINTF("Silencing audio buffer...\n");
+    int length = MAX_BUFFER_SIZE;
+    s->spk_buffer_position = length;
+    s->spk_play_position = 0;
+    memset(s->spk_buffer, 0, length);
+    s->dma_io.len = 0; /* stop any postponed samples from playing */
+}
+
+
+/* This is called after audio stops playing */
+static void dma_send_flush(DBDMA_io *io)
+{
+    DPRINTF("dma_send_flush() called\n");
+    if (DEBUG_SCREAMER) {
+        print_dma_info(io);
+    }
+    ScreamerState *s = (ScreamerState *)io->opaque;
+    reset_markers(s);
+    send_silence_to_speaker(s);
+    if (io->len > 0) {
+        dma_request(io);
+    }
+}
+
+
+static void dma_receive_flush(DBDMA_io *io)
+{
+    DPRINTF("dma_receive_flush() called\n");
+}
+
+
+/* Set the functions the DMA system will call */
+void screamer_register_dma_functions(ScreamerState *s, void *dbdma,
+                                   int send_channel, int receive_channel)
+{
+    DPRINTF("%s() called\n", __func__);
+    DPRINTF("send channel: %d\treceive channel: %d\n", send_channel,
+           receive_channel);
+    s->dbdma = dbdma;
+
+    /* Setup the DMA send system */
+    DBDMA_register_channel(s->dbdma, send_channel, s->dma_send_irq,
+                           dma_to_screamer, dma_send_flush, s);
+
+    /* Setup the DMA receive system */
+    DBDMA_register_channel(s->dbdma, receive_channel, s->dma_receive_irq,
+                           screamer_to_dma, dma_receive_flush, s);
+}
+
+/************************* End of DMA functions **************************/
+
+/* Resets this sound chip */
+static void screamer_reset(DeviceState *d)
+{
+    DPRINTF("screamer_reset() called\n");
+    ScreamerState *s = SCREAMER(d);
+    set_sound_control_reg(s, 0);
+    set_codec_control_reg(s, 0);
+    set_codec_status_reg(s, 0);
+    set_clip_count_reg(s, 0);
+    set_byte_swap_reg(s, 0);
+    set_frame_count_reg(s, 0);
+    int i, num_awacs_regs = 8;
+    for (i = 0; i < num_awacs_regs; i++) {
+        s->awacs[i] = 0;
+    }
+    set_QEMU_audio_settings(s);
+    reset_markers(s);
+    s->dma_io.len = 0;
+}
+
+/* Called when the CPU reads the memory addresses assigned to Screamer */
+static uint64_t screamer_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    ScreamerState *state = opaque;
+    uint32_t return_value;
+
+    addr = addr >> 4;
+    switch (addr) {
+    case SOUND_CONTROL_REG:
+        return_value = get_sound_control_reg(state);
+        break;
+    case CODEC_CONTROL_REG:
+        return_value = get_codec_control_reg(state);
+        break;
+    case CODEC_STATUS_REG:
+        return_value = get_codec_status_reg(state);
+        break;
+    case CLIP_COUNT_REG:
+        return_value = get_clip_count_reg(state);
+        break;
+    case BYTE_SWAP_REG:
+        return_value = get_byte_swap_reg(state);
+        break;
+    case FRAME_COUNT_REG:
+        return_value = get_frame_count_reg(state);
+        break;
+    default:
+        DPRINTF("Unknown register read - addr:%llu\tsize:%d\n", addr, size);
+        return_value = 12021981; /* Value used for debugging purposes */
+    }
+    DPRINTF("screamer_mmio_read() called addr: %llu  size: %d", addr >> 4,
+            size);
+    DPRINTF("  returning 0x%x\n", return_value);
+    return return_value;
+}
+
+
+/* Called when the CPU writes to the memory addresses assigned to Screamer */
+static void screamer_mmio_write(void *opaque, hwaddr addr, uint64_t raw_value,
+                                unsigned size)
+{
+    DPRINTF("screamer_mmio_write() called - size: %d\n", size);
+    ScreamerState *state = opaque;
+    uint32_t value = raw_value & 0xffffffff;
+    addr = addr >> 4;
+
+    switch (addr) {
+    case SOUND_CONTROL_REG:
+        set_sound_control_reg(state, value);
+        break;
+    case CODEC_CONTROL_REG:
+        set_codec_control_reg(state, value);
+        break;
+    case CODEC_STATUS_REG:
+        set_codec_status_reg(state, value);
+        break;
+    case CLIP_COUNT_REG:
+        set_clip_count_reg(state, value);
+        break;
+    case BYTE_SWAP_REG:
+        set_byte_swap_reg(state, value);
+        break;
+    case FRAME_COUNT_REG:
+        set_frame_count_reg(state, value);
+        break;
+    default:
+        DPRINTF("Unknown register write - addr:%llu\tvalue:%d\n", addr, value);
+    }
+}
+
+/* Used for memory_region_init_io() for memory mapped I/O */
+static const MemoryRegionOps screamer_ops = {
+    .read = screamer_mmio_read,
+    .write = screamer_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+/* Called when the device has become active */
+static void screamer_realize(DeviceState *dev, Error **errp)
+{
+    DPRINTF("screamer_realize() called\n");
+    screamer_reset(dev);
+}
+
+
+/*
+ * Called when an instance of the Screamer device is created.
+ * Also called when this HMP command is called: device_add screamer
+ */
+static void screamer_init(Object *obj)
+{
+    DPRINTF("screamer_init() called\n");
+
+    ScreamerState *s = (ScreamerState *)obj;
+    SysBusDevice *d = SYS_BUS_DEVICE(obj);
+    const int region_size = 5 * 32;
+
+    /* Makes the read and write ops work */
+    memory_region_init_io(&s->io_memory_region, OBJECT(s),
+                          &screamer_ops, s, SOUND_CHIP_NAME, region_size);
+
+    /* Sets the SysBusDevice's memory property */
+    sysbus_init_mmio(d, &s->io_memory_region);
+
+    /* Setup all the interrupt requests */
+    sysbus_init_irq(d, &s->irq);
+    sysbus_init_irq(d, &s->dma_send_irq);
+    sysbus_init_irq(d, &s->dma_receive_irq);
+
+    /* Registers Screamer with QEMU's audio system */
+    AUD_register_card(SOUND_CHIP_NAME, &s->card);
+}
+
+
+/*
+ * These properties are displayed when using this command in the HMP.
+ * Command-line Example: --device screamer,help
+ * HMP Example:          device-list-properties
+ */
+static Property screamer_properties[] = {
+    DEFINE_PROP_END_OF_LIST()
+};
+
+/*
+ * When saving and restoring the state of the VM, this is used to save and
+ * restore the registers.
+ */
+static const VMStateDescription vmstate_screamer = {
+    .name = "Screamer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16_ARRAY(awacs, ScreamerState, 8), /* 8 AWACS registers */
+        VMSTATE_UINT32(sound_control, ScreamerState),
+        VMSTATE_UINT32(codec_control, ScreamerState),
+        VMSTATE_UINT32(codec_status, ScreamerState),
+        VMSTATE_UINT32(clip_count, ScreamerState),
+        VMSTATE_UINT32(byte_swap, ScreamerState),
+        VMSTATE_UINT32(frame_count, ScreamerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+/*
+ * Sets the class data. It is like polymorphism and inheritance in object
+ * oriented languages.
+ */
+static void screamer_class_init(ObjectClass *class, void *data)
+{
+    DPRINTF("screamer_class_init() called\n");
+    DeviceClass *dc = DEVICE_CLASS(class);
+    dc->realize = screamer_realize;
+    dc->reset = screamer_reset;
+    dc->desc = "Apple Screamer";
+    dc->props = screamer_properties;
+    dc->vmsd = &vmstate_screamer;
+    dc->hotpluggable = false;
+}
+
+/* Used for QOM function registration */
+static const TypeInfo screamer_info = {
+    .name          = "screamer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ScreamerState),
+    .instance_init = screamer_init,
+    .class_init    = screamer_class_init,
+};
+
+/* QOM registration of above functions for calling */
+static void screamer_register_types(void)
+{
+    DPRINTF("screamer_register_types() called\n");
+    type_register_static(&screamer_info);
+}
+
+/* QEMU Object Model (QOM) stuff */
+type_init(screamer_register_types)
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index 50f20d8206..3d5f816ee8 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -37,6 +37,7 @@
 #include "hw/intc/heathrow_pic.h"
 #include "sysemu/sysemu.h"
 #include "trace.h"
+#include "include/hw/audio/screamer.h"
 
 /* Note: this code is strongly inspirated from the corresponding code
  * in PearPC */
@@ -109,7 +110,10 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
     SysBusDevice *sysbus_dev;
     Error *err = NULL;
 
-    object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err);
+    const char *realized_property = "realized";
+    bool new_value = true;
+    object_property_set_bool(OBJECT(&s->dbdma), new_value, realized_property,
+                             &err);
     if (err) {
         error_propagate(errp, err);
         return;
@@ -117,6 +121,19 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
     sysbus_dev = SYS_BUS_DEVICE(&s->dbdma);
     memory_region_add_subregion(&s->bar, 0x08000,
                                 sysbus_mmio_get_region(sysbus_dev, 0));
+    object_property_set_bool(OBJECT(&s->screamer), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    /* Add the screamer sound chip */
+    sysbus_dev = SYS_BUS_DEVICE(&s->screamer);
+    const int offset = 0x14000; /* Offset from base address register (bar) */
+    const int region_number = 0; /* which memory region to use */
+    memory_region_add_subregion(&s->bar, offset,
+                                sysbus_mmio_get_region(sysbus_dev,
+                                                       region_number));
 
     qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0);
     qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK);
@@ -386,6 +403,19 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
         memory_region_add_subregion(&s->bar, 0x16000,
                                     sysbus_mmio_get_region(sysbus_dev, 0));
     }
+
+    /* Screamer Sound Chip */
+    const int gpio_0 = 0;
+    const int gpio_1 = 1;
+    const int transmit_channel = 0x10;
+    const int receive_channel = 0x12;
+    sysbus_dev = SYS_BUS_DEVICE(&s->screamer);
+    sysbus_connect_irq(sysbus_dev, gpio_0, qdev_get_gpio_in(pic_dev,
+                                           NEWWORLD_SCREAMER_IRQ));
+    sysbus_connect_irq(sysbus_dev, gpio_1, qdev_get_gpio_in(pic_dev,
+                                           NEWWORLD_SCREAMER_DMA_IRQ));
+    screamer_register_dma_functions(SCREAMER(sysbus_dev), &s->dbdma,
+                                    transmit_channel, receive_channel);
 }
 
 static void macio_newworld_init(Object *obj)
@@ -420,6 +450,9 @@ static void macio_instance_init(Object *obj)
                          TYPE_MAC_DBDMA);
 
     macio_init_child_obj(s, "escc", &s->escc, sizeof(s->escc), TYPE_ESCC);
+
+    macio_init_child_obj(s, SOUND_CHIP_NAME, &s->screamer, sizeof(s->screamer),
+                         TYPE_SCREAMER);
 }
 
 static const VMStateDescription vmstate_macio_oldworld = {
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index f927ec9c74..987e2dc0c9 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -95,6 +95,7 @@ config MAC_NEWWORLD
     select MACIO_GPIO
     select MAC_PMU
     select UNIN_PCI
+    select SCREAMER
 
 config E500
     bool
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index 6af87d1fa0..c65f2fd15f 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -34,6 +34,8 @@
 #include "hw/misc/mos6522.h"
 #include "hw/pci/pci_host.h"
 #include "hw/pci-host/uninorth.h"
+#include "hw/ppc/mac_dbdma.h"
+#include "audio/audio.h"
 
 /* SMP is not enabled, for now */
 #define MAX_CPUS 1
@@ -68,6 +70,9 @@
 #define NEWWORLD_IDE1_DMA_IRQ  0x3
 #define NEWWORLD_EXTING_GPIO1  0x2f
 #define NEWWORLD_EXTING_GPIO9  0x37
+#define NEWWORLD_SCREAMER_IRQ  0x18
+#define NEWWORLD_SCREAMER_DMA_IRQ 0x9
+#define NEWWORLD_SCREAMER_RX_IRQ 0xa
 
 /* Core99 machine */
 #define TYPE_CORE99_MACHINE MACHINE_TYPE_NAME("mac99")
diff --git a/include/hw/audio/screamer.h b/include/hw/audio/screamer.h
new file mode 100644
index 0000000000..7155541688
--- /dev/null
+++ b/include/hw/audio/screamer.h
@@ -0,0 +1,42 @@
+/*
+ * File: screamer.h
+ * Description: header file to the hw/audio/screamer.c file
+ */
+
+#ifndef screamer_h
+#define screamer_h
+
+#include <inttypes.h>
+#include "audio/audio.h"
+#include "hw/ppc/mac_dbdma.h"
+
+#define TYPE_SCREAMER "screamer"
+#define SCREAMER(obj) OBJECT_CHECK(ScreamerState, (obj), TYPE_SCREAMER)
+#define SOUND_CHIP_NAME "Screamer Sound Chip"
+#define MAX_BUFFER_SIZE (128 * 64)
+
+typedef struct ScreamerState {
+    SysBusDevice parent_obj;
+    uint16_t awacs[8]; /* Shadow/awacs registers */
+    uint32_t sound_control;
+    uint32_t codec_control;
+    uint32_t codec_status;
+    uint32_t clip_count;
+    uint32_t byte_swap;
+    uint32_t frame_count;
+    SWVoiceOut *speaker_voice;
+    DBDMAState *dbdma;
+    qemu_irq dma_send_irq;
+    qemu_irq dma_receive_irq;
+    qemu_irq irq;
+    QEMUSoundCard card;
+    MemoryRegion io_memory_region;
+    uint8_t spk_buffer[MAX_BUFFER_SIZE];
+    uint16_t spk_buffer_position, spk_play_position;
+    DBDMA_io dma_io;
+} ScreamerState;
+
+void screamer_register_dma_functions(ScreamerState *s, void *dbdma,
+                                     int send_channel, int receive_channel);
+
+#endif /* screamer_h */
diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h
index 070a694eb5..81ad552d61 100644
--- a/include/hw/misc/macio/macio.h
+++ b/include/hw/misc/macio/macio.h
@@ -35,6 +35,7 @@
 #include "hw/ppc/mac.h"
 #include "hw/ppc/mac_dbdma.h"
 #include "hw/ppc/openpic.h"
+#include "hw/audio/screamer.h"
 
 /* MacIO virtual bus */
 #define TYPE_MACIO_BUS "macio-bus"
@@ -86,6 +87,7 @@ typedef struct MacIOState {
     PMUState pmu;
     DBDMAState dbdma;
     ESCCState escc;
+    ScreamerState screamer;
     uint64_t frequency;
 } MacIOState;
 
-- 
2.14.3 (Apple Git-98)



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
@ 2020-01-05  1:58 Programmingkid
  2020-01-05 14:39 ` Programmingkid
  2020-01-11  0:32 ` Zoltán Kővágó
  0 siblings, 2 replies; 9+ messages in thread
From: Programmingkid @ 2020-01-05  1:58 UTC (permalink / raw)
  To: qemu Developers, Howard Spoelstra, Zoltán, mark Cave-Ayland
  Cc: Gerd Hoffmann

I found the patch that breaks Screamer sound support for qemu-system-ppc. It is this:

commit 2ceb8240fa4e4e30fb853565eb2bed3032d74f62
Author: Kővágó, Zoltán <dirty.ice.hu@gmail.com>
Date:   Thu Sep 19 23:24:11 2019 +0200

    coreaudio: port to the new audio backend api
    
    Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
    Message-id: 586a1e66de5cbc6c5234f9ae556d24befb6afada.1568927990.git.DirtY.iCE.hu@gmail.com
    Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>


Reversing this patch should make the Screamer patch work with the current git version of QEMU.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
  2020-01-05  1:58 Programmingkid
@ 2020-01-05 14:39 ` Programmingkid
  2020-01-11  0:32 ` Zoltán Kővágó
  1 sibling, 0 replies; 9+ messages in thread
From: Programmingkid @ 2020-01-05 14:39 UTC (permalink / raw)
  To: qemu Developers, Howard Spoelstra, Zoltán, Mark Cave-Ayland,
	Peter Maydell, Gerd Hoffmann


> On Jan 4, 2020, at 8:58 PM, Programmingkid <programmingkidx@gmail.com> wrote:
> 
> I found the patch that breaks Screamer sound support for qemu-system-ppc. It is this:
> 
> commit 2ceb8240fa4e4e30fb853565eb2bed3032d74f62
> Author: Kővágó, Zoltán <dirty.ice.hu@gmail.com>
> Date:   Thu Sep 19 23:24:11 2019 +0200
> 
>    coreaudio: port to the new audio backend api
> 
>    Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
>    Message-id: 586a1e66de5cbc6c5234f9ae556d24befb6afada.1568927990.git.DirtY.iCE.hu@gmail.com
>    Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> 
> 
> Reversing this patch should make the Screamer patch work with the current git version of QEMU.

@Peter Maydell

Does QEMU play audio correctly on your version of Mac OS X? I am using Mac OS 10.12 and the audio sound demonically loud and scary. I am currently at this git revision:

f0dcfddecee8b860e015bb07d67cfcbdfbfd51d

Merge: 40f09ee833 725fe5d10d
Author: Peter Maydell <peter.maydell@linaro.org>
Date:   Fri Jan 3 17:18:08 2020 +0000

    Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging

I have ran several tests with qemu-system-i386 using Windows guest with the ac97 and sb16 sound cards. It sounds just as bad for me on qemu-system-ppc. 

Thank you.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
  2020-01-05  1:58 Programmingkid
  2020-01-05 14:39 ` Programmingkid
@ 2020-01-11  0:32 ` Zoltán Kővágó
  2020-01-11  0:59   ` Programmingkid
  2020-01-28  8:30   ` Volker Rümelin
  1 sibling, 2 replies; 9+ messages in thread
From: Zoltán Kővágó @ 2020-01-11  0:32 UTC (permalink / raw)
  To: Programmingkid, qemu Developers, Howard Spoelstra,
	mark Cave-Ayland
  Cc: Gerd Hoffmann

[-- Attachment #1: Type: text/plain, Size: 1098 bytes --]

On 2020-01-05 02:58, Programmingkid wrote:
> I found the patch that breaks Screamer sound support for qemu-system-ppc. It is this:
> 
> commit 2ceb8240fa4e4e30fb853565eb2bed3032d74f62
> Author: Kővágó, Zoltán <dirty.ice.hu@gmail.com>
> Date:   Thu Sep 19 23:24:11 2019 +0200
> 
>      coreaudio: port to the new audio backend api
>      
>      Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
>      Message-id: 586a1e66de5cbc6c5234f9ae556d24befb6afada.1568927990.git.DirtY.iCE.hu@gmail.com
>      Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> 
> 
> Reversing this patch should make the Screamer patch work with the current git version of QEMU.
> 

Hi,

Unfortunately it's not that simple to simply revert the patch since the 
old backend api no longer exists.  Also I don't have a Mac so it's 
almost impossible for me to test the results.  I looked at the specified 
commit and I think I found a problem, could you please apply the 
attached patch on the current git master and check whether it solves the 
problem?  If yes I'll turn it into a proper patch.

Regards,
Zoltan


[-- Attachment #2: coreaudio_test.diff --]
[-- Type: text/x-patch, Size: 3838 bytes --]

diff --git a/audio/audio_template.h b/audio/audio_template.h
index 3287d7075e..a7b46b8363 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -153,6 +153,13 @@ static int glue (audio_pcm_sw_init_, TYPE) (
     sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
 #endif
 
+#ifdef FLOAT_MIXENG
+#ifdef DAC
+    sw->conv = mixeng_conv_float;
+#else
+    sw->clip = mixeng_clip_float;
+#endif
+#else
 #ifdef DAC
     sw->conv = mixeng_conv
 #else
@@ -162,6 +169,7 @@ static int glue (audio_pcm_sw_init_, TYPE) (
         [sw->info.sign]
         [sw->info.swap_endianness]
         [audio_bits_to_index (sw->info.bits)];
+#endif
 
     sw->name = g_strdup (name);
     err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
diff --git a/audio/mixeng.h b/audio/mixeng.h
index 18e62c7c49..343f5fb810 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -41,6 +41,11 @@ typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
 extern t_sample *mixeng_conv[2][2][2][3];
 extern f_sample *mixeng_clip[2][2][2][3];
 
+#ifdef FLOAT_MIXENG
+void mixeng_conv_float(struct st_sample *dst, const void *src, int samples);
+void mixeng_clip_float(void *dst, const struct st_sample *src, int samples);
+#endif
+
 void *st_rate_start (int inrate, int outrate);
 void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
                   size_t *isamp, size_t *osamp);
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 66f0f459cf..4e7e509ad0 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -471,20 +471,6 @@ static OSStatus audioDeviceIOProc(
     return 0;
 }
 
-static UInt32 coreaudio_get_flags(struct audio_pcm_info *info,
-                                  struct audsettings *as)
-{
-    UInt32 flags = info->sign ? kAudioFormatFlagIsSignedInteger : 0;
-    if (as->endianness) { /* 0 = little, 1 = big */
-        flags |= kAudioFormatFlagIsBigEndian;
-    }
-
-    if (flags == 0) { /* must not be 0 */
-        flags = kAudioFormatFlagsAreAllClear;
-    }
-    return flags;
-}
-
 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
                               void *drv_opaque)
 {
@@ -572,15 +558,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
 
     /* set Samplerate */
     core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
-    core->outputStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
-    core->outputStreamBasicDescription.mFormatFlags =
-        coreaudio_get_flags(&hw->info, as);
-    core->outputStreamBasicDescription.mBytesPerPacket =
-        core->outputStreamBasicDescription.mBytesPerFrame =
-        hw->info.nchannels * hw->info.bits / 8;
-    core->outputStreamBasicDescription.mFramesPerPacket = 1;
-    core->outputStreamBasicDescription.mChannelsPerFrame = hw->info.nchannels;
-    core->outputStreamBasicDescription.mBitsPerChannel = hw->info.bits;
 
     status = coreaudio_set_streamformat(core->outputDeviceID,
                                         &core->outputStreamBasicDescription);
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 2f5ba71381..424ffe30d7 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -267,6 +267,27 @@ f_sample *mixeng_clip[2][2][2][3] = {
     }
 };
 
+#ifdef FLOAT_MIXENG
+void mixeng_conv_float(struct st_sample *dst, const void *src, int samples)
+{
+    float *in = (float *) src;
+    while (samples--) {
+        dst->l = *in++;
+        dst->r = *in++;
+        dst++;
+    }
+}
+
+void mixeng_clip_float(void *dst, const struct st_sample *src, int samples)
+{
+    float *out = (float *) dst;
+    while (samples--) {
+        *out++ = src->l;
+        *out++ = src->r;
+        src++;
+    }
+}
+#endif
 
 void audio_sample_to_uint64(void *samples, int pos,
                             uint64_t *left, uint64_t *right)

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
  2020-01-11  0:32 ` Zoltán Kővágó
@ 2020-01-11  0:59   ` Programmingkid
  2020-01-28  8:30   ` Volker Rümelin
  1 sibling, 0 replies; 9+ messages in thread
From: Programmingkid @ 2020-01-11  0:59 UTC (permalink / raw)
  To: Zoltán Kővágó
  Cc: Gerd Hoffmann, Mark Cave-Ayland, qemu Developers,
	Howard Spoelstra


> On Jan 10, 2020, at 7:32 PM, Zoltán Kővágó <dirty.ice.hu@gmail.com> wrote:
> 
> On 2020-01-05 02:58, Programmingkid wrote:
>> I found the patch that breaks Screamer sound support for qemu-system-ppc. It is this:
>> commit 2ceb8240fa4e4e30fb853565eb2bed3032d74f62
>> Author: Kővágó, Zoltán <dirty.ice.hu@gmail.com>
>> Date:   Thu Sep 19 23:24:11 2019 +0200
>>     coreaudio: port to the new audio backend api
>>          Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
>>     Message-id: 586a1e66de5cbc6c5234f9ae556d24befb6afada.1568927990.git.DirtY.iCE.hu@gmail.com
>>     Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>> Reversing this patch should make the Screamer patch work with the current git version of QEMU.
> 
> Hi,
> 
> Unfortunately it's not that simple to simply revert the patch since the old backend api no longer exists.  Also I don't have a Mac so it's almost impossible for me to test the results.  I looked at the specified commit and I think I found a problem, could you please apply the attached patch on the current git master and check whether it solves the problem?  If yes I'll turn it into a proper patch.
> 
> Regards,
> Zoltan
> 
> <coreaudio_test.diff>

Sorry it did not fix the problem. I only hear pops occasionally. Most of the time only silence can be heard.

Thank you for the patch. 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
  2020-01-11  0:32 ` Zoltán Kővágó
  2020-01-11  0:59   ` Programmingkid
@ 2020-01-28  8:30   ` Volker Rümelin
  2020-01-28  9:38     ` Howard Spoelstra
  2020-02-02 19:47     ` Zoltán Kővágó
  1 sibling, 2 replies; 9+ messages in thread
From: Volker Rümelin @ 2020-01-28  8:30 UTC (permalink / raw)
  To: Zoltán Kővágó, Programmingkid,
	qemu Developers, Howard Spoelstra, Mark Cave-Ayland
  Cc: Gerd Hoffmann

> Hi,
>
> Unfortunately it's not that simple to simply revert the patch since the old backend api no longer exists.  Also I don't have a Mac so it's almost impossible for me to test the results.  I looked at the specified commit and I think I found a problem, could you please apply the attached patch on the current git master and check whether it solves the problem?  If yes I'll turn it into a proper patch.
>
> Regards,
> Zoltan
>

Hi Zoltán,

I also don't have a Mac so I tested your patch with a slightly modified sdlaudio version. I found two bugs in your patch. With the bugs fixed I have working SDL2 audio playback with float type samples. Now I wonder if the fixed patch also fixes coreaudio playback. Depending on how busy you are I can just write a review for your patch and let you handle the rest, or may I send a modified version of your patch to the mailing list for testing?

With best regards
Volker


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
  2020-01-28  8:30   ` Volker Rümelin
@ 2020-01-28  9:38     ` Howard Spoelstra
  2020-01-29  7:09       ` Volker Rümelin
  2020-02-02 19:47     ` Zoltán Kővágó
  1 sibling, 1 reply; 9+ messages in thread
From: Howard Spoelstra @ 2020-01-28  9:38 UTC (permalink / raw)
  To: Volker Rümelin
  Cc: Programmingkid, Gerd Hoffmann, Mark Cave-Ayland, qemu Developers,
	Zoltán Kővágó

[-- Attachment #1: Type: text/plain, Size: 3201 bytes --]

On Tue, Jan 28, 2020 at 9:30 AM Volker Rümelin <vr_qemu@t-online.de> wrote:

> > Hi,
> >
> > Unfortunately it's not that simple to simply revert the patch since the
> old backend api no longer exists.  Also I don't have a Mac so it's almost
> impossible for me to test the results.  I looked at the specified commit
> and I think I found a problem, could you please apply the attached patch on
> the current git master and check whether it solves the problem?  If yes
> I'll turn it into a proper patch.
> >
> > Regards,
> > Zoltan
> >
>
> Hi Zoltán,
>
> I also don't have a Mac so I tested your patch with a slightly modified
> sdlaudio version. I found two bugs in your patch. With the bugs fixed I
> have working SDL2 audio playback with float type samples. Now I wonder if
> the fixed patch also fixes coreaudio playback. Depending on how busy you
> are I can just write a review for your patch and let you handle the rest,
> or may I send a modified version of your patch to the mailing list for
> testing?
>
> With best regards
> Volker
>

Hi Volker,

I can test for coreaudio. Can you let us know exactly what you fixed in the
patch?
While cross compiling for windows, I saw these errors (besides some casting
issues):
line 56: buffer2  (should be *buffer2?)
line 455: ret  (should be ret2?)

audio/dsoundaudio.c:56:20: error: variable or field 'buffer2' declared void
   56 |     void *buffer1, buffer2;
      |                    ^~~~~~~
audio/dsoundaudio.c: In function 'dsound_get_buffer_out':
audio/dsoundaudio.c:428:18: error: returning 'int' from a function with
return type 'void *' makes pointer from integer without a cast
[-Werror=int-conversion]
  428 |         return ds->buffer2;
      |                ~~^~~~~~~~~
audio/dsoundaudio.c:451:17: error: assignment to 'int' from 'void *' makes
integer from pointer without a cast [-Werror=int-conversion]
  451 |     ds->buffer2 = ret2;
      |                 ^
audio/dsoundaudio.c:455:12: error: 'ret' undeclared (first use in this
function); did you mean 'ret2'?
  455 |     return ret;
      |            ^~~
      |            ret2
audio/dsoundaudio.c:455:12: note: each undeclared identifier is reported
only once for each function it appears in
audio/dsoundaudio.c: In function 'dsound_put_buffer_out':
audio/dsoundaudio.c:471:49: error: passing argument 3 of
'dsound_unlock_out' makes pointer from integer without a cast
[-Werror=int-conversion]
  471 |     err = dsound_unlock_out(dsb, ds->buffer1, ds->buffer2,
ds->size1, ds->size2);
      |                                               ~~^~~~~~~~~
      |                                                 |
      |                                                 int
In file included from audio/dsoundaudio.c:267:
audio/dsound_template.h:49:12: note: expected 'LPVOID' {aka 'void *'} but
argument is of type 'int'
   49 |     LPVOID p2,
      |     ~~~~~~~^~
audio/dsoundaudio.c: In function 'dsound_get_buffer_out':
audio/dsoundaudio.c:456:1: error: control reaches end of non-void function
[-Werror=return-type]
  456 | }
      | ^
cc1: all warnings being treated as errors

Best,
Howard

[-- Attachment #2: Type: text/html, Size: 4060 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
  2020-01-28  9:38     ` Howard Spoelstra
@ 2020-01-29  7:09       ` Volker Rümelin
  0 siblings, 0 replies; 9+ messages in thread
From: Volker Rümelin @ 2020-01-29  7:09 UTC (permalink / raw)
  To: Howard Spoelstra
  Cc: Programmingkid, Gerd Hoffmann, Mark Cave-Ayland, qemu Developers,
	Zoltán Kővágó


>
> Hi Volker,
>
> I can test for coreaudio. Can you let us know exactly what you fixed in the patch?

Hi Howard,

I wrote a patch that tries to fix the problems in Zoltán's patch. The changes in coreaudio.c are untested. I'll send it as a reply to this mail. Please apply Zoltan's patch and then my patch to qemu master.

> While cross compiling for windows, I saw these errors (besides some casting issues):
> line 56: buffer2  (should be *buffer2?)
> line 455: ret  (should be ret2?)
>
> audio/dsoundaudio.c:56:20: error: variable or field 'buffer2' declared void
>    56 |     void *buffer1, buffer2;
>       |                    ^~~~~~~
> audio/dsoundaudio.c: In function 'dsound_get_buffer_out':

I'm sorry, but I can't build and test on Windows.

With best regards,
Volker


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] Implement the Screamer sound chip for the mac99 machine type
  2020-01-28  8:30   ` Volker Rümelin
  2020-01-28  9:38     ` Howard Spoelstra
@ 2020-02-02 19:47     ` Zoltán Kővágó
  1 sibling, 0 replies; 9+ messages in thread
From: Zoltán Kővágó @ 2020-02-02 19:47 UTC (permalink / raw)
  To: Volker Rümelin, Programmingkid, qemu Developers,
	Howard Spoelstra, Mark Cave-Ayland
  Cc: Gerd Hoffmann

On 2020-01-28 09:30, Volker Rümelin wrote:
>> Hi,
>>
>> Unfortunately it's not that simple to simply revert the patch since the old backend api no longer exists.  Also I don't have a Mac so it's almost impossible for me to test the results.  I looked at the specified commit and I think I found a problem, could you please apply the attached patch on the current git master and check whether it solves the problem?  If yes I'll turn it into a proper patch.
>>
>> Regards,
>> Zoltan
>>
> 
> Hi Zoltán,
> 
> I also don't have a Mac so I tested your patch with a slightly modified sdlaudio version. I found two bugs in your patch. With the bugs fixed I have working SDL2 audio playback with float type samples. Now I wonder if the fixed patch also fixes coreaudio playback. Depending on how busy you are I can just write a review for your patch and let you handle the rest, or may I send a modified version of your patch to the mailing list for testing?
> 
> With best regards
> Volker
Hi,

Maybe I'm a bit late since you already did it, but go ahead, I don't 
have too much time to work on qemu recently.

Regards,
Zoltan


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2020-02-02 19:47 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-12-29  2:45 [PATCH v2] Implement the Screamer sound chip for the mac99 machine type John Arbuckle
  -- strict thread matches above, loose matches on Subject: below --
2020-01-05  1:58 Programmingkid
2020-01-05 14:39 ` Programmingkid
2020-01-11  0:32 ` Zoltán Kővágó
2020-01-11  0:59   ` Programmingkid
2020-01-28  8:30   ` Volker Rümelin
2020-01-28  9:38     ` Howard Spoelstra
2020-01-29  7:09       ` Volker Rümelin
2020-02-02 19:47     ` Zoltán Kővágó

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).