mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +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 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
|
||||
static short Int2Short(int i)
|
||||
{
|
||||
|
@ -330,23 +334,85 @@ void CSound::RateConvert(int SampleID)
|
|||
|
||||
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)
|
||||
{
|
||||
CSample *pSample;
|
||||
int SampleID = -1;
|
||||
char aError[100];
|
||||
WavpackContext *pContext;
|
||||
|
||||
// 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;
|
||||
return -1;
|
||||
|
||||
if(!m_pStorage)
|
||||
return -1;
|
||||
|
@ -358,67 +424,19 @@ int CSound::LoadWV(const char *pFilename)
|
|||
return -1;
|
||||
}
|
||||
|
||||
SampleID = AllocID();
|
||||
int SampleID = AllocID();
|
||||
if(SampleID < 0)
|
||||
return -1;
|
||||
pSample = &m_aSamples[SampleID];
|
||||
|
||||
pContext = WavpackOpenFileInput(ReadData, aError);
|
||||
if (pContext)
|
||||
{
|
||||
int m_aSamples = WavpackGetNumSamples(pContext);
|
||||
int BitsPerSample = WavpackGetBitsPerSample(pContext);
|
||||
unsigned int SampleRate = WavpackGetSampleRate(pContext);
|
||||
int m_aChannels = WavpackGetNumChannels(pContext);
|
||||
int *pData;
|
||||
int *pSrc;
|
||||
short *pDst;
|
||||
int i;
|
||||
// read the whole file into memory
|
||||
int DataSize = io_length(ms_File);
|
||||
char *pData = new char[DataSize];
|
||||
io_read(ms_File, pData, DataSize);
|
||||
io_close(ms_File);
|
||||
|
||||
pSample->m_Channels = m_aChannels;
|
||||
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);
|
||||
}
|
||||
SampleID = DecodeWV(SampleID, pData, DataSize);
|
||||
|
||||
delete[] pData;
|
||||
io_close(ms_File);
|
||||
ms_File = NULL;
|
||||
|
||||
|
@ -429,6 +447,29 @@ int CSound::LoadWV(const char *pFilename)
|
|||
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)
|
||||
{
|
||||
if(SampleID == -1 || SampleID >= NUM_SAMPLES)
|
||||
|
|
|
@ -24,10 +24,12 @@ public:
|
|||
// TODO: Refactor: clean this mess up
|
||||
static IOHANDLE ms_File;
|
||||
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 int LoadWV(const char *pFilename);
|
||||
virtual int LoadWVFromMem(const void *pData, unsigned DataSize);
|
||||
virtual void UnloadSample(int SampleID);
|
||||
|
||||
virtual float GetSampleDuration(int SampleID); // in s
|
||||
|
|
|
@ -19,6 +19,7 @@ public:
|
|||
virtual bool IsSoundEnabled() = 0;
|
||||
|
||||
virtual int LoadWV(const char *pFilename) = 0;
|
||||
virtual int LoadWVFromMem(const void *pData, unsigned DataSize) = 0;
|
||||
virtual void UnloadSample(int SampleID) = 0;
|
||||
|
||||
virtual float GetSampleDuration(int SampleID) = 0; // in s
|
||||
|
|
|
@ -42,11 +42,9 @@ void CMapSounds::OnMapLoad()
|
|||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
void *pData = pMap->GetData(pImg->m_ImageData);
|
||||
m_aTextures[i] = Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, CImageInfo::FORMAT_RGBA, pData, CImageInfo::FORMAT_RGBA, 0);
|
||||
pMap->UnloadData(pImg->m_ImageData);
|
||||
*/
|
||||
void *pData = pMap->GetData(pSound->m_SoundData);
|
||||
m_aSounds[i] = Sound()->LoadWVFromMem(pData, pSound->m_SoundDataSize);
|
||||
pMap->UnloadData(pSound->m_SoundData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,11 @@ CEditorImage::~CEditorImage()
|
|||
CEditorSound::~CEditorSound()
|
||||
{
|
||||
m_pEditor->Sound()->UnloadSample(m_SoundID);
|
||||
if(m_pData)
|
||||
{
|
||||
delete[] m_pData;
|
||||
m_pData = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
CLayerGroup::CLayerGroup()
|
||||
|
@ -2873,8 +2878,19 @@ void CEditor::AddSound(const char *pFileName, int StorageType, void *pUser)
|
|||
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
|
||||
int SoundId = pEditor->Sound()->LoadWV(pFileName);
|
||||
int SoundId = pEditor->Sound()->LoadWVFromMem(pData, DataSize);
|
||||
if(SoundId == -1)
|
||||
return;
|
||||
|
||||
|
@ -2882,6 +2898,8 @@ void CEditor::AddSound(const char *pFileName, int StorageType, void *pUser)
|
|||
CEditorSound *pSound = new CEditorSound(pEditor);
|
||||
pSound->m_SoundID = SoundId;
|
||||
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));
|
||||
pEditor->m_Map.m_lSounds.add(pSound);
|
||||
|
||||
|
|
|
@ -314,6 +314,9 @@ public:
|
|||
m_aName[0] = 0;
|
||||
m_External = 0;
|
||||
m_SoundID = 0;
|
||||
|
||||
m_pData = 0x0;
|
||||
m_DataSize = 0;
|
||||
}
|
||||
|
||||
~CEditorSound();
|
||||
|
@ -321,6 +324,9 @@ public:
|
|||
int m_SoundID;
|
||||
int m_External;
|
||||
char m_aName[128];
|
||||
|
||||
void *m_pData;
|
||||
unsigned m_DataSize;
|
||||
};
|
||||
|
||||
class CEditorMap
|
||||
|
|
|
@ -284,11 +284,14 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
|
|||
Item.m_External = pSound->m_External;
|
||||
Item.m_SoundName = df.AddData(str_length(pSound->m_aName)+1, pSound->m_aName);
|
||||
if(pSound->m_External)
|
||||
{
|
||||
Item.m_SoundDataSize = 0;
|
||||
Item.m_SoundData = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
// Item.m_ImageData = df.AddData(Item.m_Width*Item.m_Height*4, pImg->m_pData);
|
||||
Item.m_SoundData = df.AddData(pSound->m_DataSize, pSound->m_pData);
|
||||
Item.m_SoundDataSize = pSound->m_DataSize;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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
|
||||
{
|
||||
/*
|
||||
pImg->m_Width = pItem->m_Width;
|
||||
pImg->m_Height = pItem->m_Height;
|
||||
pImg->m_Format = CImageInfo::FORMAT_RGBA;
|
||||
pSound->m_DataSize = pItem->m_SoundDataSize;
|
||||
|
||||
// copy image data
|
||||
void *pData = DataFile.GetData(pItem->m_ImageData);
|
||||
pImg->m_pData = mem_alloc(pImg->m_Width*pImg->m_Height*4, 1);
|
||||
mem_copy(pImg->m_pData, pData, pImg->m_Width*pImg->m_Height*4);
|
||||
pImg->m_TexID = m_pEditor->Graphics()->LoadTextureRaw(pImg->m_Width, pImg->m_Height, pImg->m_Format, pImg->m_pData, CImageInfo::FORMAT_AUTO, 0);
|
||||
*/
|
||||
// copy sample data
|
||||
void *pData = DataFile.GetData(pItem->m_SoundData);
|
||||
pSound->m_pData = mem_alloc(pSound->m_DataSize, 1);
|
||||
mem_copy(pSound->m_pData, pData, pSound->m_DataSize);
|
||||
pSound->m_SoundID = m_pEditor->Sound()->LoadWVFromMem(pSound->m_pData, pSound->m_DataSize);
|
||||
}
|
||||
|
||||
// copy image name
|
||||
|
|
|
@ -362,6 +362,7 @@ struct CMapItemSound
|
|||
|
||||
int m_SoundName;
|
||||
int m_SoundData;
|
||||
int m_SoundDataSize;
|
||||
} ;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue