diff --git a/.gitattributes b/.gitattributes index 2df1b578800..42ebb9036f3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1620,6 +1620,8 @@ src/emu/sound/es5506.c svneol=native#text/plain src/emu/sound/es5506.h svneol=native#text/plain src/emu/sound/es8712.c svneol=native#text/plain src/emu/sound/es8712.h svneol=native#text/plain +src/emu/sound/esqpump.c svneol=native#text/plain +src/emu/sound/esqpump.h svneol=native#text/plain src/emu/sound/filter.c svneol=native#text/plain src/emu/sound/filter.h svneol=native#text/plain src/emu/sound/flt_rc.c svneol=native#text/plain diff --git a/src/emu/sound/esqpump.c b/src/emu/sound/esqpump.c new file mode 100644 index 00000000000..0efc4a6d1fa --- /dev/null +++ b/src/emu/sound/esqpump.c @@ -0,0 +1,169 @@ +/*************************************************************************** + + esqpump.c - Ensoniq 5505/5506 to 5510 interface. + + By Christian Brunschen + +***************************************************************************/ + +#include "sound/esqpump.h" + +const device_type ESQ_5505_5510_PUMP = &device_creator; + +esq_5505_5510_pump::esq_5505_5510_pump(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ESQ_5505_5510_PUMP, "ESQ_5505_5510_PUMP", tag, owner, clock, "esq_5505_5510_pump", __FILE__), + device_sound_interface(mconfig, *this), + m_esp_halted(true) +{ +} + +void esq_5505_5510_pump::device_start() +{ + logerror("Clock = %d\n", clock()); + + m_stream = machine().sound().stream_alloc(*this, 8, 2, clock(), this); + m_timer = timer_alloc(0); + m_timer->enable(false); + +#if PUMP_DETECT_SILENCE + silent_for = 500; + was_silence = 1; +#endif +#if !PUMP_FAKE_ESP_PROCESSING + ticks_spent_processing = 0; + samples_processed = 0; +#endif +#if PUMP_TRACK_SAMPLES + last_samples = 0; + last_ticks = osd_ticks(); + next_report_ticks = last_ticks + osd_ticks_per_second(); +#endif + +#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM + memset(e, 0, 0x4000 * sizeof(e[0])); + ei = 0; +#endif +} + +void esq_5505_5510_pump::device_stop() +{ + m_timer->enable(false); +} + +void esq_5505_5510_pump::device_reset() +{ + INT64 nsec_per_sample = 100 * 16 * 21; + attotime sample_time(0, 1000000000 * nsec_per_sample); + attotime initial_delay(0, 0); + + m_timer->adjust(initial_delay, 0, sample_time); + m_timer->enable(true); +} + +void esq_5505_5510_pump::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + if (samples != 1) { + logerror("Pump: request for %d samples\n", samples); + } + + stream_sample_t *left = outputs[0], *right = outputs[1]; + for (int i = 0; i < samples; i++) + { +#define SAMPLE_SHIFT 4 + // anything for the 'aux' output? + INT16 l = inputs[0][i] >> SAMPLE_SHIFT; + INT16 r = inputs[1][i] >> SAMPLE_SHIFT; + + // push the samples into the ESP + m_esp->ser_w(0, inputs[2][i] >> SAMPLE_SHIFT); + m_esp->ser_w(1, inputs[3][i] >> SAMPLE_SHIFT); + m_esp->ser_w(2, inputs[4][i] >> SAMPLE_SHIFT); + m_esp->ser_w(3, inputs[5][i] >> SAMPLE_SHIFT); + m_esp->ser_w(4, inputs[6][i] >> SAMPLE_SHIFT); + m_esp->ser_w(5, inputs[7][i] >> SAMPLE_SHIFT); + +#if PUMP_FAKE_ESP_PROCESSING + m_esp->ser_w(6, m_esp->ser_r(0) + m_esp->ser_r(2) + m_esp->ser_r(4)); + m_esp->ser_w(7, m_esp->ser_r(1) + m_esp->ser_r(3) + m_esp->ser_r(5)); +#else + if (!m_esp_halted) { + logerror("passing one sample through ESP\n"); + osd_ticks_t a = osd_ticks(); + m_esp->run_once(); + osd_ticks_t b = osd_ticks(); + ticks_spent_processing += (b - a); + samples_processed++; + } +#endif + + // read the processed result from the ESP and add to the saved AUX data + INT16 ll = m_esp->ser_r(6); + INT16 rr = m_esp->ser_r(7); + l += ll; + r += rr; + +#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM + // if we're processing the fake program through the ESP, the result should just be that of adding the inputs + INT32 el = (inputs[2][i]) + (inputs[4][i]) + (inputs[6][i]); + INT32 er = (inputs[3][i]) + (inputs[5][i]) + (inputs[7][i]); + INT32 e_next = el + er; + e[(ei + 0x1d0f) % 0x4000] = e_next; + + if (l != e[ei]) { + fprintf(stderr, "expected (%d) but have (%d)\n", e[ei], l); + } + ei = (ei + 1) % 0x4000; +#endif + + // write the combined data to the output + *left++ = l; + *right++ = r; + } + +#if PUMP_DETECT_SILENCE + for (int i = 0; i < samples; i++) { + if (outputs[0][i] == 0 && outputs[1][i] == 0) { + silent_for++; + } else { + silent_for = 0; + } + } + bool silence = silent_for >= 500; + if (was_silence != silence) { + if (!silence) { + fprintf(stderr, ".-*\n"); + } else { + fprintf(stderr, "*-.\n"); + } + was_silence = silence; + } +#endif + +#if PUMP_TRACK_SAMPLES + last_samples += samples; + osd_ticks_t now = osd_ticks(); + if (now >= next_report_ticks) + { + osd_ticks_t elapsed = now - last_ticks; + osd_ticks_t tps = osd_ticks_per_second(); + fprintf(stderr, "Pump: %d samples in %" I64FMT "d ticks for %f Hz\n", last_samples, elapsed, last_samples * (double)tps / (double)elapsed); + last_ticks = now; + while (next_report_ticks <= now) { + next_report_ticks += tps; + } + last_samples = 0; + +#if !PUMP_FAKE_ESP_PROCESSING + fprintf(stderr, " ESP spent %" I64FMT "d ticks on %d samples, %f ticks per sample\n", ticks_spent_processing, samples_processed, (double)ticks_spent_processing / (double)samples_processed); + ticks_spent_processing = 0; + samples_processed = 0; +#endif + } +#endif +} + +void esq_5505_5510_pump::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { + // ecery time there's a new sample period, update the stream! + m_stream->update(); +} + diff --git a/src/emu/sound/esqpump.h b/src/emu/sound/esqpump.h new file mode 100644 index 00000000000..fbead6b485a --- /dev/null +++ b/src/emu/sound/esqpump.h @@ -0,0 +1,123 @@ +#pragma once + +#ifndef _ESQPUMP_H_ +#define _ESQPUMP_H_ + +#include "emu.h" +#include "sound/es5506.h" +#include "cpu/es5510/es5510.h" + +#define PUMP_DETECT_SILENCE 0 +#define PUMP_TRACK_SAMPLES 0 +#define PUMP_FAKE_ESP_PROCESSING 0 +#define PUMP_REPLACE_ESP_PROGRAM 0 + +class esq_5505_5510_pump : public device_t, + public device_sound_interface +{ +public: + esq_5505_5510_pump(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_otis(es5505_device *otis) { m_otis = otis; } + void set_esp(es5510_device *esp) { m_esp = esp; } + void set_esp_halted(bool esp_halted) { + m_esp_halted = esp_halted; + logerror("ESP-halted -> %d\n", m_esp_halted); + if (!esp_halted) { + +#if PUMP_REPLACE_ESP_PROGRAM + m_esp->write_reg(245, 0x1d0f << 8); // dlength = 0x3fff, 16-sample delay + + int pc = 0; + for (pc = 0; pc < 0xc0; pc++) { + m_esp->write_reg(pc, 0); + } + pc = 0; + // replace the ESP program with a simple summing & single-sample delay + m_esp->_instr(pc++) = 0xffffeaa09000; // MOV SER0R > grp_a0 + m_esp->_instr(pc++) = 0xffffeba00000; // ADD SER0L, gpr_a0 > gpr_a0 + m_esp->_instr(pc++) = 0xffffeca00000; // ADD SER1R, gpr_a0 > gpr_a0 + m_esp->_instr(pc++) = 0xffffeda00000; // ADD SER1L, gpr_a0 > gpr_a0 + m_esp->_instr(pc++) = 0xffffeea00000; // ADD SER2R, gpr_a0 > gpr_a0 + + m_esp->_instr(pc ) = 0xffffefa00000; // ADD SER2L, gpr_a0 > gpr_a0; prepare to read from delay 2 instructions from now, offset = 0 + m_esp->write_reg(pc++, 0); //offset into delay + + m_esp->_instr(pc ) = 0xffffa0a09508; // MOV gpr_a0 > delay + offset + m_esp->write_reg(pc++, 1 << 8); // offset into delay - -1 samples + + m_esp->_instr(pc++) = 0xffff00a19928; // MOV DIL > gpr_a1; read Delay and dump FIFO (so that the value gets written) + + m_esp->_instr(pc++) = 0xffffa1f09000; // MOV gpr_a1 > SER3R + m_esp->_instr(pc++) = 0xffffa1f19000; // MOV gpr_a1 > SER3L + + m_esp->_instr(pc++) = 0xffffffff0000; // NO-OP + m_esp->_instr(pc++) = 0xffffffff0000; // NO-OP + m_esp->_instr(pc++) = 0xfffffffff000; // END + + while (pc < 160) { + m_esp->_instr(pc++) = 0xffffffffffff; // no-op + } +#endif + + // m_esp->list_program(print_to_stderr); + } + } + bool get_esp_halted() { + return m_esp_halted; + } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // timer callback overrides + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // internal state: + // sound stream + sound_stream *m_stream; + + // per-sample timer + emu_timer *m_timer; + + // OTIS sound generator + es5505_device *m_otis; + + // ESP signal processor + es5510_device *m_esp; + + // Is the ESP halted by the CPU? + bool m_esp_halted; + +#if !PUMP_FAKE_ESP_PROCESSING + osd_ticks_t ticks_spent_processing; + int samples_processed; +#endif + +#if PUMP_DETECT_SILENCE + int silent_for; + bool was_silence; +#endif + +#if PUMP_TRACK_SAMPLES + int last_samples; + osd_ticks_t last_ticks; + osd_ticks_t next_report_ticks; +#endif + +#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM + INT16 e[0x4000]; + int ei; +#endif +}; + +extern const device_type ESQ_5505_5510_PUMP; + +#endif diff --git a/src/emu/sound/sound.mak b/src/emu/sound/sound.mak index 3280185dd0a..e7656a3fe34 100644 --- a/src/emu/sound/sound.mak +++ b/src/emu/sound/sound.mak @@ -154,6 +154,15 @@ SOUNDOBJS += $(SOUNDOBJ)/es5506.o endif +#------------------------------------------------- +# Ensoniq "pump" device, interfaces 5505/5506 with 5510 +#@src/emu/sound/esqpump.h,SOUNDS += ESQPUMP +#------------------------------------------------- + +ifneq ($(filter ESQPUMP,$(SOUNDS)),) +SOUNDOBJS += $(SOUNDOBJ)/esqpump.o +endif + #------------------------------------------------- # Excellent Systems ADPCM sound chip diff --git a/src/mess/drivers/esq5505.c b/src/mess/drivers/esq5505.c index b7be7254633..a302a43f076 100644 --- a/src/mess/drivers/esq5505.c +++ b/src/mess/drivers/esq5505.c @@ -2,10 +2,11 @@ esq5505.c - Ensoniq ES5505 + ES5510 based synthesizers and samplers - Ensoniq VFX, VFX-SD, EPS, EPS-16 Plus, SD-1, SD-1 32, and SQ-1 (SQ-1 Plus, + Ensoniq VFX, VFX-SD, EPS, EPS-16 Plus, SD-1, SD-1 32, SQ-1 and SQ-R (SQ-1 Plus, SQ-2, and KS-32 are known to also be this architecture). - The Taito sound system in taito_en.c is directly derived from the SQ-1. + The Taito sound system in taito_en.c is directly derived from the 32-voice version + of the SD-1. Driver by R. Belmont with thanks to Parduz, Christian Brunschen, and Phil Bennett @@ -106,7 +107,21 @@ 5 = Volume Slider 6 = Battery 7 = Voltage Reference - + + SQ-1: + 4 = second digit of patch # becomes 2 + 5 = first digit of patch # becomes 2 + 6 = second digit of patch # becomes 4 + 7 = first digit of patch # becomes 4 + 8 = trk07 4volume=99 + 12 = patch -1 + 13 = patch +1 + 14 = second digit of patch # becomes 5 + 15 = first digit of patch # becomes 5 + 20 = select sound? + 22 = second digit of patch # becomes 6 + 23 = first digit of patch # becomes 6 + ***************************************************************************/ #include @@ -114,6 +129,7 @@ #include "emu.h" #include "cpu/m68000/m68000.h" #include "sound/es5506.h" +#include "sound/esqpump.h" #include "machine/n68681.h" #include "cpu/es5510/es5510.h" #include "machine/wd_fdc.h" @@ -143,277 +159,6 @@ void print_to_stderr(const char *format, ...) va_end(arg); } -#define PUMP_DETECT_SILENCE 0 -#define PUMP_TRACK_SAMPLES 0 -#define PUMP_FAKE_ESP_PROCESSING 0 -#define PUMP_REPLACE_ESP_PROGRAM 0 - -class esq_5505_5510_pump : public device_t, - public device_sound_interface -{ -public: - esq_5505_5510_pump(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - - void set_otis(es5505_device *otis) { m_otis = otis; } - void set_esp(es5510_device *esp) { m_esp = esp; } - void set_esp_halted(bool esp_halted) { - m_esp_halted = esp_halted; - logerror("ESP-halted -> %d\n", m_esp_halted); - if (!esp_halted) { - -#if PUMP_REPLACE_ESP_PROGRAM - m_esp->write_reg(245, 0x1d0f << 8); // dlength = 0x3fff, 16-sample delay - - int pc = 0; - for (pc = 0; pc < 0xc0; pc++) { - m_esp->write_reg(pc, 0); - } - pc = 0; - // replace the ESP program with a simple summing & single-sample delay - m_esp->_instr(pc++) = 0xffffeaa09000; // MOV SER0R > grp_a0 - m_esp->_instr(pc++) = 0xffffeba00000; // ADD SER0L, gpr_a0 > gpr_a0 - m_esp->_instr(pc++) = 0xffffeca00000; // ADD SER1R, gpr_a0 > gpr_a0 - m_esp->_instr(pc++) = 0xffffeda00000; // ADD SER1L, gpr_a0 > gpr_a0 - m_esp->_instr(pc++) = 0xffffeea00000; // ADD SER2R, gpr_a0 > gpr_a0 - - m_esp->_instr(pc ) = 0xffffefa00000; // ADD SER2L, gpr_a0 > gpr_a0; prepare to read from delay 2 instructions from now, offset = 0 - m_esp->write_reg(pc++, 0); //offset into delay - - m_esp->_instr(pc ) = 0xffffa0a09508; // MOV gpr_a0 > delay + offset - m_esp->write_reg(pc++, 1 << 8); // offset into delay - -1 samples - - m_esp->_instr(pc++) = 0xffff00a19928; // MOV DIL > gpr_a1; read Delay and dump FIFO (so that the value gets written) - - m_esp->_instr(pc++) = 0xffffa1f09000; // MOV gpr_a1 > SER3R - m_esp->_instr(pc++) = 0xffffa1f19000; // MOV gpr_a1 > SER3L - - m_esp->_instr(pc++) = 0xffffffff0000; // NO-OP - m_esp->_instr(pc++) = 0xffffffff0000; // NO-OP - m_esp->_instr(pc++) = 0xfffffffff000; // END - - while (pc < 160) { - m_esp->_instr(pc++) = 0xffffffffffff; // no-op - } -#endif - - // m_esp->list_program(print_to_stderr); - } - } - bool get_esp_halted() { - return m_esp_halted; - } - -protected: - // device-level overrides - virtual void device_start(); - virtual void device_stop(); - virtual void device_reset(); - - // sound stream update overrides - virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); - - // timer callback overrides - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); - -private: - // internal state: - // sound stream - sound_stream *m_stream; - - // per-sample timer - emu_timer *m_timer; - - // OTIS sound generator - es5505_device *m_otis; - - // ESP signal processor - es5510_device *m_esp; - - // Is the ESP halted by the CPU? - bool m_esp_halted; - -#if !PUMP_FAKE_ESP_PROCESSING - osd_ticks_t ticks_spent_processing; - int samples_processed; -#endif - -#if PUMP_DETECT_SILENCE - int silent_for; - bool was_silence; -#endif - -#if PUMP_TRACK_SAMPLES - int last_samples; - osd_ticks_t last_ticks; - osd_ticks_t next_report_ticks; -#endif - -#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM - INT16 e[0x4000]; - int ei; -#endif -}; - -const device_type ESQ_5505_5510_PUMP = &device_creator; - -esq_5505_5510_pump::esq_5505_5510_pump(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, ESQ_5505_5510_PUMP, "ESQ_5505_5510_PUMP", tag, owner, clock, "esq_5505_5510_pump", __FILE__), - device_sound_interface(mconfig, *this), - m_esp_halted(true) -{ -} - -void esq_5505_5510_pump::device_start() -{ - logerror("Clock = %d\n", clock()); - - m_stream = machine().sound().stream_alloc(*this, 8, 2, clock(), this); - m_timer = timer_alloc(0); - m_timer->enable(false); - -#if PUMP_DETECT_SILENCE - silent_for = 500; - was_silence = 1; -#endif -#if !PUMP_FAKE_ESP_PROCESSING - ticks_spent_processing = 0; - samples_processed = 0; -#endif -#if PUMP_TRACK_SAMPLES - last_samples = 0; - last_ticks = osd_ticks(); - next_report_ticks = last_ticks + osd_ticks_per_second(); -#endif - -#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM - memset(e, 0, 0x4000 * sizeof(e[0])); - ei = 0; -#endif -} - -void esq_5505_5510_pump::device_stop() -{ - m_timer->enable(false); -} - -void esq_5505_5510_pump::device_reset() -{ - INT64 nsec_per_sample = 100 * 16 * 21; - attotime sample_time(0, 1000000000 * nsec_per_sample); - attotime initial_delay(0, 0); - - m_timer->adjust(initial_delay, 0, sample_time); - m_timer->enable(true); -} - -void esq_5505_5510_pump::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) -{ - if (samples != 1) { - logerror("Pump: request for %d samples\n", samples); - } - - stream_sample_t *left = outputs[0], *right = outputs[1]; - for (int i = 0; i < samples; i++) - { -#define SAMPLE_SHIFT 4 - // anything for the 'aux' output? - INT16 l = inputs[0][i] >> SAMPLE_SHIFT; - INT16 r = inputs[1][i] >> SAMPLE_SHIFT; - - // push the samples into the ESP - m_esp->ser_w(0, inputs[2][i] >> SAMPLE_SHIFT); - m_esp->ser_w(1, inputs[3][i] >> SAMPLE_SHIFT); - m_esp->ser_w(2, inputs[4][i] >> SAMPLE_SHIFT); - m_esp->ser_w(3, inputs[5][i] >> SAMPLE_SHIFT); - m_esp->ser_w(4, inputs[6][i] >> SAMPLE_SHIFT); - m_esp->ser_w(5, inputs[7][i] >> SAMPLE_SHIFT); - -#if PUMP_FAKE_ESP_PROCESSING - m_esp->ser_w(6, m_esp->ser_r(0) + m_esp->ser_r(2) + m_esp->ser_r(4)); - m_esp->ser_w(7, m_esp->ser_r(1) + m_esp->ser_r(3) + m_esp->ser_r(5)); -#else - if (!m_esp_halted) { - logerror("passing one sample through ESP\n"); - osd_ticks_t a = osd_ticks(); - m_esp->run_once(); - osd_ticks_t b = osd_ticks(); - ticks_spent_processing += (b - a); - samples_processed++; - } -#endif - - // read the processed result from the ESP and add to the saved AUX data - INT16 ll = m_esp->ser_r(6); - INT16 rr = m_esp->ser_r(7); - l += ll; - r += rr; - -#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM - // if we're processing the fake program through the ESP, the result should just be that of adding the inputs - INT32 el = (inputs[2][i]) + (inputs[4][i]) + (inputs[6][i]); - INT32 er = (inputs[3][i]) + (inputs[5][i]) + (inputs[7][i]); - INT32 e_next = el + er; - e[(ei + 0x1d0f) % 0x4000] = e_next; - - if (l != e[ei]) { - fprintf(stderr, "expected (%d) but have (%d)\n", e[ei], l); - } - ei = (ei + 1) % 0x4000; -#endif - - // write the combined data to the output - *left++ = l; - *right++ = r; - } - -#if PUMP_DETECT_SILENCE - for (int i = 0; i < samples; i++) { - if (outputs[0][i] == 0 && outputs[1][i] == 0) { - silent_for++; - } else { - silent_for = 0; - } - } - bool silence = silent_for >= 500; - if (was_silence != silence) { - if (!silence) { - fprintf(stderr, ".-*\n"); - } else { - fprintf(stderr, "*-.\n"); - } - was_silence = silence; - } -#endif - -#if PUMP_TRACK_SAMPLES - last_samples += samples; - osd_ticks_t now = osd_ticks(); - if (now >= next_report_ticks) - { - osd_ticks_t elapsed = now - last_ticks; - osd_ticks_t tps = osd_ticks_per_second(); - fprintf(stderr, "Pump: %d samples in %" I64FMT "d ticks for %f Hz\n", last_samples, elapsed, last_samples * (double)tps / (double)elapsed); - last_ticks = now; - while (next_report_ticks <= now) { - next_report_ticks += tps; - } - last_samples = 0; - -#if !PUMP_FAKE_ESP_PROCESSING - fprintf(stderr, " ESP spent %" I64FMT "d ticks on %d samples, %f ticks per sample\n", ticks_spent_processing, samples_processed, (double)ticks_spent_processing / (double)samples_processed); - ticks_spent_processing = 0; - samples_processed = 0; -#endif - } -#endif -} - -void esq_5505_5510_pump::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { - // ecery time there's a new sample period, update the stream! - m_stream->update(); -} - - class esq5505_state : public driver_device { public: diff --git a/src/mess/mess.mak b/src/mess/mess.mak index 259c16adea2..65ef581de4c 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -249,6 +249,7 @@ SOUNDS += AWACS #SOUNDS += YMZ770 SOUNDS += T6721A SOUNDS += MOS7360 +SOUNDS += ESQPUMP #------------------------------------------------- # specify available video cores