mirror of
https://github.com/holub/mame
synced 2025-07-05 18:08:04 +03:00
(MESS) modernized socrates sound device. (nw)
This commit is contained in:
parent
fa3c472a80
commit
18c3038d92
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user