mirror of
https://github.com/Team-Resurgent/UIXLiteFTP.git
synced 2026-08-15 11:18:21 -07:00
243 lines
6.3 KiB
C++
243 lines
6.3 KiB
C++
#include "audioPlayer.h"
|
|
#include "stringUtility.h"
|
|
#include "fileSystem.h"
|
|
#include "pointerMap.h"
|
|
#include "context.h"
|
|
#include "utils.h"
|
|
#include "resources.h"
|
|
|
|
#include <dmusici.h>
|
|
#include <dsound.h>
|
|
|
|
#define STB_VORBIS_HEADER_ONLY
|
|
#include "stb_vorbis.cpp"
|
|
#include "stb.h"
|
|
|
|
#define AUDIO_PACKETS 64
|
|
#define AUDIO_OUTPUT_BUF_SIZE 8192
|
|
|
|
extern "C"
|
|
{
|
|
extern BOOL g_fDirectSoundDisableBusyWaitWarning;
|
|
}
|
|
|
|
namespace {
|
|
|
|
pointerMap<audioContainer*>* mAudioContainerMap;
|
|
LPDIRECTSOUND8 mDirectSoundDevice;
|
|
uint32_t mUniqueSoundId;
|
|
bool mPause;
|
|
CRITICAL_SECTION mPlayerMutex;
|
|
}
|
|
|
|
bool audioPlayer::init()
|
|
{
|
|
InitializeCriticalSection(&mPlayerMutex);
|
|
|
|
g_fDirectSoundDisableBusyWaitWarning = TRUE;
|
|
|
|
mAudioContainerMap = new pointerMap<audioContainer*>(true);
|
|
mUniqueSoundId = 0;
|
|
|
|
HRESULT hr = DirectSoundCreate( NULL, &mDirectSoundDevice, NULL );
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
bool audioPlayer::close()
|
|
{
|
|
for (uint32_t i = 0; i < mAudioContainerMap->count(); i++)
|
|
{
|
|
audioContainer* sound = mAudioContainerMap->get(i);
|
|
EnterCriticalSection(&mPlayerMutex);
|
|
sound->requestStop = true;
|
|
LeaveCriticalSection(&mPlayerMutex);
|
|
}
|
|
delete(mAudioContainerMap);
|
|
if (mDirectSoundDevice)
|
|
{
|
|
mDirectSoundDevice->Release();
|
|
mDirectSoundDevice = NULL;
|
|
}
|
|
DeleteCriticalSection(&mPlayerMutex);
|
|
return true;
|
|
}
|
|
|
|
uint32_t audioPlayer::play()
|
|
{
|
|
if (mPause == true || mAudioContainerMap->count() >= 20)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
mUniqueSoundId++;
|
|
|
|
audioContainer* sound = new audioContainer();
|
|
sound->id = mUniqueSoundId;
|
|
sound->requestStop = false;
|
|
sound->thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)process, (void*)sound, 0, NULL);
|
|
mAudioContainerMap->add(mUniqueSoundId, sound);
|
|
|
|
utils::debugPrint("Sound %i play start with thread handle %i\n", mUniqueSoundId, sound->thread);
|
|
|
|
return mUniqueSoundId;
|
|
}
|
|
|
|
bool audioPlayer::stop(uint32_t key)
|
|
{
|
|
audioContainer* sound = mAudioContainerMap->get(key);
|
|
if (sound == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
EnterCriticalSection(&mPlayerMutex);
|
|
sound->requestStop = true;
|
|
LeaveCriticalSection(&mPlayerMutex);
|
|
return true;
|
|
}
|
|
|
|
void audioPlayer::pause(bool value)
|
|
{
|
|
mPause = value;
|
|
}
|
|
|
|
uint64_t WINAPI audioPlayer::process(void* param)
|
|
{
|
|
audioContainer* container = (audioContainer*)param;
|
|
bool repeat = true;
|
|
|
|
int error;
|
|
stb_vorbis *vorbis = stb_vorbis_open_memory(engine_room_ogg, sizeof(engine_room_ogg), &error, NULL);
|
|
if (vorbis == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
stb_vorbis_info vorbisInfo = stb_vorbis_get_info(vorbis);
|
|
|
|
WAVEFORMATEX waveFormat;
|
|
memset(&waveFormat, 0, sizeof(waveFormat));
|
|
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
|
|
waveFormat.nChannels = vorbisInfo.channels;
|
|
waveFormat.nSamplesPerSec = vorbisInfo.sample_rate;
|
|
waveFormat.wBitsPerSample = sizeof(short) * 8;
|
|
waveFormat.nBlockAlign = (waveFormat.wBitsPerSample >> 3) * waveFormat.nChannels;
|
|
waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign * waveFormat.nSamplesPerSec;
|
|
|
|
DSSTREAMDESC streamDesc;
|
|
memset(&streamDesc, 0, sizeof(streamDesc));
|
|
streamDesc.dwMaxAttachedPackets = AUDIO_PACKETS;
|
|
streamDesc.lpwfxFormat = &waveFormat;
|
|
|
|
LPDIRECTSOUNDSTREAM directSoundStream;
|
|
mDirectSoundDevice->CreateSoundStream(&streamDesc, &directSoundStream, NULL);
|
|
|
|
directSoundStream->SetVolume(0);
|
|
directSoundStream->SetHeadroom(0);
|
|
|
|
DSMIXBINVOLUMEPAIR mixBinVolumePair[6];
|
|
mixBinVolumePair[0].dwMixBin = DSMIXBIN_FRONT_LEFT;
|
|
mixBinVolumePair[0].lVolume = DSBVOLUME_MAX;
|
|
mixBinVolumePair[1].dwMixBin = DSMIXBIN_FRONT_RIGHT;
|
|
mixBinVolumePair[1].lVolume = DSBVOLUME_MAX;
|
|
mixBinVolumePair[2].dwMixBin = DSMIXBIN_FRONT_CENTER;
|
|
mixBinVolumePair[2].lVolume = DSBVOLUME_MIN;
|
|
mixBinVolumePair[3].dwMixBin = DSMIXBIN_LOW_FREQUENCY;
|
|
mixBinVolumePair[3].lVolume = DSBVOLUME_MIN;
|
|
mixBinVolumePair[4].dwMixBin = DSMIXBIN_BACK_LEFT;
|
|
mixBinVolumePair[4].lVolume = DSBVOLUME_MIN;
|
|
mixBinVolumePair[5].dwMixBin = DSMIXBIN_BACK_RIGHT;
|
|
mixBinVolumePair[5].lVolume = DSBVOLUME_MIN;
|
|
|
|
DSMIXBINS mixBins;
|
|
mixBins.dwMixBinCount = 6;
|
|
mixBins.lpMixBinVolumePairs = mixBinVolumePair;
|
|
directSoundStream->SetMixBins(&mixBins);
|
|
|
|
uint32_t* packetStatus = (uint32_t*)malloc(AUDIO_PACKETS * sizeof(uint32_t));
|
|
memset(packetStatus, 0, AUDIO_PACKETS * sizeof(uint32_t));
|
|
uint32_t* completedSize = (uint32_t*)malloc(AUDIO_PACKETS * sizeof(uint32_t));
|
|
memset(completedSize, 0, AUDIO_PACKETS * sizeof(uint32_t));
|
|
|
|
char* decodeBuffer = (char *)malloc(AUDIO_PACKETS * AUDIO_OUTPUT_BUF_SIZE);
|
|
|
|
utils::debugPrint("Sound %i play loop begin\n", container->id);
|
|
|
|
bool eof = false;
|
|
while (true)
|
|
{
|
|
EnterCriticalSection(&mPlayerMutex);
|
|
bool requestStop = container->requestStop;
|
|
LeaveCriticalSection(&mPlayerMutex);
|
|
|
|
if (mPause == true)
|
|
{
|
|
DirectSoundDoWork();
|
|
Sleep(10);
|
|
continue;
|
|
}
|
|
|
|
if (eof == true || requestStop == true)
|
|
{
|
|
DirectSoundDoWork();
|
|
Sleep(10);
|
|
break;
|
|
}
|
|
|
|
directSoundStream->SetVolume(0);
|
|
|
|
for (int i = 0; i < AUDIO_PACKETS; i++)
|
|
{
|
|
if (packetStatus[i] != XMEDIAPACKET_STATUS_PENDING)
|
|
{
|
|
char *decodeBufferOffset = decodeBuffer + (i * AUDIO_OUTPUT_BUF_SIZE);
|
|
const int bytesRead = (int)stb_vorbis_get_samples_short_interleaved(vorbis, vorbisInfo.channels, (short*)decodeBufferOffset, AUDIO_OUTPUT_BUF_SIZE / sizeof(short)) * vorbisInfo.channels * sizeof(short);
|
|
if (bytesRead != AUDIO_OUTPUT_BUF_SIZE)
|
|
{
|
|
memset(decodeBufferOffset + bytesRead, 0, AUDIO_OUTPUT_BUF_SIZE - bytesRead);
|
|
}
|
|
if (bytesRead != 0)
|
|
{
|
|
XMEDIAPACKET mediaPacket;
|
|
memset(&mediaPacket, 0, sizeof(mediaPacket));
|
|
mediaPacket.pvBuffer = decodeBufferOffset;
|
|
mediaPacket.dwMaxSize = bytesRead;
|
|
mediaPacket.pdwCompletedSize = &completedSize[i];
|
|
mediaPacket.pdwStatus = &packetStatus[i];
|
|
directSoundStream->Process(&mediaPacket, NULL);
|
|
}
|
|
else if (repeat == true)
|
|
{
|
|
stb_vorbis_seek(vorbis, 0);
|
|
}
|
|
else
|
|
{
|
|
eof = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
DirectSoundDoWork();
|
|
Sleep(100);
|
|
}
|
|
|
|
int maxSamples = ((AUDIO_PACKETS * AUDIO_OUTPUT_BUF_SIZE) / sizeof(short)) / vorbisInfo.channels;
|
|
int waitTime = (int)(maxSamples / (vorbisInfo.sample_rate / 1000.0f));
|
|
Sleep(waitTime);
|
|
|
|
directSoundStream->FlushEx(0, DSSTREAMFLUSHEX_ASYNC);
|
|
directSoundStream->Release();
|
|
|
|
free(packetStatus);
|
|
free(completedSize);
|
|
free(decodeBuffer);
|
|
stb_vorbis_close(vorbis);
|
|
|
|
utils::debugPrint("Sound %i ending\n", container->id);
|
|
|
|
mAudioContainerMap->removeKey(container->id);
|
|
|
|
return 1;
|
|
}
|