[Audio] Add direct sound driver
This commit is contained in:
parent
38b5131f16
commit
48e649f6b0
|
@ -9,6 +9,7 @@ EndProject
|
|||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project64", "Source\Project64\Project64.vcxproj", "{7E534C8E-1ACE-4A88-8807-39A11ED4DA18}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A4D13408-A794-4199-8FC7-4A9A32505005} = {A4D13408-A794-4199-8FC7-4A9A32505005}
|
||||
{D233025A-231F-4A43-92B6-E87193C60ACC} = {D233025A-231F-4A43-92B6-E87193C60ACC}
|
||||
{FD617E80-9E40-4138-85DA-B94633972E6A} = {FD617E80-9E40-4138-85DA-B94633972E6A}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
|
|
@ -14,7 +14,11 @@
|
|||
* *
|
||||
****************************************************************************/
|
||||
#include <Common/Util.h>
|
||||
#ifdef _WIN32
|
||||
#include <Project64-audio/Driver/DirectSound.h>
|
||||
#else
|
||||
#include <Project64-audio/Driver/OpenSLES.h>
|
||||
#endif
|
||||
#include "audio_1.1.h"
|
||||
#include "Version.h"
|
||||
#include <stdio.h>
|
||||
|
@ -32,7 +36,11 @@ AUDIO_INFO g_AudioInfo;
|
|||
bool g_PluginInit = false;
|
||||
uint32_t g_Dacrate = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
DirectSoundDriver * g_SoundDriver = NULL;
|
||||
#else
|
||||
OpenSLESDriver * g_SoundDriver = NULL;
|
||||
#endif
|
||||
|
||||
void PluginInit(void)
|
||||
{
|
||||
|
@ -159,7 +167,9 @@ EXPORT int32_t CALL InitiateAudio(AUDIO_INFO Audio_Info)
|
|||
delete g_SoundDriver;
|
||||
}
|
||||
g_AudioInfo = Audio_Info;
|
||||
#ifdef ANDROID
|
||||
#ifdef _WIN32
|
||||
g_SoundDriver = new DirectSoundDriver;
|
||||
#else
|
||||
g_SoundDriver = new OpenSLESDriver;
|
||||
#endif
|
||||
WriteTrace(TraceAudioInterface, TraceDebug, "Done (res: true)");
|
||||
|
|
|
@ -8,4 +8,7 @@
|
|||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "audio_1.1.h"
|
||||
|
||||
extern AUDIO_INFO g_AudioInfo;
|
||||
|
|
|
@ -30,6 +30,16 @@ enum
|
|||
SYSTEM_MPAL = 2,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
AI_STATUS_FIFO_FULL = 0x80000000, /* Bit 31: full */
|
||||
AI_STATUS_DMA_BUSY = 0x40000000, /* Bit 30: busy */
|
||||
|
||||
MI_INTR_AI = 0x04, /* Bit 2: AI intr */
|
||||
AI_CONTROL_DMA_ON = 0x01,
|
||||
AI_CONTROL_DMA_OFF = 0x00,
|
||||
};
|
||||
|
||||
/***** Structures *****/
|
||||
typedef struct
|
||||
{
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64-audio - A Nintendo 64 audio plugin. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2017 Project64. All rights reserved. *
|
||||
* Copyright (C) 2000-2015 Azimer. All rights reserved. *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#include <windows.h>
|
||||
#include <mmreg.h>
|
||||
#include <dsound.h>
|
||||
#include "DirectSound.h"
|
||||
#include "AudioMain.h"
|
||||
#include "trace.h"
|
||||
#include "AudioSettings.h"
|
||||
|
||||
DirectSoundDriver::DirectSoundDriver() :
|
||||
m_AudioIsDone(true),
|
||||
m_LOCK_SIZE(0),
|
||||
m_lpds(NULL),
|
||||
m_lpdsb(NULL),
|
||||
m_lpdsbuf(NULL),
|
||||
m_handleAudioThread(NULL),
|
||||
m_dwAudioThreadId(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectSoundDriver::Initialize()
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Start");
|
||||
if (!SoundDriverBase::Initialize())
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Done (res: false)");
|
||||
return false;
|
||||
}
|
||||
|
||||
CGuard guard(m_CS);
|
||||
LPDIRECTSOUND8 & lpds = (LPDIRECTSOUND8 &)m_lpds;
|
||||
HRESULT hr = DirectSoundCreate8(NULL, &lpds, NULL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceWarning, "Unable to DirectSoundCreate (hr: 0x%08X)", hr);
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Done (res: false)");
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = lpds->SetCooperativeLevel((HWND)g_AudioInfo.hwnd, DSSCL_PRIORITY);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceWarning, "Failed to SetCooperativeLevel (hr: 0x%08X)", hr);
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Done (res: false)");
|
||||
return false;
|
||||
}
|
||||
|
||||
LPDIRECTSOUNDBUFFER & lpdsbuf = (LPDIRECTSOUNDBUFFER &)m_lpdsbuf;
|
||||
if (lpdsbuf)
|
||||
{
|
||||
IDirectSoundBuffer_Release(lpdsbuf);
|
||||
lpdsbuf = NULL;
|
||||
}
|
||||
DSBUFFERDESC dsPrimaryBuff = { 0 };
|
||||
dsPrimaryBuff.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsPrimaryBuff.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
|
||||
dsPrimaryBuff.dwBufferBytes = 0;
|
||||
dsPrimaryBuff.lpwfxFormat = NULL;
|
||||
|
||||
WAVEFORMATEX wfm = { 0 };
|
||||
wfm.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfm.nChannels = 2;
|
||||
wfm.nSamplesPerSec = 44100;
|
||||
wfm.wBitsPerSample = 16;
|
||||
wfm.nBlockAlign = wfm.wBitsPerSample / 8 * wfm.nChannels;
|
||||
wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign;
|
||||
|
||||
LPDIRECTSOUNDBUFFER & lpdsb = (LPDIRECTSOUNDBUFFER &)m_lpdsb;
|
||||
hr = lpds->CreateSoundBuffer(&dsPrimaryBuff, &lpdsb, NULL);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
lpdsb->SetFormat(&wfm);
|
||||
lpdsb->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Done (res: true)");
|
||||
return true;
|
||||
}
|
||||
|
||||
void DirectSoundDriver::StopAudio()
|
||||
{
|
||||
if (m_handleAudioThread != NULL)
|
||||
{
|
||||
m_AudioIsDone = true;
|
||||
if (WaitForSingleObject((HANDLE)m_handleAudioThread, 5000) == WAIT_TIMEOUT)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceError, "time out on close");
|
||||
|
||||
TerminateThread((HANDLE)m_handleAudioThread, 1);
|
||||
}
|
||||
CloseHandle((HANDLE)m_handleAudioThread);
|
||||
m_handleAudioThread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void DirectSoundDriver::StartAudio()
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Start");
|
||||
if (m_handleAudioThread == NULL)
|
||||
{
|
||||
m_AudioIsDone = false;
|
||||
m_handleAudioThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)stAudioThreadProc, this, 0, (LPDWORD)&m_dwAudioThreadId);
|
||||
|
||||
LPDIRECTSOUNDBUFFER & lpdsbuf = (LPDIRECTSOUNDBUFFER &)m_lpdsbuf;
|
||||
if (lpdsbuf != NULL)
|
||||
{
|
||||
lpdsbuf->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
}
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Done");
|
||||
}
|
||||
|
||||
void DirectSoundDriver::SetFrequency(uint32_t Frequency)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Start (Frequency: 0x%08X)", Frequency);
|
||||
StopAudio();
|
||||
m_LOCK_SIZE = (uint32_t)((Frequency / BufferFPS)) * 4;
|
||||
SetSegmentSize(m_LOCK_SIZE, Frequency);
|
||||
|
||||
StartAudio();
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Done");
|
||||
}
|
||||
|
||||
void DirectSoundDriver::SetSegmentSize(uint32_t length, uint32_t SampleRate)
|
||||
{
|
||||
if (SampleRate == 0) { return; }
|
||||
CGuard guard(m_CS);
|
||||
|
||||
WAVEFORMATEX wfm = { 0 };
|
||||
wfm.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfm.nChannels = 2;
|
||||
wfm.nSamplesPerSec = SampleRate;
|
||||
wfm.wBitsPerSample = 16;
|
||||
wfm.nBlockAlign = wfm.wBitsPerSample / 8 * wfm.nChannels;
|
||||
wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign;
|
||||
|
||||
DSBUFFERDESC dsbdesc = { 0 };
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE;
|
||||
dsbdesc.dwBufferBytes = length * DS_SEGMENTS;
|
||||
dsbdesc.lpwfxFormat = &wfm;
|
||||
|
||||
LPDIRECTSOUND8 & lpds = (LPDIRECTSOUND8 &)m_lpds;
|
||||
LPDIRECTSOUNDBUFFER & lpdsbuf = (LPDIRECTSOUNDBUFFER &)m_lpdsbuf;
|
||||
if (lpds != NULL)
|
||||
{
|
||||
HRESULT hr = lpds->CreateSoundBuffer(&dsbdesc, &lpdsbuf, NULL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceWarning, "CreateSoundBuffer failed (hr: 0x%08X)", hr);
|
||||
}
|
||||
}
|
||||
|
||||
if (lpdsbuf != NULL)
|
||||
{
|
||||
lpdsbuf->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
}
|
||||
|
||||
void DirectSoundDriver::AudioThreadProc()
|
||||
{
|
||||
LPDIRECTSOUNDBUFFER & lpdsbuff = (LPDIRECTSOUNDBUFFER &)m_lpdsbuf;
|
||||
while (lpdsbuff == NULL && !m_AudioIsDone)
|
||||
{
|
||||
Sleep(10);
|
||||
}
|
||||
|
||||
if (!m_AudioIsDone)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Audio Thread Started...");
|
||||
DWORD dwStatus;
|
||||
lpdsbuff->GetStatus(&dwStatus);
|
||||
if ((dwStatus & DSBSTATUS_PLAYING) == 0)
|
||||
{
|
||||
lpdsbuff->Play(0, 0, 0);
|
||||
}
|
||||
|
||||
SetThreadPriority(m_handleAudioThread, THREAD_PRIORITY_HIGHEST);
|
||||
}
|
||||
|
||||
uint32_t next_pos = 0, write_pos = 0, last_pos = 0;
|
||||
while (lpdsbuff != NULL && !m_AudioIsDone)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "last_pos: 0x%08X write_pos: 0x%08X next_pos: 0x%08X", last_pos, write_pos, next_pos);
|
||||
while (last_pos == write_pos)
|
||||
{ // Cycle around until a new buffer position is available
|
||||
if (lpdsbuff == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Check to see if the audio pointer moved on to the next segment
|
||||
if (write_pos == last_pos)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Sleep");
|
||||
Sleep(1);
|
||||
}
|
||||
uint32_t play_pos = 0;
|
||||
if (lpdsbuff == NULL || FAILED(lpdsbuff->GetCurrentPosition((unsigned long*)&play_pos, NULL)))
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Error getting audio position...");
|
||||
m_AudioIsDone = true;
|
||||
break;
|
||||
}
|
||||
write_pos = play_pos < m_LOCK_SIZE ? (m_LOCK_SIZE * DS_SEGMENTS) - m_LOCK_SIZE : ((play_pos / m_LOCK_SIZE) * m_LOCK_SIZE) - m_LOCK_SIZE;
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "play_pos: 0x%08X m_write_pos: 0x%08X next_pos: 0x%08X m_LOCK_SIZE: 0x%08X", play_pos, write_pos, next_pos, m_LOCK_SIZE);
|
||||
}
|
||||
// This means we had a buffer segment skipped
|
||||
if (next_pos != write_pos)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "segment skipped");
|
||||
}
|
||||
|
||||
// Store our last position
|
||||
last_pos = write_pos;
|
||||
|
||||
// Set out next anticipated segment
|
||||
next_pos = write_pos + m_LOCK_SIZE;
|
||||
if (next_pos >= (m_LOCK_SIZE*DS_SEGMENTS))
|
||||
{
|
||||
next_pos -= (m_LOCK_SIZE*DS_SEGMENTS);
|
||||
}
|
||||
|
||||
if (m_AudioIsDone)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Time to write out to the buffer
|
||||
LPVOID lpvPtr1, lpvPtr2;
|
||||
DWORD dwBytes1, dwBytes2;
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Lock Buffer");
|
||||
if (lpdsbuff->Lock(write_pos, m_LOCK_SIZE, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0) != DS_OK)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceError, "Error locking sound buffer");
|
||||
break;
|
||||
}
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "dwBytes1: 0x%08X dwBytes2: 0x%08X", dwBytes1, dwBytes2);
|
||||
|
||||
{
|
||||
CGuard guard(m_CS);
|
||||
LoadAiBuffer((uint8_t *)lpvPtr1, dwBytes1);
|
||||
if (dwBytes2)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Loading second buffer");
|
||||
LoadAiBuffer((BYTE *)lpvPtr2, dwBytes2);
|
||||
}
|
||||
}
|
||||
|
||||
// Fills dwBytes to the Sound Buffer
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Unlock Buffer");
|
||||
if (FAILED(lpdsbuff->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2)))
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceError, "Error unlocking sound buffer");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LPDIRECTSOUNDBUFFER & lpdsbuf = (LPDIRECTSOUNDBUFFER &)m_lpdsbuf;
|
||||
if (lpdsbuf)
|
||||
{
|
||||
lpdsbuf->Stop();
|
||||
}
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Audio Thread Terminated...");
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* Project64-audio - A Nintendo 64 audio plugin. *
|
||||
* http://www.pj64-emu.com/ *
|
||||
* Copyright (C) 2017 Project64. All rights reserved. *
|
||||
* *
|
||||
* License: *
|
||||
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
#include "SoundBase.h"
|
||||
|
||||
class DirectSoundDriver :
|
||||
public SoundDriverBase
|
||||
{
|
||||
enum { DS_SEGMENTS = 4 };
|
||||
|
||||
public:
|
||||
DirectSoundDriver();
|
||||
bool Initialize();
|
||||
void StopAudio(); // Stops the Audio PlayBack (as if paused)
|
||||
void StartAudio(); // Starts the Audio PlayBack (as if unpaused)
|
||||
void SetFrequency(uint32_t);
|
||||
|
||||
private:
|
||||
static uint32_t __stdcall stAudioThreadProc(DirectSoundDriver * _this) { _this->AudioThreadProc(); return 0; }
|
||||
|
||||
void SetSegmentSize(uint32_t length, uint32_t SampleRate);
|
||||
void AudioThreadProc();
|
||||
|
||||
bool m_AudioIsDone;
|
||||
uint32_t m_LOCK_SIZE;
|
||||
void * m_lpds;
|
||||
void * m_lpdsb;
|
||||
void * m_lpdsbuf;
|
||||
void * m_handleAudioThread;
|
||||
uint32_t m_dwAudioThreadId;
|
||||
};
|
|
@ -10,3 +10,186 @@
|
|||
* *
|
||||
****************************************************************************/
|
||||
#include "SoundBase.h"
|
||||
#include <Common/Util.h>
|
||||
#include <Project64-audio/AudioSettings.h>
|
||||
#include <Project64-audio/AudioMain.h>
|
||||
#include <Project64-audio/trace.h>
|
||||
#include <string.h>
|
||||
|
||||
SoundDriverBase::SoundDriverBase() :
|
||||
m_MaxBufferSize(MAX_SIZE),
|
||||
m_AI_DMAPrimaryBuffer(NULL),
|
||||
m_AI_DMASecondaryBuffer(NULL),
|
||||
m_AI_DMAPrimaryBytes(0),
|
||||
m_AI_DMASecondaryBytes(0),
|
||||
m_CurrentReadLoc(0),
|
||||
m_CurrentWriteLoc(0),
|
||||
m_BufferRemaining(0),
|
||||
m_SyncAudio(false)
|
||||
{
|
||||
memset(&m_Buffer, 0, sizeof(m_Buffer));
|
||||
}
|
||||
|
||||
bool SoundDriverBase::Initialize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundDriverBase::AI_SetFrequency(uint32_t Frequency)
|
||||
{
|
||||
SetFrequency(Frequency);
|
||||
m_MaxBufferSize = (uint32_t)((Frequency / BufferFPS)) * 4 * BufferLevel;
|
||||
m_BufferRemaining = 0;
|
||||
m_CurrentReadLoc = m_CurrentWriteLoc = m_BufferRemaining = 0;
|
||||
}
|
||||
|
||||
void SoundDriverBase::AI_LenChanged(uint8_t *start, uint32_t length)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Start");
|
||||
|
||||
// Bleed off some of this buffer to smooth out audio
|
||||
if (length < m_MaxBufferSize && m_SyncAudio)
|
||||
{
|
||||
while ((m_BufferRemaining) == m_MaxBufferSize)
|
||||
{
|
||||
pjutil::Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
CGuard guard(m_CS);
|
||||
BufferAudio();
|
||||
|
||||
if (m_AI_DMASecondaryBuffer != NULL)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Discarding previous secondary buffer");
|
||||
}
|
||||
m_AI_DMASecondaryBuffer = start;
|
||||
m_AI_DMASecondaryBytes = length;
|
||||
if (m_AI_DMAPrimaryBytes == 0)
|
||||
{
|
||||
m_AI_DMAPrimaryBuffer = m_AI_DMASecondaryBuffer;
|
||||
m_AI_DMASecondaryBuffer = NULL;
|
||||
m_AI_DMAPrimaryBytes = m_AI_DMASecondaryBytes;
|
||||
m_AI_DMASecondaryBytes = 0;
|
||||
}
|
||||
|
||||
*g_AudioInfo.AI_STATUS_REG = AI_STATUS_DMA_BUSY;
|
||||
if (m_AI_DMAPrimaryBytes > 0 && m_AI_DMASecondaryBytes > 0)
|
||||
{
|
||||
*g_AudioInfo.AI_STATUS_REG = (uint32_t)(AI_STATUS_DMA_BUSY | AI_STATUS_FIFO_FULL);
|
||||
}
|
||||
BufferAudio();
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Done");
|
||||
}
|
||||
|
||||
void SoundDriverBase::AI_Startup()
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Start");
|
||||
m_AI_DMAPrimaryBytes = m_AI_DMASecondaryBytes = 0;
|
||||
m_AI_DMAPrimaryBuffer = m_AI_DMASecondaryBuffer = NULL;
|
||||
m_MaxBufferSize = MAX_SIZE;
|
||||
m_CurrentReadLoc = m_CurrentWriteLoc = m_BufferRemaining = 0;
|
||||
if (Initialize())
|
||||
{
|
||||
StartAudio();
|
||||
}
|
||||
WriteTrace(TraceAudioDriver, TraceDebug, "Start");
|
||||
}
|
||||
|
||||
void SoundDriverBase::AI_Shutdown()
|
||||
{
|
||||
StopAudio();
|
||||
}
|
||||
|
||||
void SoundDriverBase::AI_Update(bool Wait)
|
||||
{
|
||||
m_AiUpdateEvent.IsTriggered(Wait ? SyncEvent::INFINITE_TIMEOUT : 0);
|
||||
}
|
||||
|
||||
void SoundDriverBase::LoadAiBuffer(uint8_t *start, uint32_t length)
|
||||
{
|
||||
uint8_t nullBuff[MAX_SIZE];
|
||||
uint8_t *ptrStart = start != NULL ? start : nullBuff;
|
||||
uint32_t writePtr = 0, bytesToMove = length;
|
||||
|
||||
if (bytesToMove > m_MaxBufferSize)
|
||||
{
|
||||
memset(ptrStart, 0, 100);
|
||||
return;
|
||||
}
|
||||
bool DMAEnabled = (*g_AudioInfo.AI_CONTROL_REG & AI_CONTROL_DMA_ON) == AI_CONTROL_DMA_ON;
|
||||
if (!DMAEnabled)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Return silence -- DMA is disabled");
|
||||
memset(ptrStart, 0, bytesToMove);
|
||||
return;
|
||||
}
|
||||
|
||||
CGuard guard(m_CS);
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Step 0: Replace depleted stored buffer for next run");
|
||||
BufferAudio();
|
||||
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Step 1: Deplete stored buffer (bytesToMove: 0x%08X m_BufferRemaining: 0x%08X)", bytesToMove, m_BufferRemaining);
|
||||
while (bytesToMove > 0 && m_BufferRemaining > 0)
|
||||
{
|
||||
*(uint32_t *)(ptrStart + writePtr) = *(uint32_t *)(m_Buffer + m_CurrentReadLoc);
|
||||
m_CurrentReadLoc += 4;
|
||||
writePtr += 4;
|
||||
m_CurrentReadLoc %= m_MaxBufferSize;
|
||||
m_BufferRemaining -= 4;
|
||||
bytesToMove -= 4;
|
||||
}
|
||||
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Step 2: Fill bytesToMove (0x%08X) with silence", bytesToMove);
|
||||
while (bytesToMove > 0)
|
||||
{
|
||||
*(uint8_t *)(ptrStart + writePtr) = 0;
|
||||
writePtr += 1;
|
||||
bytesToMove -= 1;
|
||||
}
|
||||
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Step 3: Replace depleted stored buffer for next run");
|
||||
BufferAudio();
|
||||
}
|
||||
|
||||
void SoundDriverBase::BufferAudio()
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Start (m_BufferRemaining: 0x%08X m_MaxBufferSize: 0x%08X m_AI_DMAPrimaryBytes: 0x%08X m_AI_DMASecondaryBytes: 0x%08X)", m_BufferRemaining, m_MaxBufferSize, m_AI_DMAPrimaryBytes, m_AI_DMASecondaryBytes);
|
||||
while ((m_BufferRemaining < m_MaxBufferSize) && (m_AI_DMAPrimaryBytes > 0 || m_AI_DMASecondaryBytes > 0))
|
||||
{
|
||||
*(uint16_t *)(m_Buffer + m_CurrentWriteLoc) = *(uint16_t *)(m_AI_DMAPrimaryBuffer + 2);
|
||||
*(uint16_t *)(m_Buffer + m_CurrentWriteLoc + 2) = *(uint16_t *)m_AI_DMAPrimaryBuffer;
|
||||
m_CurrentWriteLoc += 4;
|
||||
m_AI_DMAPrimaryBuffer += 4;
|
||||
m_CurrentWriteLoc %= m_MaxBufferSize;
|
||||
m_BufferRemaining += 4;
|
||||
m_AI_DMAPrimaryBytes -= 4;
|
||||
if (m_AI_DMAPrimaryBytes == 0)
|
||||
{
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Emptied Primary Buffer");
|
||||
m_AI_DMAPrimaryBytes = m_AI_DMASecondaryBytes; m_AI_DMAPrimaryBuffer = m_AI_DMASecondaryBuffer; // Switch
|
||||
m_AI_DMASecondaryBytes = 0; m_AI_DMASecondaryBuffer = NULL;
|
||||
*g_AudioInfo.AI_STATUS_REG = AI_STATUS_DMA_BUSY;
|
||||
*g_AudioInfo.AI_STATUS_REG &= ~AI_STATUS_FIFO_FULL;
|
||||
*g_AudioInfo.MI_INTR_REG |= MI_INTR_AI;
|
||||
g_AudioInfo.CheckInterrupts();
|
||||
if (m_AI_DMAPrimaryBytes == 0)
|
||||
{
|
||||
*g_AudioInfo.AI_STATUS_REG = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteTrace(TraceAudioDriver, TraceVerbose, "Done (m_BufferRemaining: 0x%08X)", m_BufferRemaining);
|
||||
}
|
||||
|
||||
void SoundDriverBase::SetFrequency(uint32_t /*Frequency*/)
|
||||
{
|
||||
}
|
||||
|
||||
void SoundDriverBase::StartAudio()
|
||||
{
|
||||
}
|
||||
|
||||
void SoundDriverBase::StopAudio()
|
||||
{
|
||||
}
|
|
@ -10,8 +10,46 @@
|
|||
* *
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
#include <Common/SyncEvent.h>
|
||||
#include <Common/CriticalSection.h>
|
||||
|
||||
class SoundDriverBase
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
BufferFPS = 90,
|
||||
BufferLevel = 2,
|
||||
};
|
||||
SoundDriverBase();
|
||||
|
||||
void AI_SetFrequency(uint32_t Frequency);
|
||||
void AI_LenChanged(uint8_t *start, uint32_t length);
|
||||
void AI_Startup();
|
||||
void AI_Shutdown();
|
||||
void AI_Update(bool Wait);
|
||||
|
||||
virtual void SetFrequency(uint32_t Frequency);
|
||||
virtual void StartAudio();
|
||||
virtual void StopAudio();
|
||||
|
||||
protected:
|
||||
enum { MAX_SIZE = 44100 * 2 * 2 }; // Max Buffer Size (44100Hz * 16bit * Stereo)
|
||||
|
||||
virtual bool Initialize();
|
||||
void LoadAiBuffer(uint8_t *start, uint32_t length); // Reads in length amount of audio bytes
|
||||
uint32_t m_MaxBufferSize; // Variable size determined by Playback rate
|
||||
CriticalSection m_CS;
|
||||
|
||||
private:
|
||||
void BufferAudio();
|
||||
|
||||
SyncEvent m_AiUpdateEvent;
|
||||
uint8_t *m_AI_DMAPrimaryBuffer, *m_AI_DMASecondaryBuffer;
|
||||
uint32_t m_AI_DMAPrimaryBytes, m_AI_DMASecondaryBytes;
|
||||
uint32_t m_BufferRemaining; // Buffer remaining
|
||||
uint32_t m_CurrentReadLoc; // Currently playing Buffer
|
||||
uint32_t m_CurrentWriteLoc; // Currently writing Buffer
|
||||
uint8_t m_Buffer[MAX_SIZE]; // Emulated buffers
|
||||
bool m_SyncAudio;
|
||||
};
|
|
@ -33,11 +33,16 @@
|
|||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>$(Root)Source\3rdParty\directx\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>dsound.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AudioMain.cpp" />
|
||||
<ClCompile Include="AudioSettings.cpp" />
|
||||
<ClCompile Include="Driver\DirectSound.cpp" />
|
||||
<ClCompile Include="Driver\OpenSLES.cpp" />
|
||||
<ClCompile Include="Driver\SoundBase.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
|
@ -46,6 +51,7 @@
|
|||
<ClInclude Include="AudioMain.h" />
|
||||
<ClInclude Include="Audio_1.1.h" />
|
||||
<ClInclude Include="AudioSettings.h" />
|
||||
<ClInclude Include="Driver\DirectSound.h" />
|
||||
<ClInclude Include="Driver\OpenSLES.h" />
|
||||
<ClInclude Include="Driver\SoundBase.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
<ClCompile Include="Driver\OpenSLES.cpp">
|
||||
<Filter>Source Files\Driver</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Driver\DirectSound.cpp">
|
||||
<Filter>Source Files\Driver</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Audio_1.1.h">
|
||||
|
@ -65,6 +68,9 @@
|
|||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Driver\DirectSound.h">
|
||||
<Filter>Header Files\Driver</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Project64-audio.rc">
|
||||
|
|
Loading…
Reference in New Issue