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