From fbdbd2491d6360fb6138caa1ac79ae89efa50079 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Mon, 9 Sep 2019 11:32:03 +0200 Subject: [PATCH] aica: implement pitch LFO and LPF envelope simplify channel serialization optimize aica channel reg write callbacks --- core/hw/aica/aica_mem.cpp | 17 +- core/hw/aica/sgc_if.cpp | 447 ++++++++++++++++++++++++++------------ core/hw/aica/sgc_if.h | 6 +- core/serialize.cpp | 19 +- core/types.h | 14 ++ 5 files changed, 334 insertions(+), 169 deletions(-) diff --git a/core/hw/aica/aica_mem.cpp b/core/hw/aica/aica_mem.cpp index 533c023cc..12ae99e29 100644 --- a/core/hw/aica/aica_mem.cpp +++ b/core/hw/aica/aica_mem.cpp @@ -39,19 +39,10 @@ void WriteReg(u32 addr,u32 data) if (addr < 0x2000) { //Channel data - u32 chan=addr>>7; - u32 reg=addr&0x7F; - if (sz==1) - { - WriteMemArr(aica_reg,addr,data,1); - WriteChannelReg8(chan,reg); - } - else - { - WriteMemArr(aica_reg,addr,data,2); - WriteChannelReg8(chan,reg); - WriteChannelReg8(chan,reg+1); - } + u32 chan = addr >> 7; + u32 reg = addr & 0x7F; + WriteMemArr(aica_reg, addr, data, sz); + WriteChannelReg(chan, reg, sz); return; } diff --git a/core/hw/aica/sgc_if.cpp b/core/hw/aica/sgc_if.cpp index 51665095e..20fc33fae 100755 --- a/core/hw/aica/sgc_if.cpp +++ b/core/hw/aica/sgc_if.cpp @@ -1,3 +1,23 @@ +/* + This file is part of reicast. + + reicast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + reicast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with reicast. If not, see . + + Some PLFO and FEG code from Highly_Theoretical lib by Neill Corlett + (https://github.com/kode54/Highly_Theoretical) + */ + #include "sgc_if.h" #include "dsp.h" #include "aica_mem.h" @@ -10,6 +30,7 @@ using namespace std; //#define CLIP_WARN #define key_printf(...) DEBUG_LOG(AICA, __VA_ARGS__) #define aeg_printf(...) DEBUG_LOG(AICA, __VA_ARGS__) +#define feg_printf(...) DEBUG_LOG(AICA, __VA_ARGS__) #define step_printf(...) DEBUG_LOG(AICA, __VA_ARGS__) #ifdef CLIP_WARN @@ -23,30 +44,36 @@ using namespace std; s32 volume_lut[16]; //255 -> mute //Converts Send levels to TL-compatible values (DISDL, etc) -u32 SendLevel[16]={255,14<<3,13<<3,12<<3,11<<3,10<<3,9<<3,8<<3,7<<3,6<<3,5<<3,4<<3,3<<3,2<<3,1<<3,0<<3}; +static const u32 SendLevel[16] = +{ + 255, 14 << 3, 13 << 3, 12 << 3, 11 << 3, 10 << 3, 9 << 3, 8 << 3, + 7 << 3, 6 << 3, 5 << 3, 4 << 3, 3 << 3, 2 << 3, 1 << 3, 0 << 3 +}; s32 tl_lut[256 + 768]; //xx.15 format. >=255 is muted //in ms :) -double AEG_Attack_Time[]= +static const double AEG_Attack_Time[]= { -1,-1,8100.0,6900.0,6000.0,4800.0,4000.0,3400.0,3000.0,2400.0,2000.0,1700.0,1500.0, 1200.0,1000.0,860.0,760.0,600.0,500.0,430.0,380.0,300.0,250.0,220.0,190.0,150.0,130.0,110.0,95.0, 76.0,63.0,55.0,47.0,38.0,31.0,27.0,24.0,19.0,15.0,13.0,12.0,9.4,7.9,6.8,6.0,4.7,3.8,3.4,3.0,2.4, 2.0,1.8,1.6,1.3,1.1,0.93,0.85,0.65,0.53,0.44,0.40,0.35,0.0,0.0 }; -double AEG_DSR_Time[]= +static const double AEG_DSR_Time[]= { -1,-1,118200.0,101300.0,88600.0,70900.0,59100.0,50700.0,44300.0,35500.0,29600.0,25300.0,22200.0,17700.0, 14800.0,12700.0,11100.0,8900.0,7400.0,6300.0,5500.0,4400.0,3700.0,3200.0,2800.0,2200.0,1800.0,1600.0,1400.0,1100.0, 920.0,790.0,690.0,550.0,460.0,390.0,340.0,270.0,230.0,200.0,170.0,140.0,110.0,98.0,85.0,68.0,57.0,49.0,43.0,34.0, 28.0,25.0,22.0,18.0,14.0,12.0,11.0,8.5,7.1,6.1,5.4,4.3,3.6,3.1 }; +static const float PLFOS_Scale[8] = { 0.f, 3.61f, 7.22f, 14.44f, 28.88f, 57.75f, 115.5f, 231.f }; +static int PLFO_Scales[8][256]; #define AEG_STEP_BITS (16) //Steps per sample u32 AEG_ATT_SPS[64]; u32 AEG_DSR_SPS[64]; -const char* stream_names[]= +static const char* stream_names[]= { "0: 16-bit PCM (two's complement format)", "1: 8-bit PCM (two's complement format)", @@ -55,17 +82,28 @@ const char* stream_names[]= }; //x.8 format -const s32 adpcm_qs[8] = +static const s32 adpcm_qs[8] = { 0x0e6, 0x0e6, 0x0e6, 0x0e6, 0x133, 0x199, 0x200, 0x266, }; //x.3 format -const s32 adpcm_scale[16] = +static const s32 adpcm_scale[16] = { 1,3,5,7,9,11,13,15, -1,-3,-5,-7,-9,-11,-13,-15, }; +static const s32 qtable[32] = { +0x0E00,0x0E80,0x0F00,0x0F80, +0x1000,0x1080,0x1100,0x1180, +0x1200,0x1280,0x1300,0x1380, +0x1400,0x1480,0x1500,0x1580, +0x1600,0x1680,0x1700,0x1780, +0x1800,0x1880,0x1900,0x1980, +0x1A00,0x1A80,0x1B00,0x1B80, +0x1C00,0x1D00,0x1E00,0x1F00 +}; + void AICA_Sample(); //Remove the fractional part , with rounding ;) -- does not need an extra bit @@ -185,7 +223,9 @@ struct ChannelCommonData //+28 TL[7:0] -- Q[4:0] u32 Q:5; - u32 rez_28_0:3; + u32 LPOFF:1; // confirmed but not documented: 0: LPF enabled, 1: LPF disabled + u32 VOFF:1; // unconfirmed: 0: attenuation enabled, 1: attenuation disabled (TL, AEG, ALFO) + u32 rez_28_0:1; u32 TL:8; @@ -321,10 +361,6 @@ struct ChannelEx void (* StepStream)(ChannelEx* ch); void (* StepStreamInitial)(ChannelEx* ch); - u8 step_stream_lut1=0 ; - u8 step_stream_lut2=0 ; - u8 step_stream_lut3=0 ; - struct { s32 val; @@ -342,9 +378,21 @@ struct ChannelEx struct { - s32 value; - _EG_state state=EG_Attack; - } FEG;//i have to figure out how this works w/ AEG and channel state, and the iir values + u32 value; + __forceinline u32 GetValue() { return value >> AEG_STEP_BITS;} + void SetValue(u32 fegb) { value = fegb << AEG_STEP_BITS; } + + _EG_state state = EG_Attack; + + SampleType prev1; + SampleType prev2; + s32 q; + u32 AttackRate; + u32 Decay1Rate; + u32 Decay2Rate; + u32 ReleaseRate; + bool active = false; + } FEG; struct { @@ -353,10 +401,8 @@ struct ChannelEx u8 state; u8 alfo; u8 alfo_shft; - u8 plfo; - u8 plfo_shft; - u8 alfo_calc_lut=0 ; - u8 plfo_calc_lut=0 ; + fp_22_10 plfo_step; + int *plfo_scale; void (* alfo_calc)(ChannelEx* ch); void (* plfo_calc)(ChannelEx* ch); __forceinline void Step(ChannelEx* ch) { counter--;if (counter==0) { state++; counter=start_value; alfo_calc(ch);plfo_calc(ch); } } @@ -372,7 +418,7 @@ struct ChannelEx ccd=(ChannelCommonData*)&ccd_raw[cn*0x80]; ChannelNumber = cn; for (u32 i=0;i<0x80;i++) - RegWrite(i); + RegWrite(i, 1); disable(); } void disable() @@ -403,17 +449,37 @@ struct ChannelEx } else { - SampleType sample=InterpolateSample(); + SampleType sample = InterpolateSample(); + + // Low-pass filter + if (FEG.active) + { + u32 fv = FEG.GetValue(); + s32 f = (((fv & 0xFF) | 0x100) << 4) >> ((fv >> 8) ^ 0x1F); + sample = f * sample + (0x2000 - f + FEG.q) * FEG.prev1 - FEG.q * FEG.prev2; + sample >>= 13; + clip16(sample); + FEG.prev2 = FEG.prev1; + FEG.prev1 = sample; + } //Volume & Mixer processing //All attenuations are added together then applied and mixed :) - + //offset is up to 511 //*Att is up to 511 //logtable handles up to 1024, anything >=255 is mute - u32 ofsatt=lfo.alfo+(AEG.GetValue()>>2); - ofsatt = min(ofsatt, (u32)255); // make sure it never gets more 255 -- it can happen with some alfo/aeg combinations + u32 ofsatt; + if (ccd->VOFF == 1) + { + ofsatt = 0; + } + else + { + ofsatt = lfo.alfo + (AEG.GetValue() >> 2); + ofsatt = min(ofsatt, (u32)255); // make sure it never gets more 255 -- it can happen with some alfo/aeg combinations + } u32 const max_att = ((16 << 4) - 1) - ofsatt; s32* logtable = ofsatt + tl_lut; @@ -466,11 +532,19 @@ struct ChannelEx if (newstate==EG_Release) ccd->KYONB=0; } + void SetFegState(_EG_state newstate) { - StepFEG=FEG_STEP_LUT[newstate]; - FEG.state=newstate; + StepFEG = FEG_STEP_LUT[newstate]; + FEG.state = newstate; + if (newstate == EG_Attack) + { + FEG.SetValue(ccd->FLV0); + FEG.prev1 = 0; + FEG.prev2 = 0; + } } + void KEY_ON() { if (AEG.state==EG_Release) @@ -496,9 +570,11 @@ struct ChannelEx adpcm.Reset(this); StepStreamInitial(this); - - key_printf("[%d] KEY_ON %s @ %f Hz, loop %d, AEG AR %d DC1R %d DC2V %d DC2R %d RR %d", ChannelNumber, stream_names[ccd->PCMS], (44100.0 * update_rate) / 1024, ccd->LPCTL, - AEG.AttackRate, AEG.Decay1Rate, AEG.Decay2Value, AEG.Decay2Rate, AEG.ReleaseRate); + key_printf("[%d] KEY_ON %s @ %f Hz, loop %d - AEG AR %d DC1R %d DC2V %d DC2R %d RR %d - KRS %d OCT %d FNS %d - PFLOS %d PFLOWS %d", + ChannelNumber, stream_names[ccd->PCMS], (44100.0 * update_rate) / 1024, ccd->LPCTL, + ccd->AR, ccd->D1R, ccd->DL << 5, ccd->D2R, ccd->RR, + ccd->KRS, ccd->OCT, ccd->FNS >> 9, + ccd->PLFOS, ccd->PLFOWS); } else { @@ -511,6 +587,7 @@ struct ChannelEx { key_printf("[%d] KEY_OFF -> Release", ChannelNumber); SetAegState(EG_Release); + SetFegState(EG_Release); //switch to release state } else @@ -527,9 +604,6 @@ struct ChannelEx StepStream=STREAM_STEP_LUT[fmt][ccd->LPCTL][ccd->LPSLNK]; StepStreamInitial=STREAM_INITAL_STEP_LUT[fmt]; - step_stream_lut1 = fmt ; - step_stream_lut2 = ccd->LPCTL ; - step_stream_lut3 = ccd->LPSLNK ; } //SA,PCMS void UpdateSA() @@ -546,31 +620,37 @@ struct ChannelEx loop.LSA=ccd->LSA; loop.LEA=ccd->LEA; } - // - u32 AEG_EffRate(u32 re) + + u32 EG_BaseRate() { - s32 rv=ccd->KRS+(ccd->FNS>>9) + re*2; + s32 rv=ccd->KRS+(ccd->FNS>>9); if (ccd->KRS==0xF) rv-=0xF; if (ccd->OCT&8) rv-=(16-ccd->OCT)*2; else rv+=ccd->OCT*2; - - if (rv<0) - rv=0; - if (rv>0x3f) - rv=0x3f; return rv; } + + u32 EG_EffRate(u32 base_rate, u32 rate) + { + s32 rv = base_rate + rate * 2; + + clip(rv, 0, 0x3f); + + return rv; + } + //D2R,D1R,AR,DL,RR,KRS, [OCT,FNS] for now void UpdateAEG() { - AEG.AttackRate = AEG_ATT_SPS[AEG_EffRate(ccd->AR)]; - AEG.Decay1Rate = AEG_DSR_SPS[AEG_EffRate(ccd->D1R)]; + s32 base_rate = EG_BaseRate(); + AEG.AttackRate = AEG_ATT_SPS[EG_EffRate(base_rate, ccd->AR)]; + AEG.Decay1Rate = AEG_DSR_SPS[EG_EffRate(base_rate, ccd->D1R)]; AEG.Decay2Value = ccd->DL<<5; - AEG.Decay2Rate = AEG_DSR_SPS[AEG_EffRate(ccd->D2R)]; - AEG.ReleaseRate = AEG_DSR_SPS[AEG_EffRate(ccd->RR)]; + AEG.Decay2Rate = AEG_DSR_SPS[EG_EffRate(base_rate, ccd->D2R)]; + AEG.ReleaseRate = AEG_DSR_SPS[EG_EffRate(base_rate, ccd->RR)]; } //OCT,FNS void UpdatePitch() @@ -586,7 +666,7 @@ struct ChannelEx this->update_rate=update_rate; } - //LFORE,LFOF,PLFOWS,PLFOS,LFOWS,ALFOS + //LFORE,LFOF,PLFOWS,PLFOS,ALFOWS,ALFOS void UpdateLFO() { { @@ -599,13 +679,11 @@ struct ChannelEx lfo.SetStartValue(O); } - lfo.plfo_shft=8-ccd->PLFOS; lfo.alfo_shft=8-ccd->ALFOS; lfo.alfo_calc=ALFOWS_CALC[ccd->ALFOWS]; lfo.plfo_calc=PLFOWS_CALC[ccd->PLFOWS]; - lfo.alfo_calc_lut=ccd->ALFOWS; - lfo.plfo_calc_lut=ccd->PLFOWS; + lfo.plfo_scale = PLFO_Scales[ccd->PLFOS]; if (ccd->LFORE) { @@ -628,8 +706,9 @@ struct ChannelEx //TL,DISDL,DIPAN,IMXL void UpdateAtts() { - u32 attFull=ccd->TL+SendLevel[ccd->DISDL]; - u32 attPan=attFull+SendLevel[(~ccd->DIPAN)&0xF]; + u32 total_level = ccd->VOFF ? 0 : ccd->TL; + u32 attFull = total_level + SendLevel[ccd->DISDL]; + u32 attPan = attFull + SendLevel[(~ccd->DIPAN) & 0xF]; //0x1* -> R decreases if (ccd->DIPAN&0x10) @@ -643,29 +722,40 @@ struct ChannelEx VolMix.DRAtt=attFull; } - VolMix.DSPAtt = ccd->TL+SendLevel[ccd->IMXL]; + VolMix.DSPAtt = total_level + SendLevel[ccd->IMXL]; } //Q,FLV0,FLV1,FLV2,FLV3,FLV4,FAR,FD1R,FD2R,FRR void UpdateFEG() { - //this needs to be filled + FEG.active = ccd->LPOFF == 0 + && (ccd->FLV0 < 0x1ff7 || ccd->FLV1 < 0x1ff7 + || ccd->FLV2 < 0x1ff7 || ccd->FLV3 < 0x1ff7 + || ccd->FLV4 < 0x1ff7); + if (!FEG.active) + return; + feg_printf("FEG active channel %d Q %d FLV: %05x %05x %05x %05x %05x AR %02x FD1R %02x FD2R %02x FRR %02x", + ChannelNumber, ccd->Q, + ccd->FLV0, ccd->FLV1, ccd->FLV2, ccd->FLV3, ccd->FLV4, + ccd->FAR, ccd->FD1R, ccd->FD2R, ccd->FRR); + FEG.q = qtable[ccd->Q]; + s32 base_rate = EG_BaseRate(); + FEG.AttackRate = AEG_DSR_SPS[EG_EffRate(base_rate, ccd->FAR)]; + FEG.Decay1Rate = AEG_DSR_SPS[EG_EffRate(base_rate, ccd->FD1R)]; + FEG.Decay2Rate = AEG_DSR_SPS[EG_EffRate(base_rate, ccd->FD2R)]; + FEG.ReleaseRate = AEG_DSR_SPS[EG_EffRate(base_rate, ccd->FRR)]; } //WHEE :D! - void RegWrite(u32 offset) + void RegWrite(u32 offset, int size) { switch(offset) { - case 0x00: //yay ? + case 0x00: + case 0x01: UpdateStreamStep(); UpdateSA(); - break; - - case 0x01: //yay ? - UpdateStreamStep(); - UpdateSA(); - if (ccd->KYONEX) + if ((offset == 0x01 || size == 2) && ccd->KYONEX) { ccd->KYONEX=0; for (int i = 0; i < 64; i++) @@ -708,7 +798,7 @@ struct ChannelEx break; case 0x1C://ALFOS,ALFOWS,PLFOS - case 0x1D://PLFOWS,LFOF,RE + case 0x1D://PLFOWS,LFOF,LFORE UpdateLFO(); break; @@ -724,11 +814,11 @@ struct ChannelEx break; case 0x28://Q - UpdateFEG(); - break; - case 0x29://TL - UpdateAtts(); + if (size == 2 || offset == 0x28) + UpdateFEG(); + if (size == 2 || offset == 0x29) + UpdateAtts(); break; case 0x2C: //FLV0 @@ -872,7 +962,7 @@ void StepDecodeSampleInitial(ChannelEx* ch) template void StreamStep(ChannelEx* ch) { - ch->step.full+=ch->update_rate; + ch->step.full += (ch->update_rate * ch->lfo.plfo_step.full) >> 10; fp_22_10 sp=ch->step; ch->step.ip=0; @@ -951,24 +1041,23 @@ void CalcPlfo(ChannelEx* ch) switch(PLFOWS) { case 0: // sawtooth - rv=ch->lfo.state; + rv = ch->lfo.state; break; case 1: // square - rv=ch->lfo.state&0x80?0x80:0x7F; + rv = ch->lfo.state & 0x80 ? 0xff : 0; break; case 2: // triangle - rv=(ch->lfo.state&0x7f)^(ch->lfo.state&0x80 ? 0x7F:0); - rv<<=1; - rv=(u8)(rv-0x80); //2's complement + rv = (ch->lfo.state & 0x7f) ^ (ch->lfo.state & 0x80 ? 0x7F : 0); + rv <<= 1; break; case 3:// random ! .. not :p - rv=(ch->lfo.state>>3)^(ch->lfo.state<<3)^(ch->lfo.state&0xE3); + rv = (ch->lfo.state >> 3) ^ (ch->lfo.state << 3) ^ (ch->lfo.state & 0xE3); break; } - ch->lfo.plfo=rv>>ch->lfo.plfo_shft; + ch->lfo.plfo_step.full = ch->lfo.plfo_scale[(u8)rv]; } template @@ -1031,8 +1120,54 @@ void AegStep(ChannelEx* ch) template void FegStep(ChannelEx* ch) { - + if (!ch->FEG.active) + return; + u32 delta; + u32 target; + switch(state) + { + case EG_Attack: + delta = ch->FEG.AttackRate; + target = ch->ccd->FLV1; + break; + case EG_Decay1: + delta = ch->FEG.Decay1Rate; + target = ch->ccd->FLV2; + break; + case EG_Decay2: + delta = ch->FEG.Decay2Rate; + target = ch->ccd->FLV3; + break; + case EG_Release: + delta = ch->FEG.ReleaseRate; + target = ch->ccd->FLV4; + break; + } + target <<= AEG_STEP_BITS; + if (ch->FEG.value < target) + { + u32 maxd = target - ch->FEG.value; + if (delta > maxd) + delta = maxd; + ch->FEG.value += delta; + } + else if (ch->FEG.value > target) + { + u32 maxd = ch->FEG.value - target; + if (delta > maxd) + delta = maxd; + ch->FEG.value -= delta; + } + else + { + if (ch->FEG.state < EG_Decay2) + { + feg_printf("[%d]FEG_step : Switching to next state: %d Freq %x", ch->ChannelNumber, (int)ch->FEG.state + 1, target >> AEG_STEP_BITS); + ch->SetFegState((_EG_state)((int)ch->FEG.state + 1)); + } + } } + void staticinitialise() { STREAM_STEP_LUT[0][0][0]=&StreamStep<0,0,0>; @@ -1138,6 +1273,15 @@ void sgc_Init() Chans[i].Init(i,aica_reg); dsp_out_vol=(DSP_OUT_VOL_REG*)&aica_reg[0x2000]; + for (int s = 0; s < 8; s++) + { + float limit = PLFOS_Scale[s]; + for (int i = -128; i < 128; i++) + { + PLFO_Scales[s][i + 128] = (u32)((1 << 10) * powf(2.0f, limit * i / 128.0f / 1200.0f)); + } + } + dsp_init(); } @@ -1146,9 +1290,9 @@ void sgc_Term() dsp_term(); } -void WriteChannelReg8(u32 channel,u32 reg) +void WriteChannelReg(u32 channel, u32 reg, int size) { - Chans[channel].RegWrite(reg); + Chans[channel].RegWrite(reg, size); } void ReadCommonReg(u32 reg,bool byte) @@ -1425,110 +1569,139 @@ bool channel_serialize(void **data, unsigned int *total_size) for ( i = 0 ; i < 64 ; i++) { - addr = Chans[i].SA - (&(aica_ram.data[0])) ; + addr = Chans[i].SA - (&(aica_ram[0])) ; REICAST_S(addr); REICAST_S(Chans[i].CA) ; REICAST_S(Chans[i].step) ; - REICAST_S(Chans[i].update_rate) ; REICAST_S(Chans[i].s0) ; REICAST_S(Chans[i].s1) ; - REICAST_S(Chans[i].loop) ; + REICAST_S(Chans[i].loop.looped) ; REICAST_S(Chans[i].adpcm.last_quant) ; + REICAST_S(Chans[i].adpcm.loopstart_quant); + REICAST_S(Chans[i].adpcm.loopstart_prev_sample); + REICAST_S(Chans[i].adpcm.in_loop); REICAST_S(Chans[i].noise_state) ; - REICAST_S(Chans[i].VolMix.DLAtt) ; - REICAST_S(Chans[i].VolMix.DRAtt) ; - REICAST_S(Chans[i].VolMix.DSPAtt) ; - - addr = Chans[i].VolMix.DSPOut - (&(dsp.MIXS[0])) ; - REICAST_S(addr); REICAST_S(Chans[i].AEG.val) ; REICAST_S(Chans[i].AEG.state) ; - REICAST_S(Chans[i].AEG.AttackRate) ; - REICAST_S(Chans[i].AEG.Decay1Rate) ; - REICAST_S(Chans[i].AEG.Decay2Rate) ; - REICAST_S(Chans[i].AEG.Decay2Value) ; - REICAST_S(Chans[i].AEG.ReleaseRate) ; - REICAST_S(Chans[i].FEG) ; - REICAST_S(Chans[i].step_stream_lut1) ; - REICAST_S(Chans[i].step_stream_lut2) ; - REICAST_S(Chans[i].step_stream_lut3) ; + REICAST_S(Chans[i].FEG.value); + REICAST_S(Chans[i].FEG.state); + REICAST_S(Chans[i].FEG.prev1); + REICAST_S(Chans[i].FEG.prev2); REICAST_S(Chans[i].lfo.counter) ; - REICAST_S(Chans[i].lfo.start_value) ; REICAST_S(Chans[i].lfo.state) ; - REICAST_S(Chans[i].lfo.alfo) ; - REICAST_S(Chans[i].lfo.alfo_shft) ; - REICAST_S(Chans[i].lfo.plfo) ; - REICAST_S(Chans[i].lfo.plfo_shft) ; - REICAST_S(Chans[i].lfo.alfo_calc_lut) ; - REICAST_S(Chans[i].lfo.plfo_calc_lut) ; REICAST_S(Chans[i].enabled) ; - REICAST_S(Chans[i].ChannelNumber) ; } - /* TODO/FIXME - no possibility for this to return false? */ return true; } -bool channel_unserialize(void **data, unsigned int *total_size) +bool channel_unserialize(void **data, unsigned int *total_size, serialize_version_enum ver) { int i = 0 ; int addr = 0 ; + u32 dum; for ( i = 0 ; i < 64 ; i++) { REICAST_US(addr); - Chans[i].SA = addr + (&(aica_ram.data[0])) ; + Chans[i].SA = addr + (&(aica_ram[0])) ; REICAST_US(Chans[i].CA) ; REICAST_US(Chans[i].step) ; - REICAST_US(Chans[i].update_rate) ; + if (ver < V7) + REICAST_US(dum); // Chans[i].update_rate + Chans[i].UpdatePitch(); REICAST_US(Chans[i].s0) ; REICAST_US(Chans[i].s1) ; - REICAST_US(Chans[i].loop) ; + REICAST_US(Chans[i].loop.looped); + if (ver < V7) + { + REICAST_US(dum); // Chans[i].loop.LSA + REICAST_US(dum); // Chans[i].loop.LEA + } + Chans[i].UpdateLoop(); REICAST_US(Chans[i].adpcm.last_quant) ; + if (ver >= V7) + { + REICAST_US(Chans[i].adpcm.loopstart_quant); + REICAST_US(Chans[i].adpcm.loopstart_prev_sample); + REICAST_US(Chans[i].adpcm.in_loop); + } + else + { + Chans[i].adpcm.in_loop = true; + Chans[i].adpcm.loopstart_quant = 0; + Chans[i].adpcm.loopstart_prev_sample = 0; + } REICAST_US(Chans[i].noise_state) ; - REICAST_US(Chans[i].VolMix.DLAtt) ; - REICAST_US(Chans[i].VolMix.DRAtt) ; - REICAST_US(Chans[i].VolMix.DSPAtt) ; - - REICAST_US(addr); - Chans[i].VolMix.DSPOut = addr + (&(dsp.MIXS[0])) ; + if (ver < V7) + { + REICAST_US(dum); // Chans[i].VolMix.DLAtt + REICAST_US(dum); // Chans[i].VolMix.DRAtt + REICAST_US(dum); // Chans[i].VolMix.DSPAtt + } + Chans[i].UpdateAtts(); + if (ver < V7) + REICAST_US(dum); // Chans[i].VolMix.DSPOut + Chans[i].UpdateDSPMIX(); REICAST_US(Chans[i].AEG.val) ; REICAST_US(Chans[i].AEG.state) ; - Chans[i].StepAEG=AEG_STEP_LUT[Chans[i].AEG.state]; - REICAST_US(Chans[i].AEG.AttackRate) ; - REICAST_US(Chans[i].AEG.Decay1Rate) ; - REICAST_US(Chans[i].AEG.Decay2Rate) ; - REICAST_US(Chans[i].AEG.Decay2Value) ; - REICAST_US(Chans[i].AEG.ReleaseRate) ; - REICAST_US(Chans[i].FEG) ; - Chans[i].StepFEG=FEG_STEP_LUT[Chans[i].FEG.state]; - REICAST_US(Chans[i].step_stream_lut1) ; - REICAST_US(Chans[i].step_stream_lut2) ; - REICAST_US(Chans[i].step_stream_lut3) ; - Chans[i].StepStream=STREAM_STEP_LUT[Chans[i].step_stream_lut1][Chans[i].step_stream_lut2][Chans[i].step_stream_lut3] ; - Chans[i].StepStreamInitial=STREAM_INITAL_STEP_LUT[Chans[i].step_stream_lut1]; + Chans[i].SetAegState(Chans[i].AEG.state); + if (ver < V7) + { + REICAST_US(dum); // Chans[i].AEG.AttackRate + REICAST_US(dum); // Chans[i].AEG.Decay1Rate + REICAST_US(dum); // Chans[i].AEG.Decay2Rate + REICAST_US(dum); // Chans[i].AEG.Decay2Value + REICAST_US(dum); // Chans[i].AEG.ReleaseRate + } + Chans[i].UpdateAEG(); + REICAST_US(Chans[i].FEG.value); + REICAST_US(Chans[i].FEG.state); + if (ver >= V7) + { + REICAST_US(Chans[i].FEG.prev1); + REICAST_US(Chans[i].FEG.prev2); + } + else + { + Chans[i].FEG.prev1 = 0; + Chans[i].FEG.prev2 = 0; + } + Chans[i].SetFegState(Chans[i].FEG.state); + Chans[i].UpdateFEG(); + if (ver < V7) + { + u8 dumu8; + REICAST_US(dumu8); // Chans[i].step_stream_lut1 + REICAST_US(dumu8); // Chans[i].step_stream_lut2 + REICAST_US(dumu8); // Chans[i].step_stream_lut3 + } + Chans[i].UpdateStreamStep(); REICAST_US(Chans[i].lfo.counter) ; - REICAST_US(Chans[i].lfo.start_value) ; + if (ver < V7) + REICAST_US(dum); // Chans[i].lfo.start_value REICAST_US(Chans[i].lfo.state) ; - REICAST_US(Chans[i].lfo.alfo) ; - REICAST_US(Chans[i].lfo.alfo_shft) ; - REICAST_US(Chans[i].lfo.plfo) ; - REICAST_US(Chans[i].lfo.plfo_shft) ; - REICAST_US(Chans[i].lfo.alfo_calc_lut) ; - REICAST_US(Chans[i].lfo.plfo_calc_lut) ; - Chans[i].lfo.alfo_calc = ALFOWS_CALC[Chans[i].lfo.alfo_calc_lut]; - Chans[i].lfo.plfo_calc = PLFOWS_CALC[Chans[i].lfo.plfo_calc_lut]; + if (ver < V7) + { + u8 dumu8; + REICAST_US(dumu8); // Chans[i].lfo.alfo + REICAST_US(dumu8); // Chans[i].lfo.alfo_shft + REICAST_US(dumu8); // Chans[i].lfo.plfo + REICAST_US(dumu8); // Chans[i].lfo.plfo_shft + REICAST_US(dumu8); // Chans[i].lfo.alfo_calc_lut + REICAST_US(dumu8); // Chans[i].lfo.plfo_calc_lut + } + Chans[i].UpdateLFO(); REICAST_US(Chans[i].enabled) ; - REICAST_US(Chans[i].ChannelNumber) ; - + if (ver < V7) + REICAST_US(dum); // Chans[i].ChannelNumber } - /* TODO/FIXME - no possibility for this to return false? */ return true; } diff --git a/core/hw/aica/sgc_if.h b/core/hw/aica/sgc_if.h index 151987d6c..b3295aed8 100644 --- a/core/hw/aica/sgc_if.h +++ b/core/hw/aica/sgc_if.h @@ -5,7 +5,7 @@ void AICA_Sample(); void AICA_Sample32(); //u32 ReadChannelReg(u32 channel,u32 reg); -void WriteChannelReg8(u32 channel,u32 reg); +void WriteChannelReg(u32 channel, u32 reg, int size); void sgc_Init(); void sgc_Term(); @@ -56,7 +56,7 @@ typedef s32 SampleType; void ReadCommonReg(u32 reg,bool byte); void WriteCommonReg8(u32 reg,u32 data); -#define clip(x,min,max) if ((x)<(min)) (x)=(min); if ((x)>(max)) (x)=(max); +#define clip(x,min,max) do { if ((x)<(min)) (x)=(min); else if ((x)>(max)) (x)=(max); } while (false) #define clip16(x) clip(x,-32768,32767) bool channel_serialize(void **data, unsigned int *total_size); -bool channel_unserialize(void **data, unsigned int *total_size); +bool channel_unserialize(void **data, unsigned int *total_size, serialize_version_enum version); diff --git a/core/serialize.cpp b/core/serialize.cpp index da37ed0bc..f88206ac6 100644 --- a/core/serialize.cpp +++ b/core/serialize.cpp @@ -30,19 +30,6 @@ extern "C" void DYNACALL TAWriteSQ(u32 address,u8* sqb); -enum serialize_version_enum { - V1, - V2, - V3, - V4, - V5_LIBRETRO_UNSUPPORTED, - V6_LIBRETRO_UNSUPPORTED, - V7_LIBRETRO, - - V5 = 800, - V6 = 801, -} ; - //./core/hw/arm7/arm_mem.cpp extern bool aica_interr; extern u32 aica_reg_L; @@ -316,7 +303,7 @@ bool dc_serialize(void **data, unsigned int *total_size) { int i = 0; int j = 0; - serialize_version_enum version = V6; + serialize_version_enum version = V7; *total_size = 0 ; @@ -618,7 +605,7 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size) REICAST_USA(aica_reg,0x8000); - channel_unserialize(data, total_size) ; + channel_unserialize(data, total_size, V7_LIBRETRO); REICAST_USA(cdda_sector,CDDA_SIZE); REICAST_US(cdda_index); @@ -988,7 +975,7 @@ bool dc_unserialize(void **data, unsigned int *total_size) REICAST_SKIP(2); REICAST_SKIP(2); } - channel_unserialize(data, total_size) ; + channel_unserialize(data, total_size, version); REICAST_USA(cdda_sector,CDDA_SIZE); REICAST_US(cdda_index); diff --git a/core/types.h b/core/types.h index db46cc95c..bd7cbef85 100644 --- a/core/types.h +++ b/core/types.h @@ -675,3 +675,17 @@ public: std::string reason; }; + +enum serialize_version_enum { + V1, + V2, + V3, + V4, + V5_LIBRETRO_UNSUPPORTED, + V6_LIBRETRO_UNSUPPORTED, + V7_LIBRETRO, + + V5 = 800, + V6 = 801, + V7 = 802, +} ;