diff options
Diffstat (limited to 'src/mame/audio/exidy440.cpp')
-rw-r--r-- | src/mame/audio/exidy440.cpp | 893 |
1 files changed, 0 insertions, 893 deletions
diff --git a/src/mame/audio/exidy440.cpp b/src/mame/audio/exidy440.cpp deleted file mode 100644 index df7c35fb084..00000000000 --- a/src/mame/audio/exidy440.cpp +++ /dev/null @@ -1,893 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - Exidy 440 sound system - - Special thanks to Zonn Moore and Neil Bradley for letting me hack - their Retrocade CVSD decoder into the sound system here. - -***************************************************************************/ - -#include "emu.h" -#include "audio/exidy440.h" -#include "includes/exidy440.h" - -#include "cpu/m6809/m6809.h" - - -#define SOUND_LOG 0 -#define FADE_TO_ZERO 1 - - -/* internal caching */ -#define MAX_CACHE_ENTRIES 1024 /* maximum separate samples we expect to ever see */ -#define SAMPLE_BUFFER_LENGTH 1024 /* size of temporary decode buffer on the stack */ - -/* FIR digital filter parameters */ -#define FIR_HISTORY_LENGTH 57 /* number of FIR coefficients */ - -/* CVSD decoding parameters */ -#define INTEGRATOR_LEAK_TC (10e3 * 0.1e-6) -#define FILTER_DECAY_TC ((18e3 + 3.3e3) * 0.33e-6) -#define FILTER_CHARGE_TC (18e3 * 0.33e-6) -#define FILTER_MIN 0.0416 -#define FILTER_MAX 1.0954 -#define SAMPLE_GAIN 10000.0 - -/* constant channel parameters */ -static const int channel_bits[4] = -{ - 4, 4, /* channels 0 and 1 are MC3418s, 4-bit CVSD */ - 3, 3 /* channels 2 and 3 are MC3417s, 3-bit CVSD */ -}; - - -/************************************* - * - * Audio CPU memory map - * - *************************************/ - -void exidy440_sound_device::exidy440_audio_map(address_map &map) -{ - map(0x0000, 0x7fff).noprw(); - map(0x8000, 0x801f).mirror(0x03e0).rw(FUNC(exidy440_sound_device::m6844_r), FUNC(exidy440_sound_device::m6844_w)); - map(0x8400, 0x840f).mirror(0x03f0).rw(FUNC(exidy440_sound_device::sound_volume_r), FUNC(exidy440_sound_device::sound_volume_w)); - map(0x8800, 0x8800).mirror(0x03ff).r(FUNC(exidy440_sound_device::sound_command_r)).nopw(); - map(0x8c00, 0x93ff).noprw(); - map(0x9400, 0x9403).mirror(0x03fc).nopr().w(FUNC(exidy440_sound_device::sound_banks_w)); - map(0x9800, 0x9800).mirror(0x03ff).nopr().w(FUNC(exidy440_sound_device::sound_interrupt_clear_w)); - map(0x9c00, 0x9fff).noprw(); - map(0xa000, 0xbfff).ram(); - map(0xc000, 0xdfff).noprw(); - map(0xe000, 0xffff).rom().region("audiocpu", 0); -} - - -DEFINE_DEVICE_TYPE(EXIDY440, exidy440_sound_device, "exidy440_sound", "Exidy 440 CVSD") - -exidy440_sound_device::exidy440_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, EXIDY440, tag, owner, clock), - device_sound_interface(mconfig, *this), - m_audiocpu(*this, "audiocpu"), - m_samples(*this, "samples"), - m_sound_command(0), - m_sound_command_ack(0), - m_mixer_buffer_left(nullptr), - m_mixer_buffer_right(nullptr), - m_sound_cache(nullptr), - m_sound_cache_end(nullptr), - m_sound_cache_max(nullptr), - m_m6844_priority(0x00), - m_m6844_interrupt(0x00), - m_m6844_chain(0x00), - m_stream(nullptr) -{ - m_sound_banks[0] = m_sound_banks[1] = m_sound_banks[2] = m_sound_banks[3] = 0; - - for (auto & elem : m_sound_channel) - { - elem.base = nullptr; - elem.offset = 0; - elem.remaining = 0; - } -} - -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- - -void exidy440_sound_device::device_add_mconfig(machine_config &config) -{ - MC6809(config, m_audiocpu, EXIDY440_AUDIO_CLOCK); - m_audiocpu->set_addrmap(AS_PROGRAM, &exidy440_sound_device::exidy440_audio_map); - -// MC3418(config, "cvsd1", EXIDY440_MC3418_CLOCK).add_route(ALL_OUTPUTS, "lspeaker", 1.0); - -// MC3418(config, "cvsd2", EXIDY440_MC3418_CLOCK).add_route(ALL_OUTPUTS, "rspeaker", 1.0); - -// MC3417(config, "cvsd3", EXIDY440_MC3417_CLOCK).add_route(ALL_OUTPUTS, "lspeaker", 1.0); - -// MC3417(config, "cvsd4", EXIDY440_MC3417_CLOCK).add_route(ALL_OUTPUTS, "rspeaker", 1.0); -} - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void exidy440_sound_device::device_start() -{ - int i, length; - - /* reset the system */ - m_sound_command = 0; - m_sound_command_ack = 1; - save_item(NAME(m_sound_command)); - save_item(NAME(m_sound_command_ack)); - - /* reset the 6844 */ - for (i = 0; i < 4; i++) - { - m_m6844_channel[i].active = 0; - m_m6844_channel[i].control = 0x00; - } - m_m6844_priority = 0x00; - m_m6844_interrupt = 0x00; - m_m6844_chain = 0x00; - - save_item(NAME(m_m6844_priority)); - save_item(NAME(m_m6844_interrupt)); - save_item(NAME(m_m6844_chain)); - - m_channel_frequency[0] = clock(); /* channels 0 and 1 are run by FCLK */ - m_channel_frequency[1] = clock(); - m_channel_frequency[2] = clock()/2; /* channels 2 and 3 are run by SCLK */ - m_channel_frequency[3] = clock()/2; - - /* get stream channels */ - m_stream = machine().sound().stream_alloc(*this, 0, 2, clock()); - - /* allocate the sample cache */ - length = m_samples.bytes() * 16 + MAX_CACHE_ENTRIES * sizeof(sound_cache_entry); - m_sound_cache = (sound_cache_entry *)auto_alloc_array_clear(machine(), uint8_t, length); - - /* determine the hard end of the cache and reset */ - m_sound_cache_max = (sound_cache_entry *)((uint8_t *)m_sound_cache + length); - reset_sound_cache(); - - /* allocate the mixer buffer */ - m_mixer_buffer_left = make_unique_clear<int32_t[]>(clock()); - m_mixer_buffer_right = make_unique_clear<int32_t[]>(clock()); - - if (SOUND_LOG) - m_debuglog = fopen("sound.log", "w"); -} - -//------------------------------------------------- -// device_stop - device-specific stop -//------------------------------------------------- - -void exidy440_sound_device::device_stop() -{ - if (SOUND_LOG && m_debuglog) - fclose(m_debuglog); -} - -/************************************* - * - * Add a bunch of samples to the mix - * - *************************************/ - -void exidy440_sound_device::add_and_scale_samples(int ch, int32_t *dest, int samples, int volume) -{ - sound_channel_data *channel = &m_sound_channel[ch]; - int16_t *srcdata; - int i; - - /* channels 2 and 3 are half-rate samples */ - if (ch & 2) - { - srcdata = &channel->base[channel->offset >> 1]; - - /* handle the edge case */ - if (channel->offset & 1) - { - *dest++ += *srcdata++ * volume / 256; - samples--; - } - - /* copy 1 for 2 to the destination */ - for (i = 0; i < samples; i += 2) - { - int16_t sample = *srcdata++ * volume / 256; - *dest++ += sample; - *dest++ += sample; - } - } - - /* channels 0 and 1 are full-rate samples */ - else - { - srcdata = &channel->base[channel->offset]; - for (i = 0; i < samples; i++) - *dest++ += *srcdata++ * volume / 256; - } -} - - - -/************************************* - * - * Mix the result to 16 bits - * - *************************************/ - -void exidy440_sound_device::mix_to_16(int length, stream_sample_t *dest_left, stream_sample_t *dest_right) -{ - int32_t *mixer_left = m_mixer_buffer_left.get(); - int32_t *mixer_right = m_mixer_buffer_right.get(); - int i, clippers = 0; - - for (i = 0; i < length; i++) - { - int32_t sample_left = *mixer_left++; - int32_t sample_right = *mixer_right++; - - if (sample_left < -32768) { sample_left = -32768; clippers++; } - else if (sample_left > 32767) { sample_left = 32767; clippers++; } - if (sample_right < -32768) { sample_right = -32768; clippers++; } - else if (sample_right > 32767) { sample_right = 32767; clippers++; } - - *dest_left++ = sample_left; - *dest_right++ = sample_right; - } -} - -/************************************* - * - * Sound command register - * - *************************************/ - -READ8_MEMBER(exidy440_sound_device::sound_command_r) -{ - /* clear the FIRQ that got us here and acknowledge the read to the main CPU */ - m_audiocpu->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE); - m_sound_command_ack = 1; - - return m_sound_command; -} - - -void exidy440_sound_device::exidy440_sound_command(uint8_t param) -{ - m_sound_command = param; - m_sound_command_ack = 0; - m_audiocpu->set_input_line(M6809_FIRQ_LINE, ASSERT_LINE); -} - - -uint8_t exidy440_sound_device::exidy440_sound_command_ack() -{ - return m_sound_command_ack; -} - - - -/************************************* - * - * Sound volume registers - * - *************************************/ - -READ8_MEMBER(exidy440_sound_device::sound_volume_r) -{ - return m_sound_volume[offset]; -} - -WRITE8_MEMBER(exidy440_sound_device::sound_volume_w) -{ - if (SOUND_LOG && m_debuglog) - fprintf(m_debuglog, "Volume %02X=%02X\n", offset, data); - - /* update the stream */ - m_stream->update(); - - /* set the new volume */ - m_sound_volume[offset] = ~data; -} - - - -/************************************* - * - * Sound interrupt handling - * - *************************************/ - -WRITE_LINE_MEMBER(exidy440_sound_device::sound_interrupt_w) -{ - if (state) - m_audiocpu->set_input_line(M6809_IRQ_LINE, ASSERT_LINE); -} - -WRITE8_MEMBER(exidy440_sound_device::sound_interrupt_clear_w) -{ - m_audiocpu->set_input_line(M6809_IRQ_LINE, CLEAR_LINE); -} - -WRITE_LINE_MEMBER(exidy440_sound_device::sound_reset_w) -{ - m_audiocpu->set_input_line(INPUT_LINE_RESET, state); -} - - - -/************************************* - * - * MC6844 DMA controller interface - * - *************************************/ - -void exidy440_sound_device::m6844_update() -{ - /* update the stream */ - m_stream->update(); -} - - -void exidy440_sound_device::m6844_finished(m6844_channel_data *channel) -{ - /* mark us inactive */ - channel->active = 0; - - /* set the final address and counter */ - channel->counter = 0; - channel->address = channel->start_address + channel->start_counter; - - /* clear the DMA busy bit and set the DMA end bit */ - channel->control &= ~0x40; - channel->control |= 0x80; -} - - - -/************************************* - * - * MC6844 DMA controller I/O - * - *************************************/ - -READ8_MEMBER(exidy440_sound_device::m6844_r) -{ - m6844_channel_data *m6844_channel = m_m6844_channel; - int result = 0; - - /* first update the current state of the DMA transfers */ - m6844_update(); - - /* switch off the offset we were given */ - switch (offset) - { - /* upper byte of address */ - case 0x00: - case 0x04: - case 0x08: - case 0x0c: - result = m6844_channel[offset / 4].address >> 8; - break; - - /* lower byte of address */ - case 0x01: - case 0x05: - case 0x09: - case 0x0d: - result = m6844_channel[offset / 4].address & 0xff; - break; - - /* upper byte of counter */ - case 0x02: - case 0x06: - case 0x0a: - case 0x0e: - result = m6844_channel[offset / 4].counter >> 8; - break; - - /* lower byte of counter */ - case 0x03: - case 0x07: - case 0x0b: - case 0x0f: - result = m6844_channel[offset / 4].counter & 0xff; - break; - - /* channel control */ - case 0x10: - case 0x11: - case 0x12: - case 0x13: - result = m6844_channel[offset - 0x10].control; - - /* a read here clears the DMA end flag */ - m6844_channel[offset - 0x10].control &= ~0x80; - break; - - /* priority control */ - case 0x14: - result = m_m6844_priority; - break; - - /* interrupt control */ - case 0x15: - - /* update the global DMA end flag */ - m_m6844_interrupt &= ~0x80; - m_m6844_interrupt |= (m6844_channel[0].control & 0x80) | - (m6844_channel[1].control & 0x80) | - (m6844_channel[2].control & 0x80) | - (m6844_channel[3].control & 0x80); - - result = m_m6844_interrupt; - break; - - /* chaining control */ - case 0x16: - result = m_m6844_chain; - break; - - /* 0x17-0x1f not used */ - default: break; - } - - return result; -} - - -WRITE8_MEMBER(exidy440_sound_device::m6844_w) -{ - m6844_channel_data *m6844_channel = m_m6844_channel; - int i; - - /* first update the current state of the DMA transfers */ - m6844_update(); - - /* switch off the offset we were given */ - switch (offset) - { - /* upper byte of address */ - case 0x00: - case 0x04: - case 0x08: - case 0x0c: - m6844_channel[offset / 4].address = (m6844_channel[offset / 4].address & 0xff) | (data << 8); - break; - - /* lower byte of address */ - case 0x01: - case 0x05: - case 0x09: - case 0x0d: - m6844_channel[offset / 4].address = (m6844_channel[offset / 4].address & 0xff00) | (data & 0xff); - break; - - /* upper byte of counter */ - case 0x02: - case 0x06: - case 0x0a: - case 0x0e: - m6844_channel[offset / 4].counter = (m6844_channel[offset / 4].counter & 0xff) | (data << 8); - break; - - /* lower byte of counter */ - case 0x03: - case 0x07: - case 0x0b: - case 0x0f: - m6844_channel[offset / 4].counter = (m6844_channel[offset / 4].counter & 0xff00) | (data & 0xff); - break; - - /* channel control */ - case 0x10: - case 0x11: - case 0x12: - case 0x13: - m6844_channel[offset - 0x10].control = (m6844_channel[offset - 0x10].control & 0xc0) | (data & 0x3f); - break; - - /* priority control */ - case 0x14: - m_m6844_priority = data; - - /* update the sound playback on each channel */ - for (i = 0; i < 4; i++) - { - /* if we're going active... */ - if (!m6844_channel[i].active && (data & (1 << i))) - { - /* mark us active */ - m6844_channel[i].active = 1; - - /* set the DMA busy bit and clear the DMA end bit */ - m6844_channel[i].control |= 0x40; - m6844_channel[i].control &= ~0x80; - - /* set the starting address, counter, and time */ - m6844_channel[i].start_address = m6844_channel[i].address; - m6844_channel[i].start_counter = m6844_channel[i].counter; - - /* generate and play the sample */ - play_cvsd(i); - } - - /* if we're going inactive... */ - else if (m6844_channel[i].active && !(data & (1 << i))) - { - /* mark us inactive */ - m6844_channel[i].active = 0; - - /* stop playing the sample */ - stop_cvsd(i); - } - } - break; - - /* interrupt control */ - case 0x15: - m_m6844_interrupt = (m_m6844_interrupt & 0x80) | (data & 0x7f); - break; - - /* chaining control */ - case 0x16: - m_m6844_chain = data; - break; - - /* 0x17-0x1f not used */ - default: break; - } -} - - - -/************************************* - * - * Sound cache management - * - *************************************/ - -void exidy440_sound_device::reset_sound_cache() -{ - m_sound_cache_end = m_sound_cache; -} - - -int16_t *exidy440_sound_device::add_to_sound_cache(uint8_t *input, int address, int length, int bits, int frequency) -{ - sound_cache_entry *current = m_sound_cache_end; - - /* compute where the end will be once we add this entry */ - m_sound_cache_end = (sound_cache_entry *)((uint8_t *)current + sizeof(sound_cache_entry) + length * 16); - - /* if this will overflow the cache, reset and re-add */ - if (m_sound_cache_end > m_sound_cache_max) - { - reset_sound_cache(); - return add_to_sound_cache(input, address, length, bits, frequency); - } - - /* fill in this entry */ - current->next = m_sound_cache_end; - current->address = address; - current->length = length; - current->bits = bits; - current->frequency = frequency; - - /* decode the data into the cache */ - decode_and_filter_cvsd(input, length, bits, frequency, current->data); - return current->data; -} - - -int16_t *exidy440_sound_device::find_or_add_to_sound_cache(int address, int length, int bits, int frequency) -{ - sound_cache_entry *current; - - for (current = m_sound_cache; current < m_sound_cache_end; current = current->next) - if (current->address == address && current->length == length && current->bits == bits && current->frequency == frequency) - return current->data; - - return add_to_sound_cache(&m_samples[address], address, length, bits, frequency); -} - - - -/************************************* - * - * Internal CVSD decoder and player - * - *************************************/ - -void exidy440_sound_device::play_cvsd(int ch) -{ - sound_channel_data *channel = &m_sound_channel[ch]; - int address = m_m6844_channel[ch].address; - int length = m_m6844_channel[ch].counter; - int16_t *base; - - /* add the bank number to the address */ - if (m_sound_banks[ch] & 1) - address += 0x00000; - else if (m_sound_banks[ch] & 2) - address += 0x08000; - else if (m_sound_banks[ch] & 4) - address += 0x10000; - else if (m_sound_banks[ch] & 8) - address += 0x18000; - - /* compute the base address in the converted samples array */ - base = find_or_add_to_sound_cache(address, length, channel_bits[ch], m_channel_frequency[ch]); - if (!base) - return; - - /* if the length is 0 or 1, just do an immediate end */ - if (length <= 3) - { - channel->base = base; - channel->offset = length; - channel->remaining = 0; - m6844_finished(&m_m6844_channel[ch]); - return; - } - - if (SOUND_LOG && m_debuglog) - fprintf(m_debuglog, "Sound channel %d play at %02X,%04X, length = %04X, volume = %02X/%02X\n", - ch, m_sound_banks[ch], - m_m6844_channel[ch].address, m_m6844_channel[ch].counter, - m_sound_volume[ch * 2], m_sound_volume[ch * 2 + 1]); - - /* set the pointer and count */ - channel->base = base; - channel->offset = 0; - channel->remaining = length * 8; - - /* channels 2 and 3 play twice as slow, so we need to count twice as many samples */ - if (ch & 2) channel->remaining *= 2; -} - - -void exidy440_sound_device::stop_cvsd(int ch) -{ - /* the DMA channel is marked inactive; that will kill the audio */ - m_sound_channel[ch].remaining = 0; - m_stream->update(); - - if (SOUND_LOG && m_debuglog) - fprintf(m_debuglog, "Channel %d stop\n", ch); -} - - - -/************************************* - * - * FIR digital filter - * - *************************************/ - -void exidy440_sound_device::fir_filter(int32_t *input, int16_t *output, int count) -{ - while (count--) - { - int32_t result = (input[-1] - input[-8] - input[-48] + input[-55]) << 2; - result += (input[0] + input[-18] + input[-38] + input[-56]) << 3; - result += (-input[-2] - input[-4] + input[-5] + input[-51] - input[-52] - input[-54]) << 4; - result += (-input[-3] - input[-11] - input[-45] - input[-53]) << 5; - result += (input[-6] + input[-7] - input[-9] - input[-15] - input[-41] - input[-47] + input[-49] + input[-50]) << 6; - result += (-input[-10] + input[-12] + input[-13] + input[-14] + input[-21] + input[-35] + input[-42] + input[-43] + input[-44] - input[-46]) << 7; - result += (-input[-16] - input[-17] + input[-19] + input[-37] - input[-39] - input[-40]) << 8; - result += (input[-20] - input[-22] - input[-24] + input[-25] + input[-31] - input[-32] - input[-34] + input[-36]) << 9; - result += (-input[-23] - input[-33]) << 10; - result += (input[-26] + input[-30]) << 11; - result += (input[-27] + input[-28] + input[-29]) << 12; - result >>= 14; - - if (result < -32768) - result = -32768; - else if (result > 32767) - result = 32767; - - *output++ = result; - input++; - } -} - - - -/************************************* - * - * CVSD decoder - * - *************************************/ - -void exidy440_sound_device::decode_and_filter_cvsd(uint8_t *input, int bytes, int maskbits, int frequency, int16_t *output) -{ - int32_t buffer[SAMPLE_BUFFER_LENGTH + FIR_HISTORY_LENGTH]; - int total_samples = bytes * 8; - int mask = (1 << maskbits) - 1; - double filter, integrator, leak; - double charge, decay, gain; - int steps; - int chunk_start; - - /* compute the charge, decay, and leak constants */ - charge = pow(exp(-1.0), 1.0 / (FILTER_CHARGE_TC * (double)frequency)); - decay = pow(exp(-1.0), 1.0 / (FILTER_DECAY_TC * (double)frequency)); - leak = pow(exp(-1.0), 1.0 / (INTEGRATOR_LEAK_TC * (double)frequency)); - - /* compute the gain */ - gain = SAMPLE_GAIN; - - /* clear the history words for a start */ - memset(&buffer[0], 0, FIR_HISTORY_LENGTH * sizeof(int32_t)); - - /* initialize the CVSD decoder */ - steps = 0xaa; - filter = FILTER_MIN; - integrator = 0.0; - - /* loop over chunks */ - for (chunk_start = 0; chunk_start < total_samples; chunk_start += SAMPLE_BUFFER_LENGTH) - { - int32_t *bufptr = &buffer[FIR_HISTORY_LENGTH]; - int chunk_bytes; - int ind; - - /* how many samples do we generate in this chunk? */ - if (chunk_start + SAMPLE_BUFFER_LENGTH > total_samples) - chunk_bytes = (total_samples - chunk_start) / 8; - else - chunk_bytes = SAMPLE_BUFFER_LENGTH / 8; - - /* loop over samples */ - for (ind = 0; ind < chunk_bytes; ind++) - { - double temp; - int databyte = *input++; - int bit; - int sample; - - /* loop over bits in the byte, low to high */ - for (bit = 0; bit < 8; bit++) - { - /* move the estimator up or down a step based on the bit */ - if (databyte & (1 << bit)) - { - integrator += filter; - steps = (steps << 1) | 1; - } - else - { - integrator -= filter; - steps <<= 1; - } - - /* keep track of the last n bits */ - steps &= mask; - - /* simulate leakage */ - integrator *= leak; - - /* if we got all 0's or all 1's in the last n bits, bump the step up */ - if (steps == 0 || steps == mask) - { - filter = FILTER_MAX - ((FILTER_MAX - filter) * charge); - if (filter > FILTER_MAX) - filter = FILTER_MAX; - } - - /* simulate decay */ - else - { - filter *= decay; - if (filter < FILTER_MIN) - filter = FILTER_MIN; - } - - /* compute the sample as a 32-bit word */ - temp = integrator * gain; - - /* compress the sample range to fit better in a 16-bit word */ - if (temp < 0) - sample = (int)(temp / (-temp * (1.0 / 32768.0) + 1.0)); - else - sample = (int)(temp / (temp * (1.0 / 32768.0) + 1.0)); - - /* store the result to our temporary buffer */ - *bufptr++ = sample; - } - } - - /* all done with this chunk, run the filter on it */ - fir_filter(&buffer[FIR_HISTORY_LENGTH], &output[chunk_start], chunk_bytes * 8); - - /* copy the last few input samples down to the start for a new history */ - memcpy(&buffer[0], &buffer[SAMPLE_BUFFER_LENGTH], FIR_HISTORY_LENGTH * sizeof(int32_t)); - } - - /* make sure the volume goes smoothly to 0 over the last 512 samples */ - if (FADE_TO_ZERO) - { - int16_t *data; - - chunk_start = (total_samples > 512) ? total_samples - 512 : 0; - data = output + chunk_start; - for ( ; chunk_start < total_samples; chunk_start++) - { - *data = (*data * ((total_samples - chunk_start) >> 9)); - data++; - } - } -} - - -WRITE8_MEMBER(exidy440_sound_device::sound_banks_w) -{ - m_sound_banks[offset] = data; -} - -//------------------------------------------------- -// sound_stream_update - handle a stream update -//------------------------------------------------- - -void exidy440_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) -{ - int ch; - - /* reset the mixer buffers */ - memset(m_mixer_buffer_left.get(), 0, samples * sizeof(int32_t)); - memset(m_mixer_buffer_right.get(), 0, samples * sizeof(int32_t)); - - /* loop over channels */ - for (ch = 0; ch < 4; ch++) - { - sound_channel_data *channel = &m_sound_channel[ch]; - int length, volume, left = samples; - int effective_offset; - - /* if we're not active, bail */ - if (channel->remaining <= 0) - continue; - - /* see how many samples to copy */ - length = (left > channel->remaining) ? channel->remaining : left; - - /* get a pointer to the sample data and copy to the left */ - volume = m_sound_volume[2 * ch + 0]; - if (volume) - add_and_scale_samples(ch, m_mixer_buffer_left.get(), length, volume); - - /* get a pointer to the sample data and copy to the left */ - volume = m_sound_volume[2 * ch + 1]; - if (volume) - add_and_scale_samples(ch, m_mixer_buffer_right.get(), length, volume); - - /* update our counters */ - channel->offset += length; - channel->remaining -= length; - left -= length; - - /* update the MC6844 */ - effective_offset = (ch & 2) ? channel->offset / 2 : channel->offset; - m_m6844_channel[ch].address = m_m6844_channel[ch].start_address + effective_offset / 8; - m_m6844_channel[ch].counter = m_m6844_channel[ch].start_counter - effective_offset / 8; - if (m_m6844_channel[ch].counter <= 0) - { - if (SOUND_LOG && m_debuglog) - fprintf(m_debuglog, "Channel %d finished\n", ch); - m6844_finished(&m_m6844_channel[ch]); - } - } - - /* all done, time to mix it */ - mix_to_16(samples, outputs[0], outputs[1]); -} |