summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/ymz280b.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/ymz280b.cpp')
-rw-r--r--src/devices/sound/ymz280b.cpp213
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)