mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2025-04-02 10:31:51 -04:00
220 lines
5.4 KiB
C++
220 lines
5.4 KiB
C++
////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Nestopia - NES/Famicom emulator written in C++
|
|
//
|
|
// Copyright (C) 2003-2008 Martin Freij
|
|
//
|
|
// This file is part of Nestopia.
|
|
//
|
|
// Nestopia is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Nestopia is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Nestopia; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "NstIoFile.hpp"
|
|
#include "NstIoLog.hpp"
|
|
#include "NstIoArchive.hpp"
|
|
#include "NstResourceString.hpp"
|
|
#include "NstManagerPaths.hpp"
|
|
#include "NstWindowUser.hpp"
|
|
#include "NstDialogSound.hpp"
|
|
#include "NstManagerSound.hpp"
|
|
#include "NstManagerSoundRecorder.hpp"
|
|
#include "NstManagerPreferences.hpp"
|
|
|
|
namespace Nestopia
|
|
{
|
|
namespace Managers
|
|
{
|
|
struct Sound::Callbacks
|
|
{
|
|
static bool NST_CALLBACK Lock(Nes::Sound::UserData,Nes::Sound::Output&);
|
|
static void NST_CALLBACK Unlock(Nes::Sound::UserData,Nes::Sound::Output&);
|
|
};
|
|
|
|
Sound::Sound
|
|
(
|
|
Window::Custom& window,
|
|
Window::Menu& m,
|
|
Emulator& e,
|
|
const Paths& p,
|
|
const Preferences& r,
|
|
const Configuration& cfg
|
|
)
|
|
:
|
|
Manager ( e, m, this, &Sound::OnEmuEvent, IDM_OPTIONS_SOUND, &Sound::OnMenuOptionsSound ),
|
|
paths ( p ),
|
|
preferences ( r ),
|
|
directSound ( window ),
|
|
dialog ( new Window::Sound(e,directSound.GetAdapters(),p,cfg) ),
|
|
recorder ( new Recorder(m,dialog->GetRecorder(),e) )
|
|
{
|
|
Nes::Sound::Output::lockCallback.Set( &Callbacks::Lock, this );
|
|
Nes::Sound::Output::unlockCallback.Set( &Callbacks::Unlock, this );
|
|
|
|
UpdateSettings();
|
|
}
|
|
|
|
Sound::~Sound()
|
|
{
|
|
Nes::Sound::Output::lockCallback.Unset();
|
|
Nes::Sound::Output::unlockCallback.Unset();
|
|
}
|
|
|
|
bool Sound::CanRunInBackground() const
|
|
{
|
|
if (emulator.IsNsf())
|
|
return menu[IDM_MACHINE_NSF_OPTIONS_PLAYINBACKGROUND].Checked();
|
|
else
|
|
return preferences[Managers::Preferences::RUN_IN_BACKGROUND];
|
|
}
|
|
|
|
void Sound::OnEmuEvent(const Emulator::Event event,const Emulator::Data data)
|
|
{
|
|
switch (event)
|
|
{
|
|
case Emulator::EVENT_POWER_ON:
|
|
case Emulator::EVENT_SPEED:
|
|
|
|
if (emuOutput && emulator.NetPlayers() == 0)
|
|
{
|
|
Nes::Sound( emulator ).SetSpeed( emulator.GetSpeed() );
|
|
Nes::Sound( emulator ).EmptyBuffer();
|
|
}
|
|
break;
|
|
|
|
case Emulator::EVENT_REWINDING_START:
|
|
case Emulator::EVENT_REWINDING_STOP:
|
|
|
|
Nes::Sound(emulator).SetVolume
|
|
(
|
|
Nes::Sound::CHANNEL_DPCM,
|
|
event == Emulator::EVENT_REWINDING_START ? 0 : dialog->GetVolume(Nes::Sound::CHANNEL_DPCM)
|
|
);
|
|
|
|
case Emulator::EVENT_REWINDING_PREPARE:
|
|
|
|
directSound.StopStream();
|
|
break;
|
|
|
|
case Emulator::EVENT_NETPLAY_MODE:
|
|
|
|
menu[IDM_OPTIONS_SOUND].Enable( !data );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Sound::OnMenuOptionsSound(uint)
|
|
{
|
|
dialog->Open();
|
|
UpdateSettings();
|
|
}
|
|
|
|
void Sound::Save(Configuration& cfg) const
|
|
{
|
|
dialog->Save( cfg );
|
|
}
|
|
|
|
void Sound::UpdateSettings()
|
|
{
|
|
cstring errMsg = NULL;
|
|
|
|
if (dialog->SoundEnabled())
|
|
{
|
|
Nes::Sound nesSound( emulator );
|
|
|
|
errMsg = directSound.Update
|
|
(
|
|
dialog->GetAdapter(),
|
|
nesSound.GetSampleRate(),
|
|
16,
|
|
nesSound.GetSpeaker() == Nes::Sound::SPEAKER_STEREO ? DirectX::DirectSound::STEREO : DirectX::DirectSound::MONO,
|
|
emulator.IsNsf() ? 500 : (dialog->GetLatency() + 2) * 21,
|
|
dialog->GetPool(),
|
|
CanRunInBackground()
|
|
);
|
|
|
|
if (errMsg == NULL)
|
|
{
|
|
emuOutput = &output;
|
|
nesSound.SetSpeed( emulator.GetSpeed() );
|
|
recorder->Enable( &directSound.GetWaveFormat() );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
directSound.Destroy();
|
|
}
|
|
|
|
Disable( errMsg );
|
|
}
|
|
|
|
void Sound::Disable(cstring const errMsg)
|
|
{
|
|
emuOutput = NULL;
|
|
Nes::Sound( emulator ).SetVolume( Nes::Sound::ALL_CHANNELS, 0 );
|
|
recorder->Enable( NULL );
|
|
|
|
if (errMsg)
|
|
Window::User::Fail( Resource::String( IDS_ERR_SOUND_FAILED ).Invoke( errMsg ) );
|
|
}
|
|
|
|
void Sound::StartEmulation() const
|
|
{
|
|
Nes::Sound( emulator ).EmptyBuffer();
|
|
}
|
|
|
|
void Sound::StopEmulation()
|
|
{
|
|
directSound.StopStream();
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("t", on)
|
|
#endif
|
|
|
|
bool NST_CALLBACK Sound::Callbacks::Lock(Nes::Sound::UserData data,Nes::Sound::Output&)
|
|
{
|
|
Sound& sound = *static_cast<Sound*>(data);
|
|
|
|
if (sound.directSound.Streaming())
|
|
{
|
|
return sound.directSound.LockStream( sound.output.samples, sound.output.length );
|
|
}
|
|
else
|
|
{
|
|
if (sound.CanRunInBackground() != sound.directSound.GlobalFocus())
|
|
sound.UpdateSettings();
|
|
|
|
sound.directSound.StartStream();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void NST_CALLBACK Sound::Callbacks::Unlock(Nes::Sound::UserData data,Nes::Sound::Output&)
|
|
{
|
|
Sound& sound = *static_cast<Sound*>(data);
|
|
|
|
if (sound.recorder->IsRecording())
|
|
sound.recorder->Flush( sound.output );
|
|
|
|
sound.directSound.UnlockStream( sound.output.samples, sound.output.length );
|
|
}
|
|
|
|
#ifdef NST_MSVC_OPTIMIZE
|
|
#pragma optimize("", on)
|
|
#endif
|
|
}
|
|
}
|