mirror of
https://github.com/ddnet/ddnet.git
synced 2024-09-20 09:34:19 +00:00
Add embedded sound support
This commit is contained in:
parent
96a6d6d85b
commit
b5d0034674
|
@ -67,6 +67,10 @@ static int m_NextVoice = 0;
|
||||||
static int *m_pMixBuffer = 0; // buffer only used by the thread callback function
|
static int *m_pMixBuffer = 0; // buffer only used by the thread callback function
|
||||||
static unsigned m_MaxFrames = 0;
|
static unsigned m_MaxFrames = 0;
|
||||||
|
|
||||||
|
static const void *ms_pWVBuffer = 0x0;
|
||||||
|
static int ms_WVBufferPosition = 0;
|
||||||
|
static int ms_WVBufferSize = 0;
|
||||||
|
|
||||||
// TODO: there should be a faster way todo this
|
// TODO: there should be a faster way todo this
|
||||||
static short Int2Short(int i)
|
static short Int2Short(int i)
|
||||||
{
|
{
|
||||||
|
@ -330,23 +334,85 @@ void CSound::RateConvert(int SampleID)
|
||||||
|
|
||||||
int CSound::ReadData(void *pBuffer, int Size)
|
int CSound::ReadData(void *pBuffer, int Size)
|
||||||
{
|
{
|
||||||
return io_read(ms_File, pBuffer, Size);
|
int ChunkSize = min(Size, ms_WVBufferSize - ms_WVBufferPosition);
|
||||||
|
mem_copy(pBuffer, (const char *)ms_pWVBuffer + ms_WVBufferPosition, ChunkSize);
|
||||||
|
ms_WVBufferPosition += ChunkSize;
|
||||||
|
return ChunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSound::DecodeWV(int SampleID, const void *pData, unsigned DataSize)
|
||||||
|
{
|
||||||
|
if(SampleID == -1 || SampleID >= NUM_SAMPLES)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
CSample *pSample = &m_aSamples[SampleID];
|
||||||
|
char aError[100];
|
||||||
|
WavpackContext *pContext;
|
||||||
|
|
||||||
|
ms_pWVBuffer = pData;
|
||||||
|
ms_WVBufferSize = DataSize;
|
||||||
|
ms_WVBufferPosition = 0;
|
||||||
|
|
||||||
|
pContext = WavpackOpenFileInput(ReadData, aError);
|
||||||
|
if (pContext)
|
||||||
|
{
|
||||||
|
int NumSamples = WavpackGetNumSamples(pContext);
|
||||||
|
int BitsPerSample = WavpackGetBitsPerSample(pContext);
|
||||||
|
unsigned int SampleRate = WavpackGetSampleRate(pContext);
|
||||||
|
int NumChannels = WavpackGetNumChannels(pContext);
|
||||||
|
int *pSrc;
|
||||||
|
short *pDst;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pSample->m_Channels = NumChannels;
|
||||||
|
pSample->m_Rate = SampleRate;
|
||||||
|
|
||||||
|
if(pSample->m_Channels > 2)
|
||||||
|
{
|
||||||
|
dbg_msg("sound/wv", "file is not mono or stereo.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(BitsPerSample != 16)
|
||||||
|
{
|
||||||
|
dbg_msg("sound/wv", "bps is %d, not 16", BitsPerSample);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int *pBuffer = (int *)mem_alloc(4*NumSamples*NumChannels, 1);
|
||||||
|
WavpackUnpackSamples(pContext, pBuffer, NumSamples); // TODO: check return value
|
||||||
|
pSrc = pBuffer;
|
||||||
|
|
||||||
|
pSample->m_pData = (short *)mem_alloc(2*NumSamples*NumChannels, 1);
|
||||||
|
pDst = pSample->m_pData;
|
||||||
|
|
||||||
|
for (i = 0; i < NumSamples*NumChannels; i++)
|
||||||
|
*pDst++ = (short)*pSrc++;
|
||||||
|
|
||||||
|
mem_free(pBuffer);
|
||||||
|
|
||||||
|
pSample->m_NumFrames = NumSamples;
|
||||||
|
pSample->m_LoopStart = -1;
|
||||||
|
pSample->m_LoopEnd = -1;
|
||||||
|
pSample->m_PausedAt = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dbg_msg("sound/wv", "failed to decode sample (%s)", aError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SampleID;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSound::LoadWV(const char *pFilename)
|
int CSound::LoadWV(const char *pFilename)
|
||||||
{
|
{
|
||||||
CSample *pSample;
|
|
||||||
int SampleID = -1;
|
|
||||||
char aError[100];
|
|
||||||
WavpackContext *pContext;
|
|
||||||
|
|
||||||
// don't waste memory on sound when we are stress testing
|
// don't waste memory on sound when we are stress testing
|
||||||
if(g_Config.m_DbgStress)
|
if(g_Config.m_DbgStress)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// no need to load sound when we are running with no sound
|
// no need to load sound when we are running with no sound
|
||||||
if(!m_SoundEnabled)
|
if(!m_SoundEnabled)
|
||||||
return 1;
|
return -1;
|
||||||
|
|
||||||
if(!m_pStorage)
|
if(!m_pStorage)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -358,67 +424,19 @@ int CSound::LoadWV(const char *pFilename)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SampleID = AllocID();
|
int SampleID = AllocID();
|
||||||
if(SampleID < 0)
|
if(SampleID < 0)
|
||||||
return -1;
|
return -1;
|
||||||
pSample = &m_aSamples[SampleID];
|
|
||||||
|
|
||||||
pContext = WavpackOpenFileInput(ReadData, aError);
|
// read the whole file into memory
|
||||||
if (pContext)
|
int DataSize = io_length(ms_File);
|
||||||
{
|
char *pData = new char[DataSize];
|
||||||
int m_aSamples = WavpackGetNumSamples(pContext);
|
io_read(ms_File, pData, DataSize);
|
||||||
int BitsPerSample = WavpackGetBitsPerSample(pContext);
|
io_close(ms_File);
|
||||||
unsigned int SampleRate = WavpackGetSampleRate(pContext);
|
|
||||||
int m_aChannels = WavpackGetNumChannels(pContext);
|
|
||||||
int *pData;
|
|
||||||
int *pSrc;
|
|
||||||
short *pDst;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
pSample->m_Channels = m_aChannels;
|
SampleID = DecodeWV(SampleID, pData, DataSize);
|
||||||
pSample->m_Rate = SampleRate;
|
|
||||||
|
|
||||||
if(pSample->m_Channels > 2)
|
|
||||||
{
|
|
||||||
dbg_msg("sound/wv", "file is not mono or stereo. filename='%s'", pFilename);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(snd->rate != 44100)
|
|
||||||
{
|
|
||||||
dbg_msg("sound/wv", "file is %d Hz, not 44100 Hz. filename='%s'", snd->rate, filename);
|
|
||||||
return -1;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(BitsPerSample != 16)
|
|
||||||
{
|
|
||||||
dbg_msg("sound/wv", "bps is %d, not 16, filname='%s'", BitsPerSample, pFilename);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pData = (int *)mem_alloc(4*m_aSamples*m_aChannels, 1);
|
|
||||||
WavpackUnpackSamples(pContext, pData, m_aSamples); // TODO: check return value
|
|
||||||
pSrc = pData;
|
|
||||||
|
|
||||||
pSample->m_pData = (short *)mem_alloc(2*m_aSamples*m_aChannels, 1);
|
|
||||||
pDst = pSample->m_pData;
|
|
||||||
|
|
||||||
for (i = 0; i < m_aSamples*m_aChannels; i++)
|
|
||||||
*pDst++ = (short)*pSrc++;
|
|
||||||
|
|
||||||
mem_free(pData);
|
|
||||||
|
|
||||||
pSample->m_NumFrames = m_aSamples;
|
|
||||||
pSample->m_LoopStart = -1;
|
|
||||||
pSample->m_LoopEnd = -1;
|
|
||||||
pSample->m_PausedAt = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dbg_msg("sound/wv", "failed to open %s: %s", pFilename, aError);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
delete[] pData;
|
||||||
io_close(ms_File);
|
io_close(ms_File);
|
||||||
ms_File = NULL;
|
ms_File = NULL;
|
||||||
|
|
||||||
|
@ -429,6 +447,29 @@ int CSound::LoadWV(const char *pFilename)
|
||||||
return SampleID;
|
return SampleID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CSound::LoadWVFromMem(const void *pData, unsigned DataSize)
|
||||||
|
{
|
||||||
|
// don't waste memory on sound when we are stress testing
|
||||||
|
if(g_Config.m_DbgStress)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// no need to load sound when we are running with no sound
|
||||||
|
if(!m_SoundEnabled)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(!pData)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int SampleID = AllocID();
|
||||||
|
if(SampleID < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
SampleID = DecodeWV(SampleID, pData, DataSize);
|
||||||
|
|
||||||
|
RateConvert(SampleID);
|
||||||
|
return SampleID;
|
||||||
|
}
|
||||||
|
|
||||||
void CSound::UnloadSample(int SampleID)
|
void CSound::UnloadSample(int SampleID)
|
||||||
{
|
{
|
||||||
if(SampleID == -1 || SampleID >= NUM_SAMPLES)
|
if(SampleID == -1 || SampleID >= NUM_SAMPLES)
|
||||||
|
|
|
@ -24,10 +24,12 @@ public:
|
||||||
// TODO: Refactor: clean this mess up
|
// TODO: Refactor: clean this mess up
|
||||||
static IOHANDLE ms_File;
|
static IOHANDLE ms_File;
|
||||||
static int ReadData(void *pBuffer, int Size);
|
static int ReadData(void *pBuffer, int Size);
|
||||||
|
static int DecodeWV(int SampleID, const void *pData, unsigned DataSize);
|
||||||
|
|
||||||
virtual bool IsSoundEnabled() { return m_SoundEnabled != 0; }
|
virtual bool IsSoundEnabled() { return m_SoundEnabled != 0; }
|
||||||
|
|
||||||
virtual int LoadWV(const char *pFilename);
|
virtual int LoadWV(const char *pFilename);
|
||||||
|
virtual int LoadWVFromMem(const void *pData, unsigned DataSize);
|
||||||
virtual void UnloadSample(int SampleID);
|
virtual void UnloadSample(int SampleID);
|
||||||
|
|
||||||
virtual float GetSampleDuration(int SampleID); // in s
|
virtual float GetSampleDuration(int SampleID); // in s
|
||||||
|
|
|
@ -19,6 +19,7 @@ public:
|
||||||
virtual bool IsSoundEnabled() = 0;
|
virtual bool IsSoundEnabled() = 0;
|
||||||
|
|
||||||
virtual int LoadWV(const char *pFilename) = 0;
|
virtual int LoadWV(const char *pFilename) = 0;
|
||||||
|
virtual int LoadWVFromMem(const void *pData, unsigned DataSize) = 0;
|
||||||
virtual void UnloadSample(int SampleID) = 0;
|
virtual void UnloadSample(int SampleID) = 0;
|
||||||
|
|
||||||
virtual float GetSampleDuration(int SampleID) = 0; // in s
|
virtual float GetSampleDuration(int SampleID) = 0; // in s
|
||||||
|
|
|
@ -42,11 +42,9 @@ void CMapSounds::OnMapLoad()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
void *pData = pMap->GetData(pSound->m_SoundData);
|
||||||
void *pData = pMap->GetData(pImg->m_ImageData);
|
m_aSounds[i] = Sound()->LoadWVFromMem(pData, pSound->m_SoundDataSize);
|
||||||
m_aTextures[i] = Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, CImageInfo::FORMAT_RGBA, pData, CImageInfo::FORMAT_RGBA, 0);
|
pMap->UnloadData(pSound->m_SoundData);
|
||||||
pMap->UnloadData(pImg->m_ImageData);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,11 @@ CEditorImage::~CEditorImage()
|
||||||
CEditorSound::~CEditorSound()
|
CEditorSound::~CEditorSound()
|
||||||
{
|
{
|
||||||
m_pEditor->Sound()->UnloadSample(m_SoundID);
|
m_pEditor->Sound()->UnloadSample(m_SoundID);
|
||||||
|
if(m_pData)
|
||||||
|
{
|
||||||
|
delete[] m_pData;
|
||||||
|
m_pData = 0x0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CLayerGroup::CLayerGroup()
|
CLayerGroup::CLayerGroup()
|
||||||
|
@ -2873,8 +2878,19 @@ void CEditor::AddSound(const char *pFileName, int StorageType, void *pUser)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load external
|
||||||
|
IOHANDLE SoundFile = pEditor->Storage()->OpenFile(pFileName, IOFLAG_READ, IStorage::TYPE_ALL);
|
||||||
|
if(!SoundFile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// read the whole file into memory
|
||||||
|
unsigned DataSize = io_length(SoundFile);
|
||||||
|
void *pData = new char[DataSize];
|
||||||
|
io_read(SoundFile, pData, DataSize);
|
||||||
|
io_close(SoundFile);
|
||||||
|
|
||||||
// load sound
|
// load sound
|
||||||
int SoundId = pEditor->Sound()->LoadWV(pFileName);
|
int SoundId = pEditor->Sound()->LoadWVFromMem(pData, DataSize);
|
||||||
if(SoundId == -1)
|
if(SoundId == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2882,6 +2898,8 @@ void CEditor::AddSound(const char *pFileName, int StorageType, void *pUser)
|
||||||
CEditorSound *pSound = new CEditorSound(pEditor);
|
CEditorSound *pSound = new CEditorSound(pEditor);
|
||||||
pSound->m_SoundID = SoundId;
|
pSound->m_SoundID = SoundId;
|
||||||
pSound->m_External = 1; // external by default
|
pSound->m_External = 1; // external by default
|
||||||
|
pSound->m_DataSize = DataSize;
|
||||||
|
pSound->m_pData = pData;
|
||||||
str_copy(pSound->m_aName, aBuf, sizeof(pSound->m_aName));
|
str_copy(pSound->m_aName, aBuf, sizeof(pSound->m_aName));
|
||||||
pEditor->m_Map.m_lSounds.add(pSound);
|
pEditor->m_Map.m_lSounds.add(pSound);
|
||||||
|
|
||||||
|
|
|
@ -314,6 +314,9 @@ public:
|
||||||
m_aName[0] = 0;
|
m_aName[0] = 0;
|
||||||
m_External = 0;
|
m_External = 0;
|
||||||
m_SoundID = 0;
|
m_SoundID = 0;
|
||||||
|
|
||||||
|
m_pData = 0x0;
|
||||||
|
m_DataSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
~CEditorSound();
|
~CEditorSound();
|
||||||
|
@ -321,6 +324,9 @@ public:
|
||||||
int m_SoundID;
|
int m_SoundID;
|
||||||
int m_External;
|
int m_External;
|
||||||
char m_aName[128];
|
char m_aName[128];
|
||||||
|
|
||||||
|
void *m_pData;
|
||||||
|
unsigned m_DataSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CEditorMap
|
class CEditorMap
|
||||||
|
|
|
@ -284,11 +284,14 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
|
||||||
Item.m_External = pSound->m_External;
|
Item.m_External = pSound->m_External;
|
||||||
Item.m_SoundName = df.AddData(str_length(pSound->m_aName)+1, pSound->m_aName);
|
Item.m_SoundName = df.AddData(str_length(pSound->m_aName)+1, pSound->m_aName);
|
||||||
if(pSound->m_External)
|
if(pSound->m_External)
|
||||||
|
{
|
||||||
|
Item.m_SoundDataSize = 0;
|
||||||
Item.m_SoundData = -1;
|
Item.m_SoundData = -1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO
|
Item.m_SoundData = df.AddData(pSound->m_DataSize, pSound->m_pData);
|
||||||
// Item.m_ImageData = df.AddData(Item.m_Width*Item.m_Height*4, pImg->m_pData);
|
Item.m_SoundDataSize = pSound->m_DataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
df.AddItem(MAPITEMTYPE_SOUND, i, sizeof(Item), &Item);
|
df.AddItem(MAPITEMTYPE_SOUND, i, sizeof(Item), &Item);
|
||||||
|
@ -645,21 +648,26 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
|
||||||
str_format(aBuf, sizeof(aBuf),"mapres/%s.wv", pName);
|
str_format(aBuf, sizeof(aBuf),"mapres/%s.wv", pName);
|
||||||
|
|
||||||
// load external
|
// load external
|
||||||
pSound->m_SoundID = m_pEditor->Sound()->LoadWV(aBuf);
|
IOHANDLE SoundFile = pStorage->OpenFile(pName, IOFLAG_READ, IStorage::TYPE_ALL);
|
||||||
|
if(SoundFile)
|
||||||
|
{
|
||||||
|
// read the whole file into memory
|
||||||
|
pSound->m_DataSize = io_length(SoundFile);
|
||||||
|
pSound->m_pData = new char[pSound->m_DataSize];
|
||||||
|
io_read(SoundFile, pSound->m_pData, pSound->m_DataSize);
|
||||||
|
io_close(SoundFile);
|
||||||
|
pSound->m_SoundID = m_pEditor->Sound()->LoadWVFromMem(pSound->m_pData, pSound->m_DataSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
pSound->m_DataSize = pItem->m_SoundDataSize;
|
||||||
pImg->m_Width = pItem->m_Width;
|
|
||||||
pImg->m_Height = pItem->m_Height;
|
|
||||||
pImg->m_Format = CImageInfo::FORMAT_RGBA;
|
|
||||||
|
|
||||||
// copy image data
|
// copy sample data
|
||||||
void *pData = DataFile.GetData(pItem->m_ImageData);
|
void *pData = DataFile.GetData(pItem->m_SoundData);
|
||||||
pImg->m_pData = mem_alloc(pImg->m_Width*pImg->m_Height*4, 1);
|
pSound->m_pData = mem_alloc(pSound->m_DataSize, 1);
|
||||||
mem_copy(pImg->m_pData, pData, pImg->m_Width*pImg->m_Height*4);
|
mem_copy(pSound->m_pData, pData, pSound->m_DataSize);
|
||||||
pImg->m_TexID = m_pEditor->Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, pImg->m_Format, pImg->m_pData, CImageInfo::FORMAT_AUTO, 0);
|
pSound->m_SoundID = m_pEditor->Sound()->LoadWVFromMem(pSound->m_pData, pSound->m_DataSize);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy image name
|
// copy image name
|
||||||
|
|
|
@ -362,6 +362,7 @@ struct CMapItemSound
|
||||||
|
|
||||||
int m_SoundName;
|
int m_SoundName;
|
||||||
int m_SoundData;
|
int m_SoundData;
|
||||||
|
int m_SoundDataSize;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue