diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index c7cf7c73b..d7feeb22b 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -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]; + + // 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); - 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; - - 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) diff --git a/src/engine/client/sound.h b/src/engine/client/sound.h index 086f3f02b..a9735b5ff 100644 --- a/src/engine/client/sound.h +++ b/src/engine/client/sound.h @@ -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 diff --git a/src/engine/sound.h b/src/engine/sound.h index b486216d1..27476ad22 100644 --- a/src/engine/sound.h +++ b/src/engine/sound.h @@ -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 diff --git a/src/game/client/components/mapsounds.cpp b/src/game/client/components/mapsounds.cpp index c3d6727c5..2a365933c 100644 --- a/src/game/client/components/mapsounds.cpp +++ b/src/game/client/components/mapsounds.cpp @@ -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); } } diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index c6d21a0a8..c6baf74f3 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -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); diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 5aa683bdd..6bde2bb43 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -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 diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp index 86b09b713..cdf7b2254 100644 --- a/src/game/editor/io.cpp +++ b/src/game/editor/io.cpp @@ -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 diff --git a/src/game/mapitems.h b/src/game/mapitems.h index 1e2be5118..daf9c4ae5 100644 --- a/src/game/mapitems.h +++ b/src/game/mapitems.h @@ -362,6 +362,7 @@ struct CMapItemSound int m_SoundName; int m_SoundData; + int m_SoundDataSize; } ;