diff --git a/Engine/source/sfx/media/sfxSndStream.cpp b/Engine/source/sfx/media/sfxSndStream.cpp new file mode 100644 index 000000000..f7eedff92 --- /dev/null +++ b/Engine/source/sfx/media/sfxSndStream.cpp @@ -0,0 +1,187 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#include "sfx/media/sfxSndStream.h" +#include "core/stream/fileStream.h" +#include "core/stream/stream.h" +#include "console/console.h" + +#define MAX_BUFFER 4096 + +bool SFXSndStream::_readHeader() +{ + mCurPos = 0; + mBytesRead = 0; + + dMemset(&sfinfo, 0, sizeof(SF_INFO)); + + vio.get_filelen = sndFileLen; + vio.seek = sndSeek; + vio.read = sndRead; + vio.write = sndWrite; + vio.tell = sndTell; + + vio_data.length = 0; + vio_data.offset = 0; + vio_data.data = mStream; + + if ((sndFile = sf_open_virtual(&vio, SFM_READ, &sfinfo, &vio_data)) == NULL) + { + Con::printf("SFXSndStream - _readHeader failed: %s", sf_strerror(sndFile)); + return false; + } + + S32 bitsPerSample = 0; + switch ((sfinfo.format & SF_FORMAT_SUBMASK)) + { + case SF_FORMAT_PCM_S8: + case SF_FORMAT_PCM_U8: + bitsPerSample = 8; + break; + case SF_FORMAT_PCM_16: + case SF_FORMAT_VORBIS: + bitsPerSample = 16; + break; + case SF_FORMAT_PCM_24: + bitsPerSample = 24; + break; + case SF_FORMAT_PCM_32: + bitsPerSample = 32; + break; + default: + // Other formats not supported or not recognized + bitsPerSample = -1; + break; + } + + mFormat.set(sfinfo.channels, bitsPerSample * sfinfo.channels, sfinfo.samplerate); + + mSamples = sfinfo.frames; + + return true; +} + +void SFXSndStream::_close() +{ + if (!sndFile) + return; + + sf_close(sndFile); +} + +SFXSndStream* SFXSndStream::create(Stream* stream) +{ + SFXSndStream* sfxStream = new SFXSndStream(); + if (sfxStream->open(stream, true)) + return sfxStream; + + delete sfxStream; + return nullptr; +} + +void SFXSndStream::reset() +{ + vio_data.offset = 0; +} + +U32 SFXSndStream::read(U8* buffer, U32 length) +{ + U32 framesRead = 0; + + framesRead = sf_readf_short(sndFile, (short*)buffer, sfinfo.frames); + + return framesRead; +} + +bool SFXSndStream::isEOS() const +{ + return false; +} + +U32 SFXSndStream::getPosition() const +{ + return U32(); +} + +void SFXSndStream::setPosition(U32 offset) +{ +} + +sf_count_t SFXSndStream::sndSeek(sf_count_t offset, int whence, void* user_data) +{ + VIO_DATA* vf = (VIO_DATA*)user_data; + + switch (whence) + { + case SEEK_SET: + vf->offset = offset; + break; + + case SEEK_CUR: + vf->offset = vf->offset + offset; + break; + + case SEEK_END: + vf->offset = vf->length + offset; + break; + default: + break; + }; + + return vf->offset; +} + +sf_count_t SFXSndStream::sndRead(void* ptr, sf_count_t count, void* user_data) +{ + VIO_DATA* vf = (VIO_DATA*)user_data; + Stream* stream = reinterpret_cast(vf->data); + + if (vf->offset + count > vf->length) + count = vf->length - vf->offset; + + stream->read((U32)(count), reinterpret_cast(ptr)); + + vf->offset += count; + + return count; +} + +sf_count_t SFXSndStream::sndWrite(const void* ptr, sf_count_t count, void* user_data) +{ + return sf_count_t(); +} + +sf_count_t SFXSndStream::sndTell(void* user_data) +{ + VIO_DATA* vf = (VIO_DATA*)user_data; + return vf->offset; +} + +sf_count_t SFXSndStream::sndFileLen(void* user_data) +{ + VIO_DATA* vf = (VIO_DATA*)user_data; + Stream* stream = reinterpret_cast(vf->data); + + vf->length = stream->getStreamSize(); + + return vf->length; +} + diff --git a/Engine/source/sfx/media/sfxSndStream.h b/Engine/source/sfx/media/sfxSndStream.h new file mode 100644 index 000000000..a6bfbd28c --- /dev/null +++ b/Engine/source/sfx/media/sfxSndStream.h @@ -0,0 +1,92 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _SFXSNDSTREAM_H_ +#define _SFXSNDSTREAM_H_ + +#ifndef _SFXFILESTREAM_H_ +# include "sfx/sfxFileStream.h" +#endif +#include "core/util/safeDelete.h" + +#include + +/// An SFXFileStream that loads sample data from a Vorbis file. +class SFXSndStream : public SFXFileStream, + public IPositionable< U32 > +{ +public: + typedef SFXFileStream Parent; + +protected: + + // setup our vio_data struct. + typedef struct + { + sf_count_t offset, length; + Stream* data; + } VIO_DATA; + + /// Total number of bytes read from the stream so far. + U32 mBytesRead; + /// The current bitstream index. + S32 mCurPos; + + SF_VIRTUAL_IO vio; + SNDFILE* sndFile; + VIO_DATA vio_data; + SF_INFO sfinfo; + + // vio callbacks + static sf_count_t sndSeek(sf_count_t offset, int whence, void* user_data); + static sf_count_t sndRead(void *ptr, sf_count_t count, void* user_data); + static sf_count_t sndWrite(const void* ptr, sf_count_t count, void* user_data); + static sf_count_t sndTell(void* user_data); + static sf_count_t sndFileLen(void* user_data); + + // SFXStream + bool _readHeader() override; + void _close() override; + +public: + + /// + static SFXSndStream* create(Stream* stream); + + // SFXStream + void reset() override; + U32 read(U8* buffer, U32 length) override; + bool isEOS() const override; + SFXStream* clone() const override + { + SFXSndStream* stream = new SFXSndStream(*this); + if (!stream->sndFile) + SAFE_DELETE(stream); + return stream; + } + + // IPositionable + U32 getPosition() const override; + void setPosition(U32 offset) override; +}; + +#endif diff --git a/Engine/source/sfx/sfxSystem.cpp b/Engine/source/sfx/sfxSystem.cpp index f7d185d70..fe5c62afd 100644 --- a/Engine/source/sfx/sfxSystem.cpp +++ b/Engine/source/sfx/sfxSystem.cpp @@ -48,6 +48,8 @@ #include "sfx/media/sfxVorbisStream.h" #endif +#include "sfx/media/sfxSndStream.h" + MODULE_BEGIN( SFX ) @@ -355,7 +357,7 @@ void SFXSystem::init() // the order here does matter! SFXFileStream::registerExtension( ".wav", ( SFXFILESTREAM_CREATE_FN ) SFXWavStream::create ); #ifdef TORQUE_OGGVORBIS - SFXFileStream::registerExtension( ".ogg", ( SFXFILESTREAM_CREATE_FN ) SFXVorbisStream::create ); + SFXFileStream::registerExtension( ".ogg", ( SFXFILESTREAM_CREATE_FN ) SFXSndStream::create ); #endif // Create the stream thread pool.