trunk/src/mess/drivers/socrates.c
| r21541 | r21542 | |
| 652 | 652 | |
| 653 | 653 | WRITE8_MEMBER(socrates_state::socrates_sound_w) |
| 654 | 654 | { |
| 655 | | device_t *socr_snd = machine().device("soc_snd"); |
| 656 | 655 | switch(offset) |
| 657 | 656 | { |
| 658 | 657 | case 0: |
| 659 | | socrates_snd_reg0_w(socr_snd, data); |
| 658 | m_sound->reg0_w(data); |
| 660 | 659 | break; |
| 661 | 660 | case 1: |
| 662 | | socrates_snd_reg1_w(socr_snd, data); |
| 661 | m_sound->reg1_w(data); |
| 663 | 662 | break; |
| 664 | 663 | case 2: |
| 665 | | socrates_snd_reg2_w(socr_snd, data); |
| 664 | m_sound->reg2_w(data); |
| 666 | 665 | break; |
| 667 | 666 | case 3: |
| 668 | | socrates_snd_reg3_w(socr_snd, data); |
| 667 | m_sound->reg3_w(data); |
| 669 | 668 | break; |
| 670 | 669 | case 4: case 5: case 6: case 7: default: |
| 671 | | socrates_snd_reg4_w(socr_snd, data); |
| 670 | m_sound->reg4_w(data); |
| 672 | 671 | break; |
| 673 | 672 | } |
| 674 | 673 | } |
| r21541 | r21542 | |
| 942 | 941 | |
| 943 | 942 | /* sound hardware */ |
| 944 | 943 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 945 | | MCFG_SOUND_ADD("soc_snd", SOCRATES, XTAL_21_4772MHz/(512+256)) // this is correct, as strange as it sounds. |
| 944 | MCFG_SOUND_ADD("soc_snd", SOCRATES_SOUND, XTAL_21_4772MHz/(512+256)) // this is correct, as strange as it sounds. |
| 946 | 945 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 947 | 946 | |
| 948 | 947 | MCFG_CARTSLOT_ADD("cart") |
| r21541 | r21542 | |
| 976 | 975 | |
| 977 | 976 | /* sound hardware */ |
| 978 | 977 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 979 | | MCFG_SOUND_ADD("soc_snd", SOCRATES, XTAL_26_601712MHz/(512+256)) // TODO: verify divider for pal mode |
| 978 | MCFG_SOUND_ADD("soc_snd", SOCRATES_SOUND, XTAL_26_601712MHz/(512+256)) // TODO: verify divider for pal mode |
| 980 | 979 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 981 | 980 | |
| 982 | 981 | MCFG_CARTSLOT_ADD("cart") |
| r21541 | r21542 | |
| 997 | 996 | 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 |
| 998 | 997 | 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 |
| 999 | 998 | MCFG_SCREEN_UPDATE_DRIVER(socrates_state, screen_update_socrates) |
| 1000 | | MCFG_SOUND_REPLACE("soc_snd", SOCRATES, XTAL_26_601712MHz/(512+256)) // this is correct, as strange as it sounds. |
| 999 | MCFG_SOUND_REPLACE("soc_snd", SOCRATES_SOUND, XTAL_26_601712MHz/(512+256)) // this is correct, as strange as it sounds. |
| 1001 | 1000 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 1002 | 1001 | MACHINE_CONFIG_END |
| 1003 | 1002 | */ |
trunk/src/mess/audio/socrates.c
| r21541 | r21542 | |
| 10 | 10 | #include "emu.h" |
| 11 | 11 | #include "socrates.h" |
| 12 | 12 | |
| 13 | | struct SocratesASIC |
| 13 | |
| 14 | // device type definition |
| 15 | const device_type SOCRATES_SOUND = &device_creator<socrates_snd_device>; |
| 16 | |
| 17 | |
| 18 | //------------------------------------------------- |
| 19 | // socrates_snd_device - constructor |
| 20 | //------------------------------------------------- |
| 21 | |
| 22 | socrates_snd_device::socrates_snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 23 | : device_t(mconfig, SOCRATES_SOUND, "Socrates Sound", tag, owner, clock), |
| 24 | device_sound_interface(mconfig, *this) |
| 14 | 25 | { |
| 15 | | sound_stream *stream; |
| 16 | | UINT8 freq[2]; /* channel 1,2 frequencies */ |
| 17 | | UINT8 vol[2]; /* channel 1,2 volume */ |
| 18 | | UINT8 enable[2]; /* channel 1,2 enable */ |
| 19 | | UINT8 channel3; /* channel 3 weird register */ |
| 20 | | UINT8 state[3]; /* output states for channels 1,2,3 */ |
| 21 | | UINT8 accum[3]; /* accumulators for channels 1,2,3 */ |
| 22 | | UINT16 DAC_output; /* output */ |
| 23 | | }; |
| 26 | } |
| 24 | 27 | |
| 25 | 28 | |
| 26 | | INLINE SocratesASIC *get_safe_token(device_t *device) |
| 29 | //------------------------------------------------- |
| 30 | // device_start - device-specific startup |
| 31 | //------------------------------------------------- |
| 32 | |
| 33 | void socrates_snd_device::device_start() |
| 27 | 34 | { |
| 28 | | assert(device != NULL); |
| 29 | | assert(device->type() == SOCRATES); |
| 30 | | return (SocratesASIC *)downcast<socrates_snd_device *>(device)->token(); |
| 35 | m_freq[0] = m_freq[1] = 0xff; /* channel 1,2 frequency */ |
| 36 | m_vol[0] = m_vol[1] = 0x07; /* channel 1,2 volume */ |
| 37 | m_enable[0] = m_enable[1] = 0x01; /* channel 1,2 enable */ |
| 38 | m_channel3 = 0x00; /* channel 3 weird register */ |
| 39 | m_DAC_output = 0x00; /* output */ |
| 40 | m_state[0] = m_state[1] = m_state[2] = 0; |
| 41 | m_accum[0] = m_accum[1] = m_accum[2] = 0xFF; |
| 42 | m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() ? clock() : machine().sample_rate(), this); |
| 31 | 43 | } |
| 32 | 44 | |
| 33 | | static const UINT8 volumeLUT[16] = |
| 45 | |
| 46 | //------------------------------------------------- |
| 47 | // sound_stream_update - handle a stream update |
| 48 | //------------------------------------------------- |
| 49 | |
| 50 | void socrates_snd_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 34 | 51 | { |
| 52 | for (int i = 0; i < samples; i++) |
| 53 | { |
| 54 | snd_clock(); |
| 55 | outputs[0][i] = ((int)m_DAC_output<<4); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | |
| 60 | const UINT8 socrates_snd_device::s_volumeLUT[16] = |
| 61 | { |
| 35 | 62 | 0, 61, 100, 132, 158, 183, 201, 218, |
| 36 | 63 | 233, 242, 253, 255, 250, 240, 224, 211 |
| 37 | 64 | }; // this table is actually quite weird on the real console. |
| 38 | 65 | // 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. |
| 39 | | static void socrates_snd_clock(SocratesASIC *chip) /* called once per clock */ |
| 66 | |
| 67 | void socrates_snd_device::snd_clock() /* called once per clock */ |
| 40 | 68 | { |
| 41 | | int channel; |
| 42 | | for (channel = 0; channel < 2; channel++) |
| 69 | for (int channel = 0; channel < 2; channel++) |
| 43 | 70 | { |
| 44 | | if ((chip->accum[channel] == 0) && chip->enable[channel]) |
| 71 | if ((m_accum[channel] == 0) && m_enable[channel]) |
| 45 | 72 | { |
| 46 | | chip->state[channel] = (chip->state[channel]^0x1); |
| 47 | | chip->accum[channel] = chip->freq[channel]; |
| 73 | m_state[channel] = (m_state[channel]^0x1); |
| 74 | m_accum[channel] = m_freq[channel]; |
| 48 | 75 | } |
| 49 | | else if (chip->enable[channel]) |
| 76 | else if (m_enable[channel]) |
| 50 | 77 | { |
| 51 | | chip->accum[channel]--; |
| 78 | m_accum[channel]--; |
| 52 | 79 | } |
| 53 | 80 | else |
| 54 | 81 | { |
| 55 | | chip->accum[channel] = 0; // channel is disabled |
| 56 | | chip->state[channel] = 0; |
| 82 | m_accum[channel] = 0; // channel is disabled |
| 83 | m_state[channel] = 0; |
| 57 | 84 | } |
| 58 | 85 | } |
| 59 | 86 | // handle channel 3 here |
| 60 | | chip->DAC_output = (chip->state[0]?(volumeLUT[chip->vol[0]]*9.4):0); // channel 1 is ~2.4 times as loud as channel 2 |
| 61 | | chip->DAC_output += (chip->state[1]?(volumeLUT[chip->vol[1]]<<2):0); |
| 87 | 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 |
| 88 | m_DAC_output += (m_state[1]?(s_volumeLUT[m_vol[1]]<<2):0); |
| 62 | 89 | // add channel 3 to dac output here |
| 63 | 90 | } |
| 64 | 91 | |
| 65 | | /************************************* |
| 66 | | * |
| 67 | | * Stream updater |
| 68 | | * |
| 69 | | *************************************/ |
| 70 | | static STREAM_UPDATE( socrates_snd_pcm_update ) |
| 71 | | { |
| 72 | | SocratesASIC *chip = (SocratesASIC *)param; |
| 73 | | int i; |
| 74 | 92 | |
| 75 | | for (i = 0; i < samples; i++) |
| 76 | | { |
| 77 | | socrates_snd_clock(chip); |
| 78 | | outputs[0][i] = ((int)chip->DAC_output<<4); |
| 79 | | } |
| 80 | | } |
| 81 | | |
| 82 | | |
| 83 | | |
| 84 | | /************************************* |
| 85 | | * |
| 86 | | * Sound handler start |
| 87 | | * |
| 88 | | *************************************/ |
| 89 | | |
| 90 | | static DEVICE_START( socrates_snd ) |
| 93 | void socrates_snd_device::reg0_w(int data) |
| 91 | 94 | { |
| 92 | | SocratesASIC *chip = get_safe_token(device); |
| 93 | | chip->freq[0] = chip->freq[1] = 0xff; /* channel 1,2 frequency */ |
| 94 | | chip->vol[0] = chip->vol[1] = 0x07; /* channel 1,2 volume */ |
| 95 | | chip->enable[0] = chip->enable[1] = 0x01; /* channel 1,2 enable */ |
| 96 | | chip->channel3 = 0x00; /* channel 3 weird register */ |
| 97 | | chip->DAC_output = 0x00; /* output */ |
| 98 | | chip->state[0] = chip->state[1] = chip->state[2] = 0; |
| 99 | | chip->accum[0] = chip->accum[1] = chip->accum[2] = 0xFF; |
| 100 | | chip->stream = device->machine().sound().stream_alloc(*device, 0, 1, device->clock() ? device->clock() : device->machine().sample_rate(), chip, socrates_snd_pcm_update); |
| 95 | m_stream->update(); |
| 96 | m_freq[0] = data; |
| 101 | 97 | } |
| 102 | 98 | |
| 103 | | |
| 104 | | void socrates_snd_reg0_w(device_t *device, int data) |
| 99 | void socrates_snd_device::reg1_w(int data) |
| 105 | 100 | { |
| 106 | | SocratesASIC *chip = get_safe_token(device); |
| 107 | | chip->stream->update(); |
| 108 | | chip->freq[0] = data; |
| 101 | m_stream->update(); |
| 102 | m_freq[1] = data; |
| 109 | 103 | } |
| 110 | 104 | |
| 111 | | void socrates_snd_reg1_w(device_t *device, int data) |
| 105 | void socrates_snd_device::reg2_w(int data) |
| 112 | 106 | { |
| 113 | | SocratesASIC *chip = get_safe_token(device); |
| 114 | | chip->stream->update(); |
| 115 | | chip->freq[1] = data; |
| 107 | m_stream->update(); |
| 108 | m_vol[0] = data&0xF; |
| 109 | m_enable[0] = (data&0x10)>>4; |
| 116 | 110 | } |
| 117 | 111 | |
| 118 | | void socrates_snd_reg2_w(device_t *device, int data) |
| 112 | void socrates_snd_device::reg3_w(int data) |
| 119 | 113 | { |
| 120 | | SocratesASIC *chip = get_safe_token(device); |
| 121 | | chip->stream->update(); |
| 122 | | chip->vol[0] = data&0xF; |
| 123 | | chip->enable[0] = (data&0x10)>>4; |
| 114 | m_stream->update(); |
| 115 | m_vol[1] = data&0xF; |
| 116 | m_enable[1] = (data&0x10)>>4; |
| 124 | 117 | } |
| 125 | 118 | |
| 126 | | void socrates_snd_reg3_w(device_t *device, int data) |
| 119 | void socrates_snd_device::reg4_w(int data) |
| 127 | 120 | { |
| 128 | | SocratesASIC *chip = get_safe_token(device); |
| 129 | | chip->stream->update(); |
| 130 | | chip->vol[1] = data&0xF; |
| 131 | | chip->enable[1] = (data&0x10)>>4; |
| 121 | m_stream->update(); |
| 122 | m_channel3 = data; |
| 132 | 123 | } |
| 133 | | |
| 134 | | void socrates_snd_reg4_w(device_t *device, int data) |
| 135 | | { |
| 136 | | SocratesASIC *chip = get_safe_token(device); |
| 137 | | chip->stream->update(); |
| 138 | | chip->channel3 = data; |
| 139 | | } |
| 140 | | |
| 141 | | |
| 142 | | /************************************************************************** |
| 143 | | * Generic get_info |
| 144 | | **************************************************************************/ |
| 145 | | |
| 146 | | const device_type SOCRATES = &device_creator<socrates_snd_device>; |
| 147 | | |
| 148 | | socrates_snd_device::socrates_snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 149 | | : device_t(mconfig, SOCRATES, "Socrates Sound", tag, owner, clock), |
| 150 | | device_sound_interface(mconfig, *this) |
| 151 | | { |
| 152 | | m_token = global_alloc_clear(SocratesASIC); |
| 153 | | } |
| 154 | | |
| 155 | | //------------------------------------------------- |
| 156 | | // device_config_complete - perform any |
| 157 | | // operations now that the configuration is |
| 158 | | // complete |
| 159 | | //------------------------------------------------- |
| 160 | | |
| 161 | | void socrates_snd_device::device_config_complete() |
| 162 | | { |
| 163 | | } |
| 164 | | |
| 165 | | //------------------------------------------------- |
| 166 | | // device_start - device-specific startup |
| 167 | | //------------------------------------------------- |
| 168 | | |
| 169 | | void socrates_snd_device::device_start() |
| 170 | | { |
| 171 | | DEVICE_START_NAME( socrates_snd )(this); |
| 172 | | } |
| 173 | | |
| 174 | | //------------------------------------------------- |
| 175 | | // sound_stream_update - handle a stream update |
| 176 | | //------------------------------------------------- |
| 177 | | |
| 178 | | void socrates_snd_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 179 | | { |
| 180 | | // should never get here |
| 181 | | fatalerror("sound_stream_update called; not applicable to legacy sound devices\n"); |
| 182 | | } |
trunk/src/mess/audio/socrates.h
| r21541 | r21542 | |
| 3 | 3 | #ifndef __SOCR_SND_H__ |
| 4 | 4 | #define __SOCR_SND_H__ |
| 5 | 5 | |
| 6 | | void socrates_snd_reg0_w(device_t *device, int data); |
| 7 | | void socrates_snd_reg1_w(device_t *device, int data); |
| 8 | | void socrates_snd_reg2_w(device_t *device, int data); |
| 9 | | void socrates_snd_reg3_w(device_t *device, int data); |
| 10 | | void socrates_snd_reg4_w(device_t *device, int data); |
| 11 | | |
| 12 | 6 | class socrates_snd_device : public device_t, |
| 13 | | public device_sound_interface |
| 7 | public device_sound_interface |
| 14 | 8 | { |
| 15 | 9 | public: |
| 16 | 10 | socrates_snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 17 | | ~socrates_snd_device() { global_free(m_token); } |
| 18 | 11 | |
| 19 | | // access to legacy token |
| 20 | | void *token() const { assert(m_token != NULL); return m_token; } |
| 12 | void reg0_w(int data); |
| 13 | void reg1_w(int data); |
| 14 | void reg2_w(int data); |
| 15 | void reg3_w(int data); |
| 16 | void reg4_w(int data); |
| 17 | |
| 21 | 18 | protected: |
| 22 | 19 | // device-level overrides |
| 23 | | virtual void device_config_complete(); |
| 24 | 20 | virtual void device_start(); |
| 25 | 21 | |
| 26 | 22 | // sound stream update overrides |
| 27 | 23 | virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); |
| 28 | 24 | private: |
| 25 | void snd_clock(); |
| 26 | static const UINT8 s_volumeLUT[]; |
| 27 | |
| 29 | 28 | // internal state |
| 30 | | void *m_token; |
| 29 | sound_stream * m_stream; |
| 30 | UINT8 m_freq[2]; // channel 1,2 frequencies |
| 31 | UINT8 m_vol[2]; // channel 1,2 volume |
| 32 | UINT8 m_enable[2]; // channel 1,2 enable |
| 33 | UINT8 m_channel3; // channel 3 weird register |
| 34 | UINT8 m_state[3]; // output states for channels 1,2,3 |
| 35 | UINT8 m_accum[3]; // accumulators for channels 1,2,3 |
| 36 | UINT16 m_DAC_output; // output |
| 31 | 37 | }; |
| 32 | 38 | |
| 33 | | extern const device_type SOCRATES; |
| 39 | extern const device_type SOCRATES_SOUND; |
| 34 | 40 | |
| 35 | 41 | |
| 36 | 42 | #endif /* __SOCR_SND_H__ */ |