(MESS) modernized socrates sound device. (nw)

This commit is contained in:
Sandro Ronco 2013-03-02 20:41:12 +00:00
parent fa3c472a80
commit 18c3038d92
3 changed files with 116 additions and 170 deletions

View File

@ -10,173 +10,114 @@
#include "emu.h"
#include "socrates.h"
struct SocratesASIC
{
sound_stream *stream;
UINT8 freq[2]; /* channel 1,2 frequencies */
UINT8 vol[2]; /* channel 1,2 volume */
UINT8 enable[2]; /* channel 1,2 enable */
UINT8 channel3; /* channel 3 weird register */
UINT8 state[3]; /* output states for channels 1,2,3 */
UINT8 accum[3]; /* accumulators for channels 1,2,3 */
UINT16 DAC_output; /* output */
};
// device type definition
const device_type SOCRATES_SOUND = &device_creator<socrates_snd_device>;
INLINE SocratesASIC *get_safe_token(device_t *device)
{
assert(device != NULL);
assert(device->type() == SOCRATES);
return (SocratesASIC *)downcast<socrates_snd_device *>(device)->token();
}
static const UINT8 volumeLUT[16] =
{
0, 61, 100, 132, 158, 183, 201, 218,
233, 242, 253, 255, 250, 240, 224, 211
}; // this table is actually quite weird on the real console.
// 0, 0.033, 0.055, 0.07175, 0.086, 0.1, 0.11, 0.119, 0.127, 0.132, 0.138, 0.139, 0.136, 0.131, 0.122, 0.115 are the voltage amplitudes for the steps on channel 2. the last four are particularly bizarre, probably caused by some sort of internal clipping.
static void socrates_snd_clock(SocratesASIC *chip) /* called once per clock */
{
int channel;
for (channel = 0; channel < 2; channel++)
{
if ((chip->accum[channel] == 0) && chip->enable[channel])
{
chip->state[channel] = (chip->state[channel]^0x1);
chip->accum[channel] = chip->freq[channel];
}
else if (chip->enable[channel])
{
chip->accum[channel]--;
}
else
{
chip->accum[channel] = 0; // channel is disabled
chip->state[channel] = 0;
}
}
// handle channel 3 here
chip->DAC_output = (chip->state[0]?(volumeLUT[chip->vol[0]]*9.4):0); // channel 1 is ~2.4 times as loud as channel 2
chip->DAC_output += (chip->state[1]?(volumeLUT[chip->vol[1]]<<2):0);
// add channel 3 to dac output here
}
/*************************************
*
* Stream updater
*
*************************************/
static STREAM_UPDATE( socrates_snd_pcm_update )
{
SocratesASIC *chip = (SocratesASIC *)param;
int i;
for (i = 0; i < samples; i++)
{
socrates_snd_clock(chip);
outputs[0][i] = ((int)chip->DAC_output<<4);
}
}
/*************************************
*
* Sound handler start
*
*************************************/
static DEVICE_START( socrates_snd )
{
SocratesASIC *chip = get_safe_token(device);
chip->freq[0] = chip->freq[1] = 0xff; /* channel 1,2 frequency */
chip->vol[0] = chip->vol[1] = 0x07; /* channel 1,2 volume */
chip->enable[0] = chip->enable[1] = 0x01; /* channel 1,2 enable */
chip->channel3 = 0x00; /* channel 3 weird register */
chip->DAC_output = 0x00; /* output */
chip->state[0] = chip->state[1] = chip->state[2] = 0;
chip->accum[0] = chip->accum[1] = chip->accum[2] = 0xFF;
chip->stream = device->machine().sound().stream_alloc(*device, 0, 1, device->clock() ? device->clock() : device->machine().sample_rate(), chip, socrates_snd_pcm_update);
}
void socrates_snd_reg0_w(device_t *device, int data)
{
SocratesASIC *chip = get_safe_token(device);
chip->stream->update();
chip->freq[0] = data;
}
void socrates_snd_reg1_w(device_t *device, int data)
{
SocratesASIC *chip = get_safe_token(device);
chip->stream->update();
chip->freq[1] = data;
}
void socrates_snd_reg2_w(device_t *device, int data)
{
SocratesASIC *chip = get_safe_token(device);
chip->stream->update();
chip->vol[0] = data&0xF;
chip->enable[0] = (data&0x10)>>4;
}
void socrates_snd_reg3_w(device_t *device, int data)
{
SocratesASIC *chip = get_safe_token(device);
chip->stream->update();
chip->vol[1] = data&0xF;
chip->enable[1] = (data&0x10)>>4;
}
void socrates_snd_reg4_w(device_t *device, int data)
{
SocratesASIC *chip = get_safe_token(device);
chip->stream->update();
chip->channel3 = data;
}
/**************************************************************************
* Generic get_info
**************************************************************************/
const device_type SOCRATES = &device_creator<socrates_snd_device>;
//-------------------------------------------------
// socrates_snd_device - constructor
//-------------------------------------------------
socrates_snd_device::socrates_snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, SOCRATES, "Socrates Sound", tag, owner, clock),
device_sound_interface(mconfig, *this)
{
m_token = global_alloc_clear(SocratesASIC);
}
//-------------------------------------------------
// device_config_complete - perform any
// operations now that the configuration is
// complete
//-------------------------------------------------
void socrates_snd_device::device_config_complete()
: device_t(mconfig, SOCRATES_SOUND, "Socrates Sound", tag, owner, clock),
device_sound_interface(mconfig, *this)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void socrates_snd_device::device_start()
{
DEVICE_START_NAME( socrates_snd )(this);
m_freq[0] = m_freq[1] = 0xff; /* channel 1,2 frequency */
m_vol[0] = m_vol[1] = 0x07; /* channel 1,2 volume */
m_enable[0] = m_enable[1] = 0x01; /* channel 1,2 enable */
m_channel3 = 0x00; /* channel 3 weird register */
m_DAC_output = 0x00; /* output */
m_state[0] = m_state[1] = m_state[2] = 0;
m_accum[0] = m_accum[1] = m_accum[2] = 0xFF;
m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() ? clock() : machine().sample_rate(), this);
}
//-------------------------------------------------
// sound_stream_update - handle a stream update
//-------------------------------------------------
void socrates_snd_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
// should never get here
fatalerror("sound_stream_update called; not applicable to legacy sound devices\n");
for (int i = 0; i < samples; i++)
{
snd_clock();
outputs[0][i] = ((int)m_DAC_output<<4);
}
}
const UINT8 socrates_snd_device::s_volumeLUT[16] =
{
0, 61, 100, 132, 158, 183, 201, 218,
233, 242, 253, 255, 250, 240, 224, 211
}; // this table is actually quite weird on the real console.
// 0, 0.033, 0.055, 0.07175, 0.086, 0.1, 0.11, 0.119, 0.127, 0.132, 0.138, 0.139, 0.136, 0.131, 0.122, 0.115 are the voltage amplitudes for the steps on channel 2. the last four are particularly bizarre, probably caused by some sort of internal clipping.
void socrates_snd_device::snd_clock() /* called once per clock */
{
for (int channel = 0; channel < 2; channel++)
{
if ((m_accum[channel] == 0) && m_enable[channel])
{
m_state[channel] = (m_state[channel]^0x1);
m_accum[channel] = m_freq[channel];
}
else if (m_enable[channel])
{
m_accum[channel]--;
}
else
{
m_accum[channel] = 0; // channel is disabled
m_state[channel] = 0;
}
}
// handle channel 3 here
m_DAC_output = (m_state[0]?(s_volumeLUT[m_vol[0]]*9.4):0); // channel 1 is ~2.4 times as loud as channel 2
m_DAC_output += (m_state[1]?(s_volumeLUT[m_vol[1]]<<2):0);
// add channel 3 to dac output here
}
void socrates_snd_device::reg0_w(int data)
{
m_stream->update();
m_freq[0] = data;
}
void socrates_snd_device::reg1_w(int data)
{
m_stream->update();
m_freq[1] = data;
}
void socrates_snd_device::reg2_w(int data)
{
m_stream->update();
m_vol[0] = data&0xF;
m_enable[0] = (data&0x10)>>4;
}
void socrates_snd_device::reg3_w(int data)
{
m_stream->update();
m_vol[1] = data&0xF;
m_enable[1] = (data&0x10)>>4;
}
void socrates_snd_device::reg4_w(int data)
{
m_stream->update();
m_channel3 = data;
}

View File

@ -3,34 +3,40 @@
#ifndef __SOCR_SND_H__
#define __SOCR_SND_H__
void socrates_snd_reg0_w(device_t *device, int data);
void socrates_snd_reg1_w(device_t *device, int data);
void socrates_snd_reg2_w(device_t *device, int data);
void socrates_snd_reg3_w(device_t *device, int data);
void socrates_snd_reg4_w(device_t *device, int data);
class socrates_snd_device : public device_t,
public device_sound_interface
public device_sound_interface
{
public:
socrates_snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
~socrates_snd_device() { global_free(m_token); }
// access to legacy token
void *token() const { assert(m_token != NULL); return m_token; }
void reg0_w(int data);
void reg1_w(int data);
void reg2_w(int data);
void reg3_w(int data);
void reg4_w(int data);
protected:
// device-level overrides
virtual void device_config_complete();
virtual void device_start();
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
private:
void snd_clock();
static const UINT8 s_volumeLUT[];
// internal state
void *m_token;
sound_stream * m_stream;
UINT8 m_freq[2]; // channel 1,2 frequencies
UINT8 m_vol[2]; // channel 1,2 volume
UINT8 m_enable[2]; // channel 1,2 enable
UINT8 m_channel3; // channel 3 weird register
UINT8 m_state[3]; // output states for channels 1,2,3
UINT8 m_accum[3]; // accumulators for channels 1,2,3
UINT16 m_DAC_output; // output
};
extern const device_type SOCRATES;
extern const device_type SOCRATES_SOUND;
#endif /* __SOCR_SND_H__ */

View File

@ -652,23 +652,22 @@ UINT32 socrates_state::screen_update_socrates(screen_device &screen, bitmap_ind1
WRITE8_MEMBER(socrates_state::socrates_sound_w)
{
device_t *socr_snd = machine().device("soc_snd");
switch(offset)
{
case 0:
socrates_snd_reg0_w(socr_snd, data);
m_sound->reg0_w(data);
break;
case 1:
socrates_snd_reg1_w(socr_snd, data);
m_sound->reg1_w(data);
break;
case 2:
socrates_snd_reg2_w(socr_snd, data);
m_sound->reg2_w(data);
break;
case 3:
socrates_snd_reg3_w(socr_snd, data);
m_sound->reg3_w(data);
break;
case 4: case 5: case 6: case 7: default:
socrates_snd_reg4_w(socr_snd, data);
m_sound->reg4_w(data);
break;
}
}
@ -942,7 +941,7 @@ static MACHINE_CONFIG_START( socrates, socrates_state )
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("soc_snd", SOCRATES, XTAL_21_4772MHz/(512+256)) // this is correct, as strange as it sounds.
MCFG_SOUND_ADD("soc_snd", SOCRATES_SOUND, XTAL_21_4772MHz/(512+256)) // this is correct, as strange as it sounds.
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CARTSLOT_ADD("cart")
@ -976,7 +975,7 @@ static MACHINE_CONFIG_START( socrates_pal, socrates_state )
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("soc_snd", SOCRATES, XTAL_26_601712MHz/(512+256)) // TODO: verify divider for pal mode
MCFG_SOUND_ADD("soc_snd", SOCRATES_SOUND, XTAL_26_601712MHz/(512+256)) // TODO: verify divider for pal mode
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CARTSLOT_ADD("cart")
@ -997,7 +996,7 @@ static MACHINE_CONFIG_DERIVED( socrates_pal, socrates )
MCFG_SCREEN_SIZE(264, 256) // technically the screen size is 256x228 but super painter abuses what I suspect is a hardware bug to display repeated pixels of the very last pixel beyond this horizontal space, well into hblank
MCFG_SCREEN_VISIBLE_AREA(0, 263, 0, 256) // the last few rows are usually cut off by the screen bottom but are indeed displayed if you mess with v-hold
MCFG_SCREEN_UPDATE_DRIVER(socrates_state, screen_update_socrates)
MCFG_SOUND_REPLACE("soc_snd", SOCRATES, XTAL_26_601712MHz/(512+256)) // this is correct, as strange as it sounds.
MCFG_SOUND_REPLACE("soc_snd", SOCRATES_SOUND, XTAL_26_601712MHz/(512+256)) // this is correct, as strange as it sounds.
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MACHINE_CONFIG_END
*/