Add embedded sound support

This commit is contained in:
BeaR 2014-10-11 14:50:16 +02:00
parent 96a6d6d85b
commit b5d0034674
8 changed files with 158 additions and 83 deletions

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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);
*/
} }
} }

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -362,6 +362,7 @@ struct CMapItemSound
int m_SoundName; int m_SoundName;
int m_SoundData; int m_SoundData;
int m_SoundDataSize;
} ; } ;