summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/sound/snkwave.c
diff options
context:
space:
mode:
author Nicola Salmoria <nicola@mamedev.org>2008-09-04 08:57:02 +0000
committer Nicola Salmoria <nicola@mamedev.org>2008-09-04 08:57:02 +0000
commit7c90a0cd38d4816a8f252e8c4da84e9f751d8369 (patch)
tree434d0d421d10d1e05a0b93ba08fd7c45f97ab2b8 /src/emu/sound/snkwave.c
parentf724e4c6bfc1be4d3a16c7eaa243750c153129d2 (diff)
fixed emulation of the "SNK Wave" custom sound used by Marvin's Maze and Vanguard II and made it into a proper sound core
fixed palette decoding of early SNK games (from marvins to athena + fitegolf). The least significan bits were assigned incorrectly. merged marvins.c into snk.c, with all resulting fixes (removed hacks, correct shadows, scroll offsets etc)
Diffstat (limited to 'src/emu/sound/snkwave.c')
-rw-r--r--src/emu/sound/snkwave.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/src/emu/sound/snkwave.c b/src/emu/sound/snkwave.c
new file mode 100644
index 00000000000..b9319acdc13
--- /dev/null
+++ b/src/emu/sound/snkwave.c
@@ -0,0 +1,194 @@
+/***************************************************************************
+
+ SNK Wave sound driver.
+
+ This is a very simple single-voice generator with a programmable waveform.
+
+***************************************************************************/
+
+#include "sndintrf.h"
+#include "streams.h"
+#include "snkwave.h"
+
+
+#define WAVEFORM_LENGTH 16
+
+#define CLOCK_SHIFT 8
+
+
+struct snkwave_sound
+{
+ /* 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];
+};
+
+
+/* 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(struct snkwave_sound *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 void snkwave_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
+{
+ struct snkwave_sound *chip = param;
+ stream_sample_t *buffer = _buffer[0];
+
+ /* zap the contents of the buffer */
+ memset(buffer, 0, length * 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 (length-- > 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 void *snkwave_start(const char *tag, int sndindex, int clock, const void *config)
+{
+ struct snkwave_sound *chip;
+
+ assert(config == 0);
+
+ chip = auto_malloc(sizeof(*chip));
+ memset(chip, 0, sizeof(*chip));
+
+ /* adjust internal clock */
+ chip->external_clock = clock;
+
+ /* adjust output clock */
+ chip->sample_rate = chip->external_clock >> CLOCK_SHIFT;
+
+ /* get stream channels */
+ chip->stream = stream_create(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 */
+ state_save_register_item("snkwave", sndindex, chip->frequency);
+ state_save_register_item("snkwave", sndindex, chip->counter);
+ state_save_register_item("snkwave", sndindex, chip->waveform_position);
+ state_save_register_item_pointer("snkwave", sndindex, chip->waveform, WAVEFORM_LENGTH);
+
+ return chip;
+}
+
+
+/********************************************************************************/
+
+/* SNK wave register map
+ all registers are 6-bit
+ 0-1 frequency (12-bit)
+ 2-5 waveform (8 3-bit nibbles)
+*/
+
+WRITE8_HANDLER( snkwave_w )
+{
+ struct snkwave_sound *chip = sndti_token(SOUND_SNKWAVE, 0);
+
+ stream_update(chip->stream);
+
+ // 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
+ **************************************************************************/
+
+static void snkwave_set_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* no parameters to set */
+ }
+}
+
+
+void snkwave_get_info(void *token, UINT32 state, sndinfo *info)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case SNDINFO_PTR_SET_INFO: info->set_info = snkwave_set_info; break;
+ case SNDINFO_PTR_START: info->start = snkwave_start; break;
+ case SNDINFO_PTR_STOP: /* Nothing */ break;
+ case SNDINFO_PTR_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case SNDINFO_STR_NAME: info->s = "SNK Wave"; break;
+ case SNDINFO_STR_CORE_FAMILY: info->s = "SNK Wave"; break;
+ case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
+ case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
+ case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright Nicola Salmoria and the MAME Team"; break;
+ }
+}