/[pcsx2_0.9.7]/trunk/plugins/zerospu2/zeroworker.cpp
ViewVC logotype

Contents of /trunk/plugins/zerospu2/zeroworker.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 8556 byte(s)
re-commit (had local access denied errors when committing)
1 /* ZeroSPU2
2 * Copyright (C) 2006-2010 zerofrog
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "zerospu2.h"
20 #include "zeroworker.h"
21 #include "soundtouch/SoundTouch.h"
22 #ifdef __LINUX__
23 #include "WavFile.h"
24 #else
25 #include "soundtouch/WavFile.h"
26 #endif
27
28 s32 g_logsound = 0;
29 WavOutFile* g_pWavRecord=NULL; // used for recording
30
31 const s32 f[5][2] = {
32 { 0, 0 },
33 { 60, 0 },
34 { 115, -52 },
35 { 98, -55 },
36 { 122, -60 } };
37
38 s32 predict_nr, shift_factor, flags;
39 s32 s_1, s_2;
40
41 static __forceinline s32 SetPacket(s32 val)
42 {
43 s32 ret;
44 if (val & 0x8000) val |= 0xffff0000;
45 ret = (val >> shift_factor);
46 ret += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6);
47 s_2 = s_1;
48 s_1 = ret;
49
50 return ret;
51 }
52
53 void SPU2Loop(VOICE_PROCESSED* pChannel, u32 ch)
54 {
55 u8* start;
56 u32 nSample;
57
58 for (u32 ns = 0; ns < NSSIZE; ns++)
59 {
60 // fmod freq channel
61 if (pChannel->bFMod == 1 && iFMod[ns]) pChannel->FModChangeFrequency(ns);
62
63 while(pChannel->spos >= 0x10000 )
64 {
65 if (pChannel->iSBPos == 28) // 28 reached?
66 {
67 start=pChannel->pCurr; // set up the current pos
68
69 // special "stop" sign
70 if (start == (u8*)-1) //!pChannel->bOn
71 {
72 pChannel->bOn = false; // -> turn everything off
73 pChannel->ADSRX.lVolume = 0;
74 pChannel->ADSRX.EnvelopeVol = 0;
75 return; // -> and done for this channel
76 }
77
78 predict_nr = (s32)start[0];
79 shift_factor = predict_nr&0xf;
80 predict_nr >>= 4;
81 flags=(s32)start[1];
82 start += 2;
83
84 pChannel->iSBPos = 0;
85
86 // decode the 16byte packet
87 s_1 = pChannel->s_1;
88 s_2 = pChannel->s_2;
89
90 for (nSample=0; nSample<28; ++start)
91 {
92 s32 d = (s32)*start;
93 s32 s;
94
95 s = ((d & 0xf)<<12);
96 pChannel->SB[nSample++] = SetPacket(s);
97
98 s = ((d & 0xf0) << 8);
99 pChannel->SB[nSample++] = SetPacket(s);
100 }
101
102 // irq occurs no matter what core accesses the address
103 for (s32 core = 0; core < 2; ++core)
104 {
105 if (spu2attr(core).irq) // some callback and irq active?
106 {
107 // if irq address reached or irq on looping addr, when stop/loop flag is set
108 u8* pirq = (u8*)pSpuIrq[core];
109
110 if ((pirq > (start - 16) && pirq <= start) ||
111 ((flags & 1) && (pirq > (pChannel->pLoop - 16) && pirq <= pChannel->pLoop)))
112 {
113 IRQINFO |= 4 << core;
114 SPU2_LOG("SPU2Worker:interrupt\n");
115 irqCallbackSPU2();
116 }
117 }
118 }
119
120 // flag handler
121 if ((flags & 4) && (!pChannel->bIgnoreLoop))
122 pChannel->pLoop = start - 16; // loop address
123
124 if (flags & 1) // 1: stop/loop
125 {
126 // We play this block out first...
127 dwEndChannel2[ch / 24] |= (1 << (ch % 24));
128
129 if (flags != 3 || pChannel->pLoop == NULL)
130 { // and checking if pLoop is set avoids crashes, yeah
131 start = (u8*)-1;
132 pChannel->bStop = true;
133 pChannel->bIgnoreLoop = false;
134 }
135 else
136 {
137 start = pChannel->pLoop;
138 }
139 }
140
141 pChannel->pCurr = start; // store values for next cycle
142 pChannel->s_1 = s_1;
143 pChannel->s_2 = s_2;
144 }
145
146 pChannel->StoreInterpolationVal(pChannel->SB[pChannel->iSBPos++]); // get sample data
147 pChannel->spos -= 0x10000;
148 }
149
150 s32 sval = (MixADSR(pChannel) * pChannel->iGetVal()) / 1023; // mix adsr with noise or sample val.
151
152 if (pChannel->bFMod == 2) // fmod freq channel
153 {
154 // -> store 1T sample data, use that to do fmod on next channel
155 if (!pChannel->bNoise) iFMod[ns] = sval;
156 }
157 else
158 {
159 if (pChannel->bVolumeL)
160 s_buffers[ns][0] += (sval * pChannel->leftvol) >> 14;
161
162 if (pChannel->bVolumeR)
163 s_buffers[ns][1] += (sval * pChannel->rightvol) >> 14;
164 }
165
166 pChannel->spos += pChannel->sinc;
167 }
168 }
169 // simulate SPU2 for 1ms
170 void SPU2Worker()
171 {
172 // assume s_buffers are zeroed out
173 if (dwNewChannel2[0] || dwNewChannel2[1]) s_pAudioBuffers[s_nCurBuffer].newchannels++;
174
175 VOICE_PROCESSED* pChannel = voices;
176 for (u32 ch=0; ch < SPU_NUMBER_VOICES; ch++, pChannel++) // loop em all... we will collect 1 ms of sound of each playing channel
177 {
178 if (pChannel->bNew)
179 {
180 pChannel->StartSound(); // start new sound
181 dwEndChannel2[ch / 24] &= ~(1 << (ch % 24)); // clear end channel bit
182 dwNewChannel2[ch / 24] &= ~(1 << (ch % 24)); // clear channel bit
183 }
184
185 if (!pChannel->bOn) continue;
186
187 if (pChannel->iActFreq != pChannel->iUsedFreq) // new psx frequency?
188 pChannel->VoiceChangeFrequency();
189
190 // loop until 1 ms of data is reached
191 SPU2Loop(pChannel, ch);
192 }
193
194 // mix all channels
195 MixChannels(0);
196 MixChannels(1);
197
198 if ( g_bPlaySound )
199 {
200 assert( s_pCurOutput != NULL);
201
202 for (u32 ns = 0; ns < NSSIZE; ns++)
203 {
204 // clamp and write
205 clampandwrite16(s_pCurOutput[0],s_buffers[ns][0]);
206 clampandwrite16(s_pCurOutput[1],s_buffers[ns][1]);
207
208 s_pCurOutput += 2;
209 s_buffers[ns][0] = 0;
210 s_buffers[ns][1] = 0;
211 }
212 // check if end reached
213
214 if ((uptr)s_pCurOutput - (uptr)s_pAudioBuffers[s_nCurBuffer].pbuf >= 4 * NS_TOTAL_SIZE)
215 {
216
217 if ( conf.options & OPTION_RECORDING )
218 {
219 static s32 lastrectime = 0;
220 if (timeGetTime() - lastrectime > 5000)
221 {
222 WARN_LOG("ZeroSPU2: recording\n");
223 lastrectime = timeGetTime();
224 }
225 LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NS_TOTAL_SIZE);
226 }
227
228 if ( s_nQueuedBuffers >= ArraySize(s_pAudioBuffers)-1 )
229 {
230 //ZeroSPU2: dropping packets! game too fast
231 s_nDropPacket += NSFRAMES;
232 s_GlobalTimeStamp = GetMicroTime();
233 }
234 else {
235 // submit to final mixer
236 #ifdef ZEROSPU2_DEVBUILD
237 if ( g_logsound )
238 LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf + 2, 4, NS_TOTAL_SIZE);
239 #endif
240 if ( g_startcount == 0xffffffff )
241 {
242 g_startcount = timeGetTime();
243 g_packetcount = 0;
244 }
245
246 if ( conf.options & OPTION_TIMESTRETCH )
247 {
248 u32 newtotal = s_nTotalDuration - s_nDurations[s_nCurDuration];
249 u64 newtime = GetMicroTime();
250 u32 duration;
251
252 if (s_GlobalTimeStamp == 0) s_GlobalTimeStamp = newtime - NSFRAMES * 1000;
253 duration = (u32)(newtime-s_GlobalTimeStamp);
254
255 s_nDurations[s_nCurDuration] = duration;
256 s_nTotalDuration = newtotal + duration;
257 s_nCurDuration = (s_nCurDuration+1)%ArraySize(s_nDurations);
258 s_GlobalTimeStamp = newtime;
259 s_pAudioBuffers[s_nCurBuffer].timestamp = timeGetTime();
260 s_pAudioBuffers[s_nCurBuffer].avgtime = s_nTotalDuration/ArraySize(s_nDurations);
261 }
262
263 s_pAudioBuffers[s_nCurBuffer].len = 4 * NS_TOTAL_SIZE;
264 InterlockedExchangeAdd((long*)&s_nQueuedBuffers, 1);
265
266 s_nCurBuffer = (s_nCurBuffer+1)%ArraySize(s_pAudioBuffers);
267 s_pAudioBuffers[s_nCurBuffer].newchannels = 0; // reset
268 }
269
270 // restart
271 s_pCurOutput = (s16*)s_pAudioBuffers[s_nCurBuffer].pbuf;
272 }
273 }
274 }
275
276 // size is in bytes
277 void LogPacketSound(void* packet, s32 memsize)
278 {
279 u16 buf[28];
280
281 u8* pstart = (u8*)packet;
282 s_1 = s_2 = 0;
283
284 for (s32 i = 0; i < memsize; i += 16)
285 {
286 predict_nr = (s32)pstart[0];
287 shift_factor = predict_nr&0xf;
288 predict_nr >>= 4;
289 pstart += 2;
290
291 for (s32 nSample = 0;nSample < 28; ++pstart)
292 {
293 s32 d = (s32)*pstart;
294
295 s32 temp;
296
297 temp = ((d & 0xf) << 12);
298 buf[nSample++] = SetPacket(temp);
299 temp = ((d & 0xf0) << 8);
300 buf[nSample++] = SetPacket(temp);
301 }
302
303 LogRawSound(buf, 2, buf, 2, 28);
304 }
305 }
306
307 void LogRawSound(void* pleft, s32 leftstride, void* pright, s32 rightstride, s32 numsamples)
308 {
309 if (g_pWavRecord == NULL )
310 g_pWavRecord = new WavOutFile(RECORD_FILENAME, SAMPLE_RATE, 16, 2);
311
312 u8* left = (u8*)pleft;
313 u8* right = (u8*)pright;
314 static vector<s16> tempbuf;
315
316 tempbuf.resize(2 * numsamples);
317
318 for (s32 i = 0; i < numsamples; ++i)
319 {
320 tempbuf[2*i+0] = *(s16*)left;
321 tempbuf[2*i+1] = *(s16*)right;
322 left += leftstride;
323 right += rightstride;
324 }
325
326 g_pWavRecord->write(&tempbuf[0], numsamples*2);
327 }

  ViewVC Help
Powered by ViewVC 1.1.22