From b8506f31b7d16d2c24d62d829a480e6af3d3e3c0 Mon Sep 17 00:00:00 2001 From: ekeeke31 Date: Tue, 24 Aug 2010 12:48:40 +0000 Subject: [PATCH] .implemented new SN76489 core, using Blargg's blip linear implementation .improved sound chips input clock precision (float->double) --- source/sound/sn76489.c | 504 ++++++++++++++++++++--------------------- source/sound/sn76489.h | 3 +- source/sound/sound.c | 3 +- source/sound/ym2612.c | 6 +- source/sound/ym2612.h | 2 +- source/system.c | 1 + 6 files changed, 247 insertions(+), 272 deletions(-) diff --git a/source/sound/sn76489.c b/source/sound/sn76489.c index 07909d1..619b050 100644 --- a/source/sound/sn76489.c +++ b/source/sound/sn76489.c @@ -21,342 +21,318 @@ 25/04/07 Eke-Eke (Genesis Plus GX) - Removed stereo GG support (unused) - - Made SN76489_Update outputs 16bits mono samples + - Rade SN76489_Update outputs 16bits mono samples - Replaced volume table with VGM plugin's one - - 05/01/09 Eke-Eke (Genesis Plus GX) + + 05/01/09 Eke-Eke (Genesis Plus GX) - Modified Cut-Off frequency (according to Steve Snake: http://www.smspower.org/forums/viewtopic.php?t=1746) - 25/05/09 Eke-Eke (Genesis Plus GX) + 25/05/09 Eke-Eke (Genesis Plus GX) - Removed multichip support (unused) + - Removed alternate volume table, panning & mute support (unused) + - Removed configurable Feedback and Shift Register Width (always use Sega ones) + - Added linear resampling using Blip Buffer (Blargg's implementation: http://www.smspower.org/forums/viewtopic.php?t=11376) */ #include "shared.h" +#include "blip.h" -#include // for FLT_MIN -#include // for memcpy +/* Initial state of shift register */ +#define NoiseInitialState 0x8000 -#define NoiseInitialState 0x8000 /* Initial state of shift register */ -//#define PSG_CUTOFF 0x6 /* Value below which PSG does not output */ -#define PSG_CUTOFF 0x1 +/* Value below which PSG does not output */ +/*#define PSG_CUTOFF 0x6*/ +#define PSG_CUTOFF 0x1 -/* - More testing is needed to find and confirm feedback patterns for - SN76489 variants and compatible chips. -*/ -enum feedback_patterns { - FB_BBCMICRO = 0x8005, /* Texas Instruments TMS SN76489N (original) from BBC Micro computer */ - FB_SC3000 = 0x0006, /* Texas Instruments TMS SN76489AN (rev. A) from SC-3000H computer */ - FB_SEGAVDP = 0x0009, /* SN76489 clone in Sega's VDP chips (315-5124, 315-5246, 315-5313, Game Gear) */ -}; - -enum sr_widths { - SRW_SC3000BBCMICRO = 15, - SRW_SEGAVDP = 16 -}; - -enum volume_modes { - VOL_TRUNC = 0, /* Volume levels 13-15 are identical */ - VOL_FULL = 1, /* Volume levels 13-15 are unique */ -}; - -enum mute_values { - MUTE_ALLOFF = 0, /* All channels muted */ - MUTE_TONE1 = 1, /* Tone 1 mute control */ - MUTE_TONE2 = 2, /* Tone 2 mute control */ - MUTE_TONE3 = 4, /* Tone 3 mute control */ - MUTE_NOISE = 8, /* Noise mute control */ - MUTE_ALLON = 15, /* All channels enabled */ -}; +/* SN76489 clone in Sega's VDP chips (315-5124, 315-5246, 315-5313, Game Gear) */ +#define FB_SEGAVDP 0x0009 +#define SRW_SEGAVDP 16 typedef struct { - int Mute; // per-channel muting - int VolumeArray; - int BoostNoise; // double noise volume when non-zero - - /* Variables */ - float Clock; - float dClock; - int PSGStereo; - int NumClocksForSample; - int WhiteNoiseFeedback; - int SRWidth; - - /* PSG registers: */ - int Registers[8]; /* Tone, vol x4 */ - int LatchedRegister; - int NoiseShiftRegister; - int NoiseFreq; /* Noise channel signal generator frequency */ - - /* Output calculation variables */ - int ToneFreqVals[4]; /* Frequency register values (counters) */ - int ToneFreqPos[4]; /* Frequency channel flip-flops */ - int Channels[4]; /* Value of each channel, before stereo is applied */ - float IntermediatePos[4]; /* intermediate values used at boundaries between + and - (does not need double accuracy)*/ + /* Configuration */ + int BoostNoise; /* double noise volume when non-zero */ - int panning[4]; /* fake stereo - 0..127..254 */ + /* PSG registers: */ + int Registers[8]; /* Tone, vol x4 */ + int LatchedRegister; + int NoiseShiftRegister; + int NoiseFreq; /* Noise channel signal generator frequency */ + /* Output calculation variables */ + int ToneFreqVals[4]; /* Frequency register values (counters) */ + int ToneFreqPos[4]; /* Frequency channel flip-flops */ + int Channels[4]; /* Value of each channel, before stereo is applied */ + + /* Blip-Buffer variables */ + int chan_amp[4]; /* current channel amplitudes in delta buffers */ } SN76489_Context; - -static const int PSGVolumeValues[2][16] = { +static const int PSGVolumeValues[16] = { /* These values are taken from a real SMS2's output */ - {892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, /* I can't remember why 892... :P some scaling I did at some point */ - /* these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1), normalised at 760 */ - {1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0} + /*{892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, */ + /* I can't remember why 892... :P some scaling I did at some point */ + + /* these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1) */ + + 1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0 }; +static struct blip_buffer_t* blip; /* delta resampler */ + static SN76489_Context SN76489; -void SN76489_Init(float PSGClockValue, int SamplingRate) +void SN76489_Init(double PSGClockValue, int SamplingRate) { - SN76489_Context *p = &SN76489; - p->dClock=PSGClockValue/16.0/SamplingRate; - SN76489_Config(MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, config.psgBoostNoise); + SN76489_Shutdown(); + + /* SamplingRate*16 instead of PSGClockValue/16 since division would lose some + precision. blip_alloc doesn't care about the absolute sampling rate, just the + ratio to clock rate. */ + blip = blip_alloc(PSGClockValue, SamplingRate * 16.0, SamplingRate / 4); } -void SN76489_Reset(void) +void SN76489_Reset() { - SN76489_Context *p = &SN76489; - int i; + SN76489_Context *chip = &SN76489; + int i; - p->PSGStereo = 0xFF; + for(i = 0; i <= 3; i++) + { + /* Initialise PSG state */ + chip->Registers[2*i] = 1; /* tone freq=1 */ + chip->Registers[2*i+1] = 0xf; /* vol=off */ - for(i = 0; i <= 3; i++) - { - /* Initialise PSG state */ - p->Registers[2*i] = 1; /* tone freq=1 */ - p->Registers[2*i+1] = 0xf; /* vol=off */ - p->NoiseFreq = 0x10; + /* Set counters to 0 */ + chip->ToneFreqVals[i] = 0; - /* Set counters to 0 */ - p->ToneFreqVals[i] = 0; + /* Set flip-flops to 1 */ + chip->ToneFreqPos[i] = 1; - /* Set flip-flops to 1 */ - p->ToneFreqPos[i] = 1; + /* Clear channels output */ + chip->Channels[i] = 0; - /* Set intermediate positions to do-not-use value */ - p->IntermediatePos[i] = FLT_MIN; + /* Clear current amplitudes in delta buffer */ + chip->chan_amp[i] = 0; + } - /* Set panning to centre */ - p->panning[0]=127; - } + chip->LatchedRegister=0; - p->LatchedRegister=0; - - /* Initialise noise generator */ - p->NoiseShiftRegister=NoiseInitialState; - - /* Zero clock */ - p->Clock=0; + /* Initialise noise generator */ + chip->NoiseShiftRegister=NoiseInitialState; + chip->NoiseFreq = 0x10; + /* Clear Blip delta buffer */ + if (blip) blip_clear(blip); } void SN76489_Shutdown(void) { + if (blip) blip_free(blip); + blip = NULL; } void SN76489_BoostNoise(int boost) { SN76489.BoostNoise = boost; -} - -void SN76489_Config(int mute, int volume, int feedback, int sr_width, int boost_noise) -{ - SN76489_Context *p = &SN76489; - - p->Mute = mute; - p->VolumeArray = volume; - p->WhiteNoiseFeedback = feedback; - p->SRWidth = sr_width; - p->BoostNoise = boost_noise; + SN76489.Channels[3]= PSGVolumeValues[SN76489.Registers[7]] << boost; } void SN76489_SetContext(uint8 *data) { - memcpy(&SN76489, data, sizeof(SN76489_Context)); + memcpy(&SN76489, data, sizeof(SN76489_Context)); } void SN76489_GetContext(uint8 *data) { - memcpy(data, &SN76489, sizeof(SN76489_Context)); + memcpy(data, &SN76489, sizeof(SN76489_Context)); } uint8 *SN76489_GetContextPtr(void) { - return (uint8 *)&SN76489; + return (uint8 *)&SN76489; } int SN76489_GetContextSize(void) { - return sizeof(SN76489_Context); + return sizeof(SN76489_Context); } void SN76489_Write(int data) { - SN76489_Context *p = &SN76489; + SN76489_Context *chip = &SN76489; - if (data&0x80) { - /* Latch/data byte %1 cc t dddd */ - p->LatchedRegister=((data>>4)&0x07); - p->Registers[p->LatchedRegister]= - (p->Registers[p->LatchedRegister] & 0x3f0) /* zero low 4 bits */ - | (data&0xf); /* and replace with data */ - } else { - /* Data byte %0 - dddddd */ - if (!(p->LatchedRegister%2)&&(p->LatchedRegister<5)) - /* Tone register */ - p->Registers[p->LatchedRegister]= - (p->Registers[p->LatchedRegister] & 0x00f) /* zero high 6 bits */ - | ((data&0x3f)<<4); /* and replace with data */ - else - /* Other register */ - p->Registers[p->LatchedRegister]=data&0x0f; /* Replace with data */ - } - switch (p->LatchedRegister) { - case 0: - case 2: + if (data & 0x80) + { + /* Latch byte %1 cc t dddd */ + chip->LatchedRegister = (data >> 4) & 0x07; + } + + int LatchedRegister = chip->LatchedRegister; + + switch (LatchedRegister) + { + case 0: + case 2: case 4: /* Tone channels */ - if (p->Registers[p->LatchedRegister]==0) p->Registers[p->LatchedRegister]=1; /* Zero frequency changed to 1 to avoid div/0 */ - break; + if (data & 0x80) + { + /* Data byte %1 cc t dddd */ + chip->Registers[LatchedRegister] = (chip->Registers[LatchedRegister] & 0x3f0) | (data & 0xf); + } + else + { + /* Data byte %0 - dddddd */ + chip->Registers[LatchedRegister] = (chip->Registers[LatchedRegister] & 0x00f) | ((data & 0x3f) << 4); + } + /* Zero frequency changed to 1 to avoid div/0 */ + if (chip->Registers[LatchedRegister] == 0) chip->Registers[LatchedRegister] = 1; + break; + + case 1: + case 3: + case 5: /* Channel attenuation */ + chip->Registers[LatchedRegister] = data & 0x0f; + chip->Channels[LatchedRegister>>1] = PSGVolumeValues[data&0x0f]; + break; + case 6: /* Noise */ - p->NoiseShiftRegister=NoiseInitialState; /* reset shift register */ - p->NoiseFreq=0x10<<(p->Registers[6]&0x3); /* set noise signal generator frequency */ - break; - } + chip->Registers[6] = data & 0x0f; + chip->NoiseShiftRegister = NoiseInitialState; /* reset shift register */ + chip->NoiseFreq = 0x10 << (data&0x3); /* set noise signal generator frequency */ + break; + + case 7: /* Noise attenuation */ + chip->Registers[7] = data&0x0f; + chip->Channels[3] = PSGVolumeValues[data&0x0f] << chip->BoostNoise; + break; + } } -void SN76489_GGStereoWrite(int data) +/* Updates tone amplitude in delta buffer. Call whenever amplitude might have changed. */ +static void UpdateToneAmplitude(SN76489_Context* chip, int i, int time) { - SN76489_Context *p = &SN76489; - p->PSGStereo=data; + int delta = (chip->Channels[i] * chip->ToneFreqPos[i]) - chip->chan_amp[i]; + if (delta != 0) + { + chip->chan_amp[i] += delta; + blip_add(blip, time, delta); + } +} + +/* Updates noise amplitude in delta buffer. Call whenever amplitude might have changed. */ +static void UpdateNoiseAmplitude(SN76489_Context* chip, int time) +{ + int delta = (chip->Channels[3] * ( chip->NoiseShiftRegister & 0x1 )) - chip->chan_amp[3]; + if (delta != 0) + { + chip->chan_amp[3] += delta; + blip_add(blip, time, delta); + } +} + +/* Runs tone channel for clock_length clocks */ +static void RunTone(SN76489_Context* chip, int i, int clock_length) + +{ + int time; + + /* Update in case a register changed etc. */ + UpdateToneAmplitude(chip, i, 0); + + /* Time of next transition */ + time = chip->ToneFreqVals[i]; + + /* Process any transitions that occur within clocks we're running */ + while (time < clock_length) + { + if (chip->Registers[i*2]>PSG_CUTOFF) { + /* Flip the flip-flop */ + chip->ToneFreqPos[i] = -chip->ToneFreqPos[i]; + } else { + /* stuck value */ + chip->ToneFreqPos[i] = 1; + } + UpdateToneAmplitude(chip, i, time); + + /* Advance to time of next transition */ + time += chip->Registers[i*2]; + } + + /* Calculate new value for register, now that next transition is past number of clocks we're running */ + chip->ToneFreqVals[i] = time - clock_length; +} + +/* Runs noise channel for clock_length clocks */ +static void RunNoise(SN76489_Context* chip, int clock_length) + +{ + int time; + + /* Noise channel: match to tone2 if in slave mode */ + int NoiseFreq = chip->NoiseFreq; + if (NoiseFreq == 0x80) + { + NoiseFreq = chip->Registers[2*2]; + chip->ToneFreqVals[3] = chip->ToneFreqVals[2]; + } + + /* Update in case a register changed etc. */ + UpdateNoiseAmplitude(chip, 0); + + /* Time of next transition */ + time = chip->ToneFreqVals[3]; + + /* Process any transitions that occur within clocks we're running */ + while ( time < clock_length ) + { + /* Flip the flip-flop */ + chip->ToneFreqPos[3] = -chip->ToneFreqPos[3]; + if (chip->ToneFreqPos[3] == 1) + { + /* On the positive edge of the square wave (only once per cycle) */ + int Feedback = chip->NoiseShiftRegister; + if ( chip->Registers[6] & 0x4 ) + { + /* White noise */ + /* Calculate parity of fed-back bits for feedback */ + /* Do some optimised calculations for common (known) feedback values */ + /* If two bits fed back, I can do Feedback=(nsr & fb) && (nsr & fb ^ fb) */ + /* since that's (one or more bits set) && (not all bits set) */ + Feedback = ((Feedback & FB_SEGAVDP) && ((Feedback & FB_SEGAVDP) ^ FB_SEGAVDP)); + } + else /* Periodic noise */ + Feedback = Feedback & 1; + + chip->NoiseShiftRegister = (chip->NoiseShiftRegister >> 1) | (Feedback << (SRW_SEGAVDP - 1)); + UpdateNoiseAmplitude(chip, time); + } + + /* Advance to time of next transition */ + time += NoiseFreq; + } + + /* Calculate new value for register, now that next transition is past number of clocks we're running */ + chip->ToneFreqVals[3] = time - clock_length; } void SN76489_Update(INT16 *buffer, int length) { - SN76489_Context *p = &SN76489; - int i, j; + int i; - for(j = 0; j < length; j++) - { - for (i=0;i<=2;++i) - if (p->IntermediatePos[i]!=FLT_MIN) - p->Channels[i]=(short)((p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->IntermediatePos[i]); - else - p->Channels[i]=(p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->ToneFreqPos[i]; - - p->Channels[3]=(short)((p->Mute >> 3 & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[7]]*(p->NoiseShiftRegister & 0x1)); - - if (p->BoostNoise) p->Channels[3]<<=1; /* double noise volume */ - - buffer[j] =0; - for (i=0;i<=3;++i) buffer[j] += p->Channels[i]; - - p->Clock+=p->dClock; - p->NumClocksForSample=(int)p->Clock; /* truncates */ - p->Clock-=p->NumClocksForSample; /* remove integer part */ - /* Looks nicer in Delphi... */ - /* Clock:=Clock+p->dClock; */ - /* NumClocksForSample:=Trunc(Clock); */ - /* Clock:=Frac(Clock); */ - - /* Decrement tone channel counters */ - for (i=0;i<=2;++i) - p->ToneFreqVals[i]-=p->NumClocksForSample; - - /* Noise channel: match to tone2 or decrement its counter */ - if (p->NoiseFreq==0x80) p->ToneFreqVals[3]=p->ToneFreqVals[2]; - else p->ToneFreqVals[3]-=p->NumClocksForSample; - - /* Tone channels: */ - for (i=0;i<=2;++i) { - if (p->ToneFreqVals[i]<=0) { /* If it gets below 0... */ - if (p->Registers[i*2]>PSG_CUTOFF) { - /* Calculate how much of the sample is + and how much is - */ - /* Go to floating point and include the clock fraction for extreme accuracy :D */ - /* Store as long int, maybe it's faster? I'm not very good at this */ - p->IntermediatePos[i]=(p->NumClocksForSample-p->Clock+2*p->ToneFreqVals[i])*p->ToneFreqPos[i]/(p->NumClocksForSample+p->Clock); - p->ToneFreqPos[i]=-p->ToneFreqPos[i]; /* Flip the flip-flop */ - } else { - p->ToneFreqPos[i]=1; /* stuck value */ - p->IntermediatePos[i]=FLT_MIN; - } - p->ToneFreqVals[i]+=p->Registers[i*2]*(p->NumClocksForSample/p->Registers[i*2]+1); - } else p->IntermediatePos[i]=FLT_MIN; - } - - /* Noise channel */ - if (p->ToneFreqVals[3]<=0) { /* If it gets below 0... */ - p->ToneFreqPos[3]=-p->ToneFreqPos[3]; /* Flip the flip-flop */ - if (p->NoiseFreq!=0x80) /* If not matching tone2, decrement counter */ - p->ToneFreqVals[3]+=p->NoiseFreq*(p->NumClocksForSample/p->NoiseFreq+1); - if (p->ToneFreqPos[3]==1) { /* Only once per cycle... */ - int Feedback; - if (p->Registers[6]&0x4) { /* White noise */ - /* Calculate parity of fed-back bits for feedback */ - switch (p->WhiteNoiseFeedback) { - /* Do some optimised calculations for common (known) feedback values */ - case 0x0003: /* SC-3000, BBC %00000011 */ - case 0x0009: /* SMS, GG, MD %00001001 */ - /* If two bits fed back, I can do Feedback=(nsr & fb) && (nsr & fb ^ fb) */ - /* since that's (one or more bits set) && (not all bits set) */ - Feedback=((p->NoiseShiftRegister&p->WhiteNoiseFeedback) && ((p->NoiseShiftRegister&p->WhiteNoiseFeedback)^p->WhiteNoiseFeedback)); - break; - default: /* Default handler for all other feedback values */ - Feedback=p->NoiseShiftRegister&p->WhiteNoiseFeedback; - Feedback^=Feedback>>8; - Feedback^=Feedback>>4; - Feedback^=Feedback>>2; - Feedback^=Feedback>>1; - Feedback&=1; - break; - } - } else /* Periodic noise */ - Feedback=p->NoiseShiftRegister&1; - - p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | (Feedback << (p->SRWidth-1)); - - /* Original code: */ - /* p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | ((p->Registers[6]&0x4?((p->NoiseShiftRegister&0x9) && (p->NoiseShiftRegister&0x9^0x9)):p->NoiseShiftRegister&1)<<15); */ - } - } - } -} - -/*void SN76489_UpdateOne(int which, int *l, int *r) -{ - INT16 tl,tr; - INT16 *buff[2]={&tl,&tr}; - SN76489_Update(which,buff,1); - *l=tl; - *r=tr; -}*/ - -int SN76489_GetMute() -{ - return SN76489.Mute; -} - -void SN76489_SetMute(int val) -{ - SN76489.Mute=val; -} - -int SN76489_GetVolType() -{ - return SN76489.VolumeArray; -} - -void SN76489_SetVolType(int val) -{ - SN76489.VolumeArray=val; -} - -void SN76489_SetPanning(int ch0, int ch1, int ch2, int ch3) -{ - SN76489.panning[0]=ch0; - SN76489.panning[1]=ch1; - SN76489.panning[2]=ch2; - SN76489.panning[3]=ch3; + SN76489_Context *chip = &SN76489; + + /* Determine how many clocks we need to run until 'length' samples are available */ + int clock_length = blip_clocks_needed(blip, length); + + /* Run noise first, since it might use current value of third tone frequency counter */ + RunNoise(chip, clock_length); + + /* Run tone channels */ + for( i = 0; i <= 2; ++i ) + RunTone(chip, i, clock_length); + + /* Read samples into output buffer */ + blip_end_frame(blip, clock_length); + blip_read_samples(blip, buffer, length, 0); } diff --git a/source/sound/sn76489.h b/source/sound/sn76489.h index 958e158..fec46d9 100644 --- a/source/sound/sn76489.h +++ b/source/sound/sn76489.h @@ -16,7 +16,7 @@ #define _SN76489_H_ /* Function prototypes */ -extern void SN76489_Init(float PSGClockValue, int SamplingRate); +extern void SN76489_Init(double PSGClockValue, int SamplingRate); extern void SN76489_Reset(void); extern void SN76489_Shutdown(void); extern void SN76489_SetContext(uint8 *data); @@ -26,7 +26,6 @@ extern int SN76489_GetContextSize(void); extern void SN76489_Write(int data); extern void SN76489_Update(INT16 *buffer, int length); extern void SN76489_BoostNoise(int boost); -extern void SN76489_Config(int mute, int volume, int feedback, int sr_width, int boost_noise); #endif /* _SN76489_H_ */ diff --git a/source/sound/sound.c b/source/sound/sound.c index 1fb868c..9c44463 100644 --- a/source/sound/sound.c +++ b/source/sound/sound.c @@ -230,8 +230,7 @@ void fm_reset(unsigned int cycles) /* Write FM chip */ void fm_write(unsigned int cycles, unsigned int address, unsigned int data) { - if (address & 1) - fm_update(cycles << 11); + if (address & 1) fm_update(cycles << 11); YM2612Write(address, data); } diff --git a/source/sound/ym2612.c b/source/sound/ym2612.c index 55b1c6f..1a12cdb 100644 --- a/source/sound/ym2612.c +++ b/source/sound/ym2612.c @@ -549,7 +549,7 @@ typedef struct typedef struct { - float clock; /* master clock (Hz) */ + double clock; /* master clock (Hz) */ UINT32 rate; /* sampling rate (Hz) */ UINT16 address; /* address register */ UINT8 status; /* status flag */ @@ -1921,7 +1921,7 @@ static void init_tables(void) /* initialize ym2612 emulator(s) */ -int YM2612Init(float clock, int rate) +int YM2612Init(double clock, int rate) { memset(&ym2612,0,sizeof(YM2612)); init_tables(); @@ -2172,7 +2172,7 @@ unsigned int YM2612GetContextSize(void) void YM2612Restore(unsigned char *buffer) { /* save current timings */ - float clock = ym2612.OPN.ST.clock; + double clock = ym2612.OPN.ST.clock; int rate = ym2612.OPN.ST.rate; /* restore internal state */ diff --git a/source/sound/ym2612.h b/source/sound/ym2612.h index b09b713..b04a6b0 100644 --- a/source/sound/ym2612.h +++ b/source/sound/ym2612.h @@ -19,7 +19,7 @@ #endif -extern int YM2612Init(float clock, int rate); +extern int YM2612Init(double clock, int rate); extern int YM2612ResetChip(void); extern void YM2612Update(long int *buffer, int length); extern void YM2612Write(unsigned int a, unsigned int v); diff --git a/source/system.c b/source/system.c index ca3c75a..308b9cf 100644 --- a/source/system.c +++ b/source/system.c @@ -311,6 +311,7 @@ void system_shutdown (void) gen_shutdown (); vdp_shutdown (); render_shutdown (); + SN76489_Shutdown (); } /****************************************************************