1 /***********************************************************************************
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
5 Jerremy Koot (jkoot@snes9x.com)
6
7 (c) Copyright 2002 - 2004 Matthew Kendora
8
9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
10
11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
14
15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
16 Kris Bleakley (codeviolation@hotmail.com)
17
18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
19 Nach (n-a-c-h@users.sourceforge.net),
20
21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
22
23 (c) Copyright 2006 - 2007 nitsuja
24
25 (c) Copyright 2009 - 2016 BearOso,
26 OV2
27
28
29 BS-X C emulator code
30 (c) Copyright 2005 - 2006 Dreamer Nom,
31 zones
32
33 C4 x86 assembler and some C emulation code
34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
35 Nach,
36 zsKnight (zsknight@zsnes.com)
37
38 C4 C++ code
39 (c) Copyright 2003 - 2006 Brad Jorsch,
40 Nach
41
42 DSP-1 emulator code
43 (c) Copyright 1998 - 2006 _Demo_,
44 Andreas Naive (andreasnaive@gmail.com),
45 Gary Henderson,
46 Ivar (ivar@snes9x.com),
47 John Weidman,
48 Kris Bleakley,
49 Matthew Kendora,
50 Nach,
51 neviksti (neviksti@hotmail.com)
52
53 DSP-2 emulator code
54 (c) Copyright 2003 John Weidman,
55 Kris Bleakley,
56 Lord Nightmare (lord_nightmare@users.sourceforge.net),
57 Matthew Kendora,
58 neviksti
59
60 DSP-3 emulator code
61 (c) Copyright 2003 - 2006 John Weidman,
62 Kris Bleakley,
63 Lancer,
64 z80 gaiden
65
66 DSP-4 emulator code
67 (c) Copyright 2004 - 2006 Dreamer Nom,
68 John Weidman,
69 Kris Bleakley,
70 Nach,
71 z80 gaiden
72
73 OBC1 emulator code
74 (c) Copyright 2001 - 2004 zsKnight,
75 pagefault (pagefault@zsnes.com),
76 Kris Bleakley
77 Ported from x86 assembler to C by sanmaiwashi
78
79 SPC7110 and RTC C++ emulator code used in 1.39-1.51
80 (c) Copyright 2002 Matthew Kendora with research by
81 zsKnight,
82 John Weidman,
83 Dark Force
84
85 SPC7110 and RTC C++ emulator code used in 1.52+
86 (c) Copyright 2009 byuu,
87 neviksti
88
89 S-DD1 C emulator code
90 (c) Copyright 2003 Brad Jorsch with research by
91 Andreas Naive,
92 John Weidman
93
94 S-RTC C emulator code
95 (c) Copyright 2001 - 2006 byuu,
96 John Weidman
97
98 ST010 C++ emulator code
99 (c) Copyright 2003 Feather,
100 John Weidman,
101 Kris Bleakley,
102 Matthew Kendora
103
104 Super FX x86 assembler emulator code
105 (c) Copyright 1998 - 2003 _Demo_,
106 pagefault,
107 zsKnight
108
109 Super FX C emulator code
110 (c) Copyright 1997 - 1999 Ivar,
111 Gary Henderson,
112 John Weidman
113
114 Sound emulator code used in 1.5-1.51
115 (c) Copyright 1998 - 2003 Brad Martin
116 (c) Copyright 1998 - 2006 Charles Bilyue'
117
118 Sound emulator code used in 1.52+
119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
120
121 S-SMP emulator code used in 1.54+
122 (c) Copyright 2016 byuu
123
124 SH assembler code partly based on x86 assembler code
125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
126
127 2xSaI filter
128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
129
130 HQ2x, HQ3x, HQ4x filters
131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
132
133 NTSC filter
134 (c) Copyright 2006 - 2007 Shay Green
135
136 GTK+ GUI code
137 (c) Copyright 2004 - 2016 BearOso
138
139 Win32 GUI code
140 (c) Copyright 2003 - 2006 blip,
141 funkyass,
142 Matthew Kendora,
143 Nach,
144 nitsuja
145 (c) Copyright 2009 - 2016 OV2
146
147 Mac OS GUI code
148 (c) Copyright 1998 - 2001 John Stiles
149 (c) Copyright 2001 - 2011 zones
150
151
152 Specific ports contains the works of other authors. See headers in
153 individual files.
154
155
156 Snes9x homepage: http://www.snes9x.com/
157
158 Permission to use, copy, modify and/or distribute Snes9x in both binary
159 and source form, for non-commercial purposes, is hereby granted without
160 fee, providing that this license information and copyright notice appear
161 with all copies and any derived work.
162
163 This software is provided 'as-is', without any express or implied
164 warranty. In no event shall the authors be held liable for any damages
165 arising from the use of this software or it's derivatives.
166
167 Snes9x is freeware for PERSONAL USE only. Commercial users should
168 seek permission of the copyright holders first. Commercial use includes,
169 but is not limited to, charging money for Snes9x or software derived from
170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
171 using Snes9x as a promotion for your commercial product.
172
173 The copyright holders request that bug fixes and improvements to the code
174 should be forwarded to them so everyone can benefit from the modifications
175 in future versions.
176
177 Super NES and Super Nintendo Entertainment System are trademarks of
178 Nintendo Co., Limited and its subsidiary companies.
179 ***********************************************************************************/
180
181
182 #include "CXAudio2.h"
183 #include "../snes9x.h"
184 #include "../apu/apu.h"
185 #include "wsnes9x.h"
186 #include <process.h>
187 #include <Dxerr.h>
188
189 /* CXAudio2
190 Implements audio output through XAudio2.
191 Basic idea: one master voice and one source voice are created;
192 the source voice consumes buffers queued by PushBuffer, plays them through
193 the master voice and calls OnBufferEnd after each buffer.
194 ProcessSound copies new samples into the buffer and queues them for playback.
195 */
196
197 /* Construction/Destruction
198 */
CXAudio2(void)199 CXAudio2::CXAudio2(void)
200 {
201 pXAudio2 = NULL;
202 pSourceVoice = NULL;
203 pMasterVoice = NULL;
204
205 sum_bufferSize = singleBufferBytes \
206 = singleBufferSamples = blockCount = 0;
207 soundBuffer = NULL;
208 initDone = false;
209 }
210
~CXAudio2(void)211 CXAudio2::~CXAudio2(void)
212 {
213 DeInitXAudio2();
214 }
215
216 /* CXAudio2::InitXAudio2
217 initializes the XAudio2 object
218 -----
219 returns true if successful, false otherwise
220 */
InitXAudio2(void)221 bool CXAudio2::InitXAudio2(void)
222 {
223 if(initDone)
224 return true;
225
226 HRESULT hr;
227 if ( FAILED(hr = XAudio2Create( &pXAudio2, 0 , XAUDIO2_DEFAULT_PROCESSOR ) ) ) {
228 DXTRACE_ERR_MSGBOX(TEXT("Unable to create XAudio2 object."),hr);
229 MessageBox (GUI.hWnd, TEXT("\
230 Unable to initialize XAudio2. You will not be able to hear any\n\
231 sound effects or music while playing.\n\n\
232 This is usually caused by not having a recent DirectX release installed."),
233 TEXT("Snes9X - Unable to Initialize XAudio2"),
234 MB_OK | MB_ICONWARNING);
235 return false;
236 }
237 initDone = true;
238 return true;
239 }
240
241 /* CXAudio2::InitVoices
242 initializes the voice objects with the current audio settings
243 -----
244 returns true if successful, false otherwise
245 */
InitVoices(void)246 bool CXAudio2::InitVoices(void)
247 {
248 HRESULT hr;
249 if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, (Settings.Stereo?2:1),
250 Settings.SoundPlaybackRate, 0, 0 , NULL ) ) ) {
251 DXTRACE_ERR_MSGBOX(TEXT("Unable to create mastering voice."),hr);
252 return false;
253 }
254
255 WAVEFORMATEX wfx;
256 wfx.wFormatTag = WAVE_FORMAT_PCM;
257 wfx.nChannels = Settings.Stereo ? 2 : 1;
258 wfx.nSamplesPerSec = Settings.SoundPlaybackRate;
259 wfx.nBlockAlign = (Settings.SixteenBitSound ? 2 : 1) * (Settings.Stereo ? 2 : 1);
260 wfx.wBitsPerSample = Settings.SixteenBitSound ? 16 : 8;
261 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
262 wfx.cbSize = 0;
263
264 if( FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx,
265 XAUDIO2_VOICE_NOSRC , XAUDIO2_DEFAULT_FREQ_RATIO, this, NULL, NULL ) ) ) {
266 DXTRACE_ERR_MSGBOX(TEXT("Unable to create source voice."),hr);
267 return false;
268 }
269
270 return true;
271 }
272
273 /* CXAudio2::DeInitXAudio2
274 deinitializes all objects
275 */
DeInitXAudio2(void)276 void CXAudio2::DeInitXAudio2(void)
277 {
278 initDone = false;
279 DeInitVoices();
280 if(pXAudio2) {
281 pXAudio2->Release();
282 pXAudio2 = NULL;
283 }
284 }
285
286 /* CXAudio2::DeInitVoices
287 deinitializes the voice objects and buffers
288 */
DeInitVoices(void)289 void CXAudio2::DeInitVoices(void)
290 {
291 if(pSourceVoice) {
292 StopPlayback();
293 pSourceVoice->DestroyVoice();
294 pSourceVoice = NULL;
295 }
296 if(pMasterVoice) {
297 pMasterVoice->DestroyVoice();
298 pMasterVoice = NULL;
299 }
300 if(soundBuffer) {
301 delete [] soundBuffer;
302 soundBuffer = NULL;
303 }
304 }
305
306 /* CXAudio2::OnBufferEnd
307 callback function called by the source voice
308 IN:
309 pBufferContext - unused
310 */
OnBufferEnd(void * pBufferContext)311 void CXAudio2::OnBufferEnd(void *pBufferContext)
312 {
313 InterlockedDecrement(&bufferCount);
314 SetEvent(GUI.SoundSyncEvent);
315 }
316
317 /* CXAudio2::PushBuffer
318 pushes one buffer onto the source voice playback queue
319 IN:
320 AudioBytes - size of the buffer
321 pAudioData - pointer to the buffer
322 pContext - context passed to the callback, currently unused
323 */
PushBuffer(UINT32 AudioBytes,BYTE * pAudioData,void * pContext)324 void CXAudio2::PushBuffer(UINT32 AudioBytes,BYTE *pAudioData,void *pContext)
325 {
326 XAUDIO2_BUFFER xa2buffer={0};
327 xa2buffer.AudioBytes=AudioBytes;
328 xa2buffer.pAudioData=pAudioData;
329 xa2buffer.pContext=pContext;
330 InterlockedIncrement(&bufferCount);
331 pSourceVoice->SubmitSourceBuffer(&xa2buffer);
332 }
333
334 /* CXAudio2::SetupSound
335 applies current sound settings by recreating the voice objects and buffers
336 -----
337 returns true if successful, false otherwise
338 */
SetupSound()339 bool CXAudio2::SetupSound()
340 {
341 if(!initDone)
342 return false;
343
344 DeInitVoices();
345
346 blockCount = 8;
347 UINT32 blockTime = GUI.SoundBufferSize / blockCount;
348
349 singleBufferSamples = (Settings.SoundPlaybackRate * blockTime * (Settings.Stereo ? 2 : 1)) / 1000;
350 singleBufferBytes = singleBufferSamples * (Settings.SixteenBitSound ? 2 : 1);
351 sum_bufferSize = singleBufferBytes * blockCount;
352
353 if (InitVoices())
354 {
355 soundBuffer = new uint8[sum_bufferSize];
356 writeOffset = 0;
357 }
358 else {
359 DeInitVoices();
360 return false;
361 }
362
363 bufferCount = 0;
364
365 BeginPlayback();
366
367 return true;
368 }
369
BeginPlayback()370 void CXAudio2::BeginPlayback()
371 {
372 pSourceVoice->Start(0);
373 }
374
StopPlayback()375 void CXAudio2::StopPlayback()
376 {
377 pSourceVoice->Stop(0);
378 }
379
380 /* CXAudio2::ProcessSound
381 The mixing function called by the sound core when new samples are available.
382 SoundBuffer is divided into blockCount blocks. If there are enought available samples and a free block,
383 the block is filled and queued to the source voice. bufferCount is increased by pushbuffer and decreased by
384 the OnBufferComplete callback.
385 */
ProcessSound()386 void CXAudio2::ProcessSound()
387 {
388 S9xFinalizeSamples();
389
390 if(!initDone)
391 return;
392
393 BYTE * curBuffer;
394
395 UINT32 availableSamples;
396
397 availableSamples = S9xGetSampleCount();
398
399 while(availableSamples > singleBufferSamples && bufferCount < blockCount) {
400 curBuffer = soundBuffer + writeOffset;
401 S9xMixSamples(curBuffer,singleBufferSamples);
402 PushBuffer(singleBufferBytes,curBuffer,NULL);
403 writeOffset+=singleBufferBytes;
404 writeOffset%=sum_bufferSize;
405 availableSamples -= singleBufferSamples;
406 }
407 }
408