mirror of
https://github.com/holub/mame
synced 2025-05-31 18:11:50 +03:00
251 lines
7.0 KiB
C
251 lines
7.0 KiB
C
/**************************************************************************************
|
|
|
|
Wonderswan sound emulation
|
|
|
|
Wilbert Pol
|
|
|
|
Sound emulation is very preliminary and far from complete
|
|
|
|
**************************************************************************************/
|
|
|
|
#include "includes/wswan.h"
|
|
|
|
|
|
// device type definition
|
|
const device_type WSWAN = &device_creator<wswan_sound_device>;
|
|
|
|
|
|
//**************************************************************************
|
|
// LIVE DEVICE
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// wswan_sound_device - constructor
|
|
//-------------------------------------------------
|
|
|
|
wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
|
: device_t(mconfig, WSWAN, "WonderSwan Custom", tag, owner, clock),
|
|
device_sound_interface(mconfig, *this),
|
|
m_channel(NULL),
|
|
m_sweep_step(0),
|
|
m_sweep_time(0),
|
|
m_sweep_count(0),
|
|
m_noise_type(0),
|
|
m_noise_reset(0),
|
|
m_noise_enable(0),
|
|
m_sample_address(0),
|
|
m_audio2_voice(0),
|
|
m_audio3_sweep(0),
|
|
m_audio4_noise(0),
|
|
m_mono(0),
|
|
m_voice_data(0),
|
|
m_output_volume(0),
|
|
m_external_stereo(0),
|
|
m_external_speaker(0),
|
|
m_noise_shift(0),
|
|
m_master_volume(0)
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// device_start - device-specific startup
|
|
//-------------------------------------------------
|
|
|
|
void wswan_sound_device::device_start()
|
|
{
|
|
m_channel = stream_alloc(0, 2, machine().sample_rate());
|
|
|
|
m_audio1.on = 0;
|
|
m_audio1.signal = 16;
|
|
m_audio1.pos = 0;
|
|
m_audio2.on = 0;
|
|
m_audio2.signal = 16;
|
|
m_audio2.pos = 0;
|
|
m_audio3.on = 0;
|
|
m_audio3.signal = 16;
|
|
m_audio3.pos = 0;
|
|
m_audio4.on = 0;
|
|
m_audio4.signal = 16;
|
|
m_audio4.pos = 0;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// sound_stream_update - handle a stream update
|
|
//-------------------------------------------------
|
|
|
|
void wswan_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
|
|
{
|
|
stream_sample_t sample, left, right;
|
|
|
|
while( samples-- > 0 )
|
|
{
|
|
left = right = 0;
|
|
|
|
if ( m_audio1.on ) {
|
|
sample = m_audio1.signal;
|
|
m_audio1.pos++;
|
|
if ( m_audio1.pos >= m_audio1.period / 2 ) {
|
|
m_audio1.pos = 0;
|
|
m_audio1.signal = -m_audio1.signal;
|
|
}
|
|
left += m_audio1.vol_left * sample;
|
|
right += m_audio1.vol_right * sample;
|
|
}
|
|
|
|
if ( m_audio2.on ) {
|
|
if ( m_audio2_voice ) {
|
|
left += (m_voice_data - 128)*(m_master_volume & 0x0f);
|
|
right += (m_voice_data - 128)*(m_master_volume & 0x0f);
|
|
} else {
|
|
sample = m_audio2.signal;
|
|
m_audio2.pos++;
|
|
if ( m_audio2.pos >= m_audio2.period / 2 ) {
|
|
m_audio2.pos = 0;
|
|
m_audio2.signal = -m_audio2.signal;
|
|
}
|
|
left += m_audio2.vol_left * sample;
|
|
right += m_audio2.vol_right * sample;
|
|
}
|
|
}
|
|
|
|
if ( m_audio3.on ) {
|
|
sample = m_audio3.signal;
|
|
m_audio3.pos++;
|
|
if ( m_audio3.pos >= m_audio3.period / 2 ) {
|
|
m_audio3.pos = 0;
|
|
m_audio3.signal = -m_audio3.signal;
|
|
}
|
|
if ( m_audio3_sweep && m_sweep_time ) {
|
|
m_sweep_count++;
|
|
if ( m_sweep_count >= m_sweep_time ) {
|
|
m_sweep_count = 0;
|
|
m_audio3.freq += m_sweep_step;
|
|
m_audio3.period = machine().sample_rate() / (3072000 / ((2048 - (m_audio3.freq & 0x7ff)) << 5));
|
|
}
|
|
}
|
|
left += m_audio3.vol_left * sample;
|
|
right += m_audio3.vol_right * sample;
|
|
}
|
|
|
|
if ( m_audio4.on ) {
|
|
if ( m_audio4_noise ) {
|
|
sample = 0;
|
|
} else {
|
|
sample = m_audio4.signal;
|
|
m_audio4.pos++;
|
|
if ( m_audio4.pos >= m_audio4.period / 2 ) {
|
|
m_audio4.pos = 0;
|
|
m_audio4.signal = -m_audio4.signal;
|
|
}
|
|
}
|
|
left += m_audio4.vol_left * sample;
|
|
right += m_audio4.vol_right * sample;
|
|
}
|
|
|
|
left <<= 5;
|
|
right <<= 5;
|
|
|
|
*(outputs[0]++) = left;
|
|
*(outputs[1]++) = right;
|
|
}
|
|
}
|
|
|
|
|
|
void wswan_sound_device::wswan_ch_set_freq( CHAN *ch, UINT16 freq )
|
|
{
|
|
freq &= 0x7ff; // docs say freq is 11bits and a few games (Morita Shougi, World Stadium + others) write 0x800 causing a divide by 0 crash
|
|
ch->freq = freq;
|
|
ch->period = machine().sample_rate() / (3072000 / ((2048 - freq) << 5));
|
|
}
|
|
|
|
WRITE8_MEMBER( wswan_sound_device::wswan_sound_port_w )
|
|
{
|
|
m_channel->update();
|
|
|
|
switch( offset ) {
|
|
case 0x80: /* Audio 1 freq (lo) */
|
|
wswan_ch_set_freq(&m_audio1, (m_audio1.freq & 0xff00) | data);
|
|
break;
|
|
case 0x81: /* Audio 1 freq (hi) */
|
|
wswan_ch_set_freq(&m_audio1, (data << 8 ) | (m_audio1.freq & 0x00ff));
|
|
break;
|
|
case 0x82: /* Audio 2 freq (lo) */
|
|
wswan_ch_set_freq(&m_audio2, (m_audio2.freq & 0xff00) | data);
|
|
break;
|
|
case 0x83: /* Audio 2 freq (hi) */
|
|
wswan_ch_set_freq(&m_audio2, (data << 8 ) | (m_audio2.freq & 0x00ff));
|
|
break;
|
|
case 0x84: /* Audio 3 freq (lo) */
|
|
wswan_ch_set_freq(&m_audio3, (m_audio3.freq & 0xff00) | data);
|
|
break;
|
|
case 0x85: /* Audio 3 freq (hi) */
|
|
wswan_ch_set_freq(&m_audio3, (data << 8) | (m_audio3.freq & 0x00ff));
|
|
break;
|
|
case 0x86: /* Audio 4 freq (lo) */
|
|
wswan_ch_set_freq(&m_audio4, (m_audio4.freq & 0xff00) | data);
|
|
break;
|
|
case 0x87: /* Audio 4 freq (hi) */
|
|
wswan_ch_set_freq(&m_audio4, (data << 8) | (m_audio4.freq & 0x00ff));
|
|
break;
|
|
case 0x88: /* Audio 1 volume */
|
|
m_audio1.vol_left = ( data & 0xF0 ) >> 4;
|
|
m_audio1.vol_right = data & 0x0F;
|
|
break;
|
|
case 0x89: /* Audio 2 volume */
|
|
m_voice_data = data;
|
|
m_audio2.vol_left = ( data & 0xF0 ) >> 4;
|
|
m_audio2.vol_right = data & 0x0F;
|
|
break;
|
|
case 0x8A: /* Audio 3 volume */
|
|
m_audio3.vol_left = ( data & 0xF0 ) >> 4;
|
|
m_audio3.vol_right = data & 0x0F;
|
|
break;
|
|
case 0x8B: /* Audio 4 volume */
|
|
m_audio4.vol_left = ( data & 0xF0 ) >> 4;
|
|
m_audio4.vol_right = data & 0x0F;
|
|
break;
|
|
case 0x8C: /* Sweep step */
|
|
m_sweep_step = (INT8)data;
|
|
break;
|
|
case 0x8D: /* Sweep time */
|
|
m_sweep_time = space.machine().sample_rate() / ( 3072000 / ( 8192 * (data + 1) ) );
|
|
break;
|
|
case 0x8E: /* Noise control */
|
|
m_noise_type = data & 0x07;
|
|
m_noise_reset = ( data & 0x08 ) >> 3;
|
|
m_noise_enable = ( data & 0x10 ) >> 4;
|
|
break;
|
|
case 0x8F: /* Sample location */
|
|
m_sample_address = data << 6;
|
|
break;
|
|
case 0x90: /* Audio control */
|
|
m_audio1.on = data & 0x01;
|
|
m_audio2.on = ( data & 0x02 ) >> 1;
|
|
m_audio3.on = ( data & 0x04 ) >> 2;
|
|
m_audio4.on = ( data & 0x08 ) >> 3;
|
|
m_audio2_voice = ( data & 0x20 ) >> 5;
|
|
m_audio3_sweep = ( data & 0x40 ) >> 6;
|
|
m_audio4_noise = ( data & 0x80 ) >> 7;
|
|
break;
|
|
case 0x91: /* Audio output */
|
|
m_mono = data & 0x01;
|
|
m_output_volume = ( data & 0x06 ) >> 1;
|
|
m_external_stereo = ( data & 0x08 ) >> 3;
|
|
m_external_speaker = 1;
|
|
break;
|
|
case 0x92: /* Noise counter shift register (lo) */
|
|
m_noise_shift = ( m_noise_shift & 0xFF00 ) | data;
|
|
break;
|
|
case 0x93: /* Noise counter shift register (hi) */
|
|
m_noise_shift = ( data << 8 ) | ( m_noise_shift & 0x00FF );
|
|
break;
|
|
case 0x94: /* Master volume */
|
|
m_master_volume = data;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|