summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/sound/snkwave.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/sound/snkwave.c')
-rw-r--r--trunk/src/emu/sound/snkwave.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/snkwave.c b/trunk/src/emu/sound/snkwave.c
new file mode 100644
index 00000000000..32d09bc167a
--- /dev/null
+++ b/trunk/src/emu/sound/snkwave.c
@@ -0,0 +1,189 @@
+/***************************************************************************
+
+ SNK Wave sound driver.
+
+ This is a very simple single-voice generator with a programmable waveform.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "snkwave.h"
+
+
+#define WAVEFORM_LENGTH 16
+
+#define CLOCK_SHIFT 8
+
+
+typedef struct _snkwave_state snkwave_state;
+struct _snkwave_state
+{
+ /* global sound parameters */
+ sound_stream * stream;
+ int external_clock;
+ int sample_rate;
+
+ /* data about the sound system */
+ UINT32 frequency;
+ UINT32 counter;
+ int waveform_position;
+
+ /* decoded waveform table */
+ INT16 waveform[WAVEFORM_LENGTH];
+};
+
+INLINE snkwave_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == SNKWAVE);
+ return (snkwave_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/* update the decoded waveform data */
+/* The programmable waveform consists of 8 3-bit nibbles.
+ The waveform goes to a 4-bit DAC and is played alternatingly forwards and
+ backwards.
+ When going forwards, bit 3 is 1. When going backwards, it's 0.
+ So the sequence 01234567 will play as
+ 89ABCDEF76543210
+*/
+static void update_waveform(snkwave_state *chip, unsigned int offset, UINT8 data)
+{
+ assert(offset < WAVEFORM_LENGTH/4);
+
+ chip->waveform[offset * 2] = ((data & 0x38) >> 3) << (12-CLOCK_SHIFT);
+ chip->waveform[offset * 2 + 1] = ((data & 0x07) >> 0) << (12-CLOCK_SHIFT);
+ chip->waveform[WAVEFORM_LENGTH-2 - offset * 2] = ~chip->waveform[offset * 2 + 1];
+ chip->waveform[WAVEFORM_LENGTH-1 - offset * 2] = ~chip->waveform[offset * 2];
+}
+
+
+/* generate sound to the mix buffer */
+static STREAM_UPDATE( snkwave_update )
+{
+ snkwave_state *chip = (snkwave_state *)param;
+ stream_sample_t *buffer = outputs[0];
+
+ /* zap the contents of the buffer */
+ memset(buffer, 0, samples * sizeof(*buffer));
+
+ assert(chip->counter < 0x1000);
+ assert(chip->frequency < 0x1000);
+
+ /* if no sound, we're done */
+ if (chip->frequency == 0xfff)
+ return;
+
+ /* generate sound into buffer while updating the counter */
+ while (samples-- > 0)
+ {
+ int loops;
+ INT16 out = 0;
+
+ loops = 1 << CLOCK_SHIFT;
+ while (loops > 0)
+ {
+ int steps = 0x1000 - chip->counter;
+
+ if (steps <= loops)
+ {
+ out += chip->waveform[chip->waveform_position] * steps;
+ chip->counter = chip->frequency;
+ chip->waveform_position = (chip->waveform_position + 1) & (WAVEFORM_LENGTH-1);
+ loops -= steps;
+ }
+ else
+ {
+ out += chip->waveform[chip->waveform_position] * loops;
+ chip->counter += loops;
+ loops = 0;
+ }
+ }
+
+ *buffer++ = out;
+ }
+}
+
+
+static DEVICE_START( snkwave )
+{
+ snkwave_state *chip = get_safe_token(device);
+
+ assert(device->static_config() == 0);
+
+ /* adjust internal clock */
+ chip->external_clock = device->clock();
+
+ /* adjust output clock */
+ chip->sample_rate = chip->external_clock >> CLOCK_SHIFT;
+
+ /* get stream channels */
+ chip->stream = device->machine().sound().stream_alloc(*device, 0, 1, chip->sample_rate, chip, snkwave_update);
+
+ /* reset all the voices */
+ chip->frequency = 0;
+ chip->counter = 0;
+ chip->waveform_position = 0;
+
+ /* register with the save state system */
+ device->save_item(NAME(chip->frequency));
+ device->save_item(NAME(chip->counter));
+ device->save_item(NAME(chip->waveform_position));
+ device->save_pointer(NAME(chip->waveform), WAVEFORM_LENGTH);
+}
+
+
+/********************************************************************************/
+
+/* SNK wave register map
+ all registers are 6-bit
+ 0-1 frequency (12-bit)
+ 2-5 waveform (8 3-bit nibbles)
+*/
+
+WRITE8_DEVICE_HANDLER( snkwave_w )
+{
+ snkwave_state *chip = get_safe_token(device);
+
+ chip->stream->update();
+
+ // all registers are 6-bit
+ data &= 0x3f;
+
+ if (offset == 0)
+ chip->frequency = (chip->frequency & 0x03f) | (data << 6);
+ else if (offset == 1)
+ chip->frequency = (chip->frequency & 0xfc0) | data;
+ else if (offset <= 5)
+ update_waveform(chip, offset - 2, data);
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+DEVICE_GET_INFO( snkwave )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(snkwave_state); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( snkwave ); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "SNK Wave"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "SNK Wave"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
+ }
+}
+
+DEFINE_LEGACY_SOUND_DEVICE(SNKWAVE, snkwave);