spu: change volume control, default it to 3/4 instead of 1/2
[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
381ea103 124static void save_channel(SPUCHAN_orig *d, const SPUCHAN *s, int ch)\r
6d866bb7 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
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->pStart = (void *)((long)s->pStart & 0x7fff0);\r
172 d->pCurr = (void *)((long)s->pCurr & 0x7fff0);\r
173 d->pLoop = (void *)((long)s->pLoop & 0x7fff0);\r
6d866bb7 174 if (s->bOn) dwChannelOn |= 1<<ch;\r
175 d->bStop = s->bStop;\r
176 d->bReverb = s->bReverb;\r
177 d->iActFreq = s->iActFreq;\r
178 d->iUsedFreq = s->iUsedFreq;\r
179 d->iLeftVolume = s->iLeftVolume;\r
180 d->bIgnoreLoop = s->bIgnoreLoop;\r
181 d->iRightVolume = s->iRightVolume;\r
182 d->iRawPitch = s->iRawPitch;\r
6d866bb7 183 d->bRVBActive = s->bRVBActive;\r
6d866bb7 184 d->bNoise = s->bNoise;\r
185 d->bFMod = s->bFMod;\r
6d866bb7 186 d->ADSRX.State = s->ADSRX.State;\r
187 d->ADSRX.AttackModeExp = s->ADSRX.AttackModeExp;\r
188 d->ADSRX.AttackRate = s->ADSRX.AttackRate;\r
189 d->ADSRX.DecayRate = s->ADSRX.DecayRate;\r
190 d->ADSRX.SustainLevel = s->ADSRX.SustainLevel;\r
191 d->ADSRX.SustainModeExp = s->ADSRX.SustainModeExp;\r
192 d->ADSRX.SustainIncrease = s->ADSRX.SustainIncrease;\r
193 d->ADSRX.SustainRate = s->ADSRX.SustainRate;\r
194 d->ADSRX.ReleaseModeExp = s->ADSRX.ReleaseModeExp;\r
195 d->ADSRX.ReleaseRate = s->ADSRX.ReleaseRate;\r
196 d->ADSRX.EnvelopeVol = s->ADSRX.EnvelopeVol;\r
197}\r
198\r
ef79bbde
P
199////////////////////////////////////////////////////////////////////////\r
200// SPUFREEZE: called by main emu on savestate load/save\r
201////////////////////////////////////////////////////////////////////////\r
202\r
203long CALLBACK SPUfreeze(uint32_t ulFreezeMode,SPUFreeze_t * pF)\r
204{\r
205 int i;SPUOSSFreeze_t * pFO;\r
206\r
207 if(!pF) return 0; // first check\r
208\r
209 if(ulFreezeMode) // info or save?\r
210 {//--------------------------------------------------//\r
211 if(ulFreezeMode==1) \r
212 memset(pF,0,sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t));\r
213\r
214 strcpy(pF->szSPUName,"PBOSS");\r
215 pF->ulFreezeVersion=5;\r
216 pF->ulFreezeSize=sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t);\r
217\r
218 if(ulFreezeMode==2) return 1; // info mode? ok, bye\r
219 // save mode:\r
220 RemoveTimer(); // stop timer\r
221\r
222 memcpy(pF->cSPURam,spuMem,0x80000); // copy common infos\r
223 memcpy(pF->cSPUPort,regArea,0x200);\r
224\r
225 if(xapGlobal && XAPlay!=XAFeed) // some xa\r
226 {\r
227 pF->xaS=*xapGlobal; \r
228 }\r
229 else \r
230 memset(&pF->xaS,0,sizeof(xa_decode_t)); // or clean xa\r
231\r
232 pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff\r
233\r
234 pFO->spuIrq=spuIrq;\r
235 if(pSpuIrq) pFO->pSpuIrq = (unsigned long)pSpuIrq-(unsigned long)spuMemC;\r
236\r
237 pFO->spuAddr=spuAddr;\r
238 if(pFO->spuAddr==0) pFO->spuAddr=0xbaadf00d;\r
239\r
3fc2a4c2 240 dwChannelOn&=~dwPendingChanOff;\r
241 dwPendingChanOff=0;\r
242\r
ef79bbde
P
243 for(i=0;i<MAXCHAN;i++)\r
244 {\r
6d866bb7 245 save_channel(&pFO->s_chan[i],&s_chan[i],i);\r
ef79bbde
P
246 if(pFO->s_chan[i].pStart)\r
247 pFO->s_chan[i].pStart-=(unsigned long)spuMemC;\r
248 if(pFO->s_chan[i].pCurr)\r
249 pFO->s_chan[i].pCurr-=(unsigned long)spuMemC;\r
250 if(pFO->s_chan[i].pLoop)\r
251 pFO->s_chan[i].pLoop-=(unsigned long)spuMemC;\r
252 }\r
253\r
254 SetupTimer(); // sound processing on again\r
255\r
256 return 1;\r
257 //--------------------------------------------------//\r
258 }\r
259 \r
260 if(ulFreezeMode!=0) return 0; // bad mode? bye\r
261\r
262 RemoveTimer(); // we stop processing while doing the save!\r
263\r
264 memcpy(spuMem,pF->cSPURam,0x80000); // get ram\r
265 memcpy(regArea,pF->cSPUPort,0x200);\r
266\r
267 if(pF->xaS.nsamples<=4032) // start xa again\r
268 SPUplayADPCMchannel(&pF->xaS);\r
269\r
270 xapGlobal=0;\r
3fc2a4c2 271 dwPendingChanOff=0;\r
ef79bbde
P
272\r
273 if(!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5)\r
274 LoadStateV5(pF);\r
275 else LoadStateUnknown(pF);\r
276\r
277 lastch = -1;\r
278\r
279 // repair some globals\r
280 for(i=0;i<=62;i+=2)\r
281 SPUwriteRegister(H_Reverb+i,regArea[(H_Reverb+i-0xc00)>>1]);\r
282 SPUwriteRegister(H_SPUReverbAddr,regArea[(H_SPUReverbAddr-0xc00)>>1]);\r
283 SPUwriteRegister(H_SPUrvolL,regArea[(H_SPUrvolL-0xc00)>>1]);\r
284 SPUwriteRegister(H_SPUrvolR,regArea[(H_SPUrvolR-0xc00)>>1]);\r
285\r
286 SPUwriteRegister(H_SPUctrl,(unsigned short)(regArea[(H_SPUctrl-0xc00)>>1]|0x4000));\r
287 SPUwriteRegister(H_SPUstat,regArea[(H_SPUstat-0xc00)>>1]);\r
288 SPUwriteRegister(H_CDLeft,regArea[(H_CDLeft-0xc00)>>1]);\r
289 SPUwriteRegister(H_CDRight,regArea[(H_CDRight-0xc00)>>1]);\r
290\r
291 // fix to prevent new interpolations from crashing\r
292 for(i=0;i<MAXCHAN;i++) s_chan[i].SB[28]=0;\r
293\r
294 SetupTimer(); // start sound processing again\r
295\r
296 return 1;\r
297}\r
298\r
299////////////////////////////////////////////////////////////////////////\r
300\r
301void LoadStateV5(SPUFreeze_t * pF)\r
302{\r
303 int i;SPUOSSFreeze_t * pFO;\r
304\r
305 pFO=(SPUOSSFreeze_t *)(pF+1);\r
306\r
307 spuIrq = pFO->spuIrq;\r
3fc2a4c2 308 if(pFO->pSpuIrq) pSpuIrq = spuMemC+((long)pFO->pSpuIrq&0x7fff0); else pSpuIrq=NULL;\r
ef79bbde
P
309\r
310 if(pFO->spuAddr)\r
311 {\r
312 spuAddr = pFO->spuAddr;\r
313 if (spuAddr == 0xbaadf00d) spuAddr = 0;\r
314 }\r
315\r
6d866bb7 316 dwNewChannel=0;\r
317 dwChannelOn=0;\r
ef79bbde
P
318 for(i=0;i<MAXCHAN;i++)\r
319 {\r
6d866bb7 320 load_channel(&s_chan[i],&pFO->s_chan[i],i);\r
ef79bbde
P
321\r
322 s_chan[i].pStart+=(unsigned long)spuMemC;\r
323 s_chan[i].pCurr+=(unsigned long)spuMemC;\r
324 s_chan[i].pLoop+=(unsigned long)spuMemC;\r
ef79bbde
P
325 }\r
326}\r
327\r
328////////////////////////////////////////////////////////////////////////\r
329\r
330void LoadStateUnknown(SPUFreeze_t * pF)\r
331{\r
332 int i;\r
333\r
334 for(i=0;i<MAXCHAN;i++)\r
335 {\r
ef79bbde 336 s_chan[i].bStop=0;\r
ef79bbde
P
337 s_chan[i].pLoop=spuMemC;\r
338 s_chan[i].pStart=spuMemC;\r
339 s_chan[i].pLoop=spuMemC;\r
ef79bbde
P
340 }\r
341\r
342 dwNewChannel=0;\r
6d866bb7 343 dwChannelOn=0;\r
ef79bbde
P
344 pSpuIrq=0;\r
345\r
346 for(i=0;i<0xc0;i++)\r
347 {\r
348 SPUwriteRegister(0x1f801c00+i*2,regArea[i]);\r
349 }\r
350}\r
351\r
352////////////////////////////////////////////////////////////////////////\r