Hi,
We've noticed that on some devices, our sound loading code takes an extremely long time compared to other devices. For example, with 25 files our sound loading times look like:
- iPad ~5 seconds.
- Galaxy S2: ~7 seconds.
- Galaxy S3: ~38 seconds.
I've narrowed it down to sound loading via profiling but unfortunately I don't have frequent access to the device in question (the S3) and haven't been able to narrow it down further. This is compiled into a Marmalade app (to run on Android).
The sound loading code wasn't written by me, so I was wondering if anyone notices anything suspect or has any suggestions based on the following code:
//--------------------------------------------
bool CSoundEffect::LoadSound(const std::string &soundFilename)
{
// Search sound filename for last . - beginning of extension
std::string::size_type extensionStartPos = soundFilename.find_last_of(".");
ASSERT_MSG_TRAP(extensionStartPos != std::string::npos, "Unable to determine extension of file " << soundFilename, return false);
// Use this to extract extension and convert it to upper case
std::string extension = soundFilename.substr(extensionStartPos + 1);
StringUtils::StringToUpper(extension);
// Search for a loader for this extension
std::map<std::string, CSoundEffect::SoundLoaderFn>::iterator iLoader = s_SoundLoaderFunctions.find(extension);
ASSERT_MSG_TRAP(iLoader != s_SoundLoaderFunctions.end(), "No sound loader function registered for images with extension " << extension, return false);
// Open sound file stream
std::ifstream soundFileStream;
soundFileStream.open((CResourceManager::Get()->GetPathPrefix() + soundFilename).c_str(), std::ios::binary);
ASSERT_MSG_TRAP(soundFileStream.is_open(), "Sound " << CResourceManager::Get()->GetPathPrefix() + soundFilename << " not found", return false);
// Attempt to use loader function to complete image data structure
bool loadResult = iLoader->second(soundFileStream, m_SoundData);
// Close file
soundFileStream.close();
ASSERT_MSG_TRAP(loadResult, "Unable to load sound " << CResourceManager::Get()->GetPathPrefix() + soundFilename, return false);
return true;
}
//----------------------------------------
Loader Code:
#include "sound_loader_voc.h"
// Project includes
#include "logger.h"
// As VC6 is basically shite and what airplay targets, IW_ALIGNED isn't properly setup in s3eTypes
#if defined _MSC_VER && defined I3D_ARCH_X86
#undef IW_ALIGNED
#define IW_ALIGNED(X) __declspec(align(X))
#endif
//--------------------------------------------
// Anonymous namespace
//--------------------------------------------
namespace
{
// Block types
enum VocBlockTypes
{
eBlockTerminator,
eBlockSoundData,
eBlockSoundContinue,
eBlockSilence,
eBlockMarker,
eBlockASCII,
eBlockRepeat,
eBlockEndRepeat,
eBlockExtendedSoundAttribute,
eBlockExtendedSoundData,
};
// Possible formats of eBlockExtendedSoundData
enum ExtendedSoundDataFormat
{
eExtendedSoundFormatPCM8 = 0x0000,
eExtendedSoundFormatADPCM4 = 0x0001,
eExtendedSoundFormatADPCM3 = 0x0002,
eExtendedSoundFormatADPCM2 = 0x0003,
eExtendedSoundFormatPCM16 = 0x0004,
eExtendedSoundFormatCCITTALaw = 0x0006,
eExtendedSoundFormatCCITTULaw = 0x0007,
eExtendedSoundFormat16ADPCM4 = 0x02000,
};
// Header structure for a VOC file
IW_ALIGNED(1) struct VocHeader
{
char m_String[19];
u8 m_Pad;
u16 m_Offset;
u16 m_Version[2];
};
// Header structure for all data blocks
IW_ALIGNED(1) struct VocDataBlockHeader
{
u8 m_Type;
u8 m_Size[3];
u32 GetSize() const{ return m_Size[0] + (m_Size[1] << 8) + (m_Size[2] << 16); }
};
// Sub-header structure for an extended sound data block
IW_ALIGNED(1) struct ExtendedSoundDataHeader
{
u32 m_SamplesPerSec;
u8 m_BitsPerSample;
u8 m_NumChannels;
u16 m_Format;
u8 m_Padding[4];
};
bool ReadHeaderGetOffset(std::istream &inputFile, u16 &offset)
{
VocHeader header;
inputFile.read(reinterpret_cast<char*>(&header), sizeof(VocHeader));
// Validate header
if(memcmp(header.m_String, "Creative Voice File", 19) != 0)
{
return false;
}
// Transfer offset
offset = header.m_Offset;
return true;
}
bool ReadDataBlockExtendedSoundData(std::istream &inputFile, CSoundEffect::SoundData &soundData)
{
// Read main block header
VocDataBlockHeader header;
inputFile.read(reinterpret_cast<char*>(&header), sizeof(VocDataBlockHeader));
// Check that we're reading the right sort of data block
ASSERT_MSG_TRAP(header.m_Type == eBlockExtendedSoundData, "Only extended sound data blocks are supported", return false);
// Read the extended header
ExtendedSoundDataHeader extendedHeader;
inputFile.read(reinterpret_cast<char*>(&extendedHeader), sizeof(ExtendedSoundDataHeader));
// Check various aspects of the sound format
ASSERT_MSG_TRAP(extendedHeader.m_BitsPerSample == 16, "s3eSound only supports 16 bit samples", return false);
ASSERT_MSG_TRAP(extendedHeader.m_NumChannels == 1, "Only mono sound is currently supported", return false);
ASSERT_MSG_TRAP(extendedHeader.m_Format == eExtendedSoundFormatPCM16, "Only 16 bit PCM is currently supported", return false);
// Transfer sample rate into sound data structure
soundData.m_SamplesPerSec = extendedHeader.m_SamplesPerSec;
// Get size of chunk, subtract header size and convert to samples
u32 numBytes = header.GetSize() - 12;
u32 numSamples = numBytes >> 1;
// Allocate memory for samples and read from file
soundData.m_Samples.resize(numSamples);
inputFile.read(reinterpret_cast<char*>(&soundData.m_Samples.front()), numBytes);
return true;
};
};
//--------------------------------------------
// SoundLoaderVoc
//--------------------------------------------
bool SoundLoaderVoc::Loader(std::istream &inputFile, CSoundEffect::SoundData &soundData)
{
// Read header, determine data offset and seek there
u16 dataOffset;
if(!ReadHeaderGetOffset(inputFile, dataOffset))
{
ASSERT_MSG(false, "Not a valid VOC file");
return false;
}
// Seek to start of data offset
inputFile.seekg(dataOffset, std::ifstream::beg);
ReadDataBlockExtendedSoundData(inputFile, soundData);
return true;
}
Thanks for reading!