decouple input/frame limiter from GPU plugin
[pcsx_rearmed.git] / plugins / dfsound / freeze.c
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
31 typedef struct\r
32 {\r
33  char          szSPUName[8];\r
34  uint32_t ulFreezeVersion;\r
35  uint32_t ulFreezeSize;\r
36  unsigned char cSPUPort[0x200];\r
37  unsigned char cSPURam[0x80000];\r
38  xa_decode_t   xaS;     \r
39 } SPUFreeze_t;\r
40 \r
41 typedef struct\r
42 {\r
43  unsigned short  spuIrq;\r
44  uint32_t   pSpuIrq;\r
45  uint32_t   spuAddr;\r
46  uint32_t   dummy1;\r
47  uint32_t   dummy2;\r
48  uint32_t   dummy3;\r
49 \r
50  SPUCHAN  s_chan[MAXCHAN];   \r
51 \r
52 } SPUOSSFreeze_t;\r
53 \r
54 ////////////////////////////////////////////////////////////////////////\r
55 \r
56 void LoadStateV5(SPUFreeze_t * pF);                    // newest version\r
57 void LoadStateUnknown(SPUFreeze_t * pF);               // unknown format\r
58 \r
59 extern int lastch;\r
60 \r
61 ////////////////////////////////////////////////////////////////////////\r
62 // SPUFREEZE: called by main emu on savestate load/save\r
63 ////////////////////////////////////////////////////////////////////////\r
64 \r
65 long CALLBACK SPUfreeze(uint32_t ulFreezeMode,SPUFreeze_t * pF)\r
66 {\r
67  int i;SPUOSSFreeze_t * pFO;\r
68 \r
69  if(!pF) return 0;                                     // first check\r
70 \r
71  if(ulFreezeMode)                                      // info or save?\r
72   {//--------------------------------------------------//\r
73    if(ulFreezeMode==1)                                 \r
74     memset(pF,0,sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t));\r
75 \r
76    strcpy(pF->szSPUName,"PBOSS");\r
77    pF->ulFreezeVersion=5;\r
78    pF->ulFreezeSize=sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t);\r
79 \r
80    if(ulFreezeMode==2) return 1;                       // info mode? ok, bye\r
81                                                        // save mode:\r
82    RemoveTimer();                                      // stop timer\r
83 \r
84    memcpy(pF->cSPURam,spuMem,0x80000);                 // copy common infos\r
85    memcpy(pF->cSPUPort,regArea,0x200);\r
86 \r
87    if(xapGlobal && XAPlay!=XAFeed)                     // some xa\r
88     {\r
89      pF->xaS=*xapGlobal;     \r
90     }\r
91    else \r
92    memset(&pF->xaS,0,sizeof(xa_decode_t));             // or clean xa\r
93 \r
94    pFO=(SPUOSSFreeze_t *)(pF+1);                       // store special stuff\r
95 \r
96    pFO->spuIrq=spuIrq;\r
97    if(pSpuIrq)  pFO->pSpuIrq  = (unsigned long)pSpuIrq-(unsigned long)spuMemC;\r
98 \r
99    pFO->spuAddr=spuAddr;\r
100    if(pFO->spuAddr==0) pFO->spuAddr=0xbaadf00d;\r
101 \r
102    for(i=0;i<MAXCHAN;i++)\r
103     {\r
104      memcpy((void *)&pFO->s_chan[i],(void *)&s_chan[i],sizeof(SPUCHAN));\r
105      if(pFO->s_chan[i].pStart)\r
106       pFO->s_chan[i].pStart-=(unsigned long)spuMemC;\r
107      if(pFO->s_chan[i].pCurr)\r
108       pFO->s_chan[i].pCurr-=(unsigned long)spuMemC;\r
109      if(pFO->s_chan[i].pLoop)\r
110       pFO->s_chan[i].pLoop-=(unsigned long)spuMemC;\r
111     }\r
112 \r
113    SetupTimer();                                       // sound processing on again\r
114 \r
115    return 1;\r
116    //--------------------------------------------------//\r
117   }\r
118                                                        \r
119  if(ulFreezeMode!=0) return 0;                         // bad mode? bye\r
120 \r
121  RemoveTimer();                                        // we stop processing while doing the save!\r
122 \r
123  memcpy(spuMem,pF->cSPURam,0x80000);                   // get ram\r
124  memcpy(regArea,pF->cSPUPort,0x200);\r
125 \r
126  if(pF->xaS.nsamples<=4032)                            // start xa again\r
127   SPUplayADPCMchannel(&pF->xaS);\r
128 \r
129  xapGlobal=0;\r
130 \r
131  if(!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5)\r
132    LoadStateV5(pF);\r
133  else LoadStateUnknown(pF);\r
134 \r
135  lastch = -1;\r
136 \r
137  // repair some globals\r
138  for(i=0;i<=62;i+=2)\r
139   SPUwriteRegister(H_Reverb+i,regArea[(H_Reverb+i-0xc00)>>1]);\r
140  SPUwriteRegister(H_SPUReverbAddr,regArea[(H_SPUReverbAddr-0xc00)>>1]);\r
141  SPUwriteRegister(H_SPUrvolL,regArea[(H_SPUrvolL-0xc00)>>1]);\r
142  SPUwriteRegister(H_SPUrvolR,regArea[(H_SPUrvolR-0xc00)>>1]);\r
143 \r
144  SPUwriteRegister(H_SPUctrl,(unsigned short)(regArea[(H_SPUctrl-0xc00)>>1]|0x4000));\r
145  SPUwriteRegister(H_SPUstat,regArea[(H_SPUstat-0xc00)>>1]);\r
146  SPUwriteRegister(H_CDLeft,regArea[(H_CDLeft-0xc00)>>1]);\r
147  SPUwriteRegister(H_CDRight,regArea[(H_CDRight-0xc00)>>1]);\r
148 \r
149  // fix to prevent new interpolations from crashing\r
150  for(i=0;i<MAXCHAN;i++) s_chan[i].SB[28]=0;\r
151 \r
152  SetupTimer();                                         // start sound processing again\r
153 \r
154  return 1;\r
155 }\r
156 \r
157 ////////////////////////////////////////////////////////////////////////\r
158 \r
159 void LoadStateV5(SPUFreeze_t * pF)\r
160 {\r
161  int i;SPUOSSFreeze_t * pFO;\r
162 \r
163  pFO=(SPUOSSFreeze_t *)(pF+1);\r
164 \r
165  spuIrq = pFO->spuIrq;\r
166  if(pFO->pSpuIrq) pSpuIrq = pFO->pSpuIrq+spuMemC; else pSpuIrq=NULL;\r
167 \r
168  if(pFO->spuAddr)\r
169   {\r
170    spuAddr = pFO->spuAddr;\r
171    if (spuAddr == 0xbaadf00d) spuAddr = 0;\r
172   }\r
173 \r
174  for(i=0;i<MAXCHAN;i++)\r
175   {\r
176    memcpy((void *)&s_chan[i],(void *)&pFO->s_chan[i],sizeof(SPUCHAN));\r
177 \r
178    s_chan[i].pStart+=(unsigned long)spuMemC;\r
179    s_chan[i].pCurr+=(unsigned long)spuMemC;\r
180    s_chan[i].pLoop+=(unsigned long)spuMemC;\r
181    s_chan[i].iMute=0;\r
182    s_chan[i].iIrqDone=0;\r
183   }\r
184 }\r
185 \r
186 ////////////////////////////////////////////////////////////////////////\r
187 \r
188 void LoadStateUnknown(SPUFreeze_t * pF)\r
189 {\r
190  int i;\r
191 \r
192  for(i=0;i<MAXCHAN;i++)\r
193   {\r
194    s_chan[i].bOn=0;\r
195    s_chan[i].bNew=0;\r
196    s_chan[i].bStop=0;\r
197    s_chan[i].ADSR.lVolume=0;\r
198    s_chan[i].pLoop=spuMemC;\r
199    s_chan[i].pStart=spuMemC;\r
200    s_chan[i].pLoop=spuMemC;\r
201    s_chan[i].iMute=0;\r
202    s_chan[i].iIrqDone=0;\r
203   }\r
204 \r
205  dwNewChannel=0;\r
206  pSpuIrq=0;\r
207 \r
208  for(i=0;i<0xc0;i++)\r
209   {\r
210    SPUwriteRegister(0x1f801c00+i*2,regArea[i]);\r
211   }\r
212 }\r
213 \r
214 ////////////////////////////////////////////////////////////////////////\r