Performance: Code optimizations (7-10% faster than 0.9.3)
This commit is contained in:
parent
6588872e42
commit
2b851d5d38
9 changed files with 184 additions and 93 deletions
143
Core/Console.cpp
143
Core/Console.cpp
|
@ -409,93 +409,92 @@ void Console::Run()
|
||||||
UpdateNesModel(true);
|
UpdateNesModel(true);
|
||||||
|
|
||||||
bool crashed = false;
|
bool crashed = false;
|
||||||
while(true) {
|
try {
|
||||||
try {
|
while(true) {
|
||||||
_cpu->Exec();
|
_cpu->Exec();
|
||||||
} catch(const std::runtime_error &ex) {
|
|
||||||
crashed = true;
|
|
||||||
MessageManager::DisplayMessage("Error", "GameCrash", ex.what());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_resetRequested) {
|
if(_resetRequested) {
|
||||||
//Used by NSF player to reset console after changing track
|
//Used by NSF player to reset console after changing track
|
||||||
//Also used with DisablePpuReset option to reset mid-frame
|
//Also used with DisablePpuReset option to reset mid-frame
|
||||||
MovieManager::Stop();
|
MovieManager::Stop();
|
||||||
ResetComponents(true);
|
ResetComponents(true);
|
||||||
_resetRequested = false;
|
_resetRequested = false;
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t currentFrameNumber = PPU::GetFrameCount();
|
|
||||||
if(currentFrameNumber != lastFrameNumber) {
|
|
||||||
_rewindManager->ProcessEndOfFrame();
|
|
||||||
EmulationSettings::DisableOverclocking(_disableOcNextFrame || NsfMapper::GetInstance());
|
|
||||||
_disableOcNextFrame = false;
|
|
||||||
|
|
||||||
//Sleep until we're ready to start the next frame
|
|
||||||
clockTimer.WaitUntil(targetTime);
|
|
||||||
|
|
||||||
if(!_pauseLock.IsFree()) {
|
|
||||||
//Need to temporarely pause the emu (to save/load a state, etc.)
|
|
||||||
_runLock.Release();
|
|
||||||
|
|
||||||
//Spin wait until we are allowed to start again
|
|
||||||
_pauseLock.WaitForRelease();
|
|
||||||
|
|
||||||
_runLock.Acquire();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool paused = EmulationSettings::IsPaused();
|
uint32_t currentFrameNumber = PPU::GetFrameCount();
|
||||||
if(paused && !_stop) {
|
if(currentFrameNumber != lastFrameNumber) {
|
||||||
MessageManager::SendNotification(ConsoleNotificationType::GamePaused);
|
_rewindManager->ProcessEndOfFrame();
|
||||||
|
EmulationSettings::DisableOverclocking(_disableOcNextFrame || NsfMapper::GetInstance());
|
||||||
//Prevent audio from looping endlessly while game is paused
|
_disableOcNextFrame = false;
|
||||||
SoundMixer::StopAudio();
|
|
||||||
|
|
||||||
_runLock.Release();
|
//Sleep until we're ready to start the next frame
|
||||||
|
clockTimer.WaitUntil(targetTime);
|
||||||
PlatformUtilities::EnableScreensaver();
|
|
||||||
while(paused && !_stop) {
|
if(!_pauseLock.IsFree()) {
|
||||||
//Sleep until emulation is resumed
|
//Need to temporarely pause the emu (to save/load a state, etc.)
|
||||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(30));
|
_runLock.Release();
|
||||||
paused = EmulationSettings::IsPaused();
|
|
||||||
|
//Spin wait until we are allowed to start again
|
||||||
|
_pauseLock.WaitForRelease();
|
||||||
|
|
||||||
|
_runLock.Acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(EmulationSettings::CheckFlag(EmulationFlags::DebuggerWindowEnabled)) {
|
bool paused = EmulationSettings::IsPaused();
|
||||||
//Prevent pausing when debugger is active
|
if(paused && !_stop) {
|
||||||
EmulationSettings::ClearFlags(EmulationFlags::Paused);
|
MessageManager::SendNotification(ConsoleNotificationType::GamePaused);
|
||||||
|
|
||||||
|
//Prevent audio from looping endlessly while game is paused
|
||||||
|
SoundMixer::StopAudio();
|
||||||
|
|
||||||
|
_runLock.Release();
|
||||||
|
|
||||||
|
PlatformUtilities::EnableScreensaver();
|
||||||
|
while(paused && !_stop) {
|
||||||
|
//Sleep until emulation is resumed
|
||||||
|
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(30));
|
||||||
|
paused = EmulationSettings::IsPaused();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(EmulationSettings::CheckFlag(EmulationFlags::DebuggerWindowEnabled)) {
|
||||||
|
//Prevent pausing when debugger is active
|
||||||
|
EmulationSettings::ClearFlags(EmulationFlags::Paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformUtilities::DisableScreensaver();
|
||||||
|
_runLock.Acquire();
|
||||||
|
MessageManager::SendNotification(ConsoleNotificationType::GameResumed);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformUtilities::DisableScreensaver();
|
_systemActionManager->ProcessSystemActions();
|
||||||
_runLock.Acquire();
|
|
||||||
MessageManager::SendNotification(ConsoleNotificationType::GameResumed);
|
|
||||||
}
|
|
||||||
|
|
||||||
_systemActionManager->ProcessSystemActions();
|
|
||||||
|
|
||||||
shared_ptr<Debugger> debugger = _debugger;
|
shared_ptr<Debugger> debugger = _debugger;
|
||||||
if(debugger) {
|
if(debugger) {
|
||||||
debugger->ProcessEvent(EventType::StartFrame);
|
debugger->ProcessEvent(EventType::StartFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get next target time, and adjust based on whether we are ahead or behind
|
//Get next target time, and adjust based on whether we are ahead or behind
|
||||||
double timeLag = EmulationSettings::GetEmulationSpeed() == 0 ? 0 : clockTimer.GetElapsedMS() - targetTime;
|
double timeLag = EmulationSettings::GetEmulationSpeed() == 0 ? 0 : clockTimer.GetElapsedMS() - targetTime;
|
||||||
UpdateNesModel(true);
|
UpdateNesModel(true);
|
||||||
targetTime = GetFrameDelay();
|
targetTime = GetFrameDelay();
|
||||||
|
|
||||||
clockTimer.Reset();
|
clockTimer.Reset();
|
||||||
targetTime -= timeLag;
|
targetTime -= timeLag;
|
||||||
if(targetTime < 0) {
|
if(targetTime < 0) {
|
||||||
targetTime = 0;
|
targetTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastFrameNumber = PPU::GetFrameCount();
|
lastFrameNumber = PPU::GetFrameCount();
|
||||||
|
|
||||||
if(_stop) {
|
if(_stop) {
|
||||||
_stop = false;
|
_stop = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch(const std::runtime_error &ex) {
|
||||||
|
crashed = true;
|
||||||
|
MessageManager::DisplayMessage("Error", "GameCrash", ex.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!crashed) {
|
if(!crashed) {
|
||||||
|
|
36
Core/PPU.cpp
36
Core/PPU.cpp
|
@ -46,6 +46,7 @@ void PPU::Reset()
|
||||||
{
|
{
|
||||||
_cyclesNeeded = 0;
|
_cyclesNeeded = 0;
|
||||||
|
|
||||||
|
_needStateUpdate = false;
|
||||||
_prevRenderingEnabled = false;
|
_prevRenderingEnabled = false;
|
||||||
_renderingEnabled = false;
|
_renderingEnabled = false;
|
||||||
|
|
||||||
|
@ -278,7 +279,8 @@ uint8_t PPU::ReadRAM(uint16_t addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateVideoRamAddr();
|
UpdateVideoRamAddr();
|
||||||
_ignoreVramRead = 2;
|
_ignoreVramRead = 6;
|
||||||
|
_needStateUpdate = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -344,6 +346,7 @@ void PPU::WriteRAM(uint16_t addr, uint8_t value)
|
||||||
|
|
||||||
//Video RAM update is apparently delayed by 2-3 PPU cycles (based on Visual NES findings)
|
//Video RAM update is apparently delayed by 2-3 PPU cycles (based on Visual NES findings)
|
||||||
//A 3-cycle delay causes issues with the scanline test.
|
//A 3-cycle delay causes issues with the scanline test.
|
||||||
|
_needStateUpdate = true;
|
||||||
_updateVramAddrDelay = 2;
|
_updateVramAddrDelay = 2;
|
||||||
_updateVramAddr = _state.TmpVideoRamAddr;
|
_updateVramAddr = _state.TmpVideoRamAddr;
|
||||||
Debugger::SetLastFramePpuScroll(_updateVramAddr, _state.XScroll, false);
|
Debugger::SetLastFramePpuScroll(_updateVramAddr, _state.XScroll, false);
|
||||||
|
@ -444,6 +447,10 @@ void PPU::SetMaskRegister(uint8_t value)
|
||||||
_flags.SpritesEnabled = (_state.Mask & 0x10) == 0x10;
|
_flags.SpritesEnabled = (_state.Mask & 0x10) == 0x10;
|
||||||
_flags.IntensifyBlue = (_state.Mask & 0x80) == 0x80;
|
_flags.IntensifyBlue = (_state.Mask & 0x80) == 0x80;
|
||||||
|
|
||||||
|
if(_renderingEnabled != (_flags.BackgroundEnabled | _flags.SpritesEnabled)) {
|
||||||
|
_needStateUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateMinimumDrawCycles();
|
UpdateMinimumDrawCycles();
|
||||||
|
|
||||||
UpdateGrayscaleAndIntensifyBits();
|
UpdateGrayscaleAndIntensifyBits();
|
||||||
|
@ -1109,9 +1116,21 @@ void PPU::Exec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_needStateUpdate) {
|
||||||
|
UpdateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPU::UpdateState()
|
||||||
|
{
|
||||||
|
_needStateUpdate = false;
|
||||||
|
|
||||||
//Rendering enabled flag is apparently set with a 1 cycle delay (i.e setting it at cycle 5 will render cycle 6 like cycle 5 and then take the new settings for cycle 7)
|
//Rendering enabled flag is apparently set with a 1 cycle delay (i.e setting it at cycle 5 will render cycle 6 like cycle 5 and then take the new settings for cycle 7)
|
||||||
_prevRenderingEnabled = _renderingEnabled;
|
_prevRenderingEnabled = _renderingEnabled;
|
||||||
_renderingEnabled = _flags.BackgroundEnabled | _flags.SpritesEnabled;
|
_renderingEnabled = _flags.BackgroundEnabled | _flags.SpritesEnabled;
|
||||||
|
if(_prevRenderingEnabled != _renderingEnabled) {
|
||||||
|
_needStateUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
if(_updateVramAddrDelay > 0) {
|
if(_updateVramAddrDelay > 0) {
|
||||||
_updateVramAddrDelay--;
|
_updateVramAddrDelay--;
|
||||||
|
@ -1121,6 +1140,15 @@ void PPU::Exec()
|
||||||
//Trigger memory read when setting the vram address - needed by MMC3 IRQ counter
|
//Trigger memory read when setting the vram address - needed by MMC3 IRQ counter
|
||||||
//"4) Should be clocked when A12 changes to 1 via $2006 write"
|
//"4) Should be clocked when A12 changes to 1 via $2006 write"
|
||||||
_mapper->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read);
|
_mapper->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read);
|
||||||
|
} else {
|
||||||
|
_needStateUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_ignoreVramRead > 0) {
|
||||||
|
_ignoreVramRead--;
|
||||||
|
if(_ignoreVramRead > 0) {
|
||||||
|
_needStateUpdate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1148,10 +1176,6 @@ void PPU::ExecStatic()
|
||||||
Instance->_cyclesNeeded--;
|
Instance->_cyclesNeeded--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(PPU::Instance->_ignoreVramRead) {
|
|
||||||
PPU::Instance->_ignoreVramRead--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::StreamState(bool saving)
|
void PPU::StreamState(bool saving)
|
||||||
|
@ -1183,7 +1207,7 @@ void PPU::StreamState(bool saving)
|
||||||
_nextTile.PaletteOffset, _nextTile.TileAddr, _previousTile.LowByte, _previousTile.HighByte, _previousTile.PaletteOffset, _spriteIndex, _spriteCount,
|
_nextTile.PaletteOffset, _nextTile.TileAddr, _previousTile.LowByte, _previousTile.HighByte, _previousTile.PaletteOffset, _spriteIndex, _spriteCount,
|
||||||
_secondaryOAMAddr, _sprite0Visible, _oamCopybuffer, _spriteInRange, _sprite0Added, _spriteAddrH, _spriteAddrL, _oamCopyDone, _nesModel, unusedSpriteDmaAddr,
|
_secondaryOAMAddr, _sprite0Visible, _oamCopybuffer, _spriteInRange, _sprite0Added, _spriteAddrH, _spriteAddrL, _oamCopyDone, _nesModel, unusedSpriteDmaAddr,
|
||||||
unusedSpriteDmaCounter, _prevRenderingEnabled, _renderingEnabled, _openBus, _ignoreVramRead, unusedSkipScrollIncrement, paletteRam, spriteRam, secondarySpriteRam,
|
unusedSpriteDmaCounter, _prevRenderingEnabled, _renderingEnabled, _openBus, _ignoreVramRead, unusedSkipScrollIncrement, paletteRam, spriteRam, secondarySpriteRam,
|
||||||
openBusDecayStamp, _cyclesNeeded, disablePpu2004Reads, disablePaletteRead, disableOamAddrBug, _overflowBugCounter, _updateVramAddr, _updateVramAddrDelay);
|
openBusDecayStamp, _cyclesNeeded, disablePpu2004Reads, disablePaletteRead, disableOamAddrBug, _overflowBugCounter, _updateVramAddr, _updateVramAddrDelay, _needStateUpdate);
|
||||||
|
|
||||||
for(int i = 0; i < 64; i++) {
|
for(int i = 0; i < 64; i++) {
|
||||||
Stream(_spriteTiles[i].SpriteX, _spriteTiles[i].LowByte, _spriteTiles[i].HighByte, _spriteTiles[i].PaletteOffset, _spriteTiles[i].HorizontalMirror, _spriteTiles[i].BackgroundPriority);
|
Stream(_spriteTiles[i].SpriteX, _spriteTiles[i].LowByte, _spriteTiles[i].HighByte, _spriteTiles[i].PaletteOffset, _spriteTiles[i].HorizontalMirror, _spriteTiles[i].BackgroundPriority);
|
||||||
|
|
|
@ -87,6 +87,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
bool _oamCopyDone;
|
bool _oamCopyDone;
|
||||||
uint8_t _overflowBugCounter;
|
uint8_t _overflowBugCounter;
|
||||||
|
|
||||||
|
bool _needStateUpdate;
|
||||||
bool _renderingEnabled;
|
bool _renderingEnabled;
|
||||||
bool _prevRenderingEnabled;
|
bool _prevRenderingEnabled;
|
||||||
|
|
||||||
|
@ -142,6 +143,8 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
void UpdateGrayscaleAndIntensifyBits();
|
void UpdateGrayscaleAndIntensifyBits();
|
||||||
virtual void SendFrame();
|
virtual void SendFrame();
|
||||||
|
|
||||||
|
void UpdateState();
|
||||||
|
|
||||||
void UpdateApuStatus();
|
void UpdateApuStatus();
|
||||||
|
|
||||||
PPURegisters GetRegisterID(uint16_t addr)
|
PPURegisters GetRegisterID(uint16_t addr)
|
||||||
|
|
|
@ -9,11 +9,15 @@ void Snapshotable::StreamStartBlock()
|
||||||
throw new std::runtime_error("Cannot start a new block before ending the last block");
|
throw new std::runtime_error("Cannot start a new block before ending the last block");
|
||||||
}
|
}
|
||||||
|
|
||||||
_blockBuffer = new uint8_t[0xFFFFF];
|
|
||||||
if(!_saving) {
|
if(!_saving) {
|
||||||
InternalStream(_blockSize);
|
InternalStream(_blockSize);
|
||||||
ArrayInfo<uint8_t> arrayInfo = { _blockBuffer, std::min((uint32_t)0xFFFFF, _blockSize) };
|
_blockSize = std::min(_blockSize, (uint32_t)0xFFFFF);
|
||||||
|
_blockBuffer = new uint8_t[_blockSize];
|
||||||
|
ArrayInfo<uint8_t> arrayInfo = { _blockBuffer, _blockSize };
|
||||||
InternalStream(arrayInfo);
|
InternalStream(arrayInfo);
|
||||||
|
} else {
|
||||||
|
_blockSize = 0x100;
|
||||||
|
_blockBuffer = new uint8_t[_blockSize];
|
||||||
}
|
}
|
||||||
_blockPosition = 0;
|
_blockPosition = 0;
|
||||||
_inBlock = true;
|
_inBlock = true;
|
||||||
|
@ -67,7 +71,8 @@ void Snapshotable::SaveSnapshot(ostream* file)
|
||||||
{
|
{
|
||||||
_stateVersion = SaveStateManager::FileFormatVersion;
|
_stateVersion = SaveStateManager::FileFormatVersion;
|
||||||
|
|
||||||
_stream = new uint8_t[0xFFFFF];
|
_streamSize = 0x1000;
|
||||||
|
_stream = new uint8_t[_streamSize];
|
||||||
_position = 0;
|
_position = 0;
|
||||||
_saving = true;
|
_saving = true;
|
||||||
|
|
||||||
|
@ -86,12 +91,11 @@ void Snapshotable::LoadSnapshot(istream* file, uint32_t stateVersion)
|
||||||
{
|
{
|
||||||
_stateVersion = stateVersion;
|
_stateVersion = stateVersion;
|
||||||
|
|
||||||
_stream = new uint8_t[0xFFFFF];
|
|
||||||
memset((char*)_stream, 0, 0xFFFFF);
|
|
||||||
_position = 0;
|
_position = 0;
|
||||||
_saving = false;
|
_saving = false;
|
||||||
|
|
||||||
file->read((char*)&_streamSize, sizeof(_streamSize));
|
file->read((char*)&_streamSize, sizeof(_streamSize));
|
||||||
|
_stream = new uint8_t[_streamSize];
|
||||||
file->read((char*)_stream, _streamSize);
|
file->read((char*)_stream, _streamSize);
|
||||||
StreamState(_saving);
|
StreamState(_saving);
|
||||||
|
|
||||||
|
|
|
@ -51,12 +51,54 @@ private:
|
||||||
bool _saving;
|
bool _saving;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void EnsureCapacity(uint32_t typeSize)
|
||||||
|
{
|
||||||
|
//Make sure the current block/stream is large enough to fit the next write
|
||||||
|
uint32_t oldSize;
|
||||||
|
uint32_t sizeRequired;
|
||||||
|
uint8_t *oldBuffer;
|
||||||
|
if(_inBlock) {
|
||||||
|
oldBuffer = _blockBuffer;
|
||||||
|
oldSize = _blockSize;
|
||||||
|
sizeRequired = _blockPosition + typeSize;
|
||||||
|
} else {
|
||||||
|
oldBuffer = _stream;
|
||||||
|
oldSize = _streamSize;
|
||||||
|
sizeRequired = _position + typeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *newBuffer = nullptr;
|
||||||
|
uint32_t newSize = oldSize * 2;
|
||||||
|
if(oldSize < sizeRequired) {
|
||||||
|
while(newSize < sizeRequired) {
|
||||||
|
newSize *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
newBuffer = new uint8_t[newSize];
|
||||||
|
memcpy(newBuffer, oldBuffer, oldSize);
|
||||||
|
delete[] oldBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newBuffer) {
|
||||||
|
if(_inBlock) {
|
||||||
|
_blockBuffer = newBuffer;
|
||||||
|
_blockSize = newSize;
|
||||||
|
} else {
|
||||||
|
_stream = newBuffer;
|
||||||
|
_streamSize = newSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void StreamElement(T &value, T defaultValue = T())
|
void StreamElement(T &value, T defaultValue = T())
|
||||||
{
|
{
|
||||||
if(_saving) {
|
if(_saving) {
|
||||||
uint8_t* bytes = (uint8_t*)&value;
|
uint8_t* bytes = (uint8_t*)&value;
|
||||||
int typeSize = sizeof(T);
|
int typeSize = sizeof(T);
|
||||||
|
|
||||||
|
EnsureCapacity(typeSize);
|
||||||
|
|
||||||
for(int i = 0; i < typeSize; i++) {
|
for(int i = 0; i < typeSize; i++) {
|
||||||
if(_inBlock) {
|
if(_inBlock) {
|
||||||
_blockBuffer[_blockPosition++] = bytes[i];
|
_blockBuffer[_blockPosition++] = bytes[i];
|
||||||
|
|
|
@ -67,6 +67,13 @@ void TraceLogger::StopLogging()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TraceLogger::LogStatic(char *log)
|
||||||
|
{
|
||||||
|
if(_instance && _instance->_logToFile && _instance->_options.ShowExtraInfo) {
|
||||||
|
LogStatic(string(log));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TraceLogger::LogStatic(string log)
|
void TraceLogger::LogStatic(string log)
|
||||||
{
|
{
|
||||||
if(_instance && _instance->_logToFile && _instance->_options.ShowExtraInfo) {
|
if(_instance && _instance->_logToFile && _instance->_options.ShowExtraInfo) {
|
||||||
|
|
|
@ -88,6 +88,7 @@ public:
|
||||||
|
|
||||||
const char* GetExecutionTrace(uint32_t lineCount);
|
const char* GetExecutionTrace(uint32_t lineCount);
|
||||||
|
|
||||||
|
static void LogStatic(char *log);
|
||||||
static void LogStatic(string log);
|
static void LogStatic(string log);
|
||||||
|
|
||||||
};
|
};
|
|
@ -149,12 +149,15 @@ bool SoundManager::InitializeDirectSound(uint32_t sampleRate, bool isStereo)
|
||||||
// Release the temporary buffer.
|
// Release the temporary buffer.
|
||||||
tempBuffer->Release();
|
tempBuffer->Release();
|
||||||
|
|
||||||
|
_playing = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SoundManager::Release()
|
void SoundManager::Release()
|
||||||
{
|
{
|
||||||
|
_playing = false;
|
||||||
_needReset = false;
|
_needReset = false;
|
||||||
_lastWriteOffset = 0;
|
_lastWriteOffset = 0;
|
||||||
|
|
||||||
|
@ -209,6 +212,7 @@ void SoundManager::Pause()
|
||||||
if(_secondaryBuffer) {
|
if(_secondaryBuffer) {
|
||||||
_secondaryBuffer->Stop();
|
_secondaryBuffer->Stop();
|
||||||
}
|
}
|
||||||
|
_playing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::Stop()
|
void SoundManager::Stop()
|
||||||
|
@ -217,12 +221,14 @@ void SoundManager::Stop()
|
||||||
_secondaryBuffer->Stop();
|
_secondaryBuffer->Stop();
|
||||||
ClearSecondaryBuffer();
|
ClearSecondaryBuffer();
|
||||||
}
|
}
|
||||||
|
_playing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundManager::Play()
|
void SoundManager::Play()
|
||||||
{
|
{
|
||||||
if(_secondaryBuffer) {
|
if(_secondaryBuffer) {
|
||||||
_secondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
|
_secondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||||
|
_playing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +238,18 @@ void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32
|
||||||
if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset) {
|
if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset) {
|
||||||
Release();
|
Release();
|
||||||
InitializeDirectSound(sampleRate, isStereo);
|
InitializeDirectSound(sampleRate, isStereo);
|
||||||
|
_secondaryBuffer->SetFrequency(sampleRate);
|
||||||
|
_emulationSpeed = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t emulationSpeed = EmulationSettings::GetEmulationSpeed();
|
||||||
|
if(emulationSpeed != _emulationSpeed) {
|
||||||
|
uint32_t targetRate = sampleRate;
|
||||||
|
if(emulationSpeed > 0 && emulationSpeed < 100) {
|
||||||
|
targetRate = (uint32_t)(targetRate * ((double)emulationSpeed / 100.0));
|
||||||
|
}
|
||||||
|
_secondaryBuffer->SetFrequency(targetRate);
|
||||||
|
_emulationSpeed = emulationSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isStereo) {
|
if(isStereo) {
|
||||||
|
@ -261,17 +279,9 @@ void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32
|
||||||
_secondaryBuffer->SetCurrentPosition(_lastWriteOffset - byteLatency);
|
_secondaryBuffer->SetCurrentPosition(_lastWriteOffset - byteLatency);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t targetRate = sampleRate;
|
|
||||||
if(EmulationSettings::GetEmulationSpeed() > 0 && EmulationSettings::GetEmulationSpeed() < 100) {
|
|
||||||
targetRate = (uint32_t)(targetRate * ((double)EmulationSettings::GetEmulationSpeed() / 100.0));
|
|
||||||
}
|
|
||||||
_secondaryBuffer->SetFrequency(targetRate);
|
|
||||||
|
|
||||||
CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize);
|
CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize);
|
||||||
|
|
||||||
DWORD status;
|
if(!_playing && _lastWriteOffset >= byteLatency) {
|
||||||
_secondaryBuffer->GetStatus(&status);
|
|
||||||
if(!(status & DSBSTATUS_PLAYING) && _lastWriteOffset >= byteLatency) {
|
|
||||||
Play();
|
Play();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -28,7 +28,6 @@ private:
|
||||||
vector<SoundDeviceInfo> GetAvailableDeviceInfo();
|
vector<SoundDeviceInfo> GetAvailableDeviceInfo();
|
||||||
static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext);
|
static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext);
|
||||||
bool InitializeDirectSound(uint32_t sampleRate, bool isStereo);
|
bool InitializeDirectSound(uint32_t sampleRate, bool isStereo);
|
||||||
void ShutdownDirectSound();
|
|
||||||
void ClearSecondaryBuffer();
|
void ClearSecondaryBuffer();
|
||||||
void CopyToSecondaryBuffer(uint8_t *data, uint32_t size);
|
void CopyToSecondaryBuffer(uint8_t *data, uint32_t size);
|
||||||
|
|
||||||
|
@ -41,6 +40,8 @@ private:
|
||||||
uint16_t _previousLatency = 0;
|
uint16_t _previousLatency = 0;
|
||||||
uint32_t _sampleRate = 0;
|
uint32_t _sampleRate = 0;
|
||||||
bool _isStereo = false;
|
bool _isStereo = false;
|
||||||
|
bool _playing = false;
|
||||||
|
uint32_t _emulationSpeed = 100;
|
||||||
|
|
||||||
IDirectSound8* _directSound;
|
IDirectSound8* _directSound;
|
||||||
IDirectSoundBuffer* _primaryBuffer;
|
IDirectSoundBuffer* _primaryBuffer;
|
||||||
|
|
Loading…
Add table
Reference in a new issue