From 85cc09e07f7451ca0675ab4e929e7b956861cf8b Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Mon, 24 Feb 2014 16:38:46 -0800 Subject: [PATCH] Updated and fixed VGM OKIM6258 support from VGMPlay 0.40.4 --- Frameworks/GME/gme/Okim6258_Emu.cpp | 5 ++ Frameworks/GME/gme/Okim6258_Emu.h | 3 + Frameworks/GME/gme/Vgm_Core.cpp | 59 ++++++++---- Frameworks/GME/gme/Vgm_Core.h | 6 +- Frameworks/GME/gme/okim6258.c | 133 ++++++++++++++++++++++++---- 5 files changed, 169 insertions(+), 37 deletions(-) diff --git a/Frameworks/GME/gme/Okim6258_Emu.cpp b/Frameworks/GME/gme/Okim6258_Emu.cpp index dce5c6552..ff4f5d631 100644 --- a/Frameworks/GME/gme/Okim6258_Emu.cpp +++ b/Frameworks/GME/gme/Okim6258_Emu.cpp @@ -36,6 +36,11 @@ void Okim6258_Emu::write( int addr, int data ) okim6258_write( chip, addr, data ); } +int Okim6258_Emu::get_clock() +{ + return okim6258_get_vclk( chip ); +} + void Okim6258_Emu::run( int pair_count, sample_t* out ) { stream_sample_t bufL[ 1024 ]; diff --git a/Frameworks/GME/gme/Okim6258_Emu.h b/Frameworks/GME/gme/Okim6258_Emu.h index 9e91d5c79..5de3ba4f3 100644 --- a/Frameworks/GME/gme/Okim6258_Emu.h +++ b/Frameworks/GME/gme/Okim6258_Emu.h @@ -16,6 +16,9 @@ public: // Resets to power-up state void reset(); + + // Returns current sample rate of the chip + int get_clock(); // Writes data to addr void write( int addr, int data ); diff --git a/Frameworks/GME/gme/Vgm_Core.cpp b/Frameworks/GME/gme/Vgm_Core.cpp index 4dfd6de42..623871b88 100644 --- a/Frameworks/GME/gme/Vgm_Core.cpp +++ b/Frameworks/GME/gme/Vgm_Core.cpp @@ -197,9 +197,19 @@ int Vgm_Core::run_pwm( int time ) return pwm.run_until( time ); } -int Vgm_Core::run_okim6258( int time ) +int Vgm_Core::run_okim6258( int chip, int time ) { - return okim6258.run_until( time ); + chip = !!chip; + if ( okim6258[chip].enabled() ) + { + int current_clock = okim6258[chip].get_clock(); + if ( okim6258_hz[chip] != current_clock ) + { + okim6258_hz[chip] = current_clock; + okim6258[chip].setup( (double)okim6258_hz[chip] / vgm_rate, 0.85, 1.0 ); + } + } + return okim6258[chip].run_until( time ); } int Vgm_Core::run_okim6295( int chip, int time ) @@ -703,8 +713,8 @@ void Vgm_Core::chip_reg_write(unsigned Sample, byte ChipType, byte ChipID, byte break; case 0x17: - if ( run_okim6258( to_fm_time( Sample ) ) ) - okim6258.write( Offset, Data ); + if ( run_okim6258( ChipID, to_fm_time( Sample ) ) ) + okim6258[ChipID].write( Offset, Data ); break; case 0x18: @@ -898,7 +908,8 @@ blargg_err_t Vgm_Core::load_mem_( byte const data [], int size ) rf5c68.enable( false ); rf5c164.enable( false ); pwm.enable( false ); - okim6258.enable( false ); + okim6258[0].enable( false ); + okim6258[1].enable( false ); okim6295[0].enable( false ); okim6295[1].enable( false ); k051649.enable( false ); @@ -1234,13 +1245,24 @@ blargg_err_t Vgm_Core::init_chips( double* rate, bool reinit ) } if ( okim6258_rate ) { + bool dual_chip = !!( header().okim6258_rate[3] & 0x40 ); if ( !reinit ) { - okim6258_hz = okim6258.set_rate( okim6258_rate, header().okim6258_flags & 0x03, ( header().okim6258_flags & 0x04 ) >> 2, ( header().okim6258_flags & 0x08 ) >> 3 ); - CHECK_ALLOC( okim6258_hz ); + okim6258_hz[0] = okim6258[0].set_rate( okim6258_rate, header().okim6258_flags & 0x03, ( header().okim6258_flags & 0x04 ) >> 2, ( header().okim6258_flags & 0x08 ) >> 3 ); + CHECK_ALLOC( okim6258_hz[0] ); } - RETURN_ERR( okim6258.setup( (double)okim6258_hz / vgm_rate, 0.85, 1.0 ) ); - okim6258.enable(); + RETURN_ERR( okim6258[0].setup( (double)okim6258_hz[0] / vgm_rate, 0.85, 1.0 ) ); + okim6258[0].enable(); + if ( dual_chip ) + { + if ( !reinit ) + { + okim6258_hz[1] = okim6258[1].set_rate( okim6258_rate, header().okim6258_flags & 0x03, ( header().okim6258_flags & 0x04 ) >> 2, ( header().okim6258_flags & 0x08 ) >> 3 ); + CHECK_ALLOC( okim6258_hz[1] ); + } + RETURN_ERR( okim6258[1].setup( (double)okim6258_hz[1] / vgm_rate, 0.85, 1.0 ) ); + okim6258[1].enable(); + } } if ( okim6295_rate ) { @@ -1384,8 +1406,11 @@ void Vgm_Core::start_track() if ( pwm.enabled() ) pwm.reset(); - if ( okim6258.enabled() ) - okim6258.reset(); + if ( okim6258[0].enabled() ) + okim6258[0].reset(); + + if ( okim6258[1].enabled() ) + okim6258[1].reset(); if ( okim6295[0].enabled() ) okim6295[0].reset(); @@ -1757,7 +1782,7 @@ blip_time_t Vgm_Core::run( vgm_time_t end_time ) break; case cmd_okim6258_write: - chip_reg_write( vgm_time, 0x17, 0x00, 0x00, pos [0] & 0x7F, pos [1] ); + chip_reg_write( vgm_time, 0x17, ChipID, 0x00, pos [0] & 0x7F, pos [1] ); pos += 2; break; @@ -2157,9 +2182,13 @@ int Vgm_Core::play_frame( blip_time_t blip_time, int sample_count, blip_sample_t { pwm.begin_frame( out ); } - if ( okim6258.enabled() ) + if ( okim6258[0].enabled() ) { - okim6258.begin_frame( out ); + okim6258[0].begin_frame( out ); + if ( okim6258[1].enabled() ) + { + okim6258[1].begin_frame( out ); + } } if ( okim6295[0].enabled() ) { @@ -2211,7 +2240,7 @@ int Vgm_Core::play_frame( blip_time_t blip_time, int sample_count, blip_sample_t run_rf5c68( pairs ); run_rf5c164( pairs ); run_pwm( pairs ); - run_okim6258( pairs ); + run_okim6258( 0, pairs ); run_okim6258( 1, pairs ); run_okim6295( 0, pairs ); run_okim6295( 1, pairs ); run_k051649( pairs ); run_k053260( pairs ); diff --git a/Frameworks/GME/gme/Vgm_Core.h b/Frameworks/GME/gme/Vgm_Core.h index c5c53ea7c..213f17994 100644 --- a/Frameworks/GME/gme/Vgm_Core.h +++ b/Frameworks/GME/gme/Vgm_Core.h @@ -150,7 +150,7 @@ public: // True if any FM chips are used by file. Always false until init_fm() // is called. bool uses_fm() const { return ym2612[0].enabled() || ym2413[0].enabled() || ym2151[0].enabled() || c140.enabled() || - segapcm.enabled() || rf5c68.enabled() || rf5c164.enabled() || pwm.enabled() || okim6258.enabled() || okim6295[0].enabled() || + segapcm.enabled() || rf5c68.enabled() || rf5c164.enabled() || pwm.enabled() || okim6258[0].enabled() || okim6295[0].enabled() || k051649.enabled() || k053260.enabled() || k054539.enabled() || ym2203[0].enabled() || ym3812[0].enabled() || ymf262[0].enabled() || ymz280b.enabled() || ym2610[0].enabled() || ym2608[0].enabled() || qsound[0].enabled() || (header().ay8910_rate[0] | header().ay8910_rate[1] | header().ay8910_rate[2] | header().ay8910_rate[3]) || @@ -205,7 +205,7 @@ public: Chip_Resampler_Emu rf5c68; Chip_Resampler_Emu rf5c164; Chip_Resampler_Emu pwm; - Chip_Resampler_Emu okim6258; int okim6258_hz; + Chip_Resampler_Emu okim6258[2]; int okim6258_hz[2]; Chip_Resampler_Emu okim6295[2]; int okim6295_hz; Chip_Resampler_Emu k051649; Chip_Resampler_Emu k053260; @@ -334,7 +334,7 @@ private: int run_rf5c68( int time ); int run_rf5c164( int time ); int run_pwm( int time ); - int run_okim6258( int time ); + int run_okim6258( int chip, int time ); int run_okim6295( int chip, int time ); int run_k051649( int time ); int run_k053260( int time ); diff --git a/Frameworks/GME/gme/okim6258.c b/Frameworks/GME/gme/okim6258.c index 351743f46..63d3e4312 100644 --- a/Frameworks/GME/gme/okim6258.c +++ b/Frameworks/GME/gme/okim6258.c @@ -42,10 +42,24 @@ struct _okim6258_state UINT8 output_bits; + // Valley Bell: Added a small queue to prevent race conditions. + UINT8 data_buf[2]; + UINT8 data_buf_pos; + // Data Empty Values: + // 00 - data written, but not read yet + // 01 - read data, waiting for next write + // 02 - tried to read, but had no data + UINT8 data_empty; + // Valley Bell: Added pan + UINT8 pan; + INT32 last_smpl; + INT32 signal; INT32 step; UINT8 clock_buffer[0x04]; + UINT32 initial_clock; + UINT8 initial_div; }; /* step size index shift table */ @@ -144,29 +158,68 @@ void okim6258_update(void *_chip, stream_sample_t **outputs, int samples) //stream_sample_t *buffer = outputs[0]; stream_sample_t *bufL = outputs[0]; stream_sample_t *bufR = outputs[1]; - + //memset(outputs[0], 0, samples * sizeof(*outputs[0])); - + if (chip->status & STATUS_PLAYING) { int nibble_shift = chip->nibble_shift; - + while (samples) { /* Compute the new amplitude and update the current step */ - int nibble = (chip->data_in >> nibble_shift) & 0xf; - + //int nibble = (chip->data_in >> nibble_shift) & 0xf; + int nibble; + INT16 sample; + + if (! nibble_shift) + { + // 1st nibble - get data + if (! chip->data_empty) + { + chip->data_in = chip->data_buf[chip->data_buf_pos >> 4]; + chip->data_buf_pos ^= 0x10; + if ((chip->data_buf_pos >> 4) == (chip->data_buf_pos & 0x0F)) + chip->data_empty ++; + } + else + { + chip->data_in = 0x80; + if (chip->data_empty < 0x80) + chip->data_empty ++; + } + } + nibble = (chip->data_in >> nibble_shift) & 0xf; + /* Output to the buffer */ - INT16 sample = clock_adpcm(chip, nibble); - + //INT16 sample = clock_adpcm(chip, nibble); + if (chip->data_empty < 0x02) + { + sample = clock_adpcm(chip, nibble); + chip->last_smpl = sample; + } + else + { + sample = chip->last_smpl; + // Valley Bell: data_empty behaviour (loosely) ported from XM6 + if (chip->data_empty >= 0x12) + { + chip->data_empty -= 0x10; + if (chip->signal < 0) + chip->signal ++; + else if (chip->signal > 0) + chip->signal --; + } + } + nibble_shift ^= 4; - + //*buffer++ = sample; - *bufL++ = sample; - *bufR++ = sample; + *bufL++ = (chip->pan & 0x02) ? 0x00 : sample; + *bufR++ = (chip->pan & 0x01) ? 0x00 : sample; samples--; } - + /* Update the parameters */ chip->nibble_shift = nibble_shift; } @@ -220,6 +273,8 @@ void * device_start_okim6258(int clock, int divider, int adpcm_type, int output_ compute_tables(); //info->master_clock = device->clock(); + info->initial_clock = clock; + info->initial_div = divider; info->master_clock = clock; info->adpcm_type = /*intf->*/adpcm_type; info->clock_buffer[0x00] = (clock & 0x000000FF) >> 0; @@ -263,9 +318,24 @@ void device_reset_okim6258(void *chip) //stream_update(info->stream); + info->master_clock = info->initial_clock; + info->clock_buffer[0x00] = (info->initial_clock & 0x000000FF) >> 0; + info->clock_buffer[0x01] = (info->initial_clock & 0x0000FF00) >> 8; + info->clock_buffer[0x02] = (info->initial_clock & 0x00FF0000) >> 16; + info->clock_buffer[0x03] = (info->initial_clock & 0xFF000000) >> 24; + info->divider = dividers[info->initial_div]; + + info->signal = -2; info->step = 0; info->status = 0; + + // Valley Bell: Added reset of the Data In register. + info->data_in = 0x00; + info->data_buf[0] = info->data_buf[1] = 0x00; + info->data_buf_pos = 0x00; + info->data_empty = 0xFF; + info->pan = 0x00; } @@ -357,8 +427,17 @@ void okim6258_data_w(void *chip, offs_t offset, UINT8 data) /* update the stream */ //stream_update(info->stream); - info->data_in = data; - info->nibble_shift = 0; + //info->data_in = data; + //info->nibble_shift = 0; + + if (info->data_empty >= 0x02) + { + info->data_buf_pos = 0x00; + info->data_buf[info->data_buf_pos & 0x0F] = 0x80; + } + info->data_buf[info->data_buf_pos & 0x0F] = data; + info->data_buf_pos ^= 0x01; + info->data_empty = 0x00; } @@ -381,24 +460,27 @@ void okim6258_ctrl_w(void *chip, offs_t offset, UINT8 data) info->status &= ~(STATUS_PLAYING | STATUS_RECORDING); return; } - + if (data & COMMAND_PLAY) { if (!(info->status & STATUS_PLAYING)) { info->status |= STATUS_PLAYING; - + /* Also reset the ADPCM parameters */ - info->signal = -2; - info->step = 0; - info->nibble_shift = 0; + //info->signal = -2; + //info->step = 0; + //info->nibble_shift = 0; } + //info->signal = -2; + info->step = 0; + info->nibble_shift = 0; } else { info->status &= ~STATUS_PLAYING; } - + if (data & COMMAND_RECORD) { /*logerror("M6258: Record enabled\n");*/ @@ -419,6 +501,16 @@ void okim6258_set_clock_byte(void *chip, UINT8 Byte, UINT8 val) return; } +static void okim6258_pan_w(void *chip, UINT8 data) +{ + okim6258_state *info = (okim6258_state *) chip; + + info->pan = data; + + return; +} + + void okim6258_write(void *chip, UINT8 Port, UINT8 Data) { switch(Port) @@ -429,6 +521,9 @@ void okim6258_write(void *chip, UINT8 Port, UINT8 Data) case 0x01: okim6258_data_w(chip, 0x00, Data); break; + case 0x02: + okim6258_pan_w(chip, Data); + break; case 0x08: case 0x09: case 0x0A: