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,36 +8,58 @@
#include "emu.h"
#include "cpu/mcs48/mcs48.h"
+#include "imagedev/cassette.h"
#include "machine/nvram.h"
+#include "softlist_dev.h"
+#include "speaker.h"
-namespace {
-
-class polysix_state : public driver_device
+class polysix_sound_block : public device_t, public device_sound_interface
{
public:
- polysix_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag)
- , m_progmcu(*this, "progmcu")
- , m_keymcu(*this, "keymcu")
- , m_keyboard(*this, "K%u", 0U)
- , m_progboard(*this, "P%u", 0U)
- , m_knobs(*this, "A%x", 0U)
- {
- }
+ polysix_sound_block(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- virtual void machine_start() override ATTR_COLD;
- void polysix(machine_config &config);
+ 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:
- required_device m_progmcu;
- required_device m_keymcu;
- std::unique_ptr m_nvram_ptr;
- required_ioport_array<10> m_keyboard;
- required_ioport_array<8> m_progboard;
- required_ioport_array<16> m_knobs;
+ static const std::array phase_step;
+ static const std::array pwm_phase_step;
+ static const std::array pw_threshold;
- std::array m_pitch;
+ 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;
@@ -54,8 +76,386 @@ private:
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);
+ }
+}
+
+
+
+
+class polysix_state : public driver_device
+{
+public:
+ polysix_state(const machine_config &mconfig, device_type type, const char *tag)
+ : 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;
+ 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)