gpu_neon: warning fix
[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
217 RemoveTimer(); // stop timer\r
218\r
219 memcpy(pF->cSPURam,spuMem,0x80000); // copy common infos\r
220 memcpy(pF->cSPUPort,regArea,0x200);\r
221\r
222 if(xapGlobal && XAPlay!=XAFeed) // some xa\r
223 {\r
224 pF->xaS=*xapGlobal; \r
225 }\r
226 else \r
227 memset(&pF->xaS,0,sizeof(xa_decode_t)); // or clean xa\r
228\r
229 pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff\r
230\r
231 pFO->spuIrq=spuIrq;\r
232 if(pSpuIrq) pFO->pSpuIrq = (unsigned long)pSpuIrq-(unsigned long)spuMemC;\r
233\r
234 pFO->spuAddr=spuAddr;\r
235 if(pFO->spuAddr==0) pFO->spuAddr=0xbaadf00d;\r
236\r
3fc2a4c2 237 dwChannelOn&=~dwPendingChanOff;\r
238 dwPendingChanOff=0;\r
239\r
ef79bbde
P
240 for(i=0;i<MAXCHAN;i++)\r
241 {\r
6d866bb7 242 save_channel(&pFO->s_chan[i],&s_chan[i],i);\r
ef79bbde
P
243 if(pFO->s_chan[i].pCurr)\r
244 pFO->s_chan[i].pCurr-=(unsigned long)spuMemC;\r
245 if(pFO->s_chan[i].pLoop)\r
246 pFO->s_chan[i].pLoop-=(unsigned long)spuMemC;\r
247 }\r
248\r
249 SetupTimer(); // sound processing on again\r
250\r
251 return 1;\r
252 //--------------------------------------------------//\r
253 }\r
254 \r
255 if(ulFreezeMode!=0) return 0; // bad mode? bye\r
256\r
257 RemoveTimer(); // we stop processing while doing the save!\r
258\r
259 memcpy(spuMem,pF->cSPURam,0x80000); // get ram\r
260 memcpy(regArea,pF->cSPUPort,0x200);\r
261\r
262 if(pF->xaS.nsamples<=4032) // start xa again\r
263 SPUplayADPCMchannel(&pF->xaS);\r
264\r
265 xapGlobal=0;\r
3fc2a4c2 266 dwPendingChanOff=0;\r
ef79bbde
P
267\r
268 if(!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5)\r
269 LoadStateV5(pF);\r
270 else LoadStateUnknown(pF);\r
271\r
272 lastch = -1;\r
273\r
274 // repair some globals\r
275 for(i=0;i<=62;i+=2)\r
276 SPUwriteRegister(H_Reverb+i,regArea[(H_Reverb+i-0xc00)>>1]);\r
277 SPUwriteRegister(H_SPUReverbAddr,regArea[(H_SPUReverbAddr-0xc00)>>1]);\r
278 SPUwriteRegister(H_SPUrvolL,regArea[(H_SPUrvolL-0xc00)>>1]);\r
279 SPUwriteRegister(H_SPUrvolR,regArea[(H_SPUrvolR-0xc00)>>1]);\r
280\r
281 SPUwriteRegister(H_SPUctrl,(unsigned short)(regArea[(H_SPUctrl-0xc00)>>1]|0x4000));\r
282 SPUwriteRegister(H_SPUstat,regArea[(H_SPUstat-0xc00)>>1]);\r
283 SPUwriteRegister(H_CDLeft,regArea[(H_CDLeft-0xc00)>>1]);\r
284 SPUwriteRegister(H_CDRight,regArea[(H_CDRight-0xc00)>>1]);\r
285\r
286 // fix to prevent new interpolations from crashing\r
287 for(i=0;i<MAXCHAN;i++) s_chan[i].SB[28]=0;\r
288\r
289 SetupTimer(); // start sound processing again\r
290\r
291 return 1;\r
292}\r
293\r
294////////////////////////////////////////////////////////////////////////\r
295\r
296void LoadStateV5(SPUFreeze_t * pF)\r
297{\r
298 int i;SPUOSSFreeze_t * pFO;\r
299\r
300 pFO=(SPUOSSFreeze_t *)(pF+1);\r
301\r
302 spuIrq = pFO->spuIrq;\r
3fc2a4c2 303 if(pFO->pSpuIrq) pSpuIrq = spuMemC+((long)pFO->pSpuIrq&0x7fff0); else pSpuIrq=NULL;\r
ef79bbde
P
304\r
305 if(pFO->spuAddr)\r
306 {\r
307 spuAddr = pFO->spuAddr;\r
308 if (spuAddr == 0xbaadf00d) spuAddr = 0;\r
309 }\r
310\r
6d866bb7 311 dwNewChannel=0;\r
312 dwChannelOn=0;\r
174c454a 313 dwChannelDead=0;\r
ef79bbde
P
314 for(i=0;i<MAXCHAN;i++)\r
315 {\r
6d866bb7 316 load_channel(&s_chan[i],&pFO->s_chan[i],i);\r
ef79bbde 317\r
ef79bbde
P
318 s_chan[i].pCurr+=(unsigned long)spuMemC;\r
319 s_chan[i].pLoop+=(unsigned long)spuMemC;\r
ef79bbde
P
320 }\r
321}\r
322\r
323////////////////////////////////////////////////////////////////////////\r
324\r
325void LoadStateUnknown(SPUFreeze_t * pF)\r
326{\r
327 int i;\r
328\r
329 for(i=0;i<MAXCHAN;i++)\r
330 {\r
ef79bbde 331 s_chan[i].bStop=0;\r
ef79bbde 332 s_chan[i].pLoop=spuMemC;\r
ef79bbde
P
333 }\r
334\r
335 dwNewChannel=0;\r
6d866bb7 336 dwChannelOn=0;\r
174c454a 337 dwChannelDead=0;\r
ef79bbde
P
338 pSpuIrq=0;\r
339\r
340 for(i=0;i<0xc0;i++)\r
341 {\r
342 SPUwriteRegister(0x1f801c00+i*2,regArea[i]);\r
343 }\r
344}\r
345\r
346////////////////////////////////////////////////////////////////////////\r