Skip to content

Commit

Permalink
Added two new unreleased Model Racing games (#5813)
Browse files Browse the repository at this point in the history
* Fixed LOG_WAV_ENABLED_ONLY (m_enable has to be checked only if LOG_WAV_ENABLED_ONLY is set)
Added log data to the right channel of the wave, accordingly to the definition declared in LOG_WAV_VALUE_R

* Fixed an error with tag() returning a ':' and generating a filename not valid in Windows environment

* Added Model Racing "Cane"

* Added Model Racing "Orbite"

* Replaced the char array with a std::string in sn76477_device::open_wav_file to override possible buffer overrun.
Minor cosmetic change in a boolean expression in sn76477_device::sound_stream_update

* Refactored "Cane" related code creating an audio device to encapsulate the audio system
Refactored "Cane" and "Orbite" creating their own classes
Other minor changes in indentation of the source code
  • Loading branch information
janniz authored and cuavas committed Oct 31, 2019
1 parent ba27354 commit f31b19f
Show file tree
Hide file tree
Showing 7 changed files with 884 additions and 12 deletions.
38 changes: 29 additions & 9 deletions src/devices/sound/sn76477.cpp
Expand Up @@ -892,9 +892,11 @@ void sn76477_device::log_complete_state()

void sn76477_device::open_wav_file()
{
char wav_file_name[30];
std::string s = tag();
std::replace(s.begin(), s.end(), ':', '_');

char const* wav_file_name = util::string_format(LOG_WAV_FILE_NAME, s).c_str();

sprintf(wav_file_name, LOG_WAV_FILE_NAME, tag());
m_file = wav_open(wav_file_name, m_our_sample_rate, 2);

LOG(1, "SN76477: Logging output: %s\n", wav_file_name);
Expand Down Expand Up @@ -1996,7 +1998,7 @@ void sn76477_device::sound_stream_update(sound_stream &stream, stream_sample_t *
*/
*buffer++ = (((voltage_out - OUT_LOW_CLIP_THRESHOLD) / (OUT_CENTER_LEVEL_VOLTAGE - OUT_LOW_CLIP_THRESHOLD)) - 1) * 32767;

if (LOG_WAV && LOG_WAV_ENABLED_ONLY && !m_enable)
if (LOG_WAV && (!m_enable || !LOG_WAV_ENABLED_ONLY))
{
int16_t log_data_l;
int16_t log_data_r;
Expand All @@ -2005,30 +2007,48 @@ void sn76477_device::sound_stream_update(sound_stream &stream, stream_sample_t *
{
case 0:
log_data_l = LOG_WAV_GAIN_FACTOR * voltage_out;
log_data_r = LOG_WAV_GAIN_FACTOR * voltage_out;
break;
case 1:
log_data_l = LOG_WAV_GAIN_FACTOR * m_enable;
log_data_r = LOG_WAV_GAIN_FACTOR * m_enable;
break;
case 2:
log_data_l = LOG_WAV_GAIN_FACTOR * m_one_shot_cap_voltage;
log_data_r = LOG_WAV_GAIN_FACTOR * m_one_shot_cap_voltage;
break;
case 3:
log_data_l = LOG_WAV_GAIN_FACTOR * m_attack_decay_cap_voltage;
log_data_r = LOG_WAV_GAIN_FACTOR * m_attack_decay_cap_voltage;
break;
case 4:
log_data_l = LOG_WAV_GAIN_FACTOR * m_slf_cap_voltage;
log_data_r = LOG_WAV_GAIN_FACTOR * m_slf_cap_voltage;
break;
case 5:
log_data_l = LOG_WAV_GAIN_FACTOR * m_vco_cap_voltage;
log_data_r = LOG_WAV_GAIN_FACTOR * m_vco_cap_voltage;
break;
case 6:
log_data_l = LOG_WAV_GAIN_FACTOR * m_noise_filter_cap_voltage;
break;
}

switch (LOG_WAV_VALUE_R)
{
case 0:
log_data_r = LOG_WAV_GAIN_FACTOR * voltage_out;
break;
case 1:
log_data_r = LOG_WAV_GAIN_FACTOR * m_enable;
break;
case 2:
log_data_r = LOG_WAV_GAIN_FACTOR * m_one_shot_cap_voltage;
break;
case 3:
log_data_r = LOG_WAV_GAIN_FACTOR * m_attack_decay_cap_voltage;
break;
case 4:
log_data_r = LOG_WAV_GAIN_FACTOR * m_slf_cap_voltage;
break;
case 5:
log_data_r = LOG_WAV_GAIN_FACTOR * m_vco_cap_voltage;
break;
case 6:
log_data_r = LOG_WAV_GAIN_FACTOR * m_noise_filter_cap_voltage;
break;
}
Expand Down
280 changes: 280 additions & 0 deletions src/mame/audio/8080bw.cpp
Expand Up @@ -24,6 +24,13 @@ MACHINE_START_MEMBER(_8080bw_state,extra_8080bw_sh)
save_item(NAME(m_port_3_last_extra));
}

/*************************************
*
* Device type globals
*
*************************************/

DEFINE_DEVICE_TYPE(CANE_AUDIO, cane_audio_device, "cane_audio", "Model Racing Cane Audio")


/*************************************
Expand Down Expand Up @@ -1397,3 +1404,276 @@ WRITE8_MEMBER( _8080bw_state::darthvdr_08_w )

m_port_1_last_extra = data;
}


/*********************************************************/
/* */
/* Model Racing "Cane" (Slightly based on Claybuster hw) */
/* */
/*********************************************************/
#define CANE_CLOCK (19968000.0)
#define CANE_H64 CANE_CLOCK /2 /2 /4

/* Nodes - Sound enable */
#define CANE_SND_EN NODE_05

/* Nodes - Adjusters */
#define CANE_VR1 NODE_07 // Gain for 76477
#define CANE_VR2 NODE_08 // VR attached to the output of the TOS
#define CANE_VR3 NODE_09 // VR for SFX generated by the 555

/* Nodes - sn76477 Sounds */
#define CANE_EXP_STREAM NODE_03
#define CANE_EXP_SND NODE_11

/* Nodes - BGM */
#define CANE_MUSIC_DATA NODE_06
#define CANE_MUSIC_NOTE NODE_40
#define CANE_MUSIC_NOTE_PF NODE_01
#define CANE_MUSIC_SND NODE_12

/* Nodes - 555 sfx */
#define CANE_76477_PIN6 NODE_13
#define CANE_555_CLAMPED NODE_14
#define CANE_555_ONESHOT NODE_15
#define CANE_555_EN NODE_16
#define CANE_TMP_SND NODE_17
#define CANE_SFX_SND NODE_18

/* Node output */
#define CANE_SOUND_OUT NODE_90

static INPUT_PORTS_START( cane_audio )
PORT_START("VR1")
PORT_ADJUSTER( 80, "VR1 - SFX from 76477" )

PORT_START("VR2")
PORT_ADJUSTER( 90, "VR2 - TOS music" )

PORT_START("VR3")
PORT_ADJUSTER( 70, "VR3 - Shoot SFX from 555" )
INPUT_PORTS_END

cane_audio_device::cane_audio_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
device_t(mconfig, CANE_AUDIO, tag, owner, clock),
m_cane_vco_timer(*this, "cane_vco_timer"),
m_sn(*this, "snsnd"),
m_discrete(*this, "discrete"),
m_cane_vco_rc_chargetime(INT_MAX)
{
}

void cane_audio_device::device_add_mconfig(machine_config &config)
{
// provare a commentare
m_cane_vco_rc_chargetime = INT_MAX;

TIMER(config, "cane_vco_timer").configure_periodic(FUNC(cane_vco_voltage_timer), attotime::from_hz(1000));

SPEAKER(config, "mono").front_center();

SN76477(config, m_sn);
// Amplitude res in the schematic is connected to a 470K potentiometer, so from the schematic is impossible to know the real res.
// This parameter drives the amp just before the audio output pin 13.
m_sn->set_amp_res(100+RES_K(20));
m_sn->set_noise_params(RES_K(39), RES_K(1), CAP_P(1000));
m_sn->set_decay_res(RES_M(1));
m_sn->set_attack_params(CAP_U(1.0), RES_K(47));
m_sn->set_feedback_res(RES_K(4.7));
m_sn->set_vco_params(0, CAP_P(3300), RES_K(100));
m_sn->set_pitch_voltage(5.0);
m_sn->set_slf_params(CAP_U(1.0), RES_K(33));
m_sn->set_oneshot_params(CAP_U(10), RES_K(100));
m_sn->set_vco_mode(0);
m_sn->set_mixer_params(0, 0, 0);
m_sn->set_envelope_params(1, 0);
m_sn->set_enable(0);
m_sn->add_route(0, "discrete", 1.0, 0);

DISCRETE(config, m_discrete, cane_discrete);
m_discrete->add_route(ALL_OUTPUTS, "mono", 1.0);
}

ioport_constructor cane_audio_device::device_input_ports() const
{
return INPUT_PORTS_NAME(cane_audio);
}

void cane_audio_device::device_start()
{
}

void cane_audio_device::cane_sh_port_1_w(u8 data)
{
/*
bit 0 - SX0 - Sound enable on mixer
bit 1 - SX1 - SN76477 - Mixer select C - pin 27
bit 2 - SX2 - SN76477 - Mixer select A - pin 26
bit 3 - SX3 - SN76477 - Mixer select B - pin 25
bit 4 - SX4 - NE555 - Trigger (Step, high output level for 1.1*RC = 1.1*100K*0.47u = 51.7 ms)
*/

m_discrete->write(CANE_SND_EN, data & 0x01); // BIT(data, 0) - bit 0 - SX0 - Sound enable on mixer
m_discrete->write(CANE_555_EN, data & 0x10); // BIT(data, 4) - bit 4 - SX4 - NE555 - Trigger

// 76477 enable bit is connected to the select line of the out port 3 (inverted).
m_sn->enable_w(1);
m_sn->set_mixer_params(BIT(data, 2), BIT(data, 3), BIT(data, 1));

m_cane_vco_timer->adjust(attotime::zero, m_cane_vco_timer->param(), attotime::from_hz(1000));
m_cane_vco_rc_chargetime = m_cane_vco_timer->start_time().as_double();

// Little hack...
// To be precise I should enable the 76477 every time the CPU reads or write to a port different from port 3
// and disable it every time the CPU read/write from/to port 3.
// Actually this can not be done easily so I decided to enable it preemptively here after every port 3 access
m_sn->enable_w(0);
}

void cane_audio_device::cane_music_w(u8 data)
{
m_sn->enable_w(1);
m_discrete->write(CANE_MUSIC_DATA, data);
}

void cane_audio_device::cane_76477_en_w(u8 data)
{
m_sn->enable_w(0);
}

void cane_audio_device::cane_76477_dis_w(u8 data)
{
m_sn->enable_w(1);
}

/*******************************************************************************************************************************************************/
/* Cane discrete implementation, slightly based on Claybuster hw. */
/* This implementation doesn't pretend to be accurate thus trying to be at least functionally similar. */
/* */
/* Port 1 - SX4 CANE_VR3 Port 1 - SX0 */
/* | | | */
/* CANE_555_EN | | */
/* | | | */
/* +------------------+ | | */
/* | CANE_555_ONESHOT | | | */
/* +------------------+ | | */
/* | | | */
/* v v | */
/* sn76477 pin 6 +------------------+ +---+ +--------------+ +---+ +--------------+ | */
/* CLAMP(0, 5V) ->| CANE_555_CLAMPED |->| * |->| CANE_TMP_SND |->| * |->| CANE_SFX_SND | CANE_SND_EN */
/* (DISCRETE_NOISE) +------------------+ +---+ +--------------+ +---+ +--------------+ | */
/* | | */
/* CANE_VR1 | | */
/* | | | */
/* v v v */
/* sn76477 output +-----------------+ +---+ +--------------+ +---+ +----------------+ */
/* DISCRETE_INPUTX_STREAM ->| CANE_EXP_STREAM |->| * |->| CANE_EXP_SND |->| + |->| CANE_SOUND_OUT |->OUT */
/* +-----------------+ +---+ +--------------+ +---+ +----------------+ */
/* ^ */
/* | */
/* CANE_MUSIC_DATA +--------------------+ +-----------+ +-----------------+ +---+ +----------------+ */
/* Port 5 data---DISCRETE_INPUT_DATA ->| CANE_MUSIC_NOTE_PF |->| CR_FILTER |->| CANE_MUSIC_NOTE |->| * |->| CANE_MUSIC_SND | */
/* DISCRETE_NOTE +--------------------+ +-----------+ +-----------------+ +---+ +----------------+ */
/* RES_K(10) ^ */
/* CAP_U(0.1) | */
/* CANE_VR2 */
/* */
/* */
/*******************************************************************************************************************************************************/
DISCRETE_SOUND_START(cane_discrete)
/************************************************/
/* Input register mapping for cane */
/************************************************/
DISCRETE_INPUT_DATA (CANE_MUSIC_DATA)

DISCRETE_INPUT_LOGIC (CANE_555_EN)

// scale to 0-2.5V
DISCRETE_INPUTX_STREAM(CANE_EXP_STREAM, 0, 0.5, 0)

DISCRETE_INPUT_LOGIC (CANE_SND_EN)

/************************************************/
/* Volume adjusters. */
/* We will set them to adjust the realitive */
/* gains. */
/************************************************/
DISCRETE_ADJUSTMENT(CANE_VR1, 0, 0.33*6, DISC_LINADJ, "VR1") // Gain for 76477
DISCRETE_ADJUSTMENT(CANE_VR2, 0, 0.33*60000, DISC_LINADJ, "VR2") // VR attached to the output of the TOS
DISCRETE_ADJUSTMENT(CANE_VR3, 0, 0.33*60000, DISC_LINADJ, "VR3") // VR for SFX generated by the 555

/************************************************/
/* From 555 */
/************************************************/
/* TODO: find real noise freq and amplitude */
/* width was simulated with ltspice using Claybuster schematic as a source and it's value is about 51ms */
DISCRETE_NOISE(CANE_76477_PIN6,
1, /* ENAB */
1280, /* FREQ - Guessed */
1, /* AMP */
0) /* BIAS - fake AC is fine*/
DISCRETE_CLAMP(CANE_555_CLAMPED,
CANE_76477_PIN6, /* input node */
0.0, /* minimum */
5.0) /* maximum */
DISCRETE_ONESHOT(CANE_555_ONESHOT,
CANE_555_EN, /* trigger node */
1, /* amplitude node or static value */
0.05, /* width (in seconds) node or static value - 50 ms*/
DISC_ONESHOT_FEDGE | DISC_ONESHOT_RETRIG) /* type of oneshot static value */

DISCRETE_MULTIPLY(CANE_TMP_SND, CANE_555_CLAMPED, CANE_555_ONESHOT)
DISCRETE_MULTIPLY(CANE_SFX_SND, CANE_TMP_SND, CANE_VR3)

/*****************************************************************************
*
* Music Generator (TOS)
*
* Values for this section of the sound hardware where derived from comments
* in the source code and the analysis of TOS.ED sources.
*
* For further info look at the relevant comments reported into
* drivers/8080bw.cpp
*
******************************************************************************/
DISCRETE_NOTE(CANE_MUSIC_NOTE_PF, 1, CANE_H64, CANE_MUSIC_DATA, 255, 1, DISC_CLK_IS_FREQ)
DISCRETE_CRFILTER(CANE_MUSIC_NOTE, CANE_MUSIC_NOTE_PF, RES_K(10), CAP_U(0.1)) // high pass filter
DISCRETE_MULTIPLY(CANE_MUSIC_SND, CANE_MUSIC_NOTE, CANE_VR2)

/******************************************************************************
*
* From 76477 output
*
******************************************************************************/
DISCRETE_MULTIPLY(CANE_EXP_SND, CANE_EXP_STREAM, CANE_VR1)

/******************************************************************************
*
* Final Mixing and Output
*
******************************************************************************/
DISCRETE_ADDER3(CANE_SOUND_OUT, CANE_SND_EN, CANE_SFX_SND, CANE_EXP_SND, CANE_MUSIC_SND)
DISCRETE_OUTPUT(CANE_SOUND_OUT, 1)

//LOG
/*
DISCRETE_WAVLOG1(CANE_EXP_STREAM, 1)
DISCRETE_WAVLOG1(CANE_EXP_SND, 1)
DISCRETE_WAVLOG1(CANE_TMP_SND, 1)
DISCRETE_WAVLOG1(CANE_SFX_SND, 1)
DISCRETE_WAVLOG1(CANE_MUSIC_NOTE, 1)
DISCRETE_WAVLOG1(CANE_MUSIC_SND, 1)
DISCRETE_WAVLOG1(CANE_SOUND_OUT, 1)
*/
DISCRETE_SOUND_END

TIMER_DEVICE_CALLBACK_MEMBER(cane_audio_device::cane_vco_voltage_timer)
{
double voltage;
voltage = 5 * (1 - exp(- (m_cane_vco_timer->fire_time().as_double() - m_cane_vco_rc_chargetime) / 47));

logerror("t = %d\n", m_cane_vco_timer->fire_time().as_double() - m_cane_vco_rc_chargetime);
logerror("vco_voltage = %d\n", voltage);

m_sn->vco_voltage_w(voltage);
}

0 comments on commit f31b19f

Please sign in to comment.