summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/roland/roland_tr707.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/roland/roland_tr707.cpp')
-rw-r--r--src/mame/roland/roland_tr707.cpp302
1 files changed, 217 insertions, 85 deletions
diff --git a/src/mame/roland/roland_tr707.cpp b/src/mame/roland/roland_tr707.cpp
index 28dbfa03a1c..01267182f56 100644
--- a/src/mame/roland/roland_tr707.cpp
+++ b/src/mame/roland/roland_tr707.cpp
@@ -1,24 +1,24 @@
// license:BSD-3-Clause
-// copyright-holders:AJR
+// copyright-holders:AJR,m1macrophage
/****************************************************************************
- Skeleton driver for Roland TR-707/727 drum machines.
+ Driver for Roland TR-707/727 drum machines.
From the Service Notes: “The differences between two models [TR-707 and
TR-727] are sound data, component values in several audio stages and a
couple of pin connections at IC30 of Voice board. Both models derive all
rhythm sounds from PCM-encoded samples of real sounds stored in ROM.”
- The TR-707 and TR-727 have 10 voices, each of which can be played independently.
- Some of the voices have two sample variations, and the hi hat voice has two
- decay variations (open and closed). Only one variation per voice can play at
- a time. This brings the total number of sounds to 15. While there are 16
- drum pads, the two "closed hi hat / short whistle" pads produce the same
- sound.
+ The TR-707 and TR-727 have 10 voices, each of which can be played
+ simultaneously. Some of the voices have two sample variations, and the
+ hi-hat voice has two decay variations (open and closed). Only one variation
+ per voice can play at a time. This brings the total number of sounds to 15.
+ While there are 16 drum pads, the two "closed hi hat" pads ("short whistle"
+ for the TR-727) produce the same sound.
There are 2 voice architectures. The "multiplex sound" section uses a single
8-bit DAC with time-multiplexing for 8 voices. The "single sound" section
- consists of two independent ROMs and 6-bit DACs. More information in:
+ consists of two independent ROMs and 6-bit DACs. More information in
tr707_audio_device::device_add_mconfig().
The TR-707/727 come with the following sounds:
@@ -85,6 +85,7 @@
#define LOG_ACCENT (1U << 4)
#define LOG_CART (1U << 5)
#define LOG_MIX (1U << 6)
+#define LOG_KEYS (1U << 7)
#define VERBOSE (LOG_GENERAL)
//#define LOG_OUTPUT_FUNC osd_printf_info
@@ -106,6 +107,18 @@ enum mux_voice
MV_COUNT
};
+constexpr const double MUX_EG_C[MV_COUNT] =
+{
+ CAP_U(0.047), // C53
+ CAP_U(0.047), // C48
+ CAP_U(0.047), // C54
+ CAP_U(0.047), // C52
+ CAP_U(0.047), // C58
+ CAP_U(1), // C47
+ CAP_U(0.047), // C57
+ CAP_U(0.047), // C55
+};
+
enum cymbal_voice
{
CV_CRASH = 0,
@@ -113,6 +126,12 @@ enum cymbal_voice
CV_COUNT
};
+constexpr const double CYMBAL_EG_C[CV_COUNT] =
+{
+ CAP_U(1), // C50
+ CAP_U(1), // C49
+};
+
enum mix_channel
{
MC_BASS = 0,
@@ -272,6 +291,8 @@ private:
const component_config m_comps;
+ const std::array<double, MV_COUNT> m_mux_eg_r;
+ const std::array<double, CV_COUNT> m_cymbal_eg_r;
required_memory_region m_mux_samples; // IC34, IC35
required_device<mb63h114_device> m_mac; // IC30
@@ -280,11 +301,11 @@ private:
required_device_array<va_vca_device, MV_COUNT> m_mux_vca;
required_device<va_rc_eg_device> m_hat_eg;
- required_memory_region_array<CV_COUNT> m_cymbal_samples;
- required_device_array<dac_6bit_r2r_device, CV_COUNT> m_cymbal_dac;
+ required_memory_region_array<CV_COUNT> m_cymbal_samples; // IC19, IC22
+ required_device_array<dac_6bit_r2r_device, CV_COUNT> m_cymbal_dac; // RA3, RA4 (RKM7LW502)
required_device_array<filter_rc_device, CV_COUNT> m_cymbal_hpf;
required_device_array<va_rc_eg_device, CV_COUNT> m_cymbal_eg;
- required_device_array<va_vca_device, CV_COUNT> m_cymbal_vca;
+ required_device_array<va_vca_device, CV_COUNT> m_cymbal_vca; // Q14, Q15 (2SD1469R)
required_ioport_array<MC_COUNT> m_level_sliders;
required_device_array<filter_volume_device, MC_COUNT> m_level;
@@ -293,9 +314,9 @@ private:
// LPFs after the voice volume faders.
required_device_array<filter_rc_device, MC_COUNT> m_voice_lpf;
- required_device<mixer_device> m_left_mixer;
- required_device<mixer_device> m_right_mixer;
- required_ioport m_master_volume;
+ required_device<filter_volume_device> m_left_level; // IC206a opamp + VR212a potentiometer.
+ required_device<filter_volume_device> m_right_level; // IC206b opamp + VR212b potentiometer.
+ required_ioport m_master_volume; // VR212
u16 m_triggers = 0x3ff;
double m_accent_level = 0;
@@ -305,6 +326,8 @@ private:
u8 m_handclap_tambourine = 0; // 0: handclap, 1: tambourine.
bool m_hat_is_closed = false;
bool m_hat_triggering = false;
+ u8 m_mux_sample = 0;
+ u8 m_mux_voice = 0;
u8 m_mac_c = 0; // Last value of IC30, output C (pin 7).
std::array<u16, CV_COUNT> m_cymbal_counter = {MAX_CYMBAL_COUNTER, MAX_CYMBAL_COUNTER}; // TC404 (IC18, IC23), TC4520 (IC20a, IC20b).
};
@@ -317,6 +340,24 @@ DEFINE_DEVICE_TYPE(TR707_AUDIO, tr707_audio_device, "tr707_audio", "TR-707 audio
tr707_audio_device::tr707_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, const component_config &components)
: device_t(mconfig, TR707_AUDIO, tag, owner, 0)
, m_comps(components)
+ , m_mux_eg_r
+ {
+ m_comps.R95,
+ m_comps.R102,
+ RES_M(4.7), // R92
+ RES_M(4.7), // R93
+ RES_M(4.7), // R85
+ RES_M(4.7), // R104
+ m_comps.R82,
+ m_comps.R91,
+ }
+ , m_cymbal_eg_r
+ {
+ // R58 is 47K in the schematic, but that causes a very quick decay.
+ // Using 470K, which matches R61 used in the ride cymbal voice below.
+ RES_K(470), // R58
+ RES_2_PARALLEL(/*R61*/RES_K(470), m_comps.R73),
+ }
, m_mux_samples(*this, ":voices")
, m_mac(*this, "mac")
, m_mux_dac(*this, "mux_dac_%u", 1)
@@ -332,8 +373,8 @@ tr707_audio_device::tr707_audio_device(const machine_config &mconfig, const char
, m_level(*this, "level_%u", 1)
, m_voice_bpf(*this, "voice_bpf_%u", 1)
, m_voice_lpf(*this, "voice_lpf_%u", 1)
- , m_left_mixer(*this, "lmixer")
- , m_right_mixer(*this, "rmixer")
+ , m_left_level(*this, "left_master_level")
+ , m_right_level(*this, "right_master_level")
, m_master_volume(*this, ":VOLUME")
{
}
@@ -368,36 +409,84 @@ void tr707_audio_device::voice_select_w(u8 data)
void tr707_audio_device::voice_trigger_w(u16 data)
{
+ constexpr double R79 = RES_R(100);
+
if ((data & 0x03ff) == m_triggers)
return;
+
+ const u16 old_triggers = m_triggers;
m_triggers = data & 0x03ff;
+ // Reset sample ROM address counters for triggered MUX voices.
m_mac->xst_w(m_triggers & 0xff);
+
+ // The EG capacitors for all triggered voices will charge through a
+ // single 100 Ohm resistor (R79). If more than one voice is triggered,
+ // there will be multiple capacitors charging in parallel. Treat that
+ // parallel capacitance as the effective capacitance of each triggered EG.
+ double effective_charge_c = 0;
+ for (int i = 0; i < MV_COUNT; ++i)
+ if (!BIT(m_triggers, i))
+ effective_charge_c += MUX_EG_C[i];
+ for (int i = 0; i < CV_COUNT; ++i)
+ if (!BIT(m_triggers, 8 + i))
+ effective_charge_c += CYMBAL_EG_C[i];
+
+ // Trigger amplitude EGs for MUX voices.
for (int i = 0; i < MV_COUNT; ++i)
{
- if (BIT(m_triggers, i))
- m_mux_eg[i]->set_target_v(0);
- else
- m_mux_eg[i]->set_instant_v(m_accent_level);
+ va_rc_eg_device *eg = m_mux_eg[i];
+ if (!BIT(m_triggers, i)) // EG attack
+ {
+ // When the trigger is active, the EG capacitor will be connected
+ // to both: the discharge resistor to ground (m_mux_eg_r[i]) and the
+ // resistor to the accent voltage (R79) via a transistor. This setup
+ // affects the effective resistance and target voltage of the RC
+ // circuit as per the equations below. The effect of the transistor
+ // in the charge path is not modelled.
+ eg->set_r(RES_2_PARALLEL(R79, m_mux_eg_r[i]));
+ eg->set_c(effective_charge_c);
+ eg->set_target_v(m_accent_level * RES_VOLTAGE_DIVIDER(R79, m_mux_eg_r[i]));
+ }
+ else // EG release
+ {
+ eg->set_r(m_mux_eg_r[i]);
+ eg->set_c(MUX_EG_C[i]);
+ eg->set_target_v(0);
+ }
}
// In addition to the EG for the DAC reference current (handled above), the
- // hi-hat voice has an additional EG and VCA that postrpocesses the DAC
+ // hi-hat voice has an additional EG and VCA that postprocesses the DAC
// output. This is used to create the open and closed hat variations.
m_hat_triggering = !BIT(m_triggers, MV_HI_HAT); // Active low.
update_hat_eg();
+ // Trigger amplitude EGs for cymbal voices.
for (int i = 0; i < CV_COUNT; ++i)
{
- if (!BIT(m_triggers, 8 + i))
+ va_rc_eg_device *eg = m_cymbal_eg[i];
+ const int trigger_index = 8 + i;
+
+ if (!BIT(m_triggers, trigger_index)) // EG attack
{
- m_cymbal_counter[i] = 0;
- m_cymbal_eg[i]->set_instant_v(m_accent_level);
+ // See comments for MUX voice triggering above.
+ eg->set_r(RES_2_PARALLEL(R79, m_cymbal_eg_r[i]));
+ eg->set_c(effective_charge_c);
+ eg->set_target_v(m_accent_level * RES_VOLTAGE_DIVIDER(R79, m_cymbal_eg_r[i]));
}
- else
+ else // EG release
{
- m_cymbal_eg[i]->set_target_v(0);
+ eg->set_r(m_cymbal_eg_r[i]);
+ eg->set_c(CYMBAL_EG_C[i]);
+ eg->set_target_v(0);
}
+
+ // The trigger signal is connected to the ROM address counter's reset
+ // inputs (active high) via a 100 pF capacitor. This setup will cause a
+ // reset on the positive edge of the trigger.
+ if (!BIT(old_triggers, trigger_index) && BIT(m_triggers, trigger_index))
+ m_cymbal_counter[i] = 0;
}
if (m_triggers != 0x3ff)
@@ -429,19 +518,6 @@ void tr707_audio_device::device_add_mconfig(machine_config &config)
MB63H114(config, m_mac, 1.6_MHz_XTAL);
m_mac->counter_cb().set(FUNC(tr707_audio_device::advance_sample_w));
- // Decay resistors for the envelope generators.
- const std::array<double, MV_COUNT> MUX_EG_R =
- {
- m_comps.R95,
- m_comps.R102,
- RES_M(4.7), // R92
- RES_M(4.7), // R93
- RES_M(4.7), // R85
- RES_M(4.7), // R104
- m_comps.R82,
- m_comps.R91,
- };
-
// Larger DAC data values result in more negative voltages. So the maximum
// voltage is produced when data = 0, and the minimum one when data = 0xff.
constexpr double MAX_MUX_EG_V = VCC;
@@ -449,17 +525,16 @@ void tr707_audio_device::device_add_mconfig(machine_config &config)
const double mux_dac_scale = -(mux_dac_vpp / 2.0) / MAX_MUX_EG_V;
// Time multiplexing is not emulated at the moment. Using 8 "virtual" DACs
- // and corresponding VCAs instead. The DAC circuit is somewhat involved. See
- // mux_dac_v() for its interpretation.
+ // and corresponding VCAs instead. The DAC circuit is somewhat elaborate.
+ // See mux_dac_v() for its interpretation.
for (int i = 0; i < MV_COUNT; ++i)
{
- VA_RC_EG(config, m_mux_eg[i]).set_r(MUX_EG_R[i]).set_c(CAP_U(0.047)); // [C48, C52-55, C57-58]
+ VA_RC_EG(config, m_mux_eg[i]).set_r(m_mux_eg_r[i]).set_c(MUX_EG_C[i]);
DAC08(config, m_mux_dac[i]);
VA_VCA(config, m_mux_vca[i]);
m_mux_dac[i]->add_route(0, m_mux_vca[i], 1.0, 0);
m_mux_eg[i]->add_route(0, m_mux_vca[i], mux_dac_scale, 1);
}
- m_mux_eg[MV_HI_HAT]->set_c(CAP_U(1)); // C47
// *** Hi-hat VCA section ***
@@ -493,24 +568,16 @@ void tr707_audio_device::device_add_mconfig(machine_config &config)
constexpr double CYMBAL_VCA_V2I_SCALE = 0.0043; // Converts from input voltage to output current.
constexpr double CYMBAL_VCA_SCALE = -CYMBAL_VCA_V2I_SCALE * RES_K(10); // [R62, R65], inverting op-amp.
- const std::array<double, CV_COUNT> CYMBAL_EG_R =
- {
- // R58 is 47K in the schematic, but that causes a very quick decay.
- // Using 470K, which matches R61 used in the ride cymbal voice below.
- RES_K(470), // R58
- RES_2_PARALLEL(/*R61*/RES_K(470), m_comps.R73),
- };
-
for (int i = 0; i < CV_COUNT; ++i)
{
- DAC_6BIT_R2R(config, m_cymbal_dac[i]).set_output_range(0, VCC);
FILTER_RC(config, m_cymbal_hpf[i]);
m_cymbal_hpf[i]->set_rc(filter_rc_device::HIGHPASS, RES_R(470), 0, 0, CAP_U(1)); // ~339 Hz, [R63, R64], [C35, C34]
+
+ DAC_6BIT_R2R(config, m_cymbal_dac[i]).set_output_range(0, VCC);
m_cymbal_dac[i]->add_route(0, m_cymbal_hpf[i], CYMBAL_HPF_SCALE);
- VA_RC_EG(config, m_cymbal_eg[i]).set_r(CYMBAL_EG_R[i]).set_c(CAP_U(1)); // [C50, C49]
+ VA_RC_EG(config, m_cymbal_eg[i]).set_r(m_cymbal_eg_r[i]).set_c(CYMBAL_EG_C[i]);
VA_VCA(config, m_cymbal_vca[i]); // 2SD1469R [Q14, Q15]
- // V2I converter is based on an op-amp in inverting configuration.
m_cymbal_hpf[i]->add_route(0, m_cymbal_vca[i], CYMBAL_VCA_SCALE, 0);
m_cymbal_eg[i]->add_route(0, m_cymbal_vca[i], 1.0 / VCC, 1);
}
@@ -596,8 +663,8 @@ void tr707_audio_device::device_add_mconfig(machine_config &config)
m_cymbal_vca[CV_RIDE],
};
- MIXER(config, m_left_mixer);
- MIXER(config, m_right_mixer);
+ auto &left_mixer = MIXER(config, "left_mixer");
+ auto &right_mixer = MIXER(config, "right_mixer");
for (int i = 0; i < MC_COUNT; ++i)
{
FILTER_BIQUAD(config, m_voice_bpf[i]);
@@ -609,22 +676,47 @@ void tr707_audio_device::device_add_mconfig(machine_config &config)
FILTER_RC(config, m_voice_lpf[i]).set_lowpass(RES_K(1), CAP_U(0.01)); // ~15.9 KHz.
m_level[i]->add_route(0, m_voice_lpf[i], 1.0);
- m_voice_lpf[i]->add_route(0, m_left_mixer, -R_MAX_MASTER_VOLUME / r_mix_left[i]); // Inverting op-amp.
- m_voice_lpf[i]->add_route(0, m_right_mixer, -R_MAX_MASTER_VOLUME / r_mix_right[i]); // Same.
+
+ m_voice_lpf[i]->add_route(0, left_mixer, -R_MAX_MASTER_VOLUME / r_mix_left[i]); // Inverting op-amp.
+ m_voice_lpf[i]->add_route(0, right_mixer, -R_MAX_MASTER_VOLUME / r_mix_right[i]); // Same.
}
+ // Model DC-blocking capacitors (C211, C212) on the opamp (IC206) inverting
+ // inputs. Those do not have corresponding resistors.
+ const filter_biquad_device::biquad_params dcblock
+ {
+ // HIGHPASS1P is a stable highpass filter with inaccurate frequency
+ // response. Good for DC-blocking (very low cutoff frequency), where
+ // frequency response does not matter.
+ .type = filter_biquad_device::biquad_type::HIGHPASS1P,
+ .fc = 0.05,
+ .q = 0, // N/A
+ .gain = 1,
+ };
+ auto &left_dcblock = FILTER_BIQUAD(config, "left_dcblock").setup(dcblock); // C211
+ auto &right_dcblock = FILTER_BIQUAD(config, "right_dcblock").setup(dcblock); // C212
+ left_mixer.add_route(0, left_dcblock, 1.0);
+ right_mixer.add_route(0, right_dcblock, 1.0);
+
+ FILTER_VOLUME(config, m_left_level); // IC206a opamp + VR212a potentiometer.
+ FILTER_VOLUME(config, m_right_level); // IC206b opamp + VR212b potentiometer.
+ left_dcblock.add_route(0, m_left_level, 1.0);
+ right_dcblock.add_route(0, m_right_level, 1.0);
+
/*** Output section ***/
// The outputs of the left and right summing op-amps are processed by BPFs
// with a flat response, and -3dB points at ~0.35 Hz and ~12.4 KHz, before
- // making it to the left and right output sockets.
+ // making it to the left and right output sockets. Note that the exact
+ // frequency response of these BPFs will be affected by the input impedance
+ // of the connected device (not emulated).
auto &left_bpf = FILTER_BIQUAD(config, "left_out_bpf");
auto &right_bpf = FILTER_BIQUAD(config, "right_out_bpf");
left_bpf.rc_rr_bandpass_setup(RES_K(1), RES_K(47), CAP_U(10), CAP_U(0.01)); // R114, R112, C79, C76
right_bpf.rc_rr_bandpass_setup(RES_K(1), RES_K(47), CAP_U(10), CAP_U(0.01)); // R113, R111, C80, C77
- m_left_mixer->add_route(0, left_bpf, 1.0);
- m_right_mixer->add_route(0, right_bpf, 1.0);
+ m_left_level->add_route(0, left_bpf, 1.0);
+ m_right_level->add_route(0, right_bpf, 1.0);
constexpr double VOLTAGE_TO_AUDIO_SCALE = 0.2;
SPEAKER(config, "speaker", 2).front();
@@ -642,6 +734,8 @@ void tr707_audio_device::device_start()
save_item(NAME(m_handclap_tambourine));
save_item(NAME(m_hat_is_closed));
save_item(NAME(m_hat_triggering));
+ save_item(NAME(m_mux_sample));
+ save_item(NAME(m_mux_voice));
save_item(NAME(m_mac_c));
save_item(NAME(m_cymbal_counter));
}
@@ -674,8 +768,8 @@ double tr707_audio_device::mux_dac_v(double v_eg, u8 data)
// formula specifies "/ 256", rather than the more intuitive "/ 255".
const double i_out = double(data) / 256.0 * i_ref;
- // Compute voltage at the DAC output. There is a "feed-forward" loop from
- // v_in to the DAC's i_out, via 2 resistors.
+ // Compute voltage at the DAC output. There is a connection from v_in to the
+ // DAC's i_out, via 2 resistors.
const double v_dac_out = v_in - (R147 + R148) * i_out;
// Compute the final output of the circuit.
@@ -684,6 +778,15 @@ double tr707_audio_device::mux_dac_v(double v_eg, u8 data)
void tr707_audio_device::advance_sample_w(offs_t offset, u16 data)
{
+ // Playback of multiplex voice samples lags one step behind the sample
+ // selection by the MAC. The DAC reference MUX (IC40) and sound output MUX
+ // (IC41) CBA inputs are configured to accommodate that. For example, the
+ // DAC reference for voice 0 (bass drum) is selected when IC40 CBA = 1.
+
+ // Latch the sample addressed in the previous step, into the multiplex
+ // voice DAC.
+ m_mux_dac[m_mux_voice]->data_w(m_mux_sample);
+
// Update MB63H114 clock inputs.
const u8 b = BIT(offset, 1);
const u8 c = BIT(offset, 2);
@@ -691,10 +794,11 @@ void tr707_audio_device::advance_sample_w(offs_t offset, u16 data)
const u8 xck2 = BIT(offset, m_comps.xck2_input);
m_mac->xck_w((b << 7) | (b << 6) | (c << 5) | (d << 4) | (d << 3) | (xck2 << 2) | (b << 1) | (b << 0));
- // Update multiplex voice DAC.
+ // Compute next multiplex voice sample. This will be latched into the DAC
+ // in the next advance_sample_w invocation.
u16 counter = 0;
- const u8 voice = offset & 0x07;
- switch (voice)
+ m_mux_voice = offset & 0x07;
+ switch (m_mux_voice)
{
case 0: counter = (data & 0x1ffe) | m_bass_variation; break;
case 1: counter = (data & 0x1ffe) | m_snare_variation; break;
@@ -702,23 +806,27 @@ void tr707_audio_device::advance_sample_w(offs_t offset, u16 data)
case 7: counter = (data & 0x1ffe) | m_handclap_tambourine; break;
default: counter = data; break;
}
- const u8 sample = m_mux_samples->as_u8((voice << 13) | counter);
- m_mux_dac[voice]->data_w(sample);
+ m_mux_sample = m_mux_samples->as_u8((m_mux_voice << 13) | counter);
// Update single sound (cymbal) DACs.
- if (!m_mac_c && c) // Positive edge of C output.
+ for (int i = 0; i < CV_COUNT; ++i)
{
+ // Once bit 15 is set, the ROM address counter stops incrementing, and
+ // no new data is latched to the DAC.
+ if (m_cymbal_counter[i] >= MAX_CYMBAL_COUNTER)
+ continue;
+
// Cymbal timing is actually controlled by output B, which is divided by
// 2 by a flipflop. But C is also B divided by 2, so using C here for
// convenience.
- for (int i = 0; i < CV_COUNT; ++i)
+ if (m_mac_c && !c) // Negative edge increments ROM address.
{
- if (m_cymbal_counter[i] < MAX_CYMBAL_COUNTER)
- {
- ++m_cymbal_counter[i];
- const u8 cymbal_sample = m_cymbal_samples[i]->as_u8(m_cymbal_counter[i] & 0x7fff);
- m_cymbal_dac[i]->data_w(cymbal_sample >> 2); // Bits D2-D7.
- }
+ ++m_cymbal_counter[i];
+ }
+ else if (!m_mac_c && c) // Positive edge latches ROM contents to DAC.
+ {
+ const u8 cymbal_sample = m_cymbal_samples[i]->as_u8(m_cymbal_counter[i] & 0x7fff);
+ m_cymbal_dac[i]->data_w(cymbal_sample >> 2); // Bits D2-D7.
}
}
m_mac_c = c;
@@ -764,8 +872,8 @@ void tr707_audio_device::update_hat_eg()
void tr707_audio_device::update_master_volume()
{
const double gain = m_master_volume->read() / 100.0;
- m_left_mixer->set_output_gain(0, gain);
- m_right_mixer->set_output_gain(0, gain);
+ m_left_level->set_gain(gain);
+ m_right_level->set_gain(gain);
LOGMASKED(LOG_MIX, "Master volume adjusted %d %f\n", m_master_volume->read(), gain);
}
@@ -906,6 +1014,7 @@ private:
required_ioport m_accent_level; // VR201, 50K(B).
output_finder<> m_layout_727;
+ output_finder<> m_layout_cart;
bool m_is_727; // Configuration. Not needed in save state.
std::vector<std::vector<seg_output>> m_seg_map; // Configuration.
@@ -953,6 +1062,7 @@ roland_tr707_state::roland_tr707_state(const machine_config &mconfig, device_typ
, m_accent_trimmer_parallel(*this, "TM3")
, m_accent_level(*this, "SLIDER_1")
, m_layout_727(*this, "is727")
+ , m_layout_cart(*this, "has_cartridge")
, m_is_727(false)
, m_seg_map(hd61602_device::NCOM, std::vector<seg_output>(hd61602_device::NSEG)) // 4x51 LCD segments.
, m_cart_bank(0)
@@ -1066,6 +1176,7 @@ void roland_tr707_state::machine_start()
save_item(NAME(m_midi_rxd_bit));
m_layout_727.resolve();
+ m_layout_cart.resolve();
m_dinsync_out.resolve();
m_cart_led.resolve();
for (std::vector<output_finder<>> &led_row : m_leds)
@@ -1084,6 +1195,7 @@ void roland_tr707_state::machine_reset()
update_internal_tempo_timer(true);
update_accent_adc();
m_layout_727 = m_is_727;
+ m_layout_cart = m_cartslot->exists() ? 1 : 0;
}
@@ -1097,12 +1209,32 @@ double roland_tr707_state::discharge_t(double r, double c, double v)
u8 roland_tr707_state::key_scan_r()
{
- u8 data = 0x00;
+ bool row_active[4] = {false, false, false, false};
+ u8 row_keys[4] = {0, 0, 0, 0};
+ for (int n = 0; n < 4; n++)
+ {
+ row_active[n] = !BIT(m_key_led_row, n);
+ row_keys[n] = m_key_switches[n]->read();
+ }
+ // In contrast to rows 1 and 2 (drum pads), rows 2 and 3 (other buttons)
+ // lack a protection diode for each key. The wiring is such that, if one
+ // of rows 2 or 3 is activated, and two keys in the same column are pressed,
+ // then the other row will also get activated.
+ if ((row_active[2] || row_active[3]) && (row_keys[2] & row_keys[3]))
+ {
+ row_active[2] = true;
+ row_active[3] = true;
+ LOGMASKED(LOG_KEYS, "Row 2/3 conflict: %02x, %02x\n", row_keys[2], row_keys[3]);
+ }
+
+ u8 data = 0x00;
for (int n = 0; n < 4; n++)
- if (!BIT(m_key_led_row, n))
- data |= m_key_switches[n]->read();
+ if (row_active[n])
+ data |= row_keys[n];
+ if (data)
+ LOGMASKED(LOG_KEYS, "Keys pressed: %02x\n", data);
return data;
}
@@ -1351,7 +1483,7 @@ void roland_tr707_state::update_accent_adc()
// for a capacitor (C15) to discharge via the Accent slider, two trimmers
// and a resistor. The firmware initiates the discharge. Once the voltage
// reaches the negative-going threshold of IC3e, IRQ2 will be asserted and
- // the capacitor will start charging.
+ // the firmware will restart the charge-discharge cycle.
constexpr const double ACCENT_MAX = RES_K(50);
constexpr const double TM2_MAX = RES_K(50);
@@ -1389,7 +1521,7 @@ void roland_tr707_state::update_accent_adc()
m_accent_adc_timer->reset();
}
- // fliflop Q connected to P51 (IRQ2).
+ // flipflop Q connected to P51 (IRQ2).
const enum line_state irq2 = m_accent_adc_ff->output_r() ? CLEAR_LINE : ASSERT_LINE;
m_maincpu->set_input_line(HD6301_IRQ2_LINE, irq2);
@@ -1597,7 +1729,7 @@ void roland_tr707_state::tr_707_727_common(machine_config &config)
MIDI_PORT(config, "mdin", midiin_slot, "midiin").rxd_handler().set(FUNC(roland_tr707_state::midi_rxd_w));
MIDI_PORT(config, "mdout", midiout_slot, "midiout");
- GENERIC_CARTSLOT(config, m_cartslot, generic_plain_slot, nullptr, "tr707_cart");
+ GENERIC_CARTSLOT(config, m_cartslot, generic_plain_slot, nullptr, "m64c_cart");
HD61602(config, m_lcdc);
m_lcdc->write_segs().set(FUNC(roland_tr707_state::lcd_seg_w));