From 68c049b67d514f685a0fbdc985d877917c5a1344 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Sun, 3 Nov 2024 18:47:24 +0100 Subject: Polysix: Add basic initial wave generation, "organ" eg, plus default nvram and floppy support. --- hash/polysix.xml | 26 ++ src/mame/korg/polysix.cpp | 626 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 521 insertions(+), 131 deletions(-) create mode 100644 hash/polysix.xml diff --git a/hash/polysix.xml b/hash/polysix.xml new file mode 100644 index 00000000000..97f5b158501 --- /dev/null +++ b/hash/polysix.xml @@ -0,0 +1,26 @@ + + + + + + + Factory presets + 1981 + Korg + + + + + + + + + + + + + + + diff --git a/src/mame/korg/polysix.cpp b/src/mame/korg/polysix.cpp index 42fd9e5b590..20fc26c49ad 100644 --- a/src/mame/korg/polysix.cpp +++ b/src/mame/korg/polysix.cpp @@ -8,10 +8,420 @@ #include "emu.h" #include "cpu/mcs48/mcs48.h" +#include "imagedev/cassette.h" #include "machine/nvram.h" +#include "softlist_dev.h" +#include "speaker.h" + + +class polysix_sound_block : public device_t, public device_sound_interface +{ +public: + polysix_sound_block(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + void set_pitch(int channel, u8 pitch); + void set_gates(u8 gates); + void set_effect_speed(u8 value); + void set_cutoff(u8 value); + void set_eg_intensity(u8 value); + void set_resonance(u8 value); + void set_attack(u8 value); + void set_decay(u8 value); + void set_suspend(u8 value); + void set_release(u8 value); + void set_keyboard_tracking(u8 value); + void set_pw_pwm(u8 value); + void set_pwm_speed(u8 value); + void set_mg_speed(u8 value); + void set_mg_delay(u8 value); + void set_mg_level(u8 value); + void set_control_low(u8 value); + void set_control_high(u8 value); + + u8 get_control_low(); + + virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + + virtual void device_start() override; + virtual void device_reset() override; + +private: + static const std::array phase_step; + static const std::array pwm_phase_step; + static const std::array pw_threshold; + + sound_stream *m_stream; + + std::array m_phase; + std::array m_organ_eg; + + float m_pwm_phase; + + std::array m_pitch; + u8 m_gates; + u8 m_current_gates; + + u8 m_effect_speed; + u8 m_cutoff; + u8 m_eg_intensity; + u8 m_resonance; + u8 m_attack; + u8 m_decay; + u8 m_suspend; + u8 m_release; + u8 m_keyboard_tracking; + u8 m_pw_pwm; + u8 m_pwm_speed; + u8 m_mg_speed; + u8 m_mg_delay; + u8 m_mg_level; + + u8 m_control_low; + u8 m_control_high; +}; + +DEFINE_DEVICE_TYPE(POLYSIX_SOUND_BLOCK, polysix_sound_block, "polysix_sound_block", "Korg Polysix sound block") + +// Phase step at 48KHz for a given pitch for the main oscillator. +// Real range is 0 (C0) to 84 (C7), since it's a 61-keys, 5 octaves +// keyboard with +/- 1 octave transpose capability. + +const std::array polysix_sound_block::phase_step = []() { + std::array steps; + // Tune A4 = 440Hz + for(int i=0; i != 0x100; i++) + steps[i] = 440.0 * pow(2, (i - 12*4 - 9)/12.0) / 48000; + return steps; +}(); + +// Phase step for the pwm. Actual curve is unclear but looks linear. + +const std::array polysix_sound_block::pwm_phase_step = []() { + std::array steps; + // 0 = 0Hz, max = 20Hz, possibly linear? + for(int i=0; i != 0x100; i++) + steps[i] = 20 * (i/255.0) / 48000; + return steps; +}(); + +// Threshold for the pulse width, linear between 0.5 and 1.1, where 1 +// is the actual max value. + +const std::array polysix_sound_block::pw_threshold = []() { + std::array thr; + for(int i=0; i != 0x100; i++) + thr[i] = 0.5 + 0.6 * (i/255.0); + return thr; +}(); + +polysix_sound_block::polysix_sound_block(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, POLYSIX_SOUND_BLOCK, tag, owner, clock) + , device_sound_interface(mconfig, *this) +{ +} + +void polysix_sound_block::device_start() +{ + m_stream = stream_alloc(0, 1, 48000); + + save_item(NAME(m_phase)); + save_item(NAME(m_organ_eg)); + save_item(NAME(m_pwm_phase)); + + save_item(NAME(m_pitch)); + save_item(NAME(m_gates)); + save_item(NAME(m_current_gates)); + save_item(NAME(m_effect_speed)); + save_item(NAME(m_cutoff)); + save_item(NAME(m_eg_intensity)); + save_item(NAME(m_resonance)); + save_item(NAME(m_attack)); + save_item(NAME(m_decay)); + save_item(NAME(m_suspend)); + save_item(NAME(m_release)); + save_item(NAME(m_keyboard_tracking)); + save_item(NAME(m_pw_pwm)); + save_item(NAME(m_pwm_speed)); + save_item(NAME(m_mg_speed)); + save_item(NAME(m_mg_delay)); + save_item(NAME(m_mg_level)); + save_item(NAME(m_control_low)); + save_item(NAME(m_control_high)); + + std::fill(m_phase.begin(), m_phase.end(), 0); + std::fill(m_organ_eg.begin(), m_organ_eg.end(), 0); + m_pwm_phase = 0; + + std::fill(m_pitch.begin(), m_pitch.end(), 0); + + m_effect_speed = 0; + m_cutoff = 0; + m_eg_intensity = 0; + m_resonance = 0; + m_attack = 0; + m_decay = 0; + m_suspend = 0; + m_release = 0; + m_keyboard_tracking = 0; + m_pw_pwm = 0; + m_pwm_speed = 0; + m_mg_speed = 0; + m_mg_delay = 0; + m_mg_level = 0; + m_control_low = 0; + m_control_high = 0; + m_gates = 0; + m_current_gates = 0; +} + +void polysix_sound_block::device_reset() +{ +} + +void polysix_sound_block::set_pitch(int channel, u8 pitch) +{ + if(m_pitch[channel] != pitch) { + m_stream->update(); + m_pitch[channel] = pitch; + + static const char *const notes[12] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; + logerror("channel %d pitch %02x %s%d\n", channel, pitch, notes[pitch % 12], (pitch/12)); + } +} + +void polysix_sound_block::set_gates(u8 gates) +{ + if(gates != m_gates) { + m_stream->update(); + m_gates = gates; + } +} + +void polysix_sound_block::set_effect_speed(u8 value) +{ + if(value != m_effect_speed) { + m_stream->update(); + m_effect_speed = value; + logerror("effect_speed = %02x\n", value); + } +} + +void polysix_sound_block::set_cutoff(u8 value) +{ + if(value != m_cutoff) { + m_stream->update(); + m_cutoff = value; + logerror("cutoff = %02x\n", value); + } +} + +void polysix_sound_block::set_eg_intensity(u8 value) +{ + if(value != m_eg_intensity) { + m_stream->update(); + m_eg_intensity = value; + logerror("eg_intensity = %02x\n", value); + } +} + +void polysix_sound_block::set_resonance(u8 value) +{ + if(value != m_resonance) { + m_stream->update(); + m_resonance = value; + logerror("resonance = %02x\n", value); + } +} + +void polysix_sound_block::set_attack(u8 value) +{ + if(value != m_attack) { + m_stream->update(); + m_attack = value; + logerror("attack = %02x\n", value); + } +} + +void polysix_sound_block::set_decay(u8 value) +{ + if(value != m_decay) { + m_stream->update(); + m_decay = value; + logerror("decay = %02x\n", value); + } +} + +void polysix_sound_block::set_suspend(u8 value) +{ + if(value != m_suspend) { + m_stream->update(); + m_suspend = value; + logerror("suspend = %02x\n", value); + } +} + +void polysix_sound_block::set_release(u8 value) +{ + if(value != m_release) { + m_stream->update(); + m_release = value; + logerror("release = %02x\n", value); + } +} + +void polysix_sound_block::set_keyboard_tracking(u8 value) +{ + if(value != m_keyboard_tracking) { + m_stream->update(); + m_keyboard_tracking = value; + logerror("keyboard_tracking = %02x\n", value); + } +} + +void polysix_sound_block::set_pw_pwm(u8 value) +{ + if(value != m_pw_pwm) { + m_stream->update(); + m_pw_pwm = value; + logerror("pw_pwm = %02x\n", value); + } +} + +void polysix_sound_block::set_pwm_speed(u8 value) +{ + if(value != m_pwm_speed) { + m_stream->update(); + m_pwm_speed = value; + logerror("pwm_speed = %02x\n", value); + } +} + +void polysix_sound_block::set_mg_speed(u8 value) +{ + if(value != m_mg_speed) { + m_stream->update(); + m_mg_speed = value; + logerror("mg_speed = %02x\n", value); + } +} + +void polysix_sound_block::set_mg_delay(u8 value) +{ + if(value != m_mg_delay) { + m_stream->update(); + m_mg_delay = value; + logerror("mg_delay = %02x\n", value); + } +} + +void polysix_sound_block::set_mg_level(u8 value) +{ + if(value != m_mg_level) { + m_stream->update(); + m_mg_level = value; + logerror("mg_level = %02x\n", value); + } +} + +void polysix_sound_block::set_control_low(u8 value) +{ + if(value != m_control_low) { + m_stream->update(); + m_control_low = value; + logerror("control low vco=%s wave=%s sub=%s mod=%s\n", + BIT(value, 0, 2) == 0 ? "16'" : BIT(value, 0, 2) == 1 ? "8'" : BIT(value, 0, 2) == 2 ? "4'" : "?", + BIT(value, 2, 2) == 1 ? "tri" : BIT(value, 2, 2) == 0 ? "pw" : BIT(value, 2, 2) == 2 ? "pwm" : "?", + BIT(value, 4, 2) == 0 ? "off" : BIT(value, 4, 2) == 1 ? "1oct" : BIT(value, 4, 2) == 2 ? "2oct" : "?", + BIT(value, 6, 2) == 0 ? "vca" : BIT(value, 6, 2) == 1 ? "vcf" : BIT(value, 6, 2) == 2 ? "vco" : "?" + ); + } +} + +void polysix_sound_block::set_control_high(u8 value) +{ + if(value != m_control_high) { + m_stream->update(); + m_control_high = value; + logerror("control high vca-mode=%s chorus=%s phase=%s ens=%s p.vol=%x\n", + BIT(value, 0) ? "eg" : "square", + BIT(value, 1) ? "on" : "off", + BIT(value, 2) ? "on" : "off", + BIT(value, 3) ? "on" : "off", + BIT(value, 4, 4) + ); + } +} + +u8 polysix_sound_block::get_control_low() +{ + return m_control_low; +} + +// #*#*#*#*#*#*#*# +void polysix_sound_block::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + for(int sample=0; sample != outputs[0].samples(); sample++) { + // u8 trigger = m_gates & ~m_current_gates; + float out = 0; + + // Step the pwm phase (common to all channels) + m_pwm_phase += pwm_phase_step[m_pwm_speed]; + while(m_pwm_phase >= 2) + m_pwm_phase -= 2; + + // Wrap into a triangle + float pwm_phase = m_pwm_phase >= 1 ? 2 - m_pwm_phase : m_pwm_phase; + + // Compute the threshold + float pw_thr = pw_threshold[m_pw_pwm]; + if(BIT(m_control_low, 3) || 1) + // PWM mode, the modulation multiplies the threshold part over 0.5 with the phase wrapped between 0.2 and 1 + pw_thr = 0.5 + (pw_thr - 0.5) * (0.2 + pwm_phase * 0.8); + + for(int channel = 0; channel != 6; channel ++) { + if((m_gates ^ m_current_gates) & (1 << channel)) + logerror("channel %d %s\n", channel, (m_gates & (1<= 4) + m_phase[channel] -= 4; + + int subosc_step = int(m_phase[channel]); + float phase = m_phase[channel] - subosc_step; + + // Generate the initial wave in the [-1, 1] range + float wave; + if(BIT(m_control_low, 2)) + // triangle + wave = 2*(phase - 0.5); + + else + // PW(M) + wave = phase >= pw_thr ? 1 : -1; + + // Add the sub-oscillator, if active + if(BIT(m_control_low, 4, 2)) + wave += (subosc_step & (BIT(m_control_low, 5, 1) ? 2 : 1)) ? 1 : 0; + + // Step the organ EG + if(BIT(m_gates, channel)) + // When gate is on, charge a 0.047uF cap through a 10K resistor + m_organ_eg[channel] += (1-m_organ_eg[channel])*0.0433581893516088; // 1-exp(-1/(10e3 * 0.047e-6 * 48000)) + else + // When gate is off, discharge a 0.047uF cap through a 230K resistor + m_organ_eg[channel] -= m_organ_eg[channel]*0.00192537196422815; // 1-exp(-1/(230e3 * 0.047e-6 * 48000)) + + out += wave * m_organ_eg[channel]; + } + + m_current_gates = m_gates; + outputs[0].put_clamp(sample, out/2); + } +} + -namespace { class polysix_state : public driver_device { @@ -20,42 +430,32 @@ public: : driver_device(mconfig, type, tag) , m_progmcu(*this, "progmcu") , m_keymcu(*this, "keymcu") + , m_sound(*this, "soundblock") , m_keyboard(*this, "K%u", 0U) , m_progboard(*this, "P%u", 0U) , m_knobs(*this, "A%x", 0U) + , m_tape_enable(*this, "TAPE") + , m_tape(*this, "tape") { } virtual void machine_start() override ATTR_COLD; void polysix(machine_config &config); + INPUT_CHANGED_MEMBER(tape_enable_w); + private: required_device m_progmcu; required_device m_keymcu; + required_device m_sound; std::unique_ptr m_nvram_ptr; required_ioport_array<10> m_keyboard; required_ioport_array<8> m_progboard; required_ioport_array<16> m_knobs; - - std::array m_pitch; - - u8 m_effect_speed; - u8 m_cutoff; - u8 m_eg_intensity; - u8 m_resonance; - u8 m_attack; - u8 m_decay; - u8 m_suspend; - u8 m_release; - u8 m_keyboard_tracking; - u8 m_pw_pwm; - u8 m_pwm_speed; - u8 m_mg_speed; - u8 m_mg_delay; - u8 m_mg_level; + required_ioport m_tape_enable; + required_device m_tape; u16 m_pleds; - u16 m_pctrl; u8 m_kleds; u8 m_prog_bus; @@ -63,10 +463,11 @@ private: u8 m_prog_p2; u8 m_key_bus; u8 m_keyon; - u8 m_key_ic2; u8 m_key_p2; u8 m_trigger; + bool m_tape_enabled; + void key_bus_w(u8 data); u8 key_p1_r(); void key_p2_w(u8 data); @@ -96,67 +497,34 @@ void polysix_state::machine_start() subdevice("nvram")->set_base(&m_nvram_ptr[0], 0x400); save_pointer(NAME(m_nvram_ptr), 0x400); - save_item(NAME(m_pitch)); save_item(NAME(m_pleds)); - save_item(NAME(m_pctrl)); save_item(NAME(m_kleds)); save_item(NAME(m_key_bus)); save_item(NAME(m_keyon)); - save_item(NAME(m_key_ic2)); save_item(NAME(m_trigger)); save_item(NAME(m_prog_bus)); save_item(NAME(m_prog_p1)); save_item(NAME(m_prog_p2)); - save_item(NAME(m_effect_speed)); - save_item(NAME(m_cutoff)); - save_item(NAME(m_eg_intensity)); - save_item(NAME(m_resonance)); - save_item(NAME(m_attack)); - save_item(NAME(m_decay)); - save_item(NAME(m_suspend)); - save_item(NAME(m_release)); - save_item(NAME(m_keyboard_tracking)); - save_item(NAME(m_pw_pwm)); - save_item(NAME(m_pwm_speed)); - save_item(NAME(m_mg_speed)); - save_item(NAME(m_mg_delay)); - save_item(NAME(m_mg_level)); - - std::fill(m_pitch.begin(), m_pitch.end(), 0); - - m_effect_speed = 0; - m_cutoff = 0; - m_eg_intensity = 0; - m_resonance = 0; - m_attack = 0; - m_decay = 0; - m_suspend = 0; - m_release = 0; - m_keyboard_tracking = 0; - m_pw_pwm = 0; - m_pwm_speed = 0; - m_mg_speed = 0; - m_mg_delay = 0; - m_mg_level = 0; + save_item(NAME(m_tape_enabled)); m_pleds = 0; m_key_bus = 0; m_keyon = 0; - m_key_ic2 = 0; m_key_p2 = 0; m_trigger = 0; m_prog_bus = 0; m_prog_p1 = 0; m_prog_p2 = 0; + + m_tape_enabled = false; } u8 polysix_state::prog_r(offs_t offset) { if(BIT(m_prog_p1, 7)) { u16 adr = BIT(m_prog_p2, 0) | (offset << 1) | ( BIT(m_prog_p2, 1) << 9); - logerror("nvram_r %03x = %x\n", adr, m_nvram_ptr[adr]); return m_nvram_ptr[adr] | 0xf0; } @@ -167,7 +535,6 @@ void polysix_state::prog_w(offs_t offset, u8 data) { if(BIT(m_prog_p1, 7)) { u16 adr = BIT(m_prog_p2, 0) | (offset << 1) | ( BIT(m_prog_p2, 1) << 9); - logerror("nvram_w %03x = %x\n", adr, data & 0x0f); m_nvram_ptr[adr] = data & 0x0f; } } @@ -191,37 +558,20 @@ void polysix_state::prog_p1_w(u8 data) if(BIT(chg, 6) && BIT(m_prog_p1, 6)) { switch(m_prog_p2 & 0xf) { - case 0x0: if(m_prog_bus != m_effect_speed) logerror("effect_speed = %02x\n", m_prog_bus); break; - case 0x1: if(m_prog_bus != m_cutoff) logerror("cutoff = %02x\n", m_prog_bus); break; - case 0x2: if(m_prog_bus != m_eg_intensity) logerror("eg_intensity = %02x\n", m_prog_bus); break; - case 0x3: if(m_prog_bus != m_resonance) logerror("resonance = %02x\n", m_prog_bus); break; - case 0x4: if(m_prog_bus != m_attack) logerror("attack = %02x\n", m_prog_bus); break; - case 0x5: if(m_prog_bus != m_decay) logerror("decay = %02x\n", m_prog_bus); break; - case 0x6: if(m_prog_bus != m_suspend) logerror("suspend = %02x\n", m_prog_bus); break; - case 0x7: if(m_prog_bus != m_release) logerror("release = %02x\n", m_prog_bus); break; - case 0x8: if(m_prog_bus != m_keyboard_tracking) logerror("keyboard_tracking = %02x\n", m_prog_bus); break; - case 0x9: if(m_prog_bus != m_pw_pwm) logerror("pw_pwm = %02x\n", m_prog_bus); break; - case 0xa: if(m_prog_bus != m_pwm_speed) logerror("pwm_speed = %02x\n", m_prog_bus); break; - case 0xb: if(m_prog_bus != m_mg_speed) logerror("mg_speed = %02x\n", m_prog_bus); break; - case 0xc: if(m_prog_bus != m_mg_delay) logerror("mg_delay = %02x\n", m_prog_bus); break; - case 0xd: if(m_prog_bus != m_mg_level) logerror("mg_level = %02x\n", m_prog_bus); break; - } - - switch(m_prog_p2 & 0xf) { - case 0x0: m_effect_speed = m_prog_bus; break; - case 0x1: m_cutoff = m_prog_bus; break; - case 0x2: m_eg_intensity = m_prog_bus; break; - case 0x3: m_resonance = m_prog_bus; break; - case 0x4: m_attack = m_prog_bus; break; - case 0x5: m_decay = m_prog_bus; break; - case 0x6: m_suspend = m_prog_bus; break; - case 0x7: m_release = m_prog_bus; break; - case 0x8: m_keyboard_tracking = m_prog_bus; break; - case 0x9: m_pw_pwm = m_prog_bus; break; - case 0xa: m_pwm_speed = m_prog_bus; break; - case 0xb: m_mg_speed = m_prog_bus; break; - case 0xc: m_mg_delay = m_prog_bus; break; - case 0xd: m_mg_level = m_prog_bus; break; + case 0x0: m_sound->set_effect_speed(m_prog_bus); break; + case 0x1: m_sound->set_cutoff(m_prog_bus); break; + case 0x2: m_sound->set_eg_intensity(m_prog_bus); break; + case 0x3: m_sound->set_resonance(m_prog_bus); break; + case 0x4: m_sound->set_attack(m_prog_bus); break; + case 0x5: m_sound->set_decay(m_prog_bus); break; + case 0x6: m_sound->set_suspend(m_prog_bus); break; + case 0x7: m_sound->set_release(m_prog_bus); break; + case 0x8: m_sound->set_keyboard_tracking(m_prog_bus); break; + case 0x9: m_sound->set_pw_pwm(m_prog_bus); break; + case 0xa: m_sound->set_pwm_speed(m_prog_bus); break; + case 0xb: m_sound->set_mg_speed(m_prog_bus); break; + case 0xc: m_sound->set_mg_delay(m_prog_bus); break; + case 0xd: m_sound->set_mg_level(m_prog_bus); break; } } } @@ -232,10 +582,10 @@ void polysix_state::prog_p2_w(u8 data) m_prog_p2 = data; if(BIT(chg, 4) && !BIT(m_prog_p2, 4)) - m_pctrl = (m_pctrl & 0xff00) | m_prog_bus; + m_sound->set_control_low(m_prog_bus); if(BIT(chg, 5) && !BIT(m_prog_p2, 5)) - m_pctrl = (m_pctrl & 0x00ff) | (m_prog_bus << 8); + m_sound->set_control_high(m_prog_bus); u16 old_leds = m_pleds; @@ -259,8 +609,8 @@ void polysix_state::prog_p2_w(u8 data) BIT(m_pleds, 9) ? 'B' : '.', BIT(m_pleds, 10) ? 'C' : '.', BIT(m_pleds, 11) ? 'D' : '.', - BIT(m_pleds, 12) ? " manual" : "", - BIT(m_pleds, 13) ? " write" : ""); + BIT(m_pleds, 12) ? " manual/found" : "", + BIT(m_pleds, 13) ? " write/loading" : ""); } void polysix_state::prog_bus_w(u8 data) @@ -275,8 +625,8 @@ int polysix_state::prog_t0_r() int polysix_state::prog_t1_r() { - logerror("prog t1\n"); - return 1; + // logerror("prog t1 %f\n", m_tape->input()); + return m_tape->input() >= 0; } u8 polysix_state::key_p1_r() @@ -298,7 +648,7 @@ void polysix_state::key_bus_w(u8 data) } // cn12 at klm-371 -// cn12-17 -> int, aoki, arpeggiator +// cn12-17 -> int, acki, arpeggiator // cn12-16 = p27, gnd? // klm-367 // cn05-1 = reset @@ -312,20 +662,8 @@ void polysix_state::key_p2_w(u8 data) m_key_p2 = data; if(BIT(chg, 3) && !BIT(m_key_p2, 3)) { - u8 chgk = m_keyon ^ m_key_bus; - m_keyon = m_key_bus; - m_trigger |= m_keyon & chgk & 0x3f; - if(m_trigger) - logerror("keyon %c%c%c%c%c%c\n", - BIT(m_trigger, 0) ? '0' : '.', - BIT(m_trigger, 1) ? '1' : '.', - BIT(m_trigger, 2) ? '2' : '.', - BIT(m_trigger, 3) ? '3' : '.', - BIT(m_trigger, 4) ? '4' : '.', - BIT(m_trigger, 5) ? '5' : '.'); - m_trigger = 0; - if(BIT(chgk, 7)) - logerror("ic45 = %02x %s\n", m_keyon, machine().describe_context()); + m_sound->set_gates(m_tape_enabled ? 0 : m_key_bus & 0x3f); + // TODO logerror("ic45 = %02x %s\n", m_key_bus, machine().describe_context()); } if(BIT(chg, 4) && !BIT(m_key_p2, 4)) { @@ -342,13 +680,10 @@ void polysix_state::key_p2_w(u8 data) if(!BIT(m_key_p2, 5)) { int index = BIT(data, 0, 3); - if(m_key_bus != m_pitch[index]) { - m_pitch[index] = m_key_bus; - if(index < 6) - logerror("voice %d pitch %3d\n", index, m_key_bus); - else - logerror("key analog #%d = %3d\n", index, m_key_bus); - } + if(index < 6) + m_sound->set_pitch(index, m_key_bus); + else + ; // TODO } if(BIT(chg, 7)) @@ -359,12 +694,21 @@ void polysix_state::key_p2_w(u8 data) int polysix_state::key_t0_r() { - return BIT(m_pctrl, 0); + return !BIT(m_sound->get_control_low(), 0); } int polysix_state::key_t1_r() { - return BIT(m_pctrl, 01); + return !BIT(m_sound->get_control_low(), 01); +} + +INPUT_CHANGED_MEMBER(polysix_state::tape_enable_w) +{ + logerror("leds tape enable %s\n", newval ? "on" : "off"); + m_tape_enabled = newval; + m_progmcu->set_input_line(0, newval); + if(newval) + m_keyon = 0; } static INPUT_PORTS_START(polysix) @@ -469,21 +813,21 @@ static INPUT_PORTS_START(polysix) PORT_CONFSETTING( 0xc0, "1 octave") PORT_START("P0") - PORT_CONFNAME(0x03, 0x03, "VCO octave") - PORT_CONFSETTING( 0x01, "16'") + PORT_CONFNAME(0x03, 0x02, "VCO octave") + PORT_CONFSETTING( 0x03, "16'") PORT_CONFSETTING( 0x02, "8'") - PORT_CONFSETTING( 0x03, "4'") - PORT_CONFNAME(0x0c, 0x0c, "Waveform") - PORT_CONFSETTING( 0x04, "Triangle") - PORT_CONFSETTING( 0x08, "PW") - PORT_CONFSETTING( 0x0c, "PWM") + PORT_CONFSETTING( 0x01, "4'") + PORT_CONFNAME(0x0c, 0x08, "Waveform") + PORT_CONFSETTING( 0x08, "Triangle") + PORT_CONFSETTING( 0x0c, "PW") + PORT_CONFSETTING( 0x04, "PWM") PORT_BIT(0xf0, IP_ACTIVE_LOW, IPT_UNUSED) PORT_START("P1") - PORT_CONFNAME(0x03, 0x0c, "Sub oscillator") - PORT_CONFSETTING( 0x01, "off") + PORT_CONFNAME(0x03, 0x01, "Sub oscillator") + PORT_CONFSETTING( 0x03, "off") PORT_CONFSETTING( 0x02, "1 oct") - PORT_CONFSETTING( 0x03, "2 oct") + PORT_CONFSETTING( 0x01, "2 oct") PORT_CONFNAME(0x0c, 0x0c, "MG modulation") PORT_CONFSETTING( 0x04, "VCO") PORT_CONFSETTING( 0x08, "VCF") @@ -540,7 +884,9 @@ static INPUT_PORTS_START(polysix) PORT_START("P7") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("found / manual") PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("write / loading") - PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("write enable") + PORT_CONFNAME(0x04, 0x04, "write enable") + PORT_CONFSETTING( 0x00, "enabled") + PORT_CONFSETTING( 0x04, "disabled") PORT_BIT(0xf8, IP_ACTIVE_LOW, IPT_UNUSED) PORT_START("A0") @@ -590,6 +936,12 @@ static INPUT_PORTS_START(polysix) PORT_START("Af") PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("TAPE") + PORT_CONFNAME(0x01, 0x00, "Tape access") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(polysix_state::tape_enable_w), 0) + PORT_CONFSETTING( 0x01, "enabled") + PORT_CONFSETTING( 0x00, "disabled") + INPUT_PORTS_END void polysix_state::polysix(machine_config &config) @@ -611,6 +963,17 @@ void polysix_state::polysix(machine_config &config) m_keymcu->t1_in_cb().set(FUNC(polysix_state::key_t1_r)); NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // TC5514APL-3 + battery + + CASSETTE(config, m_tape); + m_tape->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_MUTED); + m_tape->set_interface("polysix"); + + SOFTWARE_LIST(config, "polysix").set_original("polysix"); + + POLYSIX_SOUND_BLOCK(config, m_sound); + m_sound->add_route(0, "speaker", 1.0); + + SPEAKER(config, "speaker").front_center(); } ROM_START(polysix) @@ -619,9 +982,10 @@ ROM_START(polysix) ROM_REGION(0x800, "keymcu", 0) ROM_LOAD("d8049c-217.bin", 0x000, 0x800, CRC(246d7767) SHA1(5b608c750e7fe7832070a53a74df416fd132ecb7)) -ROM_END -} // anonymous namespace + ROM_REGION(0x400, "nvram", 0) + ROM_LOAD("nvram.bin", 0x000, 0x400, CRC(1a913972) SHA1(891c7c2aa2f3cd54e3dd6847fad58ab831838c3e)) +ROM_END SYST(1980, polysix, 0, 0, polysix, polysix, polysix_state, empty_init, "Korg", "Polysix Programmable Polyphonic Synthesizer", MACHINE_IS_SKELETON) -- cgit v1.2.3