spu: some major reverb refactoring
[pcsx_rearmed.git] / plugins / dfsound / freeze.c
CommitLineData
ef79bbde
P
1/***************************************************************************\r
2 freeze.c - description\r
3 -------------------\r
4 begin : Wed May 15 2002\r
5 copyright : (C) 2002 by Pete Bernert\r
6 email : BlackDove@addcom.de\r
7 ***************************************************************************/\r
8/***************************************************************************\r
9 * *\r
10 * This program is free software; you can redistribute it and/or modify *\r
11 * it under the terms of the GNU General Public License as published by *\r
12 * the Free Software Foundation; either version 2 of the License, or *\r
13 * (at your option) any later version. See also the license.txt file for *\r
14 * additional informations. *\r
15 * *\r
16 ***************************************************************************/\r
17\r
18#include "stdafx.h"\r
19\r
20#define _IN_FREEZE\r
21\r
22#include "externals.h"\r
23#include "registers.h"\r
24#include "spu.h"\r
25#include "regs.h"\r
26\r
27////////////////////////////////////////////////////////////////////////\r
28// freeze structs\r
29////////////////////////////////////////////////////////////////////////\r
30\r
6d866bb7 31typedef struct\r
32{\r
33 int State;\r
34 int AttackModeExp;\r
35 int AttackRate;\r
36 int DecayRate;\r
37 int SustainLevel;\r
38 int SustainModeExp;\r
39 int SustainIncrease;\r
40 int SustainRate;\r
41 int ReleaseModeExp;\r
42 int ReleaseRate;\r
43 int EnvelopeVol;\r
44 long lVolume;\r
45 long lDummy1;\r
46 long lDummy2;\r
47} ADSRInfoEx_orig;\r
48\r
49typedef struct\r
50{\r
51 // no mutexes used anymore... don't need them to sync access\r
52 //HANDLE hMutex;\r
53\r
54 int bNew; // start flag\r
55\r
56 int iSBPos; // mixing stuff\r
57 int spos;\r
58 int sinc;\r
59 int SB[32+32]; // Pete added another 32 dwords in 1.6 ... prevents overflow issues with gaussian/cubic interpolation (thanx xodnizel!), and can be used for even better interpolations, eh? :)\r
60 int sval;\r
61\r
62 unsigned char * pStart; // start ptr into sound mem\r
63 unsigned char * pCurr; // current pos in sound mem\r
64 unsigned char * pLoop; // loop ptr in sound mem\r
65\r
66 int bOn; // is channel active (sample playing?)\r
67 int bStop; // is channel stopped (sample _can_ still be playing, ADSR Release phase)\r
68 int bReverb; // can we do reverb on this channel? must have ctrl register bit, to get active\r
69 int iActFreq; // current psx pitch\r
70 int iUsedFreq; // current pc pitch\r
71 int iLeftVolume; // left volume\r
72 int iLeftVolRaw; // left psx volume value\r
73 int bIgnoreLoop; // ignore loop bit, if an external loop address is used\r
74 int iMute; // mute mode\r
75 int iRightVolume; // right volume\r
76 int iRightVolRaw; // right psx volume value\r
77 int iRawPitch; // raw pitch (0...3fff)\r
78 int iIrqDone; // debug irq done flag\r
79 int s_1; // last decoding infos\r
80 int s_2;\r
81 int bRVBActive; // reverb active flag\r
82 int iRVBOffset; // reverb offset\r
83 int iRVBRepeat; // reverb repeat\r
84 int bNoise; // noise active flag\r
85 int bFMod; // freq mod (0=off, 1=sound channel, 2=freq channel)\r
86 int iRVBNum; // another reverb helper\r
87 int iOldNoise; // old noise val for this channel \r
88 ADSRInfo ADSR; // active ADSR settings\r
89 ADSRInfoEx_orig ADSRX; // next ADSR settings (will be moved to active on sample start)\r
90} SPUCHAN_orig;\r
91\r
ef79bbde
P
92typedef struct\r
93{\r
94 char szSPUName[8];\r
95 uint32_t ulFreezeVersion;\r
96 uint32_t ulFreezeSize;\r
97 unsigned char cSPUPort[0x200];\r
98 unsigned char cSPURam[0x80000];\r
99 xa_decode_t xaS; \r
100} SPUFreeze_t;\r
101\r
102typedef struct\r
103{\r
104 unsigned short spuIrq;\r
105 uint32_t pSpuIrq;\r
106 uint32_t spuAddr;\r
107 uint32_t dummy1;\r
108 uint32_t dummy2;\r
109 uint32_t dummy3;\r
110\r
6d866bb7 111 SPUCHAN_orig s_chan[MAXCHAN]; \r
ef79bbde
P
112\r
113} SPUOSSFreeze_t;\r
114\r
115////////////////////////////////////////////////////////////////////////\r
116\r
117void LoadStateV5(SPUFreeze_t * pF); // newest version\r
118void LoadStateUnknown(SPUFreeze_t * pF); // unknown format\r
119\r
120extern int lastch;\r
121\r
6d866bb7 122// we want to retain compatibility between versions,\r
123// so use original channel struct\r
124static void save_channel(SPUCHAN_orig *d, SPUCHAN *s, int ch)\r
125{\r
126 memset(d, 0, sizeof(*d));\r
127 d->bNew = !!(dwNewChannel & (1<<ch));\r
128 d->iSBPos = s->iSBPos;\r
129 d->spos = s->spos;\r
130 d->sinc = s->sinc;\r
131 memcpy(d->SB, s->SB, sizeof(d->SB));\r
132 d->pStart = s->pStart;\r
133 d->pCurr = s->pCurr;\r
134 d->pLoop = s->pLoop;\r
135 d->bOn = !!(dwChannelOn & (1<<ch));\r
136 d->bStop = s->bStop;\r
137 d->bReverb = s->bReverb;\r
138 d->iActFreq = s->iActFreq;\r
139 d->iUsedFreq = s->iUsedFreq;\r
140 d->iLeftVolume = s->iLeftVolume;\r
141 d->bIgnoreLoop = s->bIgnoreLoop;\r
142 d->iRightVolume = s->iRightVolume;\r
143 d->iRawPitch = s->iRawPitch;\r
144 d->s_1 = s->s_1;\r
145 d->s_2 = s->s_2;\r
146 d->bRVBActive = s->bRVBActive;\r
147 d->iRVBOffset = s->iRVBOffset;\r
148 d->iRVBRepeat = s->iRVBRepeat;\r
149 d->bNoise = s->bNoise;\r
150 d->bFMod = s->bFMod;\r
151 d->iRVBNum = s->iRVBNum;\r
152 d->iOldNoise = s->iOldNoise;\r
153 d->ADSRX.State = s->ADSRX.State;\r
154 d->ADSRX.AttackModeExp = s->ADSRX.AttackModeExp;\r
155 d->ADSRX.AttackRate = s->ADSRX.AttackRate;\r
156 d->ADSRX.DecayRate = s->ADSRX.DecayRate;\r
157 d->ADSRX.SustainLevel = s->ADSRX.SustainLevel;\r
158 d->ADSRX.SustainModeExp = s->ADSRX.SustainModeExp;\r
159 d->ADSRX.SustainIncrease = s->ADSRX.SustainIncrease;\r
160 d->ADSRX.SustainRate = s->ADSRX.SustainRate;\r
161 d->ADSRX.ReleaseModeExp = s->ADSRX.ReleaseModeExp;\r
162 d->ADSRX.ReleaseRate = s->ADSRX.ReleaseRate;\r
163 d->ADSRX.EnvelopeVol = s->ADSRX.EnvelopeVol;\r
164 d->ADSRX.lVolume = d->bOn; // hmh\r
165}\r
166\r
167static void load_channel(SPUCHAN *d, SPUCHAN_orig *s, int ch)\r
168{\r
169 memset(d, 0, sizeof(*d));\r
170 if (s->bNew) dwNewChannel |= 1<<ch;\r
171 d->iSBPos = s->iSBPos;\r
172 d->spos = s->spos;\r
173 d->sinc = s->sinc;\r
174 memcpy(d->SB, s->SB, sizeof(d->SB));\r
3fc2a4c2 175 d->pStart = (void *)((long)s->pStart & 0x7fff0);\r
176 d->pCurr = (void *)((long)s->pCurr & 0x7fff0);\r
177 d->pLoop = (void *)((long)s->pLoop & 0x7fff0);\r
6d866bb7 178 if (s->bOn) dwChannelOn |= 1<<ch;\r
179 d->bStop = s->bStop;\r
180 d->bReverb = s->bReverb;\r
181 d->iActFreq = s->iActFreq;\r
182 d->iUsedFreq = s->iUsedFreq;\r
183 d->iLeftVolume = s->iLeftVolume;\r
184 d->bIgnoreLoop = s->bIgnoreLoop;\r
185 d->iRightVolume = s->iRightVolume;\r
186 d->iRawPitch = s->iRawPitch;\r
187 d->s_1 = s->s_1;\r
188 d->s_2 = s->s_2;\r
189 d->bRVBActive = s->bRVBActive;\r
190 d->iRVBOffset = s->iRVBOffset;\r
191 d->iRVBRepeat = s->iRVBRepeat;\r
192 d->bNoise = s->bNoise;\r
193 d->bFMod = s->bFMod;\r
194 d->iRVBNum = s->iRVBNum;\r
195 d->iOldNoise = s->iOldNoise;\r
196 d->ADSRX.State = s->ADSRX.State;\r
197 d->ADSRX.AttackModeExp = s->ADSRX.AttackModeExp;\r
198 d->ADSRX.AttackRate = s->ADSRX.AttackRate;\r
199 d->ADSRX.DecayRate = s->ADSRX.DecayRate;\r
200 d->ADSRX.SustainLevel = s->ADSRX.SustainLevel;\r
201 d->ADSRX.SustainModeExp = s->ADSRX.SustainModeExp;\r
202 d->ADSRX.SustainIncrease = s->ADSRX.SustainIncrease;\r
203 d->ADSRX.SustainRate = s->ADSRX.SustainRate;\r
204 d->ADSRX.ReleaseModeExp = s->ADSRX.ReleaseModeExp;\r
205 d->ADSRX.ReleaseRate = s->ADSRX.ReleaseRate;\r
206 d->ADSRX.EnvelopeVol = s->ADSRX.EnvelopeVol;\r
207}\r
208\r
ef79bbde
P
209////////////////////////////////////////////////////////////////////////\r
210// SPUFREEZE: called by main emu on savestate load/save\r
211////////////////////////////////////////////////////////////////////////\r
212\r
213long CALLBACK SPUfreeze(uint32_t ulFreezeMode,SPUFreeze_t * pF)\r
214{\r
215 int i;SPUOSSFreeze_t * pFO;\r
216\r
217 if(!pF) return 0; // first check\r
218\r
219 if(ulFreezeMode) // info or save?\r
220 {//--------------------------------------------------//\r
221 if(ulFreezeMode==1) \r
222 memset(pF,0,sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t));\r
223\r
224 strcpy(pF->szSPUName,"PBOSS");\r
225 pF->ulFreezeVersion=5;\r
226 pF->ulFreezeSize=sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t);\r
227\r
228 if(ulFreezeMode==2) return 1; // info mode? ok, bye\r
229 // save mode:\r
230 RemoveTimer(); // stop timer\r
231\r
232 memcpy(pF->cSPURam,spuMem,0x80000); // copy common infos\r
233 memcpy(pF->cSPUPort,regArea,0x200);\r
234\r
235 if(xapGlobal && XAPlay!=XAFeed) // some xa\r
236 {\r
237 pF->xaS=*xapGlobal; \r
238 }\r
239 else \r
240 memset(&pF->xaS,0,sizeof(xa_decode_t)); // or clean xa\r
241\r
242 pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff\r
243\r
244 pFO->spuIrq=spuIrq;\r
245 if(pSpuIrq) pFO->pSpuIrq = (unsigned long)pSpuIrq-(unsigned long)spuMemC;\r
246\r
247 pFO->spuAddr=spuAddr;\r
248 if(pFO->spuAddr==0) pFO->spuAddr=0xbaadf00d;\r
249\r
3fc2a4c2 250 dwChannelOn&=~dwPendingChanOff;\r
251 dwPendingChanOff=0;\r
252\r
ef79bbde
P
253 for(i=0;i<MAXCHAN;i++)\r
254 {\r
6d866bb7 255 save_channel(&pFO->s_chan[i],&s_chan[i],i);\r
ef79bbde
P
256 if(pFO->s_chan[i].pStart)\r
257 pFO->s_chan[i].pStart-=(unsigned long)spuMemC;\r
258 if(pFO->s_chan[i].pCurr)\r
259 pFO->s_chan[i].pCurr-=(unsigned long)spuMemC;\r
260 if(pFO->s_chan[i].pLoop)\r
261 pFO->s_chan[i].pLoop-=(unsigned long)spuMemC;\r
262 }\r
263\r
264 SetupTimer(); // sound processing on again\r
265\r
266 return 1;\r
267 //--------------------------------------------------//\r
268 }\r
269 \r
270 if(ulFreezeMode!=0) return 0; // bad mode? bye\r
271\r
272 RemoveTimer(); // we stop processing while doing the save!\r
273\r
274 memcpy(spuMem,pF->cSPURam,0x80000); // get ram\r
275 memcpy(regArea,pF->cSPUPort,0x200);\r
276\r
277 if(pF->xaS.nsamples<=4032) // start xa again\r
278 SPUplayADPCMchannel(&pF->xaS);\r
279\r
280 xapGlobal=0;\r
3fc2a4c2 281 dwPendingChanOff=0;\r
ef79bbde
P
282\r
283 if(!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5)\r
284 LoadStateV5(pF);\r
285 else LoadStateUnknown(pF);\r
286\r
287 lastch = -1;\r
288\r
289 // repair some globals\r
290 for(i=0;i<=62;i+=2)\r
291 SPUwriteRegister(H_Reverb+i,regArea[(H_Reverb+i-0xc00)>>1]);\r
292 SPUwriteRegister(H_SPUReverbAddr,regArea[(H_SPUReverbAddr-0xc00)>>1]);\r
293 SPUwriteRegister(H_SPUrvolL,regArea[(H_SPUrvolL-0xc00)>>1]);\r
294 SPUwriteRegister(H_SPUrvolR,regArea[(H_SPUrvolR-0xc00)>>1]);\r
295\r
296 SPUwriteRegister(H_SPUctrl,(unsigned short)(regArea[(H_SPUctrl-0xc00)>>1]|0x4000));\r
297 SPUwriteRegister(H_SPUstat,regArea[(H_SPUstat-0xc00)>>1]);\r
298 SPUwriteRegister(H_CDLeft,regArea[(H_CDLeft-0xc00)>>1]);\r
299 SPUwriteRegister(H_CDRight,regArea[(H_CDRight-0xc00)>>1]);\r
300\r
301 // fix to prevent new interpolations from crashing\r
302 for(i=0;i<MAXCHAN;i++) s_chan[i].SB[28]=0;\r
303\r
304 SetupTimer(); // start sound processing again\r
305\r
306 return 1;\r
307}\r
308\r
309////////////////////////////////////////////////////////////////////////\r
310\r
311void LoadStateV5(SPUFreeze_t * pF)\r
312{\r
313 int i;SPUOSSFreeze_t * pFO;\r
314\r
315 pFO=(SPUOSSFreeze_t *)(pF+1);\r
316\r
317 spuIrq = pFO->spuIrq;\r
3fc2a4c2 318 if(pFO->pSpuIrq) pSpuIrq = spuMemC+((long)pFO->pSpuIrq&0x7fff0); else pSpuIrq=NULL;\r
ef79bbde
P
319\r
320 if(pFO->spuAddr)\r
321 {\r
322 spuAddr = pFO->spuAddr;\r
323 if (spuAddr == 0xbaadf00d) spuAddr = 0;\r
324 }\r
325\r
6d866bb7 326 dwNewChannel=0;\r
327 dwChannelOn=0;\r
ef79bbde
P
328 for(i=0;i<MAXCHAN;i++)\r
329 {\r
6d866bb7 330 load_channel(&s_chan[i],&pFO->s_chan[i],i);\r
ef79bbde
P
331\r
332 s_chan[i].pStart+=(unsigned long)spuMemC;\r
333 s_chan[i].pCurr+=(unsigned long)spuMemC;\r
334 s_chan[i].pLoop+=(unsigned long)spuMemC;\r
ef79bbde
P
335 }\r
336}\r
337\r
338////////////////////////////////////////////////////////////////////////\r
339\r
340void LoadStateUnknown(SPUFreeze_t * pF)\r
341{\r
342 int i;\r
343\r
344 for(i=0;i<MAXCHAN;i++)\r
345 {\r
ef79bbde 346 s_chan[i].bStop=0;\r
ef79bbde
P
347 s_chan[i].pLoop=spuMemC;\r
348 s_chan[i].pStart=spuMemC;\r
349 s_chan[i].pLoop=spuMemC;\r
ef79bbde
P
350 }\r
351\r
352 dwNewChannel=0;\r
6d866bb7 353 dwChannelOn=0;\r
ef79bbde
P
354 pSpuIrq=0;\r
355\r
356 for(i=0;i<0xc0;i++)\r
357 {\r
358 SPUwriteRegister(0x1f801c00+i*2,regArea[i]);\r
359 }\r
360}\r
361\r
362////////////////////////////////////////////////////////////////////////\r