mirror of https://github.com/snes9xgit/snes9x.git
win32: Add a WaveOut driver.
This commit is contained in:
parent
fd177fb317
commit
ed3beae304
|
@ -0,0 +1,176 @@
|
|||
/*****************************************************************************\
|
||||
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
||||
This file is licensed under the Snes9x License.
|
||||
For further information, consult the LICENSE file in the root directory.
|
||||
\*****************************************************************************/
|
||||
|
||||
#include "CWaveOut.h"
|
||||
#include "../snes9x.h"
|
||||
#include "../apu/apu.h"
|
||||
#include "wsnes9x.h"
|
||||
|
||||
CWaveOut::CWaveOut(void)
|
||||
{
|
||||
hWaveOut = NULL;
|
||||
initDone = false;
|
||||
}
|
||||
|
||||
CWaveOut::~CWaveOut(void)
|
||||
{
|
||||
DeInitSoundOutput();
|
||||
}
|
||||
|
||||
void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
|
||||
{
|
||||
if (uMsg == WOM_DONE)
|
||||
{
|
||||
InterlockedDecrement(((volatile LONG *)dwUser));
|
||||
SetEvent(GUI.SoundSyncEvent);
|
||||
}
|
||||
}
|
||||
|
||||
bool CWaveOut::SetupSound()
|
||||
{
|
||||
WAVEFORMATEX wfx;
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 2;
|
||||
wfx.nSamplesPerSec = Settings.SoundPlaybackRate;
|
||||
wfx.nBlockAlign = 2 * 2;
|
||||
wfx.wBitsPerSample = 16;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
wfx.cbSize = 0;
|
||||
|
||||
waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)WaveCallback, (DWORD_PTR)&bufferCount, CALLBACK_FUNCTION);
|
||||
|
||||
UINT32 blockTime = GUI.SoundBufferSize / blockCount;
|
||||
singleBufferSamples = (Settings.SoundPlaybackRate * blockTime) / 1000;
|
||||
singleBufferSamples *= 2;
|
||||
singleBufferBytes = singleBufferSamples * 2;
|
||||
sumBufferSize = singleBufferBytes * blockCount;
|
||||
writeOffset = 0;
|
||||
partialOffset = 0;
|
||||
|
||||
waveHeaders.resize(blockCount);
|
||||
for (auto &w : waveHeaders)
|
||||
{
|
||||
w.lpData = (LPSTR)LocalAlloc(LMEM_FIXED, singleBufferBytes);
|
||||
w.dwBufferLength = singleBufferBytes;
|
||||
w.dwBytesRecorded = 0;
|
||||
w.dwUser = 0;
|
||||
w.dwFlags = 0;
|
||||
w.dwLoops = 0;
|
||||
w.lpNext = 0;
|
||||
w.reserved = 0;
|
||||
waveOutPrepareHeader(hWaveOut, &w, sizeof(WAVEHDR));
|
||||
}
|
||||
initDone = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWaveOut::SetVolume(double volume)
|
||||
{
|
||||
waveOutSetVolume(hWaveOut, 0xffffffff);
|
||||
}
|
||||
|
||||
void CWaveOut::BeginPlayback()
|
||||
{
|
||||
waveOutRestart(hWaveOut);
|
||||
}
|
||||
|
||||
bool CWaveOut::InitSoundOutput()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWaveOut::DeInitSoundOutput()
|
||||
{
|
||||
if (!initDone)
|
||||
return;
|
||||
|
||||
waveOutReset(hWaveOut);
|
||||
|
||||
if (!waveHeaders.empty())
|
||||
{
|
||||
for (auto &w : waveHeaders)
|
||||
{
|
||||
waveOutUnprepareHeader(hWaveOut, &w, sizeof(WAVEHDR));
|
||||
LocalFree(w.lpData);
|
||||
}
|
||||
}
|
||||
waveHeaders.clear();
|
||||
|
||||
waveOutClose(hWaveOut);
|
||||
|
||||
initDone = false;
|
||||
}
|
||||
|
||||
void CWaveOut::StopPlayback()
|
||||
{
|
||||
waveOutPause(hWaveOut);
|
||||
}
|
||||
|
||||
void CWaveOut::ProcessSound()
|
||||
{
|
||||
int freeBytes = ((blockCount - bufferCount) * singleBufferBytes) - partialOffset;
|
||||
|
||||
if (Settings.DynamicRateControl)
|
||||
{
|
||||
S9xUpdateDynamicRate(freeBytes, sumBufferSize);
|
||||
}
|
||||
|
||||
UINT32 availableSamples;
|
||||
|
||||
availableSamples = S9xGetSampleCount();
|
||||
|
||||
if (Settings.DynamicRateControl)
|
||||
{
|
||||
// Using rate control, we should always keep the emulator's sound buffers empty to
|
||||
// maintain an accurate measurement.
|
||||
if (availableSamples > (freeBytes >> 1))
|
||||
{
|
||||
S9xClearSamples();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!initDone)
|
||||
return;
|
||||
|
||||
if (partialOffset != 0) {
|
||||
UINT32 samplesleftinblock = (singleBufferBytes - partialOffset) >> 1;
|
||||
BYTE *offsetBuffer = (BYTE *)waveHeaders[writeOffset].lpData + partialOffset;
|
||||
|
||||
if (availableSamples <= samplesleftinblock)
|
||||
{
|
||||
S9xMixSamples(offsetBuffer, availableSamples);
|
||||
partialOffset += availableSamples << 1;
|
||||
availableSamples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
S9xMixSamples(offsetBuffer, samplesleftinblock);
|
||||
partialOffset = 0;
|
||||
availableSamples -= samplesleftinblock;
|
||||
waveOutWrite(hWaveOut, &waveHeaders[writeOffset], sizeof(WAVEHDR));
|
||||
InterlockedIncrement(&bufferCount);
|
||||
writeOffset++;
|
||||
writeOffset %= bufferCount;
|
||||
}
|
||||
}
|
||||
|
||||
while (availableSamples >= singleBufferSamples && bufferCount < blockCount) {
|
||||
BYTE *curBuffer = (BYTE *)waveHeaders[writeOffset].lpData;
|
||||
S9xMixSamples(curBuffer, singleBufferSamples);
|
||||
waveOutWrite(hWaveOut, &waveHeaders[writeOffset], sizeof(WAVEHDR));
|
||||
InterlockedIncrement(&bufferCount);
|
||||
writeOffset++;
|
||||
writeOffset %= bufferCount;
|
||||
availableSamples -= singleBufferSamples;
|
||||
}
|
||||
|
||||
if (availableSamples > 0 && bufferCount < blockCount) {
|
||||
S9xMixSamples((BYTE *)waveHeaders[writeOffset].lpData, availableSamples);
|
||||
partialOffset = availableSamples << 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*****************************************************************************\
|
||||
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
||||
This file is licensed under the Snes9x License.
|
||||
For further information, consult the LICENSE file in the root directory.
|
||||
\*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../snes9x.h"
|
||||
#include <windows.h>
|
||||
#include "IS9xSoundOutput.h"
|
||||
#include <mmsystem.h>
|
||||
#include <vector>
|
||||
|
||||
class CWaveOut : public IS9xSoundOutput
|
||||
{
|
||||
private:
|
||||
void BeginPlayback(void);
|
||||
void StopPlayback(void);
|
||||
void ProcessSound(void);
|
||||
|
||||
HWAVEOUT hWaveOut;
|
||||
bool initDone;
|
||||
|
||||
volatile LONG bufferCount;
|
||||
UINT32 sumBufferSize;
|
||||
UINT32 singleBufferSamples;
|
||||
UINT32 singleBufferBytes;
|
||||
const UINT32 blockCount = 8;
|
||||
UINT32 writeOffset;
|
||||
UINT32 partialOffset;
|
||||
std::vector<WAVEHDR> waveHeaders;
|
||||
|
||||
public:
|
||||
CWaveOut(void);
|
||||
~CWaveOut(void);
|
||||
|
||||
// Inherited from IS9xSoundOutput
|
||||
bool InitSoundOutput(void);
|
||||
void DeInitSoundOutput(void);
|
||||
bool SetupSound(void);
|
||||
void SetVolume(double volume);
|
||||
};
|
|
@ -439,6 +439,7 @@
|
|||
<ClInclude Include="cgMini.h" />
|
||||
<ClInclude Include="COpenGL.h" />
|
||||
<ClInclude Include="CShaderParamDlg.h" />
|
||||
<ClInclude Include="CWaveOut.h" />
|
||||
<ClInclude Include="CXAudio2.h" />
|
||||
<ClInclude Include="dxerr.h" />
|
||||
<ClInclude Include="gl_core_3_1.h" />
|
||||
|
@ -582,6 +583,7 @@
|
|||
<ClCompile Include="CGLCG.cpp" />
|
||||
<ClCompile Include="COpenGL.cpp" />
|
||||
<ClCompile Include="CShaderParamDlg.cpp" />
|
||||
<ClCompile Include="CWaveOut.cpp" />
|
||||
<ClCompile Include="CXAudio2.cpp" />
|
||||
<ClCompile Include="DumpAtEnd.cpp" />
|
||||
<ClCompile Include="dxerr.cpp" />
|
||||
|
|
|
@ -291,6 +291,9 @@
|
|||
<ClInclude Include="..\shaders\SPIRV-Cross\spirv_parser.hpp">
|
||||
<Filter>Shaders</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CWaveOut.h">
|
||||
<Filter>GUI\SoundDriver</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\bsx.cpp">
|
||||
|
@ -623,6 +626,9 @@
|
|||
<ClCompile Include="..\shaders\SPIRV-Cross\spirv_parser.cpp">
|
||||
<Filter>Shaders</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CWaveOut.cpp">
|
||||
<Filter>GUI\SoundDriver</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="rsrc\nodrop.cur">
|
||||
|
|
Loading…
Reference in New Issue