diff options
Diffstat (limited to 'src/devices/sound/ymz280b.cpp')
-rw-r--r-- | src/devices/sound/ymz280b.cpp | 213 |
1 files changed, 96 insertions, 117 deletions
diff --git a/src/devices/sound/ymz280b.cpp b/src/devices/sound/ymz280b.cpp index 0b182509fb5..6873048624f 100644 --- a/src/devices/sound/ymz280b.cpp +++ b/src/devices/sound/ymz280b.cpp @@ -25,7 +25,7 @@ hardware currently emulated that uses external handlers. It also happens to be the only one using 16-bit PCM. - Some other drivers (eg. bishi.c, bfm_sc4/5.c) also use ROM readback. + Some other drivers (eg. bishi.cpp, bfm_sc4/5.cpp) also use ROM readback. */ @@ -40,11 +40,10 @@ #define MAX_SAMPLE_CHUNK 10000 -#define FRAC_BITS 14 -#define FRAC_ONE (1 << FRAC_BITS) -#define FRAC_MASK (FRAC_ONE - 1) +static constexpr unsigned FRAC_BITS = 9; +static constexpr s32 FRAC_ONE = 1 << FRAC_BITS; -#define INTERNAL_BUFFER_SIZE (1 << 15) +//#define INTERNAL_BUFFER_SIZE (1 << 15) #define INTERNAL_SAMPLE_RATE (m_master_clock * 2.0) @@ -68,34 +67,36 @@ void ymz280b_device::update_irq_state() if (irq_bits && !m_irq_state) { m_irq_state = 1; - if (!m_irq_handler.isnull()) + if (!m_irq_handler.isunset()) m_irq_handler(1); - else logerror("YMZ280B: IRQ generated, but no callback specified!\n"); + else + logerror("YMZ280B: IRQ generated, but no callback specified!\n"); } else if (!irq_bits && m_irq_state) { m_irq_state = 0; - if (!m_irq_handler.isnull()) + if (!m_irq_handler.isunset()) m_irq_handler(0); - else logerror("YMZ280B: IRQ generated, but no callback specified!\n"); + else + logerror("YMZ280B: IRQ generated, but no callback specified!\n"); } } -void ymz280b_device::update_step(struct YMZ280BVoice *voice) +void ymz280b_device::update_step(YMZ280BVoice *voice) { - double frequency; + int frequency; /* compute the frequency */ if (voice->mode == 1) - frequency = m_master_clock * (double)((voice->fnum & 0x0ff) + 1) * (1.0 / 256.0); + frequency = voice->fnum & 0x0ff; else - frequency = m_master_clock * (double)((voice->fnum & 0x1ff) + 1) * (1.0 / 256.0); - voice->output_step = (uint32_t)(frequency * (double)FRAC_ONE / INTERNAL_SAMPLE_RATE); + frequency = voice->fnum & 0x1ff; + voice->output_step = frequency + 1; // ((fnum + 1) * (input clock / 384)) / 256 } -void ymz280b_device::update_volumes(struct YMZ280BVoice *voice) +void ymz280b_device::update_volumes(YMZ280BVoice *voice) { if (voice->pan == 8) { @@ -119,24 +120,24 @@ void ymz280b_device::update_volumes(struct YMZ280BVoice *voice) void ymz280b_device::device_post_load() { - for (auto & elem : m_voice) + for (size_t i = 0; i < std::size(m_voice); i++) { - struct YMZ280BVoice *voice = &elem; + YMZ280BVoice *voice = &m_voice[i]; update_step(voice); if(voice->irq_schedule) - voice->timer->adjust(attotime::zero); + voice->timer->adjust(attotime::zero, i); } } -void ymz280b_device::update_irq_state_timer_common(int voicenum) +TIMER_CALLBACK_MEMBER(ymz280b_device::update_irq_state_timer_common) { - struct YMZ280BVoice *voice = &m_voice[voicenum]; + YMZ280BVoice *voice = &m_voice[param]; if(!voice->irq_schedule) return; voice->playing = 0; - m_status_register |= 1 << voicenum; + m_status_register |= 1 << param; update_irq_state(); voice->irq_schedule = 0; } @@ -165,7 +166,7 @@ static void compute_tables() ***********************************************************************************************/ -int ymz280b_device::generate_adpcm(struct YMZ280BVoice *voice, int16_t *buffer, int samples) +int ymz280b_device::generate_adpcm(YMZ280BVoice *voice, s16 *buffer, int samples) { int position = voice->position; int signal = voice->signal; @@ -277,7 +278,7 @@ int ymz280b_device::generate_adpcm(struct YMZ280BVoice *voice, int16_t *buffer, ***********************************************************************************************/ -int ymz280b_device::generate_pcm8(struct YMZ280BVoice *voice, int16_t *buffer, int samples) +int ymz280b_device::generate_pcm8(YMZ280BVoice *voice, s16 *buffer, int samples) { int position = voice->position; int val; @@ -292,7 +293,7 @@ int ymz280b_device::generate_pcm8(struct YMZ280BVoice *voice, int16_t *buffer, i val = read_byte(position / 2); /* output to the buffer, scaling by the volume */ - *buffer++ = (int8_t)val * 256; + *buffer++ = (s8)val * 256; samples--; /* next! */ @@ -315,7 +316,7 @@ int ymz280b_device::generate_pcm8(struct YMZ280BVoice *voice, int16_t *buffer, i val = read_byte(position / 2); /* output to the buffer, scaling by the volume */ - *buffer++ = (int8_t)val * 256; + *buffer++ = (s8)val * 256; samples--; /* next! */ @@ -347,7 +348,7 @@ int ymz280b_device::generate_pcm8(struct YMZ280BVoice *voice, int16_t *buffer, i ***********************************************************************************************/ -int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, int16_t *buffer, int samples) +int ymz280b_device::generate_pcm16(YMZ280BVoice *voice, s16 *buffer, int samples) { int position = voice->position; int val; @@ -359,7 +360,7 @@ int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, int16_t *buffer, while (samples) { /* fetch the current value */ - val = (int16_t)((read_byte(position / 2 + 1) << 8) + read_byte(position / 2 + 0)); + val = (s16)((read_byte(position / 2 + 1) << 8) + read_byte(position / 2 + 0)); /* output to the buffer, scaling by the volume */ *buffer++ = val; @@ -382,7 +383,7 @@ int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, int16_t *buffer, while (samples) { /* fetch the current value */ - val = (int16_t)((read_byte(position / 2 + 1) << 8) + read_byte(position / 2 + 0)); + val = (s16)((read_byte(position / 2 + 1) << 8) + read_byte(position / 2 + 0)); /* output to the buffer, scaling by the volume */ *buffer++ = val; @@ -416,28 +417,21 @@ int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, int16_t *buffer, // sound_stream_update - handle a stream update //------------------------------------------------- -void ymz280b_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +void ymz280b_device::sound_stream_update(sound_stream &stream) { - stream_sample_t *lacc = outputs[0]; - stream_sample_t *racc = outputs[1]; int v; - /* clear out the accumulator */ - memset(lacc, 0, samples * sizeof(lacc[0])); - memset(racc, 0, samples * sizeof(racc[0])); - /* loop over voices */ for (v = 0; v < 8; v++) { - struct YMZ280BVoice *voice = &m_voice[v]; - int16_t prev = voice->last_sample; - int16_t curr = voice->curr_sample; - int16_t *curr_data = m_scratch.get(); - int32_t *ldest = lacc; - int32_t *rdest = racc; - uint32_t new_samples, samples_left; - uint32_t final_pos; - int remaining = samples; + YMZ280BVoice *voice = &m_voice[v]; + s16 prev = voice->last_sample; + s16 curr = voice->curr_sample; + s16 *curr_data = m_scratch.get(); + s32 sampindex = 0; + u32 new_samples, samples_left; + u32 final_pos; + int remaining = stream.samples(); int lvol = voice->output_left; int rvol = voice->output_right; @@ -446,7 +440,6 @@ void ymz280b_device::sound_stream_update(sound_stream &stream, stream_sample_t * { /* make sure next sound plays immediately */ voice->output_pos = FRAC_ONE; - continue; } @@ -454,9 +447,10 @@ void ymz280b_device::sound_stream_update(sound_stream &stream, stream_sample_t * /* interpolate */ while (remaining > 0 && voice->output_pos < FRAC_ONE) { - int interp_sample = (((int32_t)prev * (FRAC_ONE - voice->output_pos)) + ((int32_t)curr * voice->output_pos)) >> FRAC_BITS; - *ldest++ += interp_sample * lvol; - *rdest++ += interp_sample * rvol; + int interp_sample = ((s32(prev) * (FRAC_ONE - voice->output_pos)) + (s32(curr) * voice->output_pos)) >> FRAC_BITS; + stream.add_int(0, sampindex, interp_sample * lvol / 2, 32768 * 256); + stream.add_int(1, sampindex, interp_sample * rvol / 2, 32768 * 256); + sampindex++; voice->output_pos += voice->output_step; remaining--; } @@ -503,7 +497,7 @@ void ymz280b_device::sound_stream_update(sound_stream &stream, stream_sample_t * voice->playing = 0; /* set update_irq_state_timer. IRQ is signaled on next CPU execution. */ - voice->timer->adjust(attotime::zero); + voice->timer->adjust(attotime::zero, v); voice->irq_schedule = 1; } } @@ -518,9 +512,10 @@ void ymz280b_device::sound_stream_update(sound_stream &stream, stream_sample_t * /* interpolate */ while (remaining > 0 && voice->output_pos < FRAC_ONE) { - int interp_sample = (((int32_t)prev * (FRAC_ONE - voice->output_pos)) + ((int32_t)curr * voice->output_pos)) >> FRAC_BITS; - *ldest++ += interp_sample * lvol; - *rdest++ += interp_sample * rvol; + int interp_sample = ((s32(prev) * (FRAC_ONE - voice->output_pos)) + (s32(curr) * voice->output_pos)) >> FRAC_BITS; + stream.add_int(0, sampindex, interp_sample * lvol / 2, 32768 * 256); + stream.add_int(1, sampindex, interp_sample * rvol / 2, 32768 * 256); + sampindex++; voice->output_pos += voice->output_step; remaining--; } @@ -538,12 +533,6 @@ void ymz280b_device::sound_stream_update(sound_stream &stream, stream_sample_t * voice->last_sample = prev; voice->curr_sample = curr; } - - for (v = 0; v < samples; v++) - { - outputs[0][v] /= 256; - outputs[1][v] /= 256; - } } @@ -559,19 +548,18 @@ void ymz280b_device::device_start() /* initialize the rest of the structure */ m_master_clock = (double)clock() / 384.0; - m_irq_handler.resolve(); for (int i = 0; i < 8; i++) { - m_voice[i].timer = timer_alloc(i); + m_voice[i].timer = timer_alloc(FUNC(ymz280b_device::update_irq_state_timer_common), this); } /* create the stream */ - m_stream = machine().sound().stream_alloc(*this, 0, 2, INTERNAL_SAMPLE_RATE); + m_stream = stream_alloc(0, 2, INTERNAL_SAMPLE_RATE); /* allocate memory */ assert(MAX_SAMPLE_CHUNK < 0x10000); - m_scratch = std::make_unique<int16_t[]>(MAX_SAMPLE_CHUNK); + m_scratch = std::make_unique<s16[]>(MAX_SAMPLE_CHUNK); /* state save */ save_item(NAME(m_current_register)); @@ -585,33 +573,31 @@ void ymz280b_device::device_start() save_item(NAME(m_ext_readlatch)); save_item(NAME(m_ext_mem_address_hi)); save_item(NAME(m_ext_mem_address_mid)); - for (int j = 0; j < 8; j++) - { - save_item(NAME(m_voice[j].playing), j); - save_item(NAME(m_voice[j].ended), j); - save_item(NAME(m_voice[j].keyon), j); - save_item(NAME(m_voice[j].looping), j); - save_item(NAME(m_voice[j].mode), j); - save_item(NAME(m_voice[j].fnum), j); - save_item(NAME(m_voice[j].level), j); - save_item(NAME(m_voice[j].pan), j); - save_item(NAME(m_voice[j].start), j); - save_item(NAME(m_voice[j].stop), j); - save_item(NAME(m_voice[j].loop_start), j); - save_item(NAME(m_voice[j].loop_end), j); - save_item(NAME(m_voice[j].position), j); - save_item(NAME(m_voice[j].signal), j); - save_item(NAME(m_voice[j].step), j); - save_item(NAME(m_voice[j].loop_signal), j); - save_item(NAME(m_voice[j].loop_step), j); - save_item(NAME(m_voice[j].loop_count), j); - save_item(NAME(m_voice[j].output_left), j); - save_item(NAME(m_voice[j].output_right), j); - save_item(NAME(m_voice[j].output_pos), j); - save_item(NAME(m_voice[j].last_sample), j); - save_item(NAME(m_voice[j].curr_sample), j); - save_item(NAME(m_voice[j].irq_schedule), j); - } + + save_item(STRUCT_MEMBER(m_voice, playing)); + save_item(STRUCT_MEMBER(m_voice, ended)); + save_item(STRUCT_MEMBER(m_voice, keyon)); + save_item(STRUCT_MEMBER(m_voice, looping)); + save_item(STRUCT_MEMBER(m_voice, mode)); + save_item(STRUCT_MEMBER(m_voice, fnum)); + save_item(STRUCT_MEMBER(m_voice, level)); + save_item(STRUCT_MEMBER(m_voice, pan)); + save_item(STRUCT_MEMBER(m_voice, start)); + save_item(STRUCT_MEMBER(m_voice, stop)); + save_item(STRUCT_MEMBER(m_voice, loop_start)); + save_item(STRUCT_MEMBER(m_voice, loop_end)); + save_item(STRUCT_MEMBER(m_voice, position)); + save_item(STRUCT_MEMBER(m_voice, signal)); + save_item(STRUCT_MEMBER(m_voice, step)); + save_item(STRUCT_MEMBER(m_voice, loop_signal)); + save_item(STRUCT_MEMBER(m_voice, loop_step)); + save_item(STRUCT_MEMBER(m_voice, loop_count)); + save_item(STRUCT_MEMBER(m_voice, output_left)); + save_item(STRUCT_MEMBER(m_voice, output_right)); + save_item(STRUCT_MEMBER(m_voice, output_pos)); + save_item(STRUCT_MEMBER(m_voice, last_sample)); + save_item(STRUCT_MEMBER(m_voice, curr_sample)); + save_item(STRUCT_MEMBER(m_voice, irq_schedule)); #if YMZ280B_MAKE_WAVS m_wavresample = wav_open("resamp.wav", INTERNAL_SAMPLE_RATE, 2); @@ -638,7 +624,7 @@ void ymz280b_device::device_reset() /* clear other voice parameters */ for (auto &elem : m_voice) { - struct YMZ280BVoice *voice = &elem; + YMZ280BVoice *voice = &elem; voice->curr_sample = 0; voice->last_sample = 0; @@ -648,15 +634,6 @@ void ymz280b_device::device_reset() } -void ymz280b_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - if (id < 8) - update_irq_state_timer_common( id ); - else - throw emu_fatalerror("Unknown id in ymz280b_device::device_timer"); -} - - void ymz280b_device::device_clock_changed() { m_master_clock = (double)clock() / 384.0; @@ -664,7 +641,7 @@ void ymz280b_device::device_clock_changed() } -void ymz280b_device::rom_bank_updated() +void ymz280b_device::rom_bank_pre_change() { m_stream->update(); } @@ -678,13 +655,10 @@ void ymz280b_device::rom_bank_updated() void ymz280b_device::write_to_register(int data) { - struct YMZ280BVoice *voice; - int i; - /* lower registers follow a pattern */ if (m_current_register < 0x80) { - voice = &m_voice[(m_current_register >> 2) & 7]; + YMZ280BVoice *voice = &m_voice[(m_current_register >> 2) & 7]; switch (m_current_register & 0xe3) { @@ -696,8 +670,10 @@ void ymz280b_device::write_to_register(int data) case 0x01: /* pitch upper 1 bit, loop, key on, mode */ voice->fnum = (voice->fnum & 0xff) | ((data & 0x01) << 8); voice->looping = (data & 0x10) >> 4; - if ((data & 0x60) == 0) data &= 0x7f; /* ignore mode setting and set to same state as KON=0 */ - else voice->mode = (data & 0x60) >> 5; + if ((data & 0x60) == 0) + data &= 0x7f; /* ignore mode setting and set to same state as KON=0 */ + else + voice->mode = (data & 0x60) >> 5; if (!voice->keyon && (data & 0x80) && m_keyon_enable) { voice->playing = 1; @@ -831,7 +807,7 @@ void ymz280b_device::write_to_register(int data) if (m_keyon_enable && !(data & 0x80)) { - for (i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { m_voice[i].playing = 0; @@ -841,7 +817,7 @@ void ymz280b_device::write_to_register(int data) } else if (!m_keyon_enable && (data & 0x80)) { - for (i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { if (m_voice[i].keyon && m_voice[i].looping) m_voice[i].playing = 1; @@ -868,17 +844,19 @@ void ymz280b_device::write_to_register(int data) int ymz280b_device::compute_status() { - uint8_t result; + u8 result; /* force an update */ m_stream->update(); result = m_status_register; - /* clear the IRQ state */ - m_status_register = 0; - update_irq_state(); - + if (!machine().side_effects_disabled()) + { + /* clear the IRQ state */ + m_status_register = 0; + update_irq_state(); + } return result; } @@ -898,9 +876,10 @@ u8 ymz280b_device::read(offs_t offset) return 0xff; /* read from external memory */ - uint8_t ret = m_ext_readlatch; + u8 ret = m_ext_readlatch; m_ext_readlatch = read_byte(m_ext_mem_address); - m_ext_mem_address = (m_ext_mem_address + 1) & 0xffffff; + if (!machine().side_effects_disabled()) + m_ext_mem_address = (m_ext_mem_address + 1) & 0xffffff; return ret; } else @@ -924,10 +903,10 @@ void ymz280b_device::write(offs_t offset, u8 data) DEFINE_DEVICE_TYPE(YMZ280B, ymz280b_device, "ymz280b", "Yamaha YMZ280B PCMD8") -ymz280b_device::ymz280b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +ymz280b_device::ymz280b_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, YMZ280B, tag, owner, clock) , device_sound_interface(mconfig, *this) - , device_rom_interface(mconfig, *this, 24) + , device_rom_interface(mconfig, *this) , m_current_register(0) , m_status_register(0) , m_irq_state(0) |