trunk/src/emu/sound/snkwave.c
| r19927 | r19928 | |
| 10 | 10 | #include "snkwave.h" |
| 11 | 11 | |
| 12 | 12 | |
| 13 | | #define WAVEFORM_LENGTH 16 |
| 14 | | |
| 15 | 13 | #define CLOCK_SHIFT 8 |
| 16 | 14 | |
| 17 | 15 | |
| 18 | | struct snkwave_state |
| 19 | | { |
| 20 | | /* global sound parameters */ |
| 21 | | sound_stream * stream; |
| 22 | | int external_clock; |
| 23 | | int sample_rate; |
| 16 | const device_type SNKWAVE = &device_creator<snkwave_device>; |
| 24 | 17 | |
| 25 | | /* data about the sound system */ |
| 26 | | UINT32 frequency; |
| 27 | | UINT32 counter; |
| 28 | | int waveform_position; |
| 18 | //------------------------------------------------- |
| 19 | // snkwave_device - constructor |
| 20 | //------------------------------------------------- |
| 29 | 21 | |
| 30 | | /* decoded waveform table */ |
| 31 | | INT16 waveform[WAVEFORM_LENGTH]; |
| 32 | | }; |
| 33 | | |
| 34 | | INLINE snkwave_state *get_safe_token(device_t *device) |
| 22 | snkwave_device::snkwave_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 23 | : device_t(mconfig, SNKWAVE, "SNK Wave", tag, owner, clock), |
| 24 | device_sound_interface(mconfig, *this), |
| 25 | m_stream(NULL), |
| 26 | m_external_clock(0), |
| 27 | m_sample_rate(0), |
| 28 | m_frequency(0), |
| 29 | m_counter(0), |
| 30 | m_waveform_position(0) |
| 35 | 31 | { |
| 36 | | assert(device != NULL); |
| 37 | | assert(device->type() == SNKWAVE); |
| 38 | | return (snkwave_state *)downcast<snkwave_device *>(device)->token(); |
| 39 | 32 | } |
| 40 | 33 | |
| 34 | //------------------------------------------------- |
| 35 | // device_start - device-specific startup |
| 36 | //------------------------------------------------- |
| 41 | 37 | |
| 42 | | /* update the decoded waveform data */ |
| 43 | | /* The programmable waveform consists of 8 3-bit nibbles. |
| 44 | | The waveform goes to a 4-bit DAC and is played alternatingly forwards and |
| 45 | | backwards. |
| 46 | | When going forwards, bit 3 is 1. When going backwards, it's 0. |
| 47 | | So the sequence 01234567 will play as |
| 48 | | 89ABCDEF76543210 |
| 49 | | */ |
| 50 | | static void update_waveform(snkwave_state *chip, unsigned int offset, UINT8 data) |
| 38 | void snkwave_device::device_start() |
| 51 | 39 | { |
| 52 | | assert(offset < WAVEFORM_LENGTH/4); |
| 40 | assert(static_config() == 0); |
| 53 | 41 | |
| 54 | | chip->waveform[offset * 2] = ((data & 0x38) >> 3) << (12-CLOCK_SHIFT); |
| 55 | | chip->waveform[offset * 2 + 1] = ((data & 0x07) >> 0) << (12-CLOCK_SHIFT); |
| 56 | | chip->waveform[WAVEFORM_LENGTH-2 - offset * 2] = ~chip->waveform[offset * 2 + 1]; |
| 57 | | chip->waveform[WAVEFORM_LENGTH-1 - offset * 2] = ~chip->waveform[offset * 2]; |
| 42 | /* adjust internal clock */ |
| 43 | m_external_clock = clock(); |
| 44 | |
| 45 | /* adjust output clock */ |
| 46 | m_sample_rate = m_external_clock >> CLOCK_SHIFT; |
| 47 | |
| 48 | /* get stream channels */ |
| 49 | m_stream = stream_alloc(0, 1, m_sample_rate); |
| 50 | |
| 51 | /* reset all the voices */ |
| 52 | m_frequency = 0; |
| 53 | m_counter = 0; |
| 54 | m_waveform_position = 0; |
| 55 | |
| 56 | /* register with the save state system */ |
| 57 | save_item(NAME(m_frequency)); |
| 58 | save_item(NAME(m_counter)); |
| 59 | save_item(NAME(m_waveform_position)); |
| 60 | save_pointer(NAME(m_waveform), SNKWAVE_WAVEFORM_LENGTH); |
| 58 | 61 | } |
| 59 | 62 | |
| 60 | 63 | |
| 61 | | /* generate sound to the mix buffer */ |
| 62 | | static STREAM_UPDATE( snkwave_update ) |
| 64 | //------------------------------------------------- |
| 65 | // sound_stream_update - handle update requests |
| 66 | // for our sound stream |
| 67 | //------------------------------------------------- |
| 68 | |
| 69 | void snkwave_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 63 | 70 | { |
| 64 | | snkwave_state *chip = (snkwave_state *)param; |
| 65 | 71 | stream_sample_t *buffer = outputs[0]; |
| 66 | 72 | |
| 67 | 73 | /* zap the contents of the buffer */ |
| 68 | 74 | memset(buffer, 0, samples * sizeof(*buffer)); |
| 69 | 75 | |
| 70 | | assert(chip->counter < 0x1000); |
| 71 | | assert(chip->frequency < 0x1000); |
| 76 | assert(m_counter < 0x1000); |
| 77 | assert(m_frequency < 0x1000); |
| 72 | 78 | |
| 73 | 79 | /* if no sound, we're done */ |
| 74 | | if (chip->frequency == 0xfff) |
| 80 | if (m_frequency == 0xfff) |
| 75 | 81 | return; |
| 76 | 82 | |
| 77 | 83 | /* generate sound into buffer while updating the counter */ |
| r19927 | r19928 | |
| 83 | 89 | loops = 1 << CLOCK_SHIFT; |
| 84 | 90 | while (loops > 0) |
| 85 | 91 | { |
| 86 | | int steps = 0x1000 - chip->counter; |
| 92 | int steps = 0x1000 - m_counter; |
| 87 | 93 | |
| 88 | 94 | if (steps <= loops) |
| 89 | 95 | { |
| 90 | | out += chip->waveform[chip->waveform_position] * steps; |
| 91 | | chip->counter = chip->frequency; |
| 92 | | chip->waveform_position = (chip->waveform_position + 1) & (WAVEFORM_LENGTH-1); |
| 96 | out += m_waveform[m_waveform_position] * steps; |
| 97 | m_counter = m_frequency; |
| 98 | m_waveform_position = (m_waveform_position + 1) & (SNKWAVE_WAVEFORM_LENGTH-1); |
| 93 | 99 | loops -= steps; |
| 94 | 100 | } |
| 95 | 101 | else |
| 96 | 102 | { |
| 97 | | out += chip->waveform[chip->waveform_position] * loops; |
| 98 | | chip->counter += loops; |
| 103 | out += m_waveform[m_waveform_position] * loops; |
| 104 | m_counter += loops; |
| 99 | 105 | loops = 0; |
| 100 | 106 | } |
| 101 | 107 | } |
| r19927 | r19928 | |
| 105 | 111 | } |
| 106 | 112 | |
| 107 | 113 | |
| 108 | | static DEVICE_START( snkwave ) |
| 109 | | { |
| 110 | | snkwave_state *chip = get_safe_token(device); |
| 111 | | |
| 112 | | assert(device->static_config() == 0); |
| 113 | | |
| 114 | | /* adjust internal clock */ |
| 115 | | chip->external_clock = device->clock(); |
| 116 | | |
| 117 | | /* adjust output clock */ |
| 118 | | chip->sample_rate = chip->external_clock >> CLOCK_SHIFT; |
| 119 | | |
| 120 | | /* get stream channels */ |
| 121 | | chip->stream = device->machine().sound().stream_alloc(*device, 0, 1, chip->sample_rate, chip, snkwave_update); |
| 122 | | |
| 123 | | /* reset all the voices */ |
| 124 | | chip->frequency = 0; |
| 125 | | chip->counter = 0; |
| 126 | | chip->waveform_position = 0; |
| 127 | | |
| 128 | | /* register with the save state system */ |
| 129 | | device->save_item(NAME(chip->frequency)); |
| 130 | | device->save_item(NAME(chip->counter)); |
| 131 | | device->save_item(NAME(chip->waveform_position)); |
| 132 | | device->save_pointer(NAME(chip->waveform), WAVEFORM_LENGTH); |
| 133 | | } |
| 134 | | |
| 135 | | |
| 136 | | /********************************************************************************/ |
| 137 | | |
| 138 | 114 | /* SNK wave register map |
| 139 | 115 | all registers are 6-bit |
| 140 | 116 | 0-1 frequency (12-bit) |
| 141 | 117 | 2-5 waveform (8 3-bit nibbles) |
| 142 | 118 | */ |
| 143 | 119 | |
| 144 | | WRITE8_DEVICE_HANDLER( snkwave_w ) |
| 120 | WRITE8_MEMBER( snkwave_device::snkwave_w ) |
| 145 | 121 | { |
| 146 | | snkwave_state *chip = get_safe_token(device); |
| 122 | m_stream->update(); |
| 147 | 123 | |
| 148 | | chip->stream->update(); |
| 149 | | |
| 150 | 124 | // all registers are 6-bit |
| 151 | 125 | data &= 0x3f; |
| 152 | 126 | |
| 153 | 127 | if (offset == 0) |
| 154 | | chip->frequency = (chip->frequency & 0x03f) | (data << 6); |
| 128 | m_frequency = (m_frequency & 0x03f) | (data << 6); |
| 155 | 129 | else if (offset == 1) |
| 156 | | chip->frequency = (chip->frequency & 0xfc0) | data; |
| 130 | m_frequency = (m_frequency & 0xfc0) | data; |
| 157 | 131 | else if (offset <= 5) |
| 158 | | update_waveform(chip, offset - 2, data); |
| 132 | update_waveform(offset - 2, data); |
| 159 | 133 | } |
| 160 | 134 | |
| 161 | | const device_type SNKWAVE = &device_creator<snkwave_device>; |
| 162 | 135 | |
| 163 | | snkwave_device::snkwave_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 164 | | : device_t(mconfig, SNKWAVE, "SNK Wave", tag, owner, clock), |
| 165 | | device_sound_interface(mconfig, *this) |
| 136 | /* update the decoded waveform data */ |
| 137 | /* The programmable waveform consists of 8 3-bit nibbles. |
| 138 | The waveform goes to a 4-bit DAC and is played alternatingly forwards and |
| 139 | backwards. |
| 140 | When going forwards, bit 3 is 1. When going backwards, it's 0. |
| 141 | So the sequence 01234567 will play as |
| 142 | 89ABCDEF76543210 |
| 143 | */ |
| 144 | void snkwave_device::update_waveform(unsigned int offset, UINT8 data) |
| 166 | 145 | { |
| 167 | | m_token = global_alloc_clear(snkwave_state); |
| 168 | | } |
| 146 | assert(offset < SNKWAVE_WAVEFORM_LENGTH/4); |
| 169 | 147 | |
| 170 | | //------------------------------------------------- |
| 171 | | // device_config_complete - perform any |
| 172 | | // operations now that the configuration is |
| 173 | | // complete |
| 174 | | //------------------------------------------------- |
| 175 | | |
| 176 | | void snkwave_device::device_config_complete() |
| 177 | | { |
| 148 | m_waveform[offset * 2] = ((data & 0x38) >> 3) << (12-CLOCK_SHIFT); |
| 149 | m_waveform[offset * 2 + 1] = ((data & 0x07) >> 0) << (12-CLOCK_SHIFT); |
| 150 | m_waveform[SNKWAVE_WAVEFORM_LENGTH-2 - offset * 2] = ~m_waveform[offset * 2 + 1]; |
| 151 | m_waveform[SNKWAVE_WAVEFORM_LENGTH-1 - offset * 2] = ~m_waveform[offset * 2]; |
| 178 | 152 | } |
| 179 | 153 | |
| 180 | | //------------------------------------------------- |
| 181 | | // device_start - device-specific startup |
| 182 | | //------------------------------------------------- |
| 183 | 154 | |
| 184 | | void snkwave_device::device_start() |
| 185 | | { |
| 186 | | DEVICE_START_NAME( snkwave )(this); |
| 187 | | } |
| 188 | | |
| 189 | | //------------------------------------------------- |
| 190 | | // sound_stream_update - handle a stream update |
| 191 | | //------------------------------------------------- |
| 192 | | |
| 193 | | void snkwave_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 194 | | { |
| 195 | | // should never get here |
| 196 | | fatalerror("sound_stream_update called; not applicable to legacy sound devices\n"); |
| 197 | | } |
| 198 | | |
| 199 | | |
trunk/src/emu/sound/snkwave.h
| r19927 | r19928 | |
| 3 | 3 | #ifndef __SNKWAVE_H__ |
| 4 | 4 | #define __SNKWAVE_H__ |
| 5 | 5 | |
| 6 | | #include "devlegcy.h" |
| 6 | #define SNKWAVE_WAVEFORM_LENGTH 16 |
| 7 | 7 | |
| 8 | | DECLARE_WRITE8_DEVICE_HANDLER( snkwave_w ); |
| 8 | //************************************************************************** |
| 9 | // INTERFACE CONFIGURATION MACROS |
| 10 | //************************************************************************** |
| 9 | 11 | |
| 12 | #define MCFG_SNKWAVE_ADD(_tag, _clock) \ |
| 13 | MCFG_DEVICE_ADD(_tag, SNKWAVE, _clock) \ |
| 14 | |
| 15 | #define MCFG_SNKWAVE_REPLACE(_tag, _clock) \ |
| 16 | MCFG_DEVICE_REPLACE(_tag, SNKWAVE, _clock) \ |
| 17 | |
| 18 | |
| 19 | |
| 20 | //************************************************************************** |
| 21 | // TYPE DEFINITIONS |
| 22 | //************************************************************************** |
| 23 | |
| 24 | |
| 25 | // ======================> snkwave_device |
| 26 | |
| 10 | 27 | class snkwave_device : public device_t, |
| 11 | | public device_sound_interface |
| 28 | public device_sound_interface |
| 12 | 29 | { |
| 13 | 30 | public: |
| 14 | 31 | snkwave_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 15 | | ~snkwave_device() { global_free(m_token); } |
| 32 | ~snkwave_device() { } |
| 16 | 33 | |
| 17 | | // access to legacy token |
| 18 | | void *token() const { assert(m_token != NULL); return m_token; } |
| 19 | 34 | protected: |
| 20 | 35 | // device-level overrides |
| 21 | | virtual void device_config_complete(); |
| 22 | 36 | virtual void device_start(); |
| 23 | 37 | |
| 24 | 38 | // sound stream update overrides |
| 25 | 39 | virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); |
| 40 | |
| 41 | public: |
| 42 | DECLARE_WRITE8_MEMBER( snkwave_w ); |
| 43 | |
| 26 | 44 | private: |
| 27 | | // internal state |
| 28 | | void *m_token; |
| 45 | void update_waveform(unsigned int offset, UINT8 data); |
| 46 | |
| 47 | private: |
| 48 | sound_stream *m_stream; |
| 49 | int m_external_clock; |
| 50 | int m_sample_rate; |
| 51 | |
| 52 | // data about the sound system |
| 53 | UINT32 m_frequency; |
| 54 | UINT32 m_counter; |
| 55 | int m_waveform_position; |
| 56 | |
| 57 | // decoded waveform table |
| 58 | INT16 m_waveform[SNKWAVE_WAVEFORM_LENGTH]; |
| 29 | 59 | }; |
| 30 | 60 | |
| 31 | 61 | extern const device_type SNKWAVE; |