mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
This is a joined work of XK and me on improving the HLE plugin interface.
It allows run time selection of backends (AOSound, DSound and NullSound). It replaces the DSP_NULL plugin (works even better!) It also includes improved thread handling on asound, and using some common functions on both asound and windows. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2027 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -26,22 +26,23 @@ CConfig::CConfig()
|
||||
Load();
|
||||
}
|
||||
|
||||
void CConfig::LoadDefaults()
|
||||
{
|
||||
m_EnableHLEAudio = true;
|
||||
m_EnableDTKMusic = true;
|
||||
}
|
||||
|
||||
void CConfig::Load()
|
||||
{
|
||||
// first load defaults
|
||||
LoadDefaults();
|
||||
|
||||
std::string temp;
|
||||
|
||||
IniFile file;
|
||||
file.Load(FULL_CONFIG_DIR "DSP.ini");
|
||||
file.Get("Config", "EnableHLEAudio", &m_EnableHLEAudio, true); // Sound Settings
|
||||
file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true);
|
||||
file.Get("Config", "EnableThrottle", &m_EnableThrottle, true);
|
||||
|
||||
#ifdef _WIN32
|
||||
file.Get("Config", "Backend", &temp, "DSound");
|
||||
#else
|
||||
file.Get("Config", "Backend", &temp, "AOSound");
|
||||
#endif
|
||||
strncpy(sBackend, temp.c_str(), 16);
|
||||
}
|
||||
|
||||
void CConfig::Save()
|
||||
@ -51,6 +52,7 @@ void CConfig::Save()
|
||||
file.Set("Config", "EnableHLEAudio", m_EnableHLEAudio); // Sound Settings
|
||||
file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic);
|
||||
file.Set("Config", "EnableThrottle", m_EnableThrottle);
|
||||
|
||||
file.Set("Config", "Backend", sBackend);
|
||||
|
||||
file.Save(FULL_CONFIG_DIR "DSP.ini");
|
||||
}
|
||||
|
@ -22,17 +22,16 @@
|
||||
|
||||
struct CConfig
|
||||
{
|
||||
bool m_EnableHLEAudio;
|
||||
bool m_EnableDTKMusic;
|
||||
bool m_EnableThrottle;
|
||||
|
||||
CConfig();
|
||||
|
||||
void LoadDefaults();
|
||||
|
||||
void Load();
|
||||
|
||||
void Save();
|
||||
bool m_EnableHLEAudio;
|
||||
bool m_EnableDTKMusic;
|
||||
bool m_EnableThrottle;
|
||||
char sBackend[10];
|
||||
|
||||
CConfig();
|
||||
|
||||
void Load();
|
||||
|
||||
void Save();
|
||||
};
|
||||
|
||||
extern CConfig g_Config;
|
||||
|
@ -41,11 +41,15 @@ ConfigDialog::ConfigDialog(wxWindow *parent, wxWindowID id, const wxString &titl
|
||||
m_buttonEnableHLEAudio = new wxCheckBox(this, ID_ENABLE_HLE_AUDIO, wxT("Enable HLE Audio"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
m_buttonEnableDTKMusic = new wxCheckBox(this, ID_ENABLE_DTK_MUSIC, wxT("Enable DTK Music"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
m_buttonEnableThrottle = new wxCheckBox(this, ID_ENABLE_THROTTLE, wxT("Enable Other Audio (Throttle)"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
|
||||
wxStaticText *BackendText = new wxStaticText(this, wxID_ANY, wxT("Audio Backend"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_BackendSelection = new wxComboBox(this, ID_BACKEND, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxArrayBackends, 0, wxDefaultValidator);
|
||||
|
||||
// Update checkboxes
|
||||
|
||||
// Update values
|
||||
m_buttonEnableHLEAudio->SetValue(g_Config.m_EnableHLEAudio ? true : false);
|
||||
m_buttonEnableDTKMusic->SetValue(g_Config.m_EnableDTKMusic ? true : false);
|
||||
m_buttonEnableThrottle->SetValue(g_Config.m_EnableThrottle ? true : false);
|
||||
m_BackendSelection->SetValue(wxString::FromAscii(g_Config.sBackend));
|
||||
|
||||
// Add tooltips
|
||||
m_buttonEnableHLEAudio->SetToolTip(wxT("This is the most common sound type"));
|
||||
@ -60,6 +64,11 @@ ConfigDialog::ConfigDialog(wxWindow *parent, wxWindowID id, const wxString &titl
|
||||
sbSettings->Add(m_buttonEnableHLEAudio, 0, wxALL, 5);
|
||||
sbSettings->Add(m_buttonEnableDTKMusic, 0, wxALL, 5);
|
||||
sbSettings->Add(m_buttonEnableThrottle, 0, wxALL, 5);
|
||||
wxBoxSizer *sBackend = new wxBoxSizer(wxHORIZONTAL);
|
||||
sBackend->Add(BackendText, 0, wxALIGN_CENTRE_VERTICAL|wxALL, 5);
|
||||
sBackend->Add(m_BackendSelection);
|
||||
sbSettings->Add(sBackend);
|
||||
|
||||
sMain->Add(sbSettings, 0, wxEXPAND|wxALL, 5);
|
||||
wxBoxSizer *sButtons = new wxBoxSizer(wxHORIZONTAL);
|
||||
sButtons->Add(150, 0); // Lazy way to make the dialog as wide as we want it
|
||||
@ -68,6 +77,10 @@ ConfigDialog::ConfigDialog(wxWindow *parent, wxWindowID id, const wxString &titl
|
||||
this->SetSizerAndFit(sMain);
|
||||
}
|
||||
|
||||
void ConfigDialog::AddBackend(const char* backend) {
|
||||
m_BackendSelection->Append(wxString::FromAscii(backend));
|
||||
}
|
||||
|
||||
ConfigDialog::~ConfigDialog()
|
||||
{
|
||||
}
|
||||
@ -77,6 +90,7 @@ void ConfigDialog::SettingsChanged(wxCommandEvent& event)
|
||||
g_Config.m_EnableHLEAudio = m_buttonEnableHLEAudio->GetValue();
|
||||
g_Config.m_EnableDTKMusic = m_buttonEnableDTKMusic->GetValue();
|
||||
g_Config.m_EnableThrottle = m_buttonEnableThrottle->GetValue();
|
||||
strcpy(g_Config.sBackend, m_BackendSelection->GetValue().mb_str());
|
||||
g_Config.Save();
|
||||
|
||||
if (event.GetId() == wxID_OK)
|
||||
|
@ -27,31 +27,35 @@ class ConfigDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
ConfigDialog(wxWindow *parent,
|
||||
wxWindowID id = 1,
|
||||
const wxString &title = wxT("Dolphin DSP-HLE Plugin Settings"),
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxDEFAULT_DIALOG_STYLE);
|
||||
virtual ~ConfigDialog();
|
||||
|
||||
wxWindowID id = 1,
|
||||
const wxString &title = wxT("Dolphin DSP-HLE Plugin Settings"),
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxDEFAULT_DIALOG_STYLE);
|
||||
virtual ~ConfigDialog();
|
||||
void AddBackend(const char *backend);
|
||||
|
||||
private:
|
||||
DECLARE_EVENT_TABLE();
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
wxButton *m_OK;
|
||||
wxCheckBox *m_buttonEnableHLEAudio;
|
||||
wxCheckBox *m_buttonEnableDTKMusic;
|
||||
wxCheckBox *m_buttonEnableThrottle;
|
||||
wxArrayString wxArrayBackends;
|
||||
wxComboBox *m_BackendSelection;
|
||||
|
||||
wxButton *m_OK;
|
||||
wxCheckBox *m_buttonEnableHLEAudio;
|
||||
wxCheckBox *m_buttonEnableDTKMusic;
|
||||
wxCheckBox *m_buttonEnableThrottle;
|
||||
|
||||
enum
|
||||
enum
|
||||
{
|
||||
wxID_OK,
|
||||
ID_ENABLE_HLE_AUDIO,
|
||||
ID_ENABLE_DTK_MUSIC,
|
||||
ID_ENABLE_THROTTLE
|
||||
wxID_OK,
|
||||
ID_ENABLE_HLE_AUDIO,
|
||||
ID_ENABLE_DTK_MUSIC,
|
||||
ID_ENABLE_THROTTLE,
|
||||
ID_BACKEND
|
||||
};
|
||||
|
||||
void OnOK(wxCommandEvent& event);
|
||||
void SettingsChanged(wxCommandEvent& event);
|
||||
|
||||
void OnOK(wxCommandEvent& event);
|
||||
void SettingsChanged(wxCommandEvent& event);
|
||||
};
|
||||
|
||||
#endif //__DSP_HLE_CONFIGDIALOG_h__
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
// Copyright (C) 2003-2009 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -15,78 +15,74 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <ao/ao.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "AOSoundStream.h"
|
||||
|
||||
namespace AOSound
|
||||
#if defined(HAVE_AO) && HAVE_AO
|
||||
|
||||
void AOSound::SoundLoop()
|
||||
{
|
||||
pthread_t thread;
|
||||
StreamCallback callback;
|
||||
|
||||
int buf_size;
|
||||
|
||||
ao_device *device;
|
||||
ao_sample_format format;
|
||||
int default_driver;
|
||||
|
||||
int sampleRate;
|
||||
volatile int threadData;
|
||||
|
||||
short realtimeBuffer[1024 * 1024];
|
||||
|
||||
int AOSound_GetSampleRate()
|
||||
{
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
void *soundThread(void *)
|
||||
{
|
||||
ao_initialize();
|
||||
default_driver = ao_default_driver_id();
|
||||
format.bits = 16;
|
||||
format.channels = 2;
|
||||
format.rate = sampleRate;
|
||||
format.byte_format = AO_FMT_LITTLE;
|
||||
ao_initialize();
|
||||
default_driver = ao_default_driver_id();
|
||||
format.bits = 16;
|
||||
format.channels = 2;
|
||||
format.rate = sampleRate;
|
||||
format.byte_format = AO_FMT_LITTLE;
|
||||
|
||||
device = ao_open_live(default_driver, &format, NULL /* no options */);
|
||||
if (device == NULL)
|
||||
{
|
||||
fprintf(stderr, "DSP_HLE: Error opening AO device.\n");
|
||||
return false;
|
||||
}
|
||||
buf_size = format.bits/8 * format.channels * format.rate;
|
||||
device = ao_open_live(default_driver, &format, NULL /* no options */);
|
||||
if (device == NULL) {
|
||||
PanicAlert("DSP_HLE: Error opening AO device.\n");
|
||||
ao_shutdown();
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
while (!threadData)
|
||||
{
|
||||
uint_32 numBytesToRender = 256;
|
||||
(*callback)(realtimeBuffer, numBytesToRender >> 2, 16, sampleRate, 2);
|
||||
ao_play(device, (char*)realtimeBuffer, numBytesToRender);
|
||||
}
|
||||
buf_size = format.bits/8 * format.channels * format.rate;
|
||||
|
||||
ao_close(device);
|
||||
device = 0;
|
||||
ao_shutdown();
|
||||
while (!threadData) {
|
||||
soundCriticalSection->Enter();
|
||||
|
||||
uint_32 numBytesToRender = 256;
|
||||
(*callback)(realtimeBuffer, numBytesToRender >> 2, 16, sampleRate, 2);
|
||||
ao_play(device, (char*)realtimeBuffer, numBytesToRender);
|
||||
soundCriticalSection->Leave();
|
||||
soundSyncEvent->Wait();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AOSound_StartSound(int _sampleRate, StreamCallback _callback)
|
||||
{
|
||||
callback = _callback;
|
||||
threadData = 0;
|
||||
sampleRate = _sampleRate;
|
||||
memset(realtimeBuffer, 0, sizeof(realtimeBuffer));
|
||||
pthread_create(&thread, NULL, soundThread, (void *)NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AOSound_StopSound()
|
||||
{
|
||||
threadData = 1;
|
||||
void *retval;
|
||||
pthread_join(thread, &retval);
|
||||
}
|
||||
ao_close(device);
|
||||
device = NULL;
|
||||
ao_shutdown();
|
||||
}
|
||||
|
||||
void *soundThread(void *args) {
|
||||
((AOSound *)args)->SoundLoop();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool AOSound::Start() {
|
||||
memset(realtimeBuffer, 0, sizeof(realtimeBuffer));
|
||||
soundCriticalSection = new Common::CriticalSection(1);
|
||||
thread = new Common::Thread(soundThread, (void *)this);
|
||||
soundSyncEvent = new Common::Event();
|
||||
soundSyncEvent->Init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AOSound::Update() {
|
||||
soundSyncEvent->Set();
|
||||
}
|
||||
|
||||
void AOSound::Stop()
|
||||
{
|
||||
soundCriticalSection->Enter();
|
||||
threadData = 1;
|
||||
soundSyncEvent->Set();
|
||||
soundCriticalSection->Leave();
|
||||
soundSyncEvent->Shutdown();
|
||||
delete soundCriticalSection;
|
||||
delete thread;
|
||||
delete soundSyncEvent;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
// Copyright (C) 2003-2009 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -18,18 +18,69 @@
|
||||
#ifndef __AOSOUNDSTREAM_H__
|
||||
#define __AOSOUNDSTREAM_H__
|
||||
|
||||
namespace AOSound
|
||||
#include "SoundStream.h"
|
||||
|
||||
#if defined(HAVE_AO) && HAVE_AO
|
||||
#include <ao/ao.h>
|
||||
#endif
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
|
||||
class AOSound : public SoundStream
|
||||
{
|
||||
typedef void (*StreamCallback)(short* buffer, int numSamples, int bits, int rate, int channels);
|
||||
|
||||
bool AOSound_StartSound(int sampleRate, StreamCallback _callback);
|
||||
void AOSound_UpdateSound();
|
||||
void AOSound_StopSound();
|
||||
#if defined(HAVE_AO) && HAVE_AO
|
||||
|
||||
Common::Thread *thread;
|
||||
|
||||
float AOSound_GetTimer();
|
||||
int AOSound_GetCurSample();
|
||||
int AOSound_GetSampleRate();
|
||||
}
|
||||
Common::CriticalSection *soundCriticalSection;
|
||||
|
||||
Common::Event *soundSyncEvent;
|
||||
|
||||
int buf_size;
|
||||
|
||||
ao_device *device;
|
||||
ao_sample_format format;
|
||||
int default_driver;
|
||||
|
||||
short realtimeBuffer[1024 * 1024];
|
||||
|
||||
public:
|
||||
AOSound(int _sampleRate, StreamCallback _callback) :
|
||||
SoundStream(_sampleRate, _callback) {}
|
||||
|
||||
virtual ~AOSound() {}
|
||||
|
||||
virtual bool Start();
|
||||
|
||||
virtual void SoundLoop();
|
||||
|
||||
virtual void Stop();
|
||||
|
||||
static bool isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool usesMixer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Update();
|
||||
|
||||
virtual int GetSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
public:
|
||||
AOSound(int _sampleRate, StreamCallback _callback) :
|
||||
SoundStream(_sampleRate, _callback) {}
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif //__AOSOUNDSTREAM_H__
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
// Copyright (C) 2003-2009 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -15,53 +15,12 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <mmsystem.h>
|
||||
#include <dsound.h>
|
||||
|
||||
#include "DSoundStream.h"
|
||||
#include "../main.h"
|
||||
|
||||
namespace DSound
|
||||
{
|
||||
#include <dxerr.h>
|
||||
|
||||
#define BUFSIZE 32768
|
||||
#define MAXWAIT 70 //ms
|
||||
|
||||
CRITICAL_SECTION soundCriticalSection;
|
||||
HANDLE soundSyncEvent;
|
||||
HANDLE hThread;
|
||||
|
||||
StreamCallback callback;
|
||||
|
||||
IDirectSound8* ds;
|
||||
IDirectSoundBuffer* dsBuffer;
|
||||
|
||||
int bufferSize; //i bytes
|
||||
int totalRenderedBytes;
|
||||
int sampleRate;
|
||||
|
||||
// playback position
|
||||
int currentPos;
|
||||
int lastPos;
|
||||
short realtimeBuffer[1024 * 1024];
|
||||
|
||||
// We set this to shut down the sound thread.
|
||||
// 0=keep playing, 1=stop playing NOW.
|
||||
volatile int threadData;
|
||||
|
||||
|
||||
inline int FIX128(int x)
|
||||
{
|
||||
return(x & (~127));
|
||||
}
|
||||
|
||||
int DSound_GetSampleRate()
|
||||
{
|
||||
return(sampleRate);
|
||||
}
|
||||
|
||||
bool CreateBuffer()
|
||||
bool DSound::CreateBuffer()
|
||||
{
|
||||
PCMWAVEFORMAT pcmwf;
|
||||
DSBUFFERDESC dsbdesc;
|
||||
@ -80,22 +39,23 @@ bool CreateBuffer()
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS; //VIKTIGT //DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
|
||||
dsbdesc.dwBufferBytes = bufferSize = BUFSIZE;
|
||||
dsbdesc.lpwfxFormat = (WAVEFORMATEX*)&pcmwf;
|
||||
dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&pcmwf;
|
||||
|
||||
if (SUCCEEDED(ds->CreateSoundBuffer(&dsbdesc, &dsBuffer, NULL)))
|
||||
HRESULT res = ds->CreateSoundBuffer(&dsbdesc, &dsBuffer, NULL);
|
||||
if (SUCCEEDED(res))
|
||||
{
|
||||
dsBuffer->SetCurrentPosition(0);
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// Failed.
|
||||
PanicAlert("Sound buffer creation failed: %s", DXGetErrorString(res));
|
||||
dsBuffer = NULL;
|
||||
return(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WriteDataToBuffer(DWORD dwOffset, // Our own write cursor.
|
||||
bool DSound::WriteDataToBuffer(DWORD dwOffset, // Our own write cursor.
|
||||
char* soundData, // Start of our data.
|
||||
DWORD dwSoundBytes) // Size of block to copy.
|
||||
{
|
||||
@ -122,20 +82,22 @@ bool WriteDataToBuffer(DWORD dwOffset, // Our own write cursor.
|
||||
|
||||
// Release the data back to DirectSound.
|
||||
dsBuffer->Unlock(ptr1, numBytes1, ptr2, numBytes2);
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
inline int ModBufferSize(int x)
|
||||
{
|
||||
return((x + bufferSize) % bufferSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The audio thread.
|
||||
DWORD WINAPI soundThread(void*)
|
||||
DWORD WINAPI soundThread(void* args)
|
||||
{
|
||||
((DSound *)args)->SoundLoop();
|
||||
|
||||
return 0; //huzzah! :D
|
||||
}
|
||||
|
||||
void DSound::SoundLoop() {
|
||||
|
||||
currentPos = 0;
|
||||
lastPos = 0;
|
||||
|
||||
@ -144,18 +106,19 @@ DWORD WINAPI soundThread(void*)
|
||||
// dsBuffer->Lock(0, bufferSize, (void **)&p1, &num1, (void **)&p2, &num2, 0);
|
||||
dsBuffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||
|
||||
while (!threadData)
|
||||
{
|
||||
while (!threadData) {
|
||||
// No blocking inside the csection
|
||||
EnterCriticalSection(&soundCriticalSection);
|
||||
soundCriticalSection->Enter();
|
||||
dsBuffer->GetCurrentPosition((DWORD*)¤tPos, 0);
|
||||
int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos));
|
||||
int numBytesToRender = FIX128(
|
||||
ModBufferSize(currentPos - lastPos));
|
||||
|
||||
if (numBytesToRender >= 256)
|
||||
{
|
||||
if (numBytesToRender > sizeof(realtimeBuffer))
|
||||
MessageBox(0,"soundThread: too big render call",0,0);
|
||||
(*callback)(realtimeBuffer, numBytesToRender >> 2, 16, sampleRate, 2);
|
||||
PanicAlert("soundThread: too big render call");
|
||||
(*callback)(realtimeBuffer, numBytesToRender >> 2, 16,
|
||||
sampleRate, 2);
|
||||
|
||||
WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender);
|
||||
currentPos = ModBufferSize(lastPos + numBytesToRender);
|
||||
@ -164,36 +127,32 @@ DWORD WINAPI soundThread(void*)
|
||||
lastPos = currentPos;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&soundCriticalSection);
|
||||
WaitForSingleObject(soundSyncEvent, MAXWAIT);
|
||||
soundCriticalSection->Leave();
|
||||
|
||||
soundSyncEvent->Wait();
|
||||
}
|
||||
|
||||
dsBuffer->Stop();
|
||||
return(0); //hurra!
|
||||
}
|
||||
|
||||
bool DSound_StartSound(HWND window, int _sampleRate, StreamCallback _callback)
|
||||
bool DSound::Start()
|
||||
{
|
||||
callback = _callback;
|
||||
threadData = 0;
|
||||
sampleRate = _sampleRate;
|
||||
|
||||
//no security attributes, automatic resetting, init state nonset, untitled
|
||||
soundSyncEvent = CreateEvent(0, false, false, 0);
|
||||
soundSyncEvent = new Common::Event();
|
||||
soundSyncEvent->Init();
|
||||
|
||||
//vi initierar den...........
|
||||
InitializeCriticalSection(&soundCriticalSection);
|
||||
soundCriticalSection = new Common::CriticalSection();
|
||||
|
||||
//vi vill ha access till DSOUND s<>...
|
||||
if (FAILED(DirectSoundCreate8(0, &ds, 0)))
|
||||
return false;
|
||||
return false;
|
||||
|
||||
ds->SetCooperativeLevel(window, DSSCL_NORMAL);
|
||||
if(hWnd)
|
||||
ds->SetCooperativeLevel((HWND)hWnd, DSSCL_NORMAL);
|
||||
|
||||
if (!CreateBuffer())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD num1;
|
||||
short* p1;
|
||||
@ -201,48 +160,43 @@ bool DSound_StartSound(HWND window, int _sampleRate, StreamCallback _callback)
|
||||
memset(p1, 0, num1);
|
||||
dsBuffer->Unlock(p1, num1, 0, 0);
|
||||
totalRenderedBytes = -bufferSize;
|
||||
DWORD h;
|
||||
hThread = CreateThread(0, 0, soundThread, 0, 0, &h);
|
||||
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
|
||||
thread = new Common::Thread(soundThread, (void *)this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSound_UpdateSound()
|
||||
void DSound::Update()
|
||||
{
|
||||
SetEvent(soundSyncEvent);
|
||||
soundSyncEvent->Set();
|
||||
}
|
||||
|
||||
void DSound_StopSound()
|
||||
void DSound::Stop()
|
||||
{
|
||||
EnterCriticalSection(&soundCriticalSection);
|
||||
soundCriticalSection->Enter();
|
||||
threadData = 1;
|
||||
// kick the thread if it's waiting
|
||||
SetEvent(soundSyncEvent);
|
||||
LeaveCriticalSection(&soundCriticalSection);
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
CloseHandle(hThread);
|
||||
soundSyncEvent->Set();
|
||||
soundCriticalSection->Leave();
|
||||
delete soundCriticalSection;
|
||||
delete thread;
|
||||
|
||||
dsBuffer->Release();
|
||||
ds->Release();
|
||||
|
||||
CloseHandle(soundSyncEvent);
|
||||
soundSyncEvent = INVALID_HANDLE_VALUE;
|
||||
hThread = INVALID_HANDLE_VALUE;
|
||||
soundSyncEvent->Shutdown();
|
||||
delete soundSyncEvent;
|
||||
soundSyncEvent = NULL;
|
||||
thread = NULL;
|
||||
}
|
||||
|
||||
int DSound_GetCurSample()
|
||||
/* Unused, is it needed?
|
||||
int DSound::GetCurSample()
|
||||
{
|
||||
EnterCriticalSection(&soundCriticalSection);
|
||||
soundCriticalSection->Enter();
|
||||
int playCursor;
|
||||
dsBuffer->GetCurrentPosition((DWORD*)&playCursor, 0);
|
||||
playCursor = ModBufferSize(playCursor - lastPos) + totalRenderedBytes;
|
||||
LeaveCriticalSection(&soundCriticalSection);
|
||||
return(playCursor);
|
||||
soundCriticalSection->Leave();
|
||||
return playCursor;
|
||||
}
|
||||
|
||||
float DSound_GetTimer()
|
||||
{
|
||||
return((float)DSound_GetCurSample() * (1.0f / (4.0f * sampleRate)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
// Copyright (C) 2003-2009 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@ -15,21 +15,90 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef __SOUNDSTREAM_H__
|
||||
#define __SOUNDSTREAM_H__
|
||||
#ifndef __DSOUNDSTREAM_H__
|
||||
#define __DSOUNDSTREAM_H__
|
||||
#include "SoundStream.h"
|
||||
|
||||
namespace DSound
|
||||
#include "Thread.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <mmsystem.h>
|
||||
#include <dsound.h>
|
||||
|
||||
#define BUFSIZE 32768
|
||||
#define MAXWAIT 70 //ms
|
||||
|
||||
#endif
|
||||
|
||||
class DSound : public SoundStream
|
||||
{
|
||||
typedef void (*StreamCallback)(short* buffer, int numSamples, int bits, int rate, int channels);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
bool DSound_StartSound(HWND window, int sampleRate, StreamCallback _callback);
|
||||
void DSound_UpdateSound();
|
||||
void DSound_StopSound();
|
||||
Common::Thread *thread;
|
||||
|
||||
Common::CriticalSection *soundCriticalSection;
|
||||
Common::Event *soundSyncEvent;
|
||||
void *hWnd;
|
||||
|
||||
float DSound_GetTimer();
|
||||
int DSound_GetCurSample();
|
||||
int DSound_GetSampleRate();
|
||||
}
|
||||
IDirectSound8* ds;
|
||||
IDirectSoundBuffer* dsBuffer;
|
||||
|
||||
int bufferSize; //i bytes
|
||||
int totalRenderedBytes;
|
||||
|
||||
// playback position
|
||||
int currentPos;
|
||||
int lastPos;
|
||||
short realtimeBuffer[1024 * 1024];
|
||||
|
||||
inline int FIX128(int x) {
|
||||
return x & (~127);
|
||||
}
|
||||
|
||||
inline int ModBufferSize(int x) {
|
||||
return (x + bufferSize) % bufferSize;
|
||||
}
|
||||
|
||||
bool CreateBuffer();
|
||||
|
||||
bool WriteDataToBuffer(DWORD dwOffset, char* soundData,
|
||||
DWORD dwSoundBytes);
|
||||
|
||||
public:
|
||||
|
||||
DSound(int _sampleRate, StreamCallback _callback) :
|
||||
SoundStream(_sampleRate, _callback) {}
|
||||
|
||||
DSound(int _sampleRate, StreamCallback _callback, void *_hWnd) :
|
||||
SoundStream(_sampleRate, _callback), hWnd(_hWnd) {}
|
||||
|
||||
virtual ~DSound() {}
|
||||
|
||||
virtual bool Start();
|
||||
|
||||
virtual void SoundLoop();
|
||||
|
||||
virtual void Stop();
|
||||
|
||||
static bool isValid() { return true; }
|
||||
|
||||
virtual bool usesMixer() { return true; }
|
||||
|
||||
virtual void Update();
|
||||
|
||||
#else
|
||||
public:
|
||||
|
||||
DSound(int _sampleRate, StreamCallback _callback, void *hWnd = NULL) :
|
||||
SoundStream(_sampleRate, _callback) {}
|
||||
|
||||
|
||||
#endif //__SOUNDSTREAM_H__
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif //__DSOUNDSTREAM_H__
|
||||
|
@ -16,9 +16,6 @@
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
// -------------
|
||||
// This queue solution is temporary. I'll implement something more efficient later.
|
||||
#include <queue> // System
|
||||
|
||||
@ -29,14 +26,11 @@
|
||||
#include "../Globals.h"
|
||||
#include "../DSPHandler.h"
|
||||
#include "../Debugger/File.h"
|
||||
#include "../main.h"
|
||||
|
||||
#include "Mixer.h"
|
||||
#include "FixedSizeQueue.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../PCHW/DSoundStream.h"
|
||||
#endif
|
||||
///////////////////////
|
||||
|
||||
|
||||
namespace {
|
||||
@ -52,6 +46,11 @@ FixedSizeQueue<s16, queue_maxlength> sample_queue;
|
||||
|
||||
volatile bool mixer_HLEready = false;
|
||||
volatile int queue_size = 0;
|
||||
bool bThrottling = false;
|
||||
|
||||
void UpdateThrottle(bool update) {
|
||||
bThrottling = update;
|
||||
}
|
||||
|
||||
void Mixer(short *buffer, int numSamples, int bits, int rate, int channels)
|
||||
{
|
||||
@ -111,87 +110,85 @@ void Mixer_PushSamples(short *buffer, int num_stereo_samples, int sample_rate) {
|
||||
|
||||
static int PV1l=0,PV2l=0,PV3l=0,PV4l=0;
|
||||
static int PV1r=0,PV2r=0,PV3r=0,PV4r=0;
|
||||
static int acc=0;
|
||||
static int acc=0;
|
||||
|
||||
bThrottling = g_Config.m_EnableThrottle;
|
||||
|
||||
if(bThrottling) {
|
||||
|
||||
/* This is only needed for non-AX sound, currently directly
|
||||
streamed and DTK sound. For AX we call SoundStream::Update in
|
||||
AXTask() for example. */
|
||||
while (queue_size > queue_maxlength / 2) {
|
||||
soundStream->Update();
|
||||
Common::SleepCurrentThread(0);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (! (GetAsyncKeyState(VK_TAB)) && g_Config.m_EnableThrottle) {
|
||||
//convert into config option?
|
||||
const int mode = 2;
|
||||
|
||||
/* This is only needed for non-AX sound, currently directly streamed and
|
||||
DTK sound. For AX we call DSound_UpdateSound in AXTask() for example. */
|
||||
while (queue_size > queue_maxlength / 2) {
|
||||
DSound::DSound_UpdateSound();
|
||||
Sleep(0);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
while (queue_size > queue_maxlength) {
|
||||
usleep(1000);
|
||||
}
|
||||
#endif
|
||||
//convert into config option?
|
||||
const int mode = 2;
|
||||
push_sync.Enter();
|
||||
while (num_stereo_samples)
|
||||
{
|
||||
acc += sample_rate;
|
||||
while (num_stereo_samples && (acc >= 48000))
|
||||
{
|
||||
PV4l=PV3l;
|
||||
PV3l=PV2l;
|
||||
PV2l=PV1l;
|
||||
PV1l=*(buffer++); //32bit processing
|
||||
PV4r=PV3r;
|
||||
PV3r=PV2r;
|
||||
PV2r=PV1r;
|
||||
PV1r=*(buffer++); //32bit processing
|
||||
num_stereo_samples--;
|
||||
acc-=48000;
|
||||
}
|
||||
|
||||
push_sync.Enter();
|
||||
while (num_stereo_samples)
|
||||
{
|
||||
acc += sample_rate;
|
||||
while (num_stereo_samples && (acc >= 48000))
|
||||
{
|
||||
PV4l=PV3l;
|
||||
PV3l=PV2l;
|
||||
PV2l=PV1l;
|
||||
PV1l=*(buffer++); //32bit processing
|
||||
PV4r=PV3r;
|
||||
PV3r=PV2r;
|
||||
PV2r=PV1r;
|
||||
PV1r=*(buffer++); //32bit processing
|
||||
num_stereo_samples--;
|
||||
acc-=48000;
|
||||
}
|
||||
// defaults to nearest
|
||||
s32 DataL = PV1l;
|
||||
s32 DataR = PV1r;
|
||||
|
||||
// defaults to nearest
|
||||
s32 DataL = PV1l;
|
||||
s32 DataR = PV1r;
|
||||
|
||||
if (mode == 1) //linear
|
||||
{
|
||||
DataL = PV1l + ((PV2l - PV1l)*acc)/48000;
|
||||
DataR = PV1r + ((PV2r - PV1r)*acc)/48000;
|
||||
}
|
||||
else if (mode == 2) //cubic
|
||||
{
|
||||
s32 a0l = PV1l - PV2l - PV4l + PV3l;
|
||||
s32 a0r = PV1r - PV2r - PV4r + PV3r;
|
||||
s32 a1l = PV4l - PV3l - a0l;
|
||||
s32 a1r = PV4r - PV3r - a0r;
|
||||
s32 a2l = PV1l - PV4l;
|
||||
s32 a2r = PV1r - PV4r;
|
||||
s32 a3l = PV2l;
|
||||
s32 a3r = PV2r;
|
||||
if (mode == 1) //linear
|
||||
{
|
||||
DataL = PV1l + ((PV2l - PV1l)*acc)/48000;
|
||||
DataR = PV1r + ((PV2r - PV1r)*acc)/48000;
|
||||
}
|
||||
else if (mode == 2) //cubic
|
||||
{
|
||||
s32 a0l = PV1l - PV2l - PV4l + PV3l;
|
||||
s32 a0r = PV1r - PV2r - PV4r + PV3r;
|
||||
s32 a1l = PV4l - PV3l - a0l;
|
||||
s32 a1r = PV4r - PV3r - a0r;
|
||||
s32 a2l = PV1l - PV4l;
|
||||
s32 a2r = PV1r - PV4r;
|
||||
s32 a3l = PV2l;
|
||||
s32 a3r = PV2r;
|
||||
|
||||
s32 t0l = ((a0l )*acc)/48000;
|
||||
s32 t0r = ((a0r )*acc)/48000;
|
||||
s32 t1l = ((t0l+a1l)*acc)/48000;
|
||||
s32 t1r = ((t0r+a1r)*acc)/48000;
|
||||
s32 t2l = ((t1l+a2l)*acc)/48000;
|
||||
s32 t2r = ((t1r+a2r)*acc)/48000;
|
||||
s32 t3l = ((t2l+a3l));
|
||||
s32 t3r = ((t2r+a3r));
|
||||
s32 t0l = ((a0l )*acc)/48000;
|
||||
s32 t0r = ((a0r )*acc)/48000;
|
||||
s32 t1l = ((t0l+a1l)*acc)/48000;
|
||||
s32 t1r = ((t0r+a1r)*acc)/48000;
|
||||
s32 t2l = ((t1l+a2l)*acc)/48000;
|
||||
s32 t2r = ((t1r+a2r)*acc)/48000;
|
||||
s32 t3l = ((t2l+a3l));
|
||||
s32 t3r = ((t2r+a3r));
|
||||
|
||||
DataL = t3l;
|
||||
DataR = t3r;
|
||||
}
|
||||
DataL = t3l;
|
||||
DataR = t3r;
|
||||
}
|
||||
|
||||
int l = DataL, r = DataR;
|
||||
if (l < -32767) l = -32767;
|
||||
if (r < -32767) r = -32767;
|
||||
if (l > 32767) l = 32767;
|
||||
if (r > 32767) r = 32767;
|
||||
sample_queue.push(l);
|
||||
sample_queue.push(r);
|
||||
queue_size += 2;
|
||||
}
|
||||
push_sync.Leave();
|
||||
}
|
||||
|
||||
int l = DataL, r = DataR;
|
||||
if (l < -32767) l = -32767;
|
||||
if (r < -32767) r = -32767;
|
||||
if (l > 32767) l = 32767;
|
||||
if (r > 32767) r = 32767;
|
||||
sample_queue.push(l);
|
||||
sample_queue.push(r);
|
||||
queue_size += 2;
|
||||
}
|
||||
push_sync.Leave();
|
||||
}
|
||||
|
||||
|
58
Source/Plugins/Plugin_DSP_HLE/Src/PCHW/SoundStream.h
Normal file
58
Source/Plugins/Plugin_DSP_HLE/Src/PCHW/SoundStream.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2003-2009 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef __SOUNDSTREAM_H__
|
||||
#define __SOUNDSTREAM_H__
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
typedef void (*StreamCallback)(short* buffer, int numSamples, int bits, int rate, int channels);
|
||||
|
||||
class SoundStream {
|
||||
|
||||
protected:
|
||||
int sampleRate;
|
||||
|
||||
StreamCallback callback;
|
||||
|
||||
// We set this to shut down the sound thread.
|
||||
// 0=keep playing, 1=stop playing NOW.
|
||||
volatile int threadData;
|
||||
|
||||
public:
|
||||
SoundStream(int _sampleRate, StreamCallback _callback) :
|
||||
sampleRate(_sampleRate), callback(_callback), threadData(0) {}
|
||||
|
||||
virtual ~SoundStream() {}
|
||||
|
||||
static bool isValid() { return false; }
|
||||
|
||||
virtual bool usesMixer() { return false; }
|
||||
|
||||
virtual bool Start() { return false; }
|
||||
|
||||
virtual void SoundLoop() { }
|
||||
|
||||
virtual void Stop() {}
|
||||
|
||||
virtual void Update() {}
|
||||
|
||||
virtual int GetSampleRate() { return sampleRate; }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -5,10 +5,6 @@ import sys
|
||||
|
||||
name = "Plugin_DSP_HLE"
|
||||
|
||||
if not env['HAVE_AO']:
|
||||
print name + " must have AO to be build"
|
||||
Return()
|
||||
|
||||
files = [
|
||||
'DSPHandler.cpp',
|
||||
'MailHandler.cpp',
|
||||
@ -16,6 +12,7 @@ files = [
|
||||
'Config.cpp',
|
||||
'Globals.cpp',
|
||||
'PCHW/AOSoundStream.cpp',
|
||||
# 'PCHW/NullSoundStream.cpp',
|
||||
'PCHW/Mixer.cpp',
|
||||
'Debugger/File.cpp',
|
||||
'UCodes/UCode_AX.cpp',
|
||||
@ -32,7 +29,7 @@ dspenv = env.Clone()
|
||||
|
||||
if dspenv['HAVE_WX']:
|
||||
files += [
|
||||
'ConfigDlg.cpp',
|
||||
'ConfigDlg.cpp',
|
||||
'Debugger/Debugger.cpp',
|
||||
'Debugger/PBView.cpp',
|
||||
'Debugger/Mails.cpp',
|
||||
|
@ -24,11 +24,6 @@ extern CDebugger* m_frame;
|
||||
#endif
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../PCHW/DSoundStream.h"
|
||||
#else
|
||||
#include "../PCHW/AOSoundStream.h"
|
||||
#endif
|
||||
#include "../PCHW/Mixer.h"
|
||||
#include "../MailHandler.h"
|
||||
|
||||
@ -525,10 +520,10 @@ bool CUCode_AX::AXTask(u32& _uMail)
|
||||
|
||||
mixer_HLEready = true;
|
||||
SaveLog("%08x : AXLIST PB address: %08x", uAddress, m_addressPBs);
|
||||
#ifdef _WIN32
|
||||
|
||||
SaveLog("Update the SoundThread to be in sync");
|
||||
DSound::DSound_UpdateSound(); //do it in this thread to avoid sync problems
|
||||
#endif
|
||||
soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -23,12 +23,6 @@
|
||||
extern CDebugger * m_frame;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../PCHW/DSoundStream.h"
|
||||
#else
|
||||
#include "../PCHW/AOSoundStream.h"
|
||||
#endif
|
||||
|
||||
#include "../PCHW/Mixer.h"
|
||||
#include "../MailHandler.h"
|
||||
|
||||
@ -329,10 +323,7 @@ bool CUCode_AXWii::AXTask(u32& _uMail)
|
||||
lCUCode_AX->m_addressPBs = m_addressPBs; // for the sake of logging
|
||||
mixer_HLEready = true;
|
||||
SaveLog("%08x : AXLIST PB address: %08x", uAddress, m_addressPBs);
|
||||
#ifdef _WIN32
|
||||
//DebugLog("Update the SoundThread to be in sync");
|
||||
DSound::DSound_UpdateSound(); //do it in this thread to avoid sync problems
|
||||
#endif
|
||||
soundStream->Update();
|
||||
uAddress += 4;
|
||||
break;
|
||||
|
||||
|
@ -22,11 +22,6 @@
|
||||
#include "UCode_AX.h"
|
||||
#include "../main.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../PCHW/DSoundStream.h"
|
||||
#else
|
||||
#include "../PCHW/AOSoundStream.h"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Externals
|
||||
@ -112,11 +107,7 @@ inline void WriteBackPBsWii(u32 pbs_address, ParamBlockType& _pPBs, int _num)
|
||||
template<class ParamBlockType>
|
||||
inline void MixAddVoice(ParamBlockType &pb, int *templbuffer, int *temprbuffer, int _iSize, bool Wii)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ratioFactor = 32000.0f / (float)DSound::DSound_GetSampleRate();
|
||||
#else
|
||||
ratioFactor = 32000.0f / (float)AOSound::AOSound_GetSampleRate();
|
||||
#endif
|
||||
ratioFactor = 32000.0f / (float)soundStream->GetSampleRate();
|
||||
|
||||
DoVoiceHacks(pb, Wii);
|
||||
|
||||
|
@ -23,9 +23,7 @@
|
||||
#include "UCode_Zelda.h"
|
||||
#include "../MailHandler.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../PCHW/DSoundStream.h"
|
||||
#endif
|
||||
#include "../main.h"
|
||||
#include "../PCHW/Mixer.h"
|
||||
|
||||
|
||||
@ -126,10 +124,10 @@ void CUCode_Zelda::ExecuteList()
|
||||
|
||||
// We're ready to mix
|
||||
mixer_HLEready = true;
|
||||
#ifdef _WIN32
|
||||
|
||||
DebugLog("Update the SoundThread to be in sync");
|
||||
DSound::DSound_UpdateSound(); //do it in this thread to avoid sync problems
|
||||
#endif
|
||||
soundStream->Update(); //do it in this thread to avoid sync problems
|
||||
|
||||
|
||||
DebugLog("DsyncFrame");
|
||||
DebugLog("???: 0x%08x", tmp[0]);
|
||||
|
@ -15,25 +15,15 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
// -------------
|
||||
#include <iostream>
|
||||
|
||||
#include "Globals.h" // Local
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "PCHW/DSoundStream.h"
|
||||
#else
|
||||
#include "PCHW/AOSoundStream.h"
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
#include "ConfigDlg.h"
|
||||
#include "Debugger/File.h" // For file logging
|
||||
#include "Debugger/Debugger.h" // For the CDebugger class
|
||||
CDebugger* m_frame;
|
||||
#include "ConfigDlg.h"
|
||||
#include "Debugger/File.h" // For file logging
|
||||
#include "Debugger/Debugger.h" // For the CDebugger class
|
||||
CDebugger* m_frame;
|
||||
#endif
|
||||
|
||||
#include "ConsoleWindow.h" // Common: For the Windows console
|
||||
@ -42,174 +32,156 @@
|
||||
#include "PCHW/Mixer.h"
|
||||
#include "DSPHandler.h"
|
||||
#include "Config.h"
|
||||
///////////////////////////////
|
||||
|
||||
#include "PCHW/AOSoundStream.h"
|
||||
#include "PCHW/DSoundStream.h"
|
||||
#include "PCHW/NullSoundStream.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Declarations and definitions
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
DSPInitialize g_dspInitialize;
|
||||
u8* g_pMemory;
|
||||
extern std::vector<std::string> sMailLog, sMailTime;
|
||||
std::string gpName;
|
||||
|
||||
SoundStream *soundStream = NULL;
|
||||
|
||||
// Set this if you want to log audio. search for log_ai in this file to see the filename.
|
||||
static bool log_ai = false;
|
||||
static WaveFileWriter g_wave_writer;
|
||||
|
||||
|
||||
|
||||
// --------------------------------------
|
||||
// Mailbox utility
|
||||
// ----------
|
||||
struct DSPState
|
||||
{
|
||||
u32 CPUMailbox;
|
||||
bool CPUMailbox_Written[2];
|
||||
u32 CPUMailbox;
|
||||
bool CPUMailbox_Written[2];
|
||||
|
||||
u32 DSPMailbox;
|
||||
bool DSPMailbox_Read[2];
|
||||
u32 DSPMailbox;
|
||||
bool DSPMailbox_Read[2];
|
||||
|
||||
DSPState()
|
||||
{
|
||||
CPUMailbox = 0x00000000;
|
||||
CPUMailbox_Written[0] = false;
|
||||
CPUMailbox_Written[1] = false;
|
||||
DSPState()
|
||||
{
|
||||
CPUMailbox = 0x00000000;
|
||||
CPUMailbox_Written[0] = false;
|
||||
CPUMailbox_Written[1] = false;
|
||||
|
||||
DSPMailbox = 0x00000000;
|
||||
DSPMailbox_Read[0] = true;
|
||||
DSPMailbox_Read[1] = true;
|
||||
}
|
||||
DSPMailbox = 0x00000000;
|
||||
DSPMailbox_Read[0] = true;
|
||||
DSPMailbox_Read[1] = true;
|
||||
}
|
||||
};
|
||||
DSPState g_dspState;
|
||||
// -------------------
|
||||
///////////////////////////////
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// wxWidgets: Create the wxApp
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
class wxDLLApp : public wxApp
|
||||
{
|
||||
bool OnInit()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool OnInit()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
|
||||
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
|
||||
#endif
|
||||
///////////////////
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DllMain
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#ifdef _WIN32
|
||||
HINSTANCE g_hInstance = NULL;
|
||||
|
||||
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
|
||||
DWORD dwReason, // reason called
|
||||
LPVOID lpvReserved) // reserved
|
||||
DWORD dwReason, // reason called
|
||||
LPVOID lpvReserved) // reserved
|
||||
{
|
||||
switch (dwReason)
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
|
||||
// more stuff wx needs
|
||||
wxSetInstance((HINSTANCE)hinstDLL);
|
||||
int argc = 0;
|
||||
char **argv = NULL;
|
||||
wxEntryStart(argc, argv);
|
||||
// more stuff wx needs
|
||||
wxSetInstance((HINSTANCE)hinstDLL);
|
||||
int argc = 0;
|
||||
char **argv = NULL;
|
||||
wxEntryStart(argc, argv);
|
||||
|
||||
// This is for ?
|
||||
if ( !wxTheApp || !wxTheApp->CallOnInit() )
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
// This is for ?
|
||||
if ( !wxTheApp || !wxTheApp->CallOnInit() )
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
wxEntryCleanup(); // use this or get a crash
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
wxEntryCleanup(); // use this or get a crash
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_hInstance = hinstDLL;
|
||||
return(TRUE);
|
||||
g_hInstance = hinstDLL;
|
||||
return(TRUE);
|
||||
}
|
||||
#endif
|
||||
///////////////////
|
||||
|
||||
|
||||
// =======================================================================================
|
||||
// Open and close console
|
||||
// -------------------
|
||||
void OpenConsole()
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
Console::Open(155, 100, "Sound Debugging"); // give room for 100 rows
|
||||
Console::Print("OpenConsole > Console opened\n");
|
||||
MoveWindow(Console::GetHwnd(), 0,400, 1280,550, true); // move window, TODO: make this
|
||||
// adjustable from the debugging window
|
||||
#endif
|
||||
#if defined (_WIN32)
|
||||
Console::Open(155, 100, "Sound Debugging"); // give room for 100 rows
|
||||
Console::Print("OpenConsole > Console opened\n");
|
||||
MoveWindow(Console::GetHwnd(), 0,400, 1280,550, true); // move window, TODO: make this
|
||||
// adjustable from the debugging window
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseConsole()
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
FreeConsole();
|
||||
#endif
|
||||
#if defined (_WIN32)
|
||||
FreeConsole();
|
||||
#endif
|
||||
}
|
||||
// ===================
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Exported fuctions
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
// =======================================================================================
|
||||
// Create debugging window - We could use use wxWindow win; new CDebugger(win) like nJoy but I don't
|
||||
// know why it would be better. - There's a lockup problem with ShowModal(), but Show() doesn't work
|
||||
// because then DLL_PROCESS_DETACH is called immediately after DLL_PROCESS_ATTACH.
|
||||
// -------------------
|
||||
void DllDebugger(HWND _hParent, bool Show)
|
||||
{
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
|
||||
if(m_frame && Show) // if we have created it, let us show it again
|
||||
if(m_frame && Show) // if we have created it, let us show it again
|
||||
{
|
||||
m_frame->DoShow();
|
||||
m_frame->DoShow();
|
||||
}
|
||||
else if(!m_frame && Show)
|
||||
else if(!m_frame && Show)
|
||||
{
|
||||
m_frame = new CDebugger(NULL);
|
||||
m_frame->Show();
|
||||
m_frame = new CDebugger(NULL);
|
||||
m_frame->Show();
|
||||
}
|
||||
else if(m_frame && !Show)
|
||||
else if(m_frame && !Show)
|
||||
{
|
||||
m_frame->DoHide();
|
||||
m_frame->DoHide();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// ===================
|
||||
|
||||
|
||||
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
|
||||
{
|
||||
_PluginInfo->Version = 0x0100;
|
||||
_PluginInfo->Type = PLUGIN_TYPE_DSP;
|
||||
_PluginInfo->Version = 0x0100;
|
||||
_PluginInfo->Type = PLUGIN_TYPE_DSP;
|
||||
#ifdef DEBUGFAST
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-HLE Plugin (DebugFast) ");
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-HLE Plugin (DebugFast) ");
|
||||
#else
|
||||
#ifndef _DEBUG
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-HLE Plugin ");
|
||||
sprintf(_PluginInfo->Name, "Dolphin DSP-HLE Plugin ");
|
||||
#else
|
||||
sprintf(_PluginInfo ->Name, "Dolphin DSP-HLE Plugin (Debug) ");
|
||||
sprintf(_PluginInfo ->Name, "Dolphin DSP-HLE Plugin (Debug) ");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@ -220,187 +192,207 @@ void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals) {
|
||||
void DllConfig(HWND _hParent)
|
||||
{
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
// (shuffle2) TODO: reparent dlg with DolphinApp
|
||||
ConfigDialog dlg(NULL);
|
||||
dlg.ShowModal();
|
||||
// (shuffle2) TODO: reparent dlg with DolphinApp
|
||||
ConfigDialog dlg(NULL);
|
||||
if (DSound::isValid())
|
||||
dlg.AddBackend("DSound");
|
||||
if (AOSound::isValid())
|
||||
dlg.AddBackend("AOSound");
|
||||
dlg.AddBackend("NullSound");
|
||||
dlg.ShowModal();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Initialize(void *init)
|
||||
{
|
||||
g_Config.LoadDefaults();
|
||||
g_Config.Load();
|
||||
g_Config.Load();
|
||||
|
||||
g_dspInitialize = *(DSPInitialize*)init;
|
||||
g_dspInitialize = *(DSPInitialize*)init;
|
||||
|
||||
g_pMemory = g_dspInitialize.pGetMemoryPointer(0);
|
||||
g_pMemory = g_dspInitialize.pGetMemoryPointer(0);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
gpName = g_dspInitialize.pName(); // save the game name globally
|
||||
for (u32 i = 0; i < gpName.length(); ++i) // and fix it
|
||||
gpName = g_dspInitialize.pName(); // save the game name globally
|
||||
for (u32 i = 0; i < gpName.length(); ++i) // and fix it
|
||||
{
|
||||
Console::Print("%c", gpName[i]);
|
||||
std::cout << gpName[i];
|
||||
if (gpName[i] == ':') gpName[i] = ' ';
|
||||
fprintf(stderr,"%c", gpName[i]);
|
||||
std::cout << gpName[i];
|
||||
if (gpName[i] == ':') gpName[i] = ' ';
|
||||
}
|
||||
Console::Print("\n");
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
CDSPHandler::CreateInstance();
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _DEBUG
|
||||
int tmpflag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||
tmpflag |= _CRTDBG_DELAY_FREE_MEM_DF;
|
||||
_CrtSetDbgFlag(tmpflag);
|
||||
#endif
|
||||
if (log_ai) {
|
||||
g_wave_writer.Start("D:\\ai_log.wav");
|
||||
g_wave_writer.SetSkipSilence(false);
|
||||
CDSPHandler::CreateInstance();
|
||||
|
||||
if (strncasecmp(g_Config.sBackend, "DSound", 10) == 0) {
|
||||
if (DSound::isValid()) {
|
||||
soundStream = new DSound(48000, Mixer, g_dspInitialize.hWnd);
|
||||
}
|
||||
|
||||
DSound::DSound_StartSound((HWND)g_dspInitialize.hWnd, 48000, Mixer);
|
||||
#else
|
||||
AOSound::AOSound_StartSound(48000, Mixer);
|
||||
} else if(strncasecmp(g_Config.sBackend, "AOSound", 10) == 0) {
|
||||
if (AOSound::isValid())
|
||||
soundStream = new AOSound(48000, Mixer);
|
||||
} else if(strncasecmp(g_Config.sBackend, "NullSound", 10) == 0) {
|
||||
soundStream = new NullSound(48000, Mixer);
|
||||
} else {
|
||||
PanicAlert("Cannot recognize backend %s", g_Config.sBackend);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(WIN32) && defined(_DEBUG)
|
||||
int tmpflag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||
tmpflag |= _CRTDBG_DELAY_FREE_MEM_DF;
|
||||
_CrtSetDbgFlag(tmpflag);
|
||||
#endif
|
||||
|
||||
if (soundStream) {
|
||||
if(!soundStream->Start()) {
|
||||
PanicAlert("Could not initialize backend %s, falling back to NULL",
|
||||
g_Config.sBackend);
|
||||
delete soundStream;
|
||||
soundStream = new NullSound(48000, Mixer);
|
||||
soundStream->Start();
|
||||
}
|
||||
} else {
|
||||
PanicAlert("Sound backend %s is not valid, falling back to NULL",
|
||||
g_Config.sBackend);
|
||||
delete soundStream;
|
||||
soundStream = new NullSound(48000, Mixer);
|
||||
soundStream->Start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
if (log_ai)
|
||||
g_wave_writer.Stop();
|
||||
// delete the UCodes
|
||||
#ifdef _WIN32
|
||||
DSound::DSound_StopSound();
|
||||
#else
|
||||
AOSound::AOSound_StopSound();
|
||||
#endif
|
||||
CDSPHandler::Destroy();
|
||||
if (log_ai)
|
||||
g_wave_writer.Stop();
|
||||
// delete the UCodes
|
||||
soundStream->Stop();
|
||||
delete soundStream;
|
||||
soundStream = NULL;
|
||||
|
||||
CDSPHandler::Destroy();
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
// Reset mails
|
||||
if(m_frame)
|
||||
// Reset mails
|
||||
if(m_frame)
|
||||
{
|
||||
sMailLog.clear();
|
||||
sMailTime.clear();
|
||||
m_frame->sMail.clear();
|
||||
m_frame->sMailEnd.clear();
|
||||
sMailLog.clear();
|
||||
sMailTime.clear();
|
||||
m_frame->sMail.clear();
|
||||
m_frame->sMailEnd.clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DoState(unsigned char **ptr, int mode) {
|
||||
PointerWrap p(ptr, mode);
|
||||
PointerWrap p(ptr, mode);
|
||||
}
|
||||
///////////////////////////////
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Mailbox fuctions
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
unsigned short DSP_ReadMailboxHigh(bool _CPUMailbox)
|
||||
{
|
||||
if (_CPUMailbox)
|
||||
if (_CPUMailbox)
|
||||
{
|
||||
return (g_dspState.CPUMailbox >> 16) & 0xFFFF;
|
||||
return (g_dspState.CPUMailbox >> 16) & 0xFFFF;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
return CDSPHandler::GetInstance().AccessMailHandler().ReadDSPMailboxHigh();
|
||||
return CDSPHandler::GetInstance().AccessMailHandler().ReadDSPMailboxHigh();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short DSP_ReadMailboxLow(bool _CPUMailbox)
|
||||
{
|
||||
if (_CPUMailbox)
|
||||
if (_CPUMailbox)
|
||||
{
|
||||
return g_dspState.CPUMailbox & 0xFFFF;
|
||||
return g_dspState.CPUMailbox & 0xFFFF;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
return CDSPHandler::GetInstance().AccessMailHandler().ReadDSPMailboxLow();
|
||||
return CDSPHandler::GetInstance().AccessMailHandler().ReadDSPMailboxLow();
|
||||
}
|
||||
}
|
||||
|
||||
void Update_DSP_WriteRegister()
|
||||
{
|
||||
// check if the whole message is complete and if we can send it
|
||||
if (g_dspState.CPUMailbox_Written[0] && g_dspState.CPUMailbox_Written[1])
|
||||
// check if the whole message is complete and if we can send it
|
||||
if (g_dspState.CPUMailbox_Written[0] && g_dspState.CPUMailbox_Written[1])
|
||||
{
|
||||
CDSPHandler::GetInstance().SendMailToDSP(g_dspState.CPUMailbox);
|
||||
g_dspState.CPUMailbox_Written[0] = g_dspState.CPUMailbox_Written[1] = false;
|
||||
g_dspState.CPUMailbox = 0; // Mail sent so clear it to show that it is progressed
|
||||
CDSPHandler::GetInstance().SendMailToDSP(g_dspState.CPUMailbox);
|
||||
g_dspState.CPUMailbox_Written[0] = g_dspState.CPUMailbox_Written[1] = false;
|
||||
g_dspState.CPUMailbox = 0; // Mail sent so clear it to show that it is progressed
|
||||
}
|
||||
}
|
||||
|
||||
void DSP_WriteMailboxHigh(bool _CPUMailbox, unsigned short _Value)
|
||||
{
|
||||
if (_CPUMailbox)
|
||||
if (_CPUMailbox)
|
||||
{
|
||||
g_dspState.CPUMailbox = (g_dspState.CPUMailbox & 0xFFFF) | (_Value << 16);
|
||||
g_dspState.CPUMailbox_Written[0] = true;
|
||||
g_dspState.CPUMailbox = (g_dspState.CPUMailbox & 0xFFFF) | (_Value << 16);
|
||||
g_dspState.CPUMailbox_Written[0] = true;
|
||||
|
||||
Update_DSP_WriteRegister();
|
||||
Update_DSP_WriteRegister();
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
PanicAlert("CPU can't write %08x to DSP mailbox", _Value);
|
||||
PanicAlert("CPU can't write %08x to DSP mailbox", _Value);
|
||||
}
|
||||
}
|
||||
|
||||
void DSP_WriteMailboxLow(bool _CPUMailbox, unsigned short _Value)
|
||||
{
|
||||
if (_CPUMailbox)
|
||||
if (_CPUMailbox)
|
||||
{
|
||||
g_dspState.CPUMailbox = (g_dspState.CPUMailbox & 0xFFFF0000) | _Value;
|
||||
g_dspState.CPUMailbox_Written[1] = true;
|
||||
g_dspState.CPUMailbox = (g_dspState.CPUMailbox & 0xFFFF0000) | _Value;
|
||||
g_dspState.CPUMailbox_Written[1] = true;
|
||||
|
||||
Update_DSP_WriteRegister();
|
||||
Update_DSP_WriteRegister();
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
PanicAlert("CPU can't write %08x to DSP mailbox", _Value);
|
||||
PanicAlert("CPU can't write %08x to DSP mailbox", _Value);
|
||||
}
|
||||
}
|
||||
///////////////////////////////
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Other DSP fuctions
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
unsigned short DSP_WriteControlRegister(unsigned short _Value)
|
||||
{
|
||||
return CDSPHandler::GetInstance().WriteControlRegister(_Value);
|
||||
return CDSPHandler::GetInstance().WriteControlRegister(_Value);
|
||||
}
|
||||
|
||||
unsigned short DSP_ReadControlRegister()
|
||||
{
|
||||
return CDSPHandler::GetInstance().ReadControlRegister();
|
||||
return CDSPHandler::GetInstance().ReadControlRegister();
|
||||
}
|
||||
|
||||
void DSP_Update(int cycles)
|
||||
{
|
||||
CDSPHandler::GetInstance().Update();
|
||||
CDSPHandler::GetInstance().Update();
|
||||
}
|
||||
|
||||
void DSP_SendAIBuffer(unsigned int address, int sample_rate)
|
||||
{
|
||||
if(soundStream->usesMixer()) {
|
||||
short samples[16] = {0}; // interleaved stereo
|
||||
if (address) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
samples[i] = Memory_Read_U16(address + i * 2);
|
||||
}
|
||||
if (log_ai)
|
||||
g_wave_writer.AddStereoSamples(samples, 8);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
samples[i] = Memory_Read_U16(address + i * 2);
|
||||
}
|
||||
if (log_ai)
|
||||
g_wave_writer.AddStereoSamples(samples, 8);
|
||||
}
|
||||
Mixer_PushSamples(samples, 32 / 4, sample_rate);
|
||||
}
|
||||
|
||||
static int counter = 0;
|
||||
counter++;
|
||||
#ifdef _WIN32
|
||||
if ((counter & 255) == 0)
|
||||
DSound::DSound_UpdateSound();
|
||||
#endif
|
||||
/*static int counter = 0;
|
||||
counter++;
|
||||
if ((counter & 255) == 0)*/
|
||||
|
||||
|
||||
// SoundStream is updated only when necessary (there is no 70 ms limit
|
||||
// so each sample now triggers the sound stream)
|
||||
soundStream->Update();
|
||||
}
|
||||
///////////////////////////////
|
||||
|
||||
|
||||
|
@ -1,3 +1,31 @@
|
||||
// Copyright (C) 2003-2009 Dolphin Project.
|
||||
|
||||
// This program 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, version 2.0.
|
||||
|
||||
// This program 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef __MAIN_H__
|
||||
#define __MAIN_H__
|
||||
#include "PCHW/SoundStream.h"
|
||||
#include "Globals.h" // Local
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
#include "Debugger/Debugger.h"
|
||||
extern CDebugger* m_frame;
|
||||
#endif
|
||||
|
||||
extern SoundStream *soundStream;
|
||||
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user