class CSoundFile { public: CSoundFile(const std::string& sFilename); ~CSoundFile(); const std::string& GetName(); Uint8* GetData(); Uint32 GetLength(); protected: std::string m_sName; std::vector m_vAudioData; }; class CSoundPlay { public: CSoundPlay(CSoundFile& SoundFile, Uint32 nVolume); CSoundPlay(CSoundFile& SoundFile, const CVector& vecPosition, Uint32 nVolume); ~CSoundPlay(); bool Mix(Uint8* pStream, int nLength); protected: CSoundFile& m_SoundFile; Uint32 m_nPlayed; Uint32 m_nVolume; CVector m_vecPosition; bool m_bPositioned; }; class CSound { public: CSound(); ~CSound(); void Preload(const std::string& sFilename); void Play(const std::string& sFilename, Uint32 nVolume = SDL_MIX_MAXVOLUME); void Play(const std::string& sFilename, const CVector& vecPosition, Uint32 nVolume = SDL_MIX_MAXVOLUME); static void MixAudio_Gateway(void* pUserdata, Uint8* pStream, int nLength); protected: CSoundFile& FindSound(const std::string& sFilename); void MixAudio(Uint8* pStream, int nLength); std::vector m_vSounds; std::list m_vPlay; }; CSound::CSound() { /* Set 16-bit stereo audio at 22Khz */ SDL_AudioSpec AudioFormat; AudioFormat.freq = 44100; AudioFormat.format = AUDIO_S16; AudioFormat.channels = 2; AudioFormat.samples = 4096; AudioFormat.callback = &MixAudio_Gateway; AudioFormat.userdata = this; /* Open the audio device and start playing sound! */ if (SDL_OpenAudio(&AudioFormat, NULL) < 0) { throw CSDLError("SDL_OpenAudio"); } SDL_PauseAudio(0); } CSound::~CSound() { SDL_CloseAudio(); } void CSound::Preload(const std::string& sFilename) { /* Preload a sound */ m_vSounds.push_back(CSoundFile(sFilename)); } void CSound::Play(const std::string& sFilename, Uint32 nVolume) { m_vPlay.push_back(CSoundPlay(FindSound(sFilename), nVolume)); } void CSound::Play(const std::string& sFilename, const CVector& vecPosition, Uint32 nVolume) { m_vPlay.push_back(CSoundPlay(FindSound(sFilename), vecPosition, nVolume)); } CSoundFile& CSound::FindSound(const std::string& sFilename) { std::vector::iterator pEnd = m_vSounds.end(); for (std::vector::iterator pIterator = m_vSounds.begin(); pIterator < pEnd; pIterator++) { if (pIterator->GetName() == sFilename) { return *pIterator; } } throw CSDLError("Couldn't find sound " + sFilename); } void CSound::MixAudio(Uint8* pStream, int nLength) { /* Play all the sounds */ for (std::list::iterator pIterator = m_vPlay.begin(); pIterator != m_vPlay.end(); ) { // Crappy way of solving - pIterator++ after erasing fucks up (do this better) std::list::iterator pNext = pIterator; pNext++; if (!pIterator->Mix(pStream, nLength)) { m_vPlay.erase(pIterator); } pIterator = pNext; } } void CSound::MixAudio_Gateway(void* pUserdata, Uint8* pStream, int nLength) { ((CSound*) pUserdata)->MixAudio(pStream, nLength); } /*** ***/ CSoundFile::CSoundFile(const std::string& sFilename): m_sName(sFilename) { SDL_AudioSpec AudioFormat; SDL_AudioCVT AudioConverter; Uint8* pAudioData; Uint32 nAudioLength; int nConvert; /* Load WAV file */ if (!SDL_LoadWAV(("sounds/" + sFilename + ".wav").c_str(), &AudioFormat, &pAudioData, &nAudioLength)) { throw CSDLError("SDL_LoadWAV"); } /* Convert to 44100 + 2 channels + 16bit */ nConvert = SDL_BuildAudioCVT( &AudioConverter, AudioFormat.format, AudioFormat.channels, AudioFormat.freq, AUDIO_S16, 2, 44100 ); /* This can't be converted */ if (nConvert == -1) { throw CSDLError("SDL_BuildAudioCVT"); } /* Use vector to save the data instead of malloc/free */ m_vAudioData.resize(nAudioLength * AudioConverter.len_mult); memcpy(&m_vAudioData[0], pAudioData, nAudioLength); SDL_FreeWAV(pAudioData); /* If we need to convert it do it here */ if (nConvert == 1) { /* Setup for conversion */ AudioConverter.buf = &m_vAudioData[0]; AudioConverter.len = nAudioLength; /* And now we're ready to convert */ SDL_ConvertAudio(&AudioConverter); } } CSoundFile::~CSoundFile() {} Uint8* CSoundFile::GetData() { return &m_vAudioData[0]; } Uint32 CSoundFile::GetLength() { return m_vAudioData.size(); } const std::string& CSoundFile::GetName() { return m_sName; } /*** ***/ CSoundPlay::CSoundPlay(CSoundFile& SoundFile, Uint32 nVolume): m_SoundFile(SoundFile), m_nPlayed(0), m_nVolume(nVolume), m_bPositioned(false) {} CSoundPlay::CSoundPlay(CSoundFile& SoundFile, const CVector& vecPosition, Uint32 nVolume): m_SoundFile(SoundFile), m_nPlayed(0), m_nVolume(nVolume), m_vecPosition(vecPosition), m_bPositioned(true) {} CSoundPlay::~CSoundPlay() {} bool CSoundPlay::Mix(Uint8* pStream, int nLength) { int nMixLength; bool bFinished; nMixLength = m_SoundFile.GetLength() - m_nPlayed; if (nMixLength > nLength) { nMixLength = nLength; bFinished = true; } else { bFinished = false; } if (m_bPositioned) { // do something really smart here ! } SDL_MixAudio(pStream, m_SoundFile.GetData() + m_nPlayed, nMixLength, m_nVolume); m_nPlayed += nMixLength; return bFinished; }