mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-23 06:53:43 +00:00
Refactor audio buffering API, this should mainly prevent SDL audio driver from allocating memory in the mixer callback.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
#include "CoreDefs.h"
|
#include "CoreDefs.h"
|
||||||
|
#include "IGpAudioBuffer.h"
|
||||||
#include "IGpAudioDriver.h"
|
#include "IGpAudioDriver.h"
|
||||||
#include "IGpAudioChannel.h"
|
#include "IGpAudioChannel.h"
|
||||||
#include "IGpAudioChannelCallbacks.h"
|
#include "IGpAudioChannelCallbacks.h"
|
||||||
@@ -13,6 +14,8 @@
|
|||||||
|
|
||||||
#include "SDL_atomic.h"
|
#include "SDL_atomic.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <new>
|
#include <new>
|
||||||
@@ -52,22 +55,82 @@ static void AlignedFree(void *ptr)
|
|||||||
free(storageLoc);
|
free(storageLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GpAudioChannelBufferChain_SDL2 final
|
class GpAudioBuffer_SDL2 final : public IGpAudioBuffer
|
||||||
{
|
{
|
||||||
GpAudioChannelBufferChain_SDL2();
|
public:
|
||||||
|
static GpAudioBuffer_SDL2 *Create(const void *data, size_t size);
|
||||||
|
|
||||||
static GpAudioChannelBufferChain_SDL2 *Alloc();
|
void AddRef() override;
|
||||||
void Release();
|
void Release() override;
|
||||||
|
|
||||||
static const size_t kMaxCapacity = 65536;
|
const void *GetData() const;
|
||||||
|
size_t GetSize() const;
|
||||||
|
|
||||||
size_t m_consumed;
|
private:
|
||||||
size_t m_used;
|
GpAudioBuffer_SDL2(const void *data, size_t size);
|
||||||
uint8_t m_data[kMaxCapacity];
|
~GpAudioBuffer_SDL2();
|
||||||
GpAudioChannelBufferChain_SDL2 *m_next;
|
|
||||||
bool m_hasTrigger;
|
void Destroy();
|
||||||
|
|
||||||
|
const void *m_data;
|
||||||
|
size_t m_size;
|
||||||
|
SDL_atomic_t m_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GpAudioBuffer_SDL2 *GpAudioBuffer_SDL2::Create(const void *data, size_t size)
|
||||||
|
{
|
||||||
|
void *storage = malloc(size + sizeof(GpAudioBuffer_SDL2));
|
||||||
|
if (!storage)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
void *dataPos = static_cast<uint8_t*>(storage) + sizeof(GpAudioBuffer_SDL2);
|
||||||
|
memcpy(dataPos, data, size);
|
||||||
|
|
||||||
|
return new (storage) GpAudioBuffer_SDL2(dataPos, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GpAudioBuffer_SDL2::AddRef()
|
||||||
|
{
|
||||||
|
SDL_AtomicAdd(&m_count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpAudioBuffer_SDL2::Release()
|
||||||
|
{
|
||||||
|
int prevCount = SDL_AtomicAdd(&m_count, -1);
|
||||||
|
if (prevCount == 1)
|
||||||
|
this->Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *GpAudioBuffer_SDL2::GetData() const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GpAudioBuffer_SDL2::GetSize() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GpAudioBuffer_SDL2::GpAudioBuffer_SDL2(const void *data, size_t size)
|
||||||
|
: m_data(data)
|
||||||
|
, m_size(size)
|
||||||
|
{
|
||||||
|
SDL_AtomicSet(&m_count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
GpAudioBuffer_SDL2::~GpAudioBuffer_SDL2()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpAudioBuffer_SDL2::Destroy()
|
||||||
|
{
|
||||||
|
this->~GpAudioBuffer_SDL2();
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class GpAudioChannel_SDL2 final : public IGpAudioChannel
|
class GpAudioChannel_SDL2 final : public IGpAudioChannel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -80,7 +143,7 @@ public:
|
|||||||
void Release();
|
void Release();
|
||||||
|
|
||||||
void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) override;
|
void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) override;
|
||||||
void PostBuffer(const void *buffer, size_t bufferSize) override;
|
bool PostBuffer(IGpAudioBuffer *buffer) override;
|
||||||
void Stop() override;
|
void Stop() override;
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
|
|
||||||
@@ -91,14 +154,19 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool Init(GpAudioDriver_SDL2 *driver);
|
bool Init(GpAudioDriver_SDL2 *driver);
|
||||||
|
|
||||||
|
static const size_t kMaxBuffers = 16;
|
||||||
|
|
||||||
IGpAudioChannelCallbacks *m_callbacks;
|
IGpAudioChannelCallbacks *m_callbacks;
|
||||||
IGpMutex *m_mutex;
|
IGpMutex *m_mutex;
|
||||||
GpAudioDriver_SDL2 *m_owner;
|
GpAudioDriver_SDL2 *m_owner;
|
||||||
|
|
||||||
SDL_atomic_t m_refCount;
|
SDL_atomic_t m_refCount;
|
||||||
|
|
||||||
GpAudioChannelBufferChain_SDL2 *m_firstPendingBuffer;
|
GpAudioBuffer_SDL2 *m_pendingBuffers[kMaxBuffers];
|
||||||
GpAudioChannelBufferChain_SDL2 *m_lastPendingBuffer;
|
size_t m_nextPendingBufferConsumePos;
|
||||||
|
size_t m_nextPendingBufferInsertionPos;
|
||||||
|
size_t m_numQueuedBuffers;
|
||||||
|
size_t m_firstBufferSamplesConsumed;
|
||||||
|
|
||||||
GpAudioDriver_SDL2_TimePoint_t m_timestamp; // Time that audio will be consumed if posted to the channel, if m_hasTimestamp is true.
|
GpAudioDriver_SDL2_TimePoint_t m_timestamp; // Time that audio will be consumed if posted to the channel, if m_hasTimestamp is true.
|
||||||
GpAudioDriver_SDL2_Duration_t m_latency;
|
GpAudioDriver_SDL2_Duration_t m_latency;
|
||||||
@@ -118,6 +186,7 @@ public:
|
|||||||
explicit GpAudioDriver_SDL2(const GpAudioDriverProperties &properties);
|
explicit GpAudioDriver_SDL2(const GpAudioDriverProperties &properties);
|
||||||
~GpAudioDriver_SDL2();
|
~GpAudioDriver_SDL2();
|
||||||
|
|
||||||
|
IGpAudioBuffer *CreateBuffer(const void *data, size_t size) override;
|
||||||
IGpAudioChannel *CreateChannel() override;
|
IGpAudioChannel *CreateChannel() override;
|
||||||
void SetMasterVolume(uint32_t vol, uint32_t maxVolume) override;
|
void SetMasterVolume(uint32_t vol, uint32_t maxVolume) override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
@@ -162,27 +231,6 @@ private:
|
|||||||
int16_t m_audioVolumeScale;
|
int16_t m_audioVolumeScale;
|
||||||
};
|
};
|
||||||
|
|
||||||
GpAudioChannelBufferChain_SDL2::GpAudioChannelBufferChain_SDL2()
|
|
||||||
: m_used(0)
|
|
||||||
, m_consumed(0)
|
|
||||||
, m_next(nullptr)
|
|
||||||
, m_hasTrigger(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GpAudioChannelBufferChain_SDL2 *GpAudioChannelBufferChain_SDL2::Alloc()
|
|
||||||
{
|
|
||||||
void *storage = AlignedAlloc(sizeof(GpAudioChannelBufferChain_SDL2), GP_SYSTEM_MEMORY_ALIGNMENT);
|
|
||||||
return new (storage) GpAudioChannelBufferChain_SDL2();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GpAudioChannelBufferChain_SDL2::Release()
|
|
||||||
{
|
|
||||||
this->~GpAudioChannelBufferChain_SDL2();
|
|
||||||
AlignedFree(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// GpAudioChannel
|
// GpAudioChannel
|
||||||
|
|
||||||
@@ -190,8 +238,6 @@ GpAudioChannel_SDL2::GpAudioChannel_SDL2(GpAudioDriver_SDL2_Duration_t latency,
|
|||||||
: m_callbacks(nullptr)
|
: m_callbacks(nullptr)
|
||||||
, m_mutex(nullptr)
|
, m_mutex(nullptr)
|
||||||
, m_owner(nullptr)
|
, m_owner(nullptr)
|
||||||
, m_firstPendingBuffer(nullptr)
|
|
||||||
, m_lastPendingBuffer(nullptr)
|
|
||||||
, m_latency(latency)
|
, m_latency(latency)
|
||||||
, m_bufferTime(bufferTime)
|
, m_bufferTime(bufferTime)
|
||||||
, m_bufferSamplesMax(bufferSamplesMax)
|
, m_bufferSamplesMax(bufferSamplesMax)
|
||||||
@@ -199,6 +245,10 @@ GpAudioChannel_SDL2::GpAudioChannel_SDL2(GpAudioDriver_SDL2_Duration_t latency,
|
|||||||
, m_sampleRate(sampleRate)
|
, m_sampleRate(sampleRate)
|
||||||
, m_isMixing(false)
|
, m_isMixing(false)
|
||||||
, m_hasTimestamp(false)
|
, m_hasTimestamp(false)
|
||||||
|
, m_nextPendingBufferConsumePos(0)
|
||||||
|
, m_nextPendingBufferInsertionPos(0)
|
||||||
|
, m_numQueuedBuffers(0)
|
||||||
|
, m_firstBufferSamplesConsumed(0)
|
||||||
{
|
{
|
||||||
SDL_AtomicSet(&m_refCount, 1);
|
SDL_AtomicSet(&m_refCount, 1);
|
||||||
}
|
}
|
||||||
@@ -210,12 +260,7 @@ GpAudioChannel_SDL2::~GpAudioChannel_SDL2()
|
|||||||
if (m_mutex)
|
if (m_mutex)
|
||||||
m_mutex->Destroy();
|
m_mutex->Destroy();
|
||||||
|
|
||||||
while (m_firstPendingBuffer)
|
assert(m_numQueuedBuffers == 0);
|
||||||
{
|
|
||||||
GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer;
|
|
||||||
m_firstPendingBuffer = buffer->m_next;
|
|
||||||
buffer->Release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpAudioChannel_SDL2::AddRef()
|
void GpAudioChannel_SDL2::AddRef()
|
||||||
@@ -238,12 +283,21 @@ void GpAudioChannel_SDL2::SetAudioChannelContext(IGpAudioChannelCallbacks *callb
|
|||||||
m_callbacks = callbacks;
|
m_callbacks = callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpAudioChannel_SDL2::PostBuffer(const void *buffer, size_t bufferSize)
|
bool GpAudioChannel_SDL2::PostBuffer(IGpAudioBuffer *buffer)
|
||||||
{
|
{
|
||||||
|
buffer->AddRef();
|
||||||
|
|
||||||
m_mutex->Lock();
|
m_mutex->Lock();
|
||||||
|
|
||||||
|
if (m_numQueuedBuffers == kMaxBuffers)
|
||||||
|
{
|
||||||
|
m_mutex->Unlock();
|
||||||
|
buffer->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
size_t leadingSilence = 0;
|
size_t leadingSilence = 0;
|
||||||
if (m_firstPendingBuffer == nullptr && m_hasTimestamp && !m_isMixing)
|
if (m_numQueuedBuffers == 0 && m_hasTimestamp && !m_isMixing)
|
||||||
{
|
{
|
||||||
GpAudioDriver_SDL2_TimePoint_t queueTime = GpAudioDriver_SDL2::GetCurrentTime() + m_latency;
|
GpAudioDriver_SDL2_TimePoint_t queueTime = GpAudioDriver_SDL2::GetCurrentTime() + m_latency;
|
||||||
if (queueTime > m_timestamp)
|
if (queueTime > m_timestamp)
|
||||||
@@ -262,50 +316,37 @@ void GpAudioChannel_SDL2::PostBuffer(const void *buffer, size_t bufferSize)
|
|||||||
|
|
||||||
m_leadingSilence = leadingSilence;
|
m_leadingSilence = leadingSilence;
|
||||||
|
|
||||||
while (bufferSize > 0)
|
m_pendingBuffers[m_nextPendingBufferInsertionPos++] = static_cast<GpAudioBuffer_SDL2*>(buffer);
|
||||||
{
|
m_numQueuedBuffers++;
|
||||||
GpAudioChannelBufferChain_SDL2 *newBuffer = GpAudioChannelBufferChain_SDL2::Alloc();
|
|
||||||
if (newBuffer == nullptr)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (m_lastPendingBuffer == nullptr)
|
m_nextPendingBufferInsertionPos = m_nextPendingBufferInsertionPos % kMaxBuffers;
|
||||||
m_firstPendingBuffer = newBuffer;
|
|
||||||
else
|
|
||||||
m_lastPendingBuffer->m_next = newBuffer;
|
|
||||||
m_lastPendingBuffer = newBuffer;
|
|
||||||
|
|
||||||
size_t bufferable = newBuffer->kMaxCapacity;
|
|
||||||
if (bufferSize < bufferable)
|
|
||||||
bufferable = bufferSize;
|
|
||||||
|
|
||||||
memcpy(newBuffer->m_data, buffer, bufferable);
|
|
||||||
|
|
||||||
buffer = static_cast<const uint8_t*>(buffer) + bufferable;
|
|
||||||
bufferSize -= bufferable;
|
|
||||||
m_lastPendingBuffer->m_used = bufferable;
|
|
||||||
m_lastPendingBuffer->m_hasTrigger = (bufferSize == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_mutex->Unlock();
|
m_mutex->Unlock();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpAudioChannel_SDL2::Stop()
|
void GpAudioChannel_SDL2::Stop()
|
||||||
{
|
{
|
||||||
m_mutex->Lock();
|
m_mutex->Lock();
|
||||||
|
|
||||||
GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer;
|
m_leadingSilence = 0;
|
||||||
m_firstPendingBuffer = nullptr;
|
|
||||||
m_lastPendingBuffer = nullptr;
|
|
||||||
|
|
||||||
while (buffer)
|
size_t numBuffersToDischarge = m_numQueuedBuffers;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numBuffersToDischarge; i++)
|
||||||
{
|
{
|
||||||
if (buffer->m_hasTrigger && m_callbacks)
|
GpAudioBuffer_SDL2 *buffer = m_pendingBuffers[m_nextPendingBufferConsumePos];
|
||||||
|
|
||||||
|
m_nextPendingBufferConsumePos = (m_nextPendingBufferConsumePos + 1) % kMaxBuffers;
|
||||||
|
m_numQueuedBuffers--;
|
||||||
|
|
||||||
|
m_firstBufferSamplesConsumed = 0;
|
||||||
|
|
||||||
|
if (m_callbacks)
|
||||||
m_callbacks->NotifyBufferFinished();
|
m_callbacks->NotifyBufferFinished();
|
||||||
|
|
||||||
GpAudioChannelBufferChain_SDL2 *nextBuffer = buffer->m_next;
|
|
||||||
buffer->Release();
|
buffer->Release();
|
||||||
|
|
||||||
buffer = nextBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mutex->Unlock();
|
m_mutex->Unlock();
|
||||||
@@ -359,21 +400,27 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (m_firstPendingBuffer != nullptr)
|
while (m_numQueuedBuffers > 0)
|
||||||
{
|
{
|
||||||
GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer;
|
GpAudioBuffer_SDL2 *buffer = m_pendingBuffers[m_nextPendingBufferConsumePos];
|
||||||
const size_t available = (buffer->m_used - buffer->m_consumed);
|
const void *bufferData = buffer->GetData();
|
||||||
|
const size_t bufferSize = buffer->GetSize();
|
||||||
|
|
||||||
|
assert(m_firstBufferSamplesConsumed < bufferSize);
|
||||||
|
|
||||||
|
const size_t available = (bufferSize - m_firstBufferSamplesConsumed);
|
||||||
if (available <= sz)
|
if (available <= sz)
|
||||||
{
|
{
|
||||||
memcpy(output, buffer->m_data + buffer->m_consumed, available);
|
memcpy(output, static_cast<const uint8_t*>(bufferData) + m_firstBufferSamplesConsumed, available);
|
||||||
sz -= available;
|
sz -= available;
|
||||||
output += available;
|
output += available;
|
||||||
|
|
||||||
m_firstPendingBuffer = buffer->m_next;
|
m_nextPendingBufferConsumePos = (m_nextPendingBufferConsumePos + 1) % kMaxBuffers;
|
||||||
if (m_firstPendingBuffer == nullptr)
|
m_numQueuedBuffers--;
|
||||||
m_lastPendingBuffer = nullptr;
|
|
||||||
|
|
||||||
if (buffer->m_hasTrigger && m_callbacks)
|
m_firstBufferSamplesConsumed = 0;
|
||||||
|
|
||||||
|
if (m_callbacks)
|
||||||
m_callbacks->NotifyBufferFinished();
|
m_callbacks->NotifyBufferFinished();
|
||||||
|
|
||||||
buffer->Release();
|
buffer->Release();
|
||||||
@@ -383,9 +430,9 @@ void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz, GpAudioDriver_SDL2
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(output, buffer->m_data + buffer->m_consumed, sz);
|
memcpy(output, static_cast<const uint8_t*>(bufferData) + m_firstBufferSamplesConsumed, sz);
|
||||||
buffer->m_consumed += sz;
|
m_firstBufferSamplesConsumed += sz;
|
||||||
buffer += sz;
|
output += sz;
|
||||||
sz = 0;
|
sz = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -446,6 +493,11 @@ GpAudioDriver_SDL2::~GpAudioDriver_SDL2()
|
|||||||
m_mutex->Destroy();
|
m_mutex->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IGpAudioBuffer *GpAudioDriver_SDL2::CreateBuffer(const void *data, size_t size)
|
||||||
|
{
|
||||||
|
return GpAudioBuffer_SDL2::Create(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
IGpAudioChannel *GpAudioDriver_SDL2::CreateChannel()
|
IGpAudioChannel *GpAudioDriver_SDL2::CreateChannel()
|
||||||
{
|
{
|
||||||
GpAudioChannel_SDL2 *newChannel = GpAudioChannel_SDL2::Alloc(this, m_latency, m_bufferTime, m_bufferSamples, m_sampleRate);
|
GpAudioChannel_SDL2 *newChannel = GpAudioChannel_SDL2::Alloc(this, m_latency, m_bufferTime, m_bufferSamples, m_sampleRate);
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "Environ.h"
|
#include "Environ.h"
|
||||||
#include "Externs.h"
|
#include "Externs.h"
|
||||||
#include "SoundSync.h"
|
#include "SoundSync.h"
|
||||||
|
#include "IGpAudioBuffer.h"
|
||||||
#include "IGpMutex.h"
|
#include "IGpMutex.h"
|
||||||
#include "IGpSystemServices.h"
|
#include "IGpSystemServices.h"
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
@@ -29,11 +30,11 @@ PLError_t DumpMusicSounds (void);
|
|||||||
PLError_t OpenMusicChannel (void);
|
PLError_t OpenMusicChannel (void);
|
||||||
PLError_t CloseMusicChannel (void);
|
PLError_t CloseMusicChannel (void);
|
||||||
|
|
||||||
THandle<void> ParseAndConvertSound(const THandle<void> &handle);
|
IGpAudioBuffer *ParseAndConvertSound(const THandle<void> &handle);
|
||||||
|
|
||||||
|
|
||||||
PortabilityLayer::AudioChannel *musicChannel;
|
PortabilityLayer::AudioChannel *musicChannel;
|
||||||
Ptr theMusicData[kMaxMusic];
|
IGpAudioBuffer *theMusicData[kMaxMusic];
|
||||||
short musicScore[kLastMusicPiece];
|
short musicScore[kLastMusicPiece];
|
||||||
short gameScore[kLastGamePiece];
|
short gameScore[kLastGamePiece];
|
||||||
Boolean isMusicOn, isPlayMusicIdle, isPlayMusicGame;
|
Boolean isMusicOn, isPlayMusicIdle, isPlayMusicGame;
|
||||||
@@ -208,22 +209,23 @@ PLError_t LoadMusicSounds (void)
|
|||||||
theErr = PLErrors::kNone;
|
theErr = PLErrors::kNone;
|
||||||
|
|
||||||
for (i = 0; i < kMaxMusic; i++)
|
for (i = 0; i < kMaxMusic; i++)
|
||||||
theMusicData[i] = nil;
|
{
|
||||||
|
assert(theMusicData[i] == nil);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < kMaxMusic; i++)
|
for (i = 0; i < kMaxMusic; i++)
|
||||||
{
|
{
|
||||||
theSound = ParseAndConvertSound(PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('snd ', i + kBaseBufferMusicID));
|
theSound = PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('snd ', i + kBaseBufferMusicID);
|
||||||
if (theSound == nil)
|
if (theSound == nil)
|
||||||
return PLErrors::kOutOfMemory;
|
return PLErrors::kOutOfMemory;
|
||||||
|
|
||||||
soundDataSize = GetHandleSize(theSound);
|
IGpAudioBuffer *buffer = ParseAndConvertSound(theSound);
|
||||||
|
theSound.Dispose();
|
||||||
|
|
||||||
theMusicData[i] = PortabilityLayer::MemoryManager::GetInstance()->Alloc(soundDataSize);
|
if (buffer == nil)
|
||||||
if (theMusicData[i] == nil)
|
|
||||||
return PLErrors::kOutOfMemory;
|
return PLErrors::kOutOfMemory;
|
||||||
|
|
||||||
memcpy(theMusicData[i], static_cast<Byte*>(*theSound), soundDataSize);
|
theMusicData[i] = buffer;
|
||||||
theSound.Dispose();
|
|
||||||
}
|
}
|
||||||
return (theErr);
|
return (theErr);
|
||||||
}
|
}
|
||||||
@@ -240,7 +242,7 @@ PLError_t DumpMusicSounds (void)
|
|||||||
for (i = 0; i < kMaxMusic; i++)
|
for (i = 0; i < kMaxMusic; i++)
|
||||||
{
|
{
|
||||||
if (theMusicData[i] != nil)
|
if (theMusicData[i] != nil)
|
||||||
PortabilityLayer::MemoryManager::GetInstance()->Release(theMusicData[i]);
|
theMusicData[i]->Release();
|
||||||
theMusicData[i] = nil;
|
theMusicData[i] = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
#include "PLSound.h"
|
#include "PLSound.h"
|
||||||
#include "DialogManager.h"
|
#include "DialogManager.h"
|
||||||
#include "Externs.h"
|
#include "Externs.h"
|
||||||
|
#include "IGpAudioBuffer.h"
|
||||||
|
#include "IGpAudioDriver.h"
|
||||||
#include "IGpLogDriver.h"
|
#include "IGpLogDriver.h"
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
@@ -31,10 +33,10 @@ PLError_t LoadBufferSounds (void);
|
|||||||
void DumpBufferSounds (void);
|
void DumpBufferSounds (void);
|
||||||
PLError_t OpenSoundChannels (void);
|
PLError_t OpenSoundChannels (void);
|
||||||
void CloseSoundChannels (void);
|
void CloseSoundChannels (void);
|
||||||
THandle<void> ParseAndConvertSound(const THandle<void> &handle);
|
IGpAudioBuffer *ParseAndConvertSound(const THandle<void> &handle);
|
||||||
|
|
||||||
PortabilityLayer::AudioChannel *channel0, *channel1, *channel2;
|
PortabilityLayer::AudioChannel *channel0, *channel1, *channel2;
|
||||||
Ptr theSoundData[kMaxSounds];
|
IGpAudioBuffer *theSoundData[kMaxSounds];
|
||||||
short numSoundsLoaded;
|
short numSoundsLoaded;
|
||||||
Boolean soundLoaded[kMaxSounds], dontLoadSounds;
|
Boolean soundLoaded[kMaxSounds], dontLoadSounds;
|
||||||
Boolean channelOpen, isSoundOn, failedSound;
|
Boolean channelOpen, isSoundOn, failedSound;
|
||||||
@@ -192,24 +194,20 @@ PLError_t LoadTriggerSound (short soundID)
|
|||||||
|
|
||||||
theErr = PLErrors::kNone;
|
theErr = PLErrors::kNone;
|
||||||
|
|
||||||
theSound = ParseAndConvertSound(LoadHouseResource('snd ', soundID));
|
theSound = LoadHouseResource('snd ', soundID);
|
||||||
if (theSound == nil)
|
if (theSound == nil)
|
||||||
{
|
theErr = PLErrors::kResourceError;
|
||||||
theErr = PLErrors::kFileNotFound;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
soundDataSize = GetHandleSize(theSound);
|
IGpAudioBuffer *buffer = ParseAndConvertSound(theSound);
|
||||||
theSoundData[kMaxSounds - 1] = PortabilityLayer::MemoryManager::GetInstance()->Alloc(soundDataSize);
|
|
||||||
if (theSoundData[kMaxSounds - 1] == nil)
|
|
||||||
{
|
|
||||||
theSound.Dispose();
|
theSound.Dispose();
|
||||||
theErr = PLErrors::kOutOfMemory;
|
|
||||||
}
|
if (buffer == nil)
|
||||||
|
theErr = PLErrors::kResourceError;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(theSoundData[kMaxSounds - 1], (Byte*)(*theSound), soundDataSize);
|
assert(theSoundData[kMaxSounds - 1] == nil);
|
||||||
theSound.Dispose();
|
theSoundData[kMaxSounds - 1] = buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +220,7 @@ PLError_t LoadTriggerSound (short soundID)
|
|||||||
void DumpTriggerSound (void)
|
void DumpTriggerSound (void)
|
||||||
{
|
{
|
||||||
if (theSoundData[kMaxSounds - 1] != nil)
|
if (theSoundData[kMaxSounds - 1] != nil)
|
||||||
PortabilityLayer::MemoryManager::GetInstance()->Release(theSoundData[kMaxSounds - 1]);
|
theSoundData[kMaxSounds - 1]->Release();
|
||||||
theSoundData[kMaxSounds - 1] = nil;
|
theSoundData[kMaxSounds - 1] = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,21 +237,21 @@ PLError_t LoadBufferSounds (void)
|
|||||||
|
|
||||||
for (i = 0; i < kMaxSounds - 1; i++)
|
for (i = 0; i < kMaxSounds - 1; i++)
|
||||||
{
|
{
|
||||||
theSound = ParseAndConvertSound(PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('snd ', i + kBaseBufferSoundID));
|
theSound = PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('snd ', i + kBaseBufferSoundID);
|
||||||
if (theSound == nil)
|
if (theSound == nil)
|
||||||
return (PLErrors::kOutOfMemory);
|
return (PLErrors::kResourceError);
|
||||||
|
|
||||||
soundDataSize = GetHandleSize(theSound);
|
IGpAudioBuffer *buffer = ParseAndConvertSound(theSound);
|
||||||
|
|
||||||
theSoundData[i] = PortabilityLayer::MemoryManager::GetInstance()->Alloc(soundDataSize);
|
|
||||||
if (theSoundData[i] == nil)
|
|
||||||
return (PLErrors::kOutOfMemory);
|
|
||||||
|
|
||||||
memcpy(theSoundData[i], *theSound, soundDataSize);
|
|
||||||
theSound.Dispose();
|
theSound.Dispose();
|
||||||
|
|
||||||
|
if (!buffer)
|
||||||
|
return PLErrors::kResourceError;
|
||||||
|
|
||||||
|
assert(theSoundData[i] == nil);
|
||||||
|
theSoundData[i] = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
theSoundData[kMaxSounds - 1] = nil;
|
assert(theSoundData[kMaxSounds - 1] == nil);
|
||||||
|
|
||||||
return (theErr);
|
return (theErr);
|
||||||
}
|
}
|
||||||
@@ -267,7 +265,7 @@ void DumpBufferSounds (void)
|
|||||||
for (i = 0; i < kMaxSounds; i++)
|
for (i = 0; i < kMaxSounds; i++)
|
||||||
{
|
{
|
||||||
if (theSoundData[i] != nil)
|
if (theSoundData[i] != nil)
|
||||||
PortabilityLayer::MemoryManager::GetInstance()->Release(theSoundData[i]);
|
theSoundData[i]->Release();
|
||||||
theSoundData[i] = nil;
|
theSoundData[i] = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -406,23 +404,23 @@ void TellHerNoSounds (void)
|
|||||||
|
|
||||||
//-------------------------------------------------------------- ParseAndConvertSound
|
//-------------------------------------------------------------- ParseAndConvertSound
|
||||||
|
|
||||||
THandle<void> ParseAndConvertSoundChecked(const THandle<void> &handle)
|
IGpAudioBuffer *ParseAndConvertSoundChecked(const THandle<void> &handle)
|
||||||
{
|
{
|
||||||
const uint8_t *dataStart = static_cast<const uint8_t*>(*handle);
|
const uint8_t *dataStart = static_cast<const uint8_t*>(*handle);
|
||||||
const size_t size = handle.MMBlock()->m_size;
|
const size_t size = handle.MMBlock()->m_size;
|
||||||
|
|
||||||
if (size < sizeof(PortabilityLayer::RIFFTag))
|
if (size < sizeof(PortabilityLayer::RIFFTag))
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
PortabilityLayer::RIFFTag mainRiffTag;
|
PortabilityLayer::RIFFTag mainRiffTag;
|
||||||
memcpy(&mainRiffTag, dataStart, sizeof(PortabilityLayer::RIFFTag));
|
memcpy(&mainRiffTag, dataStart, sizeof(PortabilityLayer::RIFFTag));
|
||||||
|
|
||||||
if (mainRiffTag.m_tag != PortabilityLayer::WaveConstants::kRiffChunkID)
|
if (mainRiffTag.m_tag != PortabilityLayer::WaveConstants::kRiffChunkID)
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
const uint32_t riffSize = mainRiffTag.m_chunkSize;
|
const uint32_t riffSize = mainRiffTag.m_chunkSize;
|
||||||
if (riffSize < 4 || riffSize - 4 > size - sizeof(PortabilityLayer::RIFFTag))
|
if (riffSize < 4 || riffSize - 4 > size - sizeof(PortabilityLayer::RIFFTag))
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
const uint8_t *riffStart = dataStart + sizeof(PortabilityLayer::RIFFTag);
|
const uint8_t *riffStart = dataStart + sizeof(PortabilityLayer::RIFFTag);
|
||||||
const uint8_t *riffEnd = riffStart + riffSize;
|
const uint8_t *riffEnd = riffStart + riffSize;
|
||||||
@@ -434,7 +432,7 @@ THandle<void> ParseAndConvertSoundChecked(const THandle<void> &handle)
|
|||||||
memcpy(&waveMarker, riffStart, 4);
|
memcpy(&waveMarker, riffStart, 4);
|
||||||
|
|
||||||
if (waveMarker != PortabilityLayer::WaveConstants::kWaveChunkID)
|
if (waveMarker != PortabilityLayer::WaveConstants::kWaveChunkID)
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
const uint8_t *tagSearchLoc = riffStart + 4;
|
const uint8_t *tagSearchLoc = riffStart + 4;
|
||||||
|
|
||||||
@@ -442,7 +440,7 @@ THandle<void> ParseAndConvertSoundChecked(const THandle<void> &handle)
|
|||||||
while (tagSearchLoc != riffEnd)
|
while (tagSearchLoc != riffEnd)
|
||||||
{
|
{
|
||||||
if (riffEnd - tagSearchLoc < sizeof(PortabilityLayer::RIFFTag))
|
if (riffEnd - tagSearchLoc < sizeof(PortabilityLayer::RIFFTag))
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
PortabilityLayer::RIFFTag riffTag;
|
PortabilityLayer::RIFFTag riffTag;
|
||||||
memcpy(&riffTag, tagSearchLoc, sizeof(PortabilityLayer::RIFFTag));
|
memcpy(&riffTag, tagSearchLoc, sizeof(PortabilityLayer::RIFFTag));
|
||||||
@@ -455,20 +453,20 @@ THandle<void> ParseAndConvertSoundChecked(const THandle<void> &handle)
|
|||||||
const uint32_t riffTagSizeUnpadded = riffTag.m_chunkSize;
|
const uint32_t riffTagSizeUnpadded = riffTag.m_chunkSize;
|
||||||
|
|
||||||
if (riffTagSizeUnpadded == 0xffffffffU)
|
if (riffTagSizeUnpadded == 0xffffffffU)
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
const uint32_t riffTagSizePadded = riffTagSizeUnpadded + (riffTagSizeUnpadded & 1);
|
const uint32_t riffTagSizePadded = riffTagSizeUnpadded + (riffTagSizeUnpadded & 1);
|
||||||
|
|
||||||
tagSearchLoc += sizeof(PortabilityLayer::RIFFTag);
|
tagSearchLoc += sizeof(PortabilityLayer::RIFFTag);
|
||||||
|
|
||||||
if (riffEnd - tagSearchLoc < riffTagSizePadded)
|
if (riffEnd - tagSearchLoc < riffTagSizePadded)
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
tagSearchLoc += riffTagSizePadded;
|
tagSearchLoc += riffTagSizePadded;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formatTagLoc == nullptr || dataTagLoc == nullptr)
|
if (formatTagLoc == nullptr || dataTagLoc == nullptr)
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
PortabilityLayer::RIFFTag fmtTag;
|
PortabilityLayer::RIFFTag fmtTag;
|
||||||
memcpy(&fmtTag, formatTagLoc, sizeof(PortabilityLayer::RIFFTag));
|
memcpy(&fmtTag, formatTagLoc, sizeof(PortabilityLayer::RIFFTag));
|
||||||
@@ -502,7 +500,7 @@ THandle<void> ParseAndConvertSoundChecked(const THandle<void> &handle)
|
|||||||
copyableSize = sizeof(PortabilityLayer::WaveFormatChunkV1);
|
copyableSize = sizeof(PortabilityLayer::WaveFormatChunkV1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
memcpy(&formatChunkV3, formatContents, copyableSize);
|
memcpy(&formatChunkV3, formatContents, copyableSize);
|
||||||
|
|
||||||
@@ -510,35 +508,30 @@ THandle<void> ParseAndConvertSoundChecked(const THandle<void> &handle)
|
|||||||
const PortabilityLayer::WaveFormatChunkV1 formatChunkV1 = formatChunkV2.m_v1;
|
const PortabilityLayer::WaveFormatChunkV1 formatChunkV1 = formatChunkV2.m_v1;
|
||||||
|
|
||||||
if (formatChunkV1.m_bitsPerSample != 8)
|
if (formatChunkV1.m_bitsPerSample != 8)
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
if (formatChunkV1.m_formatCode != PortabilityLayer::WaveConstants::kFormatPCM ||
|
if (formatChunkV1.m_formatCode != PortabilityLayer::WaveConstants::kFormatPCM ||
|
||||||
formatChunkV1.m_numChannels != 1 ||
|
formatChunkV1.m_numChannels != 1 ||
|
||||||
formatChunkV1.m_blockAlignmentBytes != 1 ||
|
formatChunkV1.m_blockAlignmentBytes != 1 ||
|
||||||
formatChunkV1.m_bitsPerSample != 8)
|
formatChunkV1.m_bitsPerSample != 8)
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
THandle<void> convertedHandle = THandle<void>(PortabilityLayer::MemoryManager::GetInstance()->AllocHandle(4 + dataTag.m_chunkSize));
|
|
||||||
if (!convertedHandle)
|
|
||||||
return THandle<void>();
|
|
||||||
|
|
||||||
uint8_t *handleData = static_cast<uint8_t*>(*convertedHandle);
|
|
||||||
|
|
||||||
uint32_t dataSize = dataTag.m_chunkSize;
|
uint32_t dataSize = dataTag.m_chunkSize;
|
||||||
memcpy(handleData, &dataSize, 4);
|
if (dataSize > 0x1000000)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
memcpy(handleData + 4, dataContents, dataSize);
|
IGpAudioDriver *audioDriver = PLDrivers::GetAudioDriver();
|
||||||
|
if (!audioDriver)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
return convertedHandle;
|
return audioDriver->CreateBuffer(dataContents, dataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
THandle<void> ParseAndConvertSound(const THandle<void> &handle)
|
IGpAudioBuffer *ParseAndConvertSound(const THandle<void> &handle)
|
||||||
{
|
{
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return THandle<void>();
|
return nullptr;
|
||||||
|
|
||||||
THandle<void> converted = ParseAndConvertSoundChecked(handle);
|
IGpAudioBuffer *buffer = ParseAndConvertSoundChecked(handle);
|
||||||
handle.Dispose();
|
return buffer;
|
||||||
|
|
||||||
return converted;
|
|
||||||
}
|
}
|
||||||
|
67
GpAudioDriver_XAudio2/GpAudioBufferXAudio2.cpp
Normal file
67
GpAudioDriver_XAudio2/GpAudioBufferXAudio2.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include "GpAudioBufferXAudio2.h"
|
||||||
|
#include "CoreDefs.h"
|
||||||
|
#include "GpWindows.h"
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
GpAudioBufferXAudio2 *GpAudioBufferXAudio2::Create(const void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
size_t baseSize = sizeof(GpAudioBufferXAudio2);
|
||||||
|
baseSize = baseSize + GP_SYSTEM_MEMORY_ALIGNMENT - 1;
|
||||||
|
baseSize -= baseSize % GP_SYSTEM_MEMORY_ALIGNMENT;
|
||||||
|
|
||||||
|
size_t totalSize = baseSize + size;
|
||||||
|
|
||||||
|
void *storage = _aligned_malloc(totalSize, GP_SYSTEM_MEMORY_ALIGNMENT);
|
||||||
|
if (!storage)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
void *dataPos = static_cast<uint8_t*>(storage) + baseSize;
|
||||||
|
|
||||||
|
memcpy(dataPos, buffer, size);
|
||||||
|
return new (storage) GpAudioBufferXAudio2(dataPos, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpAudioBufferXAudio2::AddRef()
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&m_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpAudioBufferXAudio2::Release()
|
||||||
|
{
|
||||||
|
if (InterlockedDecrement(&m_count) == 0)
|
||||||
|
this->Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const XAUDIO2_BUFFER *GpAudioBufferXAudio2::GetXA2Buffer() const
|
||||||
|
{
|
||||||
|
return &m_xa2Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpAudioBufferXAudio2::GpAudioBufferXAudio2(const void *data, size_t size)
|
||||||
|
: m_data(data)
|
||||||
|
, m_size(size)
|
||||||
|
, m_count(1)
|
||||||
|
{
|
||||||
|
m_xa2Buffer.Flags = 0;
|
||||||
|
m_xa2Buffer.AudioBytes = static_cast<UINT32>(size);
|
||||||
|
m_xa2Buffer.pAudioData = static_cast<const BYTE*>(data);
|
||||||
|
m_xa2Buffer.PlayBegin = 0;
|
||||||
|
m_xa2Buffer.PlayLength = 0;
|
||||||
|
m_xa2Buffer.LoopBegin = 0;
|
||||||
|
m_xa2Buffer.LoopLength = 0;
|
||||||
|
m_xa2Buffer.LoopCount = 0;
|
||||||
|
m_xa2Buffer.pContext = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
GpAudioBufferXAudio2::~GpAudioBufferXAudio2()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpAudioBufferXAudio2::Destroy()
|
||||||
|
{
|
||||||
|
this->~GpAudioBufferXAudio2();
|
||||||
|
_aligned_free(this);
|
||||||
|
}
|
29
GpAudioDriver_XAudio2/GpAudioBufferXAudio2.h
Normal file
29
GpAudioDriver_XAudio2/GpAudioBufferXAudio2.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IGpAudioBuffer.h"
|
||||||
|
|
||||||
|
#include <xaudio2.h>
|
||||||
|
|
||||||
|
class GpAudioBufferXAudio2 final : public IGpAudioBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static GpAudioBufferXAudio2 *Create(const void *buffer, size_t size);
|
||||||
|
|
||||||
|
void AddRef() override;
|
||||||
|
void Release() override;
|
||||||
|
|
||||||
|
const XAUDIO2_BUFFER *GetXA2Buffer() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GpAudioBufferXAudio2(const void *data, size_t size);
|
||||||
|
~GpAudioBufferXAudio2();
|
||||||
|
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
const void *m_data;
|
||||||
|
size_t m_size;
|
||||||
|
|
||||||
|
XAUDIO2_BUFFER m_xa2Buffer;
|
||||||
|
|
||||||
|
volatile unsigned int m_count;
|
||||||
|
};
|
@@ -1,3 +1,4 @@
|
|||||||
|
#include "GpAudioBufferXAudio2.h"
|
||||||
#include "GpAudioChannelXAudio2.h"
|
#include "GpAudioChannelXAudio2.h"
|
||||||
#include "GpAudioDriverXAudio2.h"
|
#include "GpAudioDriverXAudio2.h"
|
||||||
#include "IGpAudioChannelCallbacks.h"
|
#include "IGpAudioChannelCallbacks.h"
|
||||||
@@ -77,25 +78,25 @@ void GpAudioChannelXAudio2::SetAudioChannelContext(IGpAudioChannelCallbacks *cal
|
|||||||
m_contextCallbacks = callbacks;
|
m_contextCallbacks = callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpAudioChannelXAudio2::PostBuffer(const void *buffer, size_t bufferSize)
|
bool GpAudioChannelXAudio2::PostBuffer(IGpAudioBuffer *buffer)
|
||||||
{
|
{
|
||||||
XAUDIO2_BUFFER xa2Buffer;
|
GpAudioBufferXAudio2 *xa2Buffer = static_cast<GpAudioBufferXAudio2*>(buffer);
|
||||||
xa2Buffer.Flags = 0;
|
xa2Buffer->AddRef();
|
||||||
xa2Buffer.AudioBytes = static_cast<UINT32>(bufferSize);
|
|
||||||
xa2Buffer.pAudioData = static_cast<const BYTE*>(buffer);
|
HRESULT result = m_sourceVoice->SubmitSourceBuffer(xa2Buffer->GetXA2Buffer(), nullptr);
|
||||||
xa2Buffer.PlayBegin = 0;
|
if (result != S_OK)
|
||||||
xa2Buffer.PlayLength = 0;
|
{
|
||||||
xa2Buffer.LoopBegin = 0;
|
xa2Buffer->Release();
|
||||||
xa2Buffer.LoopLength = 0;
|
return false;
|
||||||
xa2Buffer.LoopCount = 0;
|
}
|
||||||
xa2Buffer.pContext = nullptr;
|
|
||||||
|
|
||||||
m_sourceVoice->SubmitSourceBuffer(&xa2Buffer, nullptr);
|
|
||||||
if (m_voiceState == VoiceState_Idle)
|
if (m_voiceState == VoiceState_Idle)
|
||||||
{
|
{
|
||||||
m_voiceState = VoiceState_Active;
|
m_voiceState = VoiceState_Active;
|
||||||
m_sourceVoice->Start(0, 0);
|
m_sourceVoice->Start(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpAudioChannelXAudio2::Stop()
|
void GpAudioChannelXAudio2::Stop()
|
||||||
|
@@ -16,7 +16,7 @@ public:
|
|||||||
static GpAudioChannelXAudio2 *Create(GpAudioDriverXAudio2 *driver);
|
static GpAudioChannelXAudio2 *Create(GpAudioDriverXAudio2 *driver);
|
||||||
|
|
||||||
void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) override;
|
void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) override;
|
||||||
void PostBuffer(const void *buffer, size_t bufferSize) override;
|
bool PostBuffer(IGpAudioBuffer *buffer) override;
|
||||||
void Stop() override;
|
void Stop() override;
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
#include "GpAudioBufferXAudio2.h"
|
||||||
#include "GpAudioChannelXAudio2Callbacks.h"
|
#include "GpAudioChannelXAudio2Callbacks.h"
|
||||||
#include "GpAudioChannelXAudio2.h"
|
#include "GpAudioChannelXAudio2.h"
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ void GpAudioChannelXAudio2Callbacks::OnBufferStart(void* pBufferContext)
|
|||||||
|
|
||||||
void GpAudioChannelXAudio2Callbacks::OnBufferEnd(void* pBufferContext)
|
void GpAudioChannelXAudio2Callbacks::OnBufferEnd(void* pBufferContext)
|
||||||
{
|
{
|
||||||
|
static_cast<GpAudioBufferXAudio2*>(pBufferContext)->Release();
|
||||||
m_owner->OnBufferEnd();
|
m_owner->OnBufferEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
#include "GpAudioDriverXAudio2.h"
|
#include "GpAudioDriverXAudio2.h"
|
||||||
|
|
||||||
#include "IGpLogDriver.h"
|
#include "IGpLogDriver.h"
|
||||||
|
#include "GpAudioBufferXAudio2.h"
|
||||||
#include "GpAudioChannelXAudio2.h"
|
#include "GpAudioChannelXAudio2.h"
|
||||||
|
#include "CoreDefs.h"
|
||||||
|
|
||||||
#include <xaudio2.h>
|
#include <xaudio2.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
void GpAudioDriverXAudio2::Shutdown()
|
void GpAudioDriverXAudio2::Shutdown()
|
||||||
{
|
{
|
||||||
@@ -96,6 +99,11 @@ GpAudioDriverXAudio2 *GpAudioDriverXAudio2::Create(const GpAudioDriverProperties
|
|||||||
return new GpAudioDriverXAudio2(properties, realSampleRate, xa, mv);
|
return new GpAudioDriverXAudio2(properties, realSampleRate, xa, mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IGpAudioBuffer *GpAudioDriverXAudio2::CreateBuffer(const void *buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
return GpAudioBufferXAudio2::Create(buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
IGpAudioChannel *GpAudioDriverXAudio2::CreateChannel()
|
IGpAudioChannel *GpAudioDriverXAudio2::CreateChannel()
|
||||||
{
|
{
|
||||||
return GpAudioChannelXAudio2::Create(this);
|
return GpAudioChannelXAudio2::Create(this);
|
||||||
|
@@ -10,6 +10,7 @@ struct IXAudio2MasteringVoice;
|
|||||||
class GpAudioDriverXAudio2 : public IGpAudioDriver
|
class GpAudioDriverXAudio2 : public IGpAudioDriver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
IGpAudioBuffer *CreateBuffer(const void *buffer, size_t bufferSize) override;
|
||||||
IGpAudioChannel *CreateChannel() override;
|
IGpAudioChannel *CreateChannel() override;
|
||||||
void SetMasterVolume(uint32_t vol, uint32_t maxVolume) override;
|
void SetMasterVolume(uint32_t vol, uint32_t maxVolume) override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
@@ -38,11 +38,14 @@
|
|||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
<Import Project="..\GpCommon.props" />
|
<Import Project="..\GpCommon.props" />
|
||||||
|
<Import Project="..\Common.props" />
|
||||||
|
<Import Project="..\Debug.props" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
<Import Project="..\GpCommon.props" />
|
<Import Project="..\GpCommon.props" />
|
||||||
<Import Project="..\Release.props" />
|
<Import Project="..\Release.props" />
|
||||||
|
<Import Project="..\Common.props" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup />
|
<PropertyGroup />
|
||||||
@@ -69,12 +72,14 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="GpAudioBufferXAudio2.h" />
|
||||||
<ClInclude Include="GpAudioChannelXAudio2.h" />
|
<ClInclude Include="GpAudioChannelXAudio2.h" />
|
||||||
<ClInclude Include="GpAudioChannelXAudio2Callbacks.h" />
|
<ClInclude Include="GpAudioChannelXAudio2Callbacks.h" />
|
||||||
<ClInclude Include="GpAudioDriverFactoryXAudio2.h" />
|
<ClInclude Include="GpAudioDriverFactoryXAudio2.h" />
|
||||||
<ClInclude Include="GpAudioDriverXAudio2.h" />
|
<ClInclude Include="GpAudioDriverXAudio2.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="GpAudioBufferXAudio2.cpp" />
|
||||||
<ClCompile Include="GpAudioChannelXAudio2.cpp" />
|
<ClCompile Include="GpAudioChannelXAudio2.cpp" />
|
||||||
<ClCompile Include="GpAudioChannelXAudio2Callbacks.cpp" />
|
<ClCompile Include="GpAudioChannelXAudio2Callbacks.cpp" />
|
||||||
<ClCompile Include="GpAudioDriverFactoryXAudio2.cpp" />
|
<ClCompile Include="GpAudioDriverFactoryXAudio2.cpp" />
|
||||||
|
@@ -27,6 +27,9 @@
|
|||||||
<ClInclude Include="GpAudioChannelXAudio2Callbacks.h">
|
<ClInclude Include="GpAudioChannelXAudio2Callbacks.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="GpAudioBufferXAudio2.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="GpAudioDriverFactoryXAudio2.cpp">
|
<ClCompile Include="GpAudioDriverFactoryXAudio2.cpp">
|
||||||
@@ -41,6 +44,9 @@
|
|||||||
<ClCompile Include="GpAudioChannelXAudio2Callbacks.cpp">
|
<ClCompile Include="GpAudioChannelXAudio2Callbacks.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="GpAudioBufferXAudio2.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
8
GpCommon/IGpAudioBuffer.h
Normal file
8
GpCommon/IGpAudioBuffer.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct IGpAudioBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void AddRef() = 0;
|
||||||
|
virtual void Release() = 0;
|
||||||
|
};
|
@@ -3,11 +3,12 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct IGpAudioChannelCallbacks;
|
struct IGpAudioChannelCallbacks;
|
||||||
|
struct IGpAudioBuffer;
|
||||||
|
|
||||||
struct IGpAudioChannel
|
struct IGpAudioChannel
|
||||||
{
|
{
|
||||||
virtual void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) = 0;
|
virtual void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) = 0;
|
||||||
virtual void PostBuffer(const void *buffer, size_t bufferSize) = 0;
|
virtual bool PostBuffer(IGpAudioBuffer *buffer) = 0;
|
||||||
virtual void Stop() = 0;
|
virtual void Stop() = 0;
|
||||||
virtual void Destroy() = 0;
|
virtual void Destroy() = 0;
|
||||||
};
|
};
|
||||||
|
@@ -4,10 +4,12 @@
|
|||||||
|
|
||||||
struct IGpAudioChannel;
|
struct IGpAudioChannel;
|
||||||
struct IGpPrefsHandler;
|
struct IGpPrefsHandler;
|
||||||
|
struct IGpAudioBuffer;
|
||||||
|
|
||||||
struct IGpAudioDriver
|
struct IGpAudioDriver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual IGpAudioBuffer *CreateBuffer(const void *buffer, size_t bufferSize) = 0;
|
||||||
virtual IGpAudioChannel *CreateChannel() = 0;
|
virtual IGpAudioChannel *CreateChannel() = 0;
|
||||||
|
|
||||||
virtual void SetMasterVolume(uint32_t vol, uint32_t maxVolume) = 0;
|
virtual void SetMasterVolume(uint32_t vol, uint32_t maxVolume) = 0;
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
#include "PLSound.h"
|
#include "PLSound.h"
|
||||||
|
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
|
#include "IGpAudioBuffer.h"
|
||||||
#include "IGpMutex.h"
|
#include "IGpMutex.h"
|
||||||
#include "IGpThreadEvent.h"
|
#include "IGpThreadEvent.h"
|
||||||
#include "IGpAudioChannel.h"
|
#include "IGpAudioChannel.h"
|
||||||
@@ -30,7 +31,7 @@ namespace PortabilityLayer
|
|||||||
{
|
{
|
||||||
union AudioCommandParam
|
union AudioCommandParam
|
||||||
{
|
{
|
||||||
const void *m_ptr;
|
IGpAudioBuffer *m_buffer;
|
||||||
AudioChannelCallback_t m_callback;
|
AudioChannelCallback_t m_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ namespace PortabilityLayer
|
|||||||
~AudioChannelImpl();
|
~AudioChannelImpl();
|
||||||
|
|
||||||
void Destroy(bool wait) override;
|
void Destroy(bool wait) override;
|
||||||
bool AddBuffer(const void *lengthTaggedBuffer, bool blocking) override;
|
bool AddBuffer(IGpAudioBuffer *buffer, bool blocking) override;
|
||||||
bool AddCallback(AudioChannelCallback_t callback, bool blocking) override;
|
bool AddCallback(AudioChannelCallback_t callback, bool blocking) override;
|
||||||
void ClearAllCommands() override;
|
void ClearAllCommands() override;
|
||||||
void Stop() override;
|
void Stop() override;
|
||||||
@@ -70,7 +71,7 @@ namespace PortabilityLayer
|
|||||||
static const unsigned int kMaxQueuedCommands = 64;
|
static const unsigned int kMaxQueuedCommands = 64;
|
||||||
|
|
||||||
void DigestQueueItems();
|
void DigestQueueItems();
|
||||||
void DigestBufferCommand(const void *dataPointer);
|
void DigestBufferCommand(IGpAudioBuffer *buffer);
|
||||||
|
|
||||||
IGpAudioChannel *m_audioChannel;
|
IGpAudioChannel *m_audioChannel;
|
||||||
|
|
||||||
@@ -103,6 +104,16 @@ namespace PortabilityLayer
|
|||||||
m_mutex->Destroy();
|
m_mutex->Destroy();
|
||||||
m_threadEvent->Destroy();
|
m_threadEvent->Destroy();
|
||||||
m_audioChannel->Destroy();
|
m_audioChannel->Destroy();
|
||||||
|
|
||||||
|
while (m_numQueuedCommands)
|
||||||
|
{
|
||||||
|
const AudioCommand &command = m_commandQueue[m_nextDequeueCommandPos];
|
||||||
|
m_numQueuedCommands--;
|
||||||
|
m_nextDequeueCommandPos = (m_nextDequeueCommandPos + 1) % static_cast<size_t>(kMaxQueuedCommands);
|
||||||
|
|
||||||
|
if (command.m_commandType == AudioCommandTypes::kBuffer)
|
||||||
|
command.m_param.m_buffer->Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioChannelImpl::NotifyBufferFinished()
|
void AudioChannelImpl::NotifyBufferFinished()
|
||||||
@@ -167,20 +178,26 @@ namespace PortabilityLayer
|
|||||||
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
|
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioChannelImpl::AddBuffer(const void *lengthTaggedBuffer, bool blocking)
|
bool AudioChannelImpl::AddBuffer(IGpAudioBuffer *buffer, bool blocking)
|
||||||
{
|
{
|
||||||
|
buffer->AddRef();
|
||||||
|
|
||||||
AudioCommand cmd;
|
AudioCommand cmd;
|
||||||
cmd.m_commandType = AudioCommandTypes::kBuffer;
|
cmd.m_commandType = AudioCommandTypes::kBuffer;
|
||||||
cmd.m_param.m_ptr = lengthTaggedBuffer;
|
cmd.m_param.m_buffer = buffer;
|
||||||
|
|
||||||
return this->PushCommand(cmd, blocking);
|
bool pushedOK = this->PushCommand(cmd, blocking);
|
||||||
|
if (!pushedOK)
|
||||||
|
buffer->Release();
|
||||||
|
|
||||||
|
return pushedOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioChannelImpl::AddCallback(AudioChannelCallback_t callback, bool blocking)
|
bool AudioChannelImpl::AddCallback(AudioChannelCallback_t callback, bool blocking)
|
||||||
{
|
{
|
||||||
AudioCommand cmd;
|
AudioCommand cmd;
|
||||||
cmd.m_commandType = AudioCommandTypes::kCallback;
|
cmd.m_commandType = AudioCommandTypes::kCallback;
|
||||||
cmd.m_param.m_ptr = reinterpret_cast<void*>(callback);
|
cmd.m_param.m_callback = callback;
|
||||||
|
|
||||||
return this->PushCommand(cmd, blocking);
|
return this->PushCommand(cmd, blocking);
|
||||||
}
|
}
|
||||||
@@ -200,7 +217,7 @@ namespace PortabilityLayer
|
|||||||
switch (command.m_commandType)
|
switch (command.m_commandType)
|
||||||
{
|
{
|
||||||
case AudioCommandTypes::kBuffer:
|
case AudioCommandTypes::kBuffer:
|
||||||
DigestBufferCommand(command.m_param.m_ptr);
|
DigestBufferCommand(command.m_param.m_buffer);
|
||||||
assert(m_state == State_PlayingAsync);
|
assert(m_state == State_PlayingAsync);
|
||||||
m_mutex->Unlock();
|
m_mutex->Unlock();
|
||||||
return;
|
return;
|
||||||
@@ -222,16 +239,14 @@ namespace PortabilityLayer
|
|||||||
m_mutex->Unlock();
|
m_mutex->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioChannelImpl::DigestBufferCommand(const void *dataPointer)
|
void AudioChannelImpl::DigestBufferCommand(IGpAudioBuffer *buffer)
|
||||||
{
|
{
|
||||||
assert(m_state == State_Idle);
|
assert(m_state == State_Idle);
|
||||||
|
|
||||||
// At this point, the buffer should already be validated and converted, and the data pointer should point at the data tag
|
if (m_audioChannel->PostBuffer(buffer))
|
||||||
uint32_t length;
|
|
||||||
memcpy(&length, dataPointer, 4);
|
|
||||||
|
|
||||||
m_audioChannel->PostBuffer(static_cast<const uint8_t*>(dataPointer) + 4, length);
|
|
||||||
m_state = State_PlayingAsync;
|
m_state = State_PlayingAsync;
|
||||||
|
|
||||||
|
buffer->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioChannelImpl::PushCommand(const AudioCommand &command, bool blocking)
|
bool AudioChannelImpl::PushCommand(const AudioCommand &command, bool blocking)
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "PLCore.h"
|
#include "PLCore.h"
|
||||||
|
|
||||||
|
struct IGpAudioBuffer;
|
||||||
|
|
||||||
namespace PortabilityLayer
|
namespace PortabilityLayer
|
||||||
{
|
{
|
||||||
struct AudioChannel;
|
struct AudioChannel;
|
||||||
@@ -11,7 +13,7 @@ namespace PortabilityLayer
|
|||||||
struct AudioChannel
|
struct AudioChannel
|
||||||
{
|
{
|
||||||
virtual void Destroy(bool wait) = 0;
|
virtual void Destroy(bool wait) = 0;
|
||||||
virtual bool AddBuffer(const void *lengthTaggedBuffer, bool blocking) = 0;
|
virtual bool AddBuffer(IGpAudioBuffer *buffer, bool blocking) = 0;
|
||||||
virtual bool AddCallback(AudioChannelCallback_t callback, bool blocking) = 0;
|
virtual bool AddCallback(AudioChannelCallback_t callback, bool blocking) = 0;
|
||||||
virtual void ClearAllCommands() = 0;
|
virtual void ClearAllCommands() = 0;
|
||||||
virtual void Stop() = 0;
|
virtual void Stop() = 0;
|
||||||
|
Reference in New Issue
Block a user