Redesigned the audio encoding/decoding classes to get rid of libsndfile

This commit is contained in:
Laurent Gomila 2014-07-20 17:48:40 +02:00 committed by Mario Liebisch
parent 34692d5a39
commit f0608eaed8
68 changed files with 4523 additions and 2241 deletions

View file

@ -21,8 +21,10 @@ set(SRC
${INCROOT}/SoundBuffer.hpp
${SRCROOT}/SoundBufferRecorder.cpp
${INCROOT}/SoundBufferRecorder.hpp
${SRCROOT}/SoundFile.cpp
${SRCROOT}/SoundFile.hpp
${SRCROOT}/InputSoundFile.cpp
${INCROOT}/InputSoundFile.hpp
${SRCROOT}/OutputSoundFile.cpp
${INCROOT}/OutputSoundFile.hpp
${SRCROOT}/SoundRecorder.cpp
${INCROOT}/SoundRecorder.hpp
${SRCROOT}/SoundSource.cpp
@ -32,36 +34,52 @@ set(SRC
)
source_group("" FILES ${SRC})
set(CODECS_SRC
${SRCROOT}/SoundFileFactory.cpp
${INCROOT}/SoundFileFactory.hpp
${INCROOT}/SoundFileFactory.inl
${INCROOT}/SoundFileReader.hpp
${SRCROOT}/SoundFileReaderOgg.hpp
${SRCROOT}/SoundFileReaderOgg.cpp
${SRCROOT}/SoundFileReaderWav.hpp
${SRCROOT}/SoundFileReaderWav.cpp
${INCROOT}/SoundFileWriter.hpp
${SRCROOT}/SoundFileWriterWav.hpp
${SRCROOT}/SoundFileWriterWav.cpp
${SRCROOT}/SoundFileWriterOgg.hpp
${SRCROOT}/SoundFileWriterOgg.cpp
)
source_group("codecs" FILES ${CODECS_SRC})
# let CMake know about our additional audio libraries paths (on Windows and OSX)
if(SFML_OS_WINDOWS)
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/AL")
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libsndfile/windows")
elseif(SFML_OS_MACOSX)
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libsndfile/osx")
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-osx/Frameworks")
elseif(SFML_OS_ANDROID)
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/AL")
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libsndfile/android")
endif()
# find external libraries
if(NOT SFML_OS_ANDROID)
find_package(OpenAL REQUIRED)
find_package(Sndfile REQUIRED)
find_package(Vorbis REQUIRED)
else()
find_host_package(OpenAL REQUIRED)
find_host_package(Sndfile REQUIRED)
find_host_package(Vorbis REQUIRED)
endif()
include_directories(${OPENAL_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
include_directories(${OPENAL_INCLUDE_DIR})
include_directories(${VORBIS_INCLUDE_DIRS})
add_definitions(-DOV_EXCLUDE_STATIC_CALLBACKS) # avoids warnings in vorbisfile.h
# build the list of external libraries to link
if(SFML_OS_ANDROID)
list(APPEND AUDIO_EXT_LIBS android OpenSLES)
endif()
list(APPEND AUDIO_EXT_LIBS ${OPENAL_LIBRARY} ${SNDFILE_LIBRARY})
list(APPEND AUDIO_EXT_LIBS ${OPENAL_LIBRARY} ${VORBIS_LIBRARIES})
# define the sfml-audio target
sfml_add_library(sfml-audio
SOURCES ${SRC}
SOURCES ${SRC} ${CODECS_SRC}
DEPENDS sfml-system
EXTERNAL_LIBS ${AUDIO_EXT_LIBS})

View file

@ -0,0 +1,257 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/InputSoundFile.hpp>
#include <SFML/Audio/SoundFileReader.hpp>
#include <SFML/Audio/SoundFileFactory.hpp>
#include <SFML/System/InputStream.hpp>
#include <SFML/System/FileInputStream.hpp>
#include <SFML/System/MemoryInputStream.hpp>
#include <SFML/System/Err.hpp>
namespace sf
{
////////////////////////////////////////////////////////////
InputSoundFile::InputSoundFile() :
m_reader (NULL),
m_stream (NULL),
m_streamOwned (false),
m_sampleCount (0),
m_channelCount(0),
m_sampleRate (0)
{
}
////////////////////////////////////////////////////////////
InputSoundFile::~InputSoundFile()
{
// Close the file in case it was open
close();
}
////////////////////////////////////////////////////////////
bool InputSoundFile::openFromFile(const std::string& filename)
{
// If the file is already open, first close it
close();
// Find a suitable reader for the file type
m_reader = SoundFileFactory::createReaderFromFilename(filename);
if (!m_reader)
{
err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl;
return false;
}
// Wrap the file into a stream
FileInputStream* file = new FileInputStream;
m_stream = file;
m_streamOwned = true;
// Open it
if (!file->open(filename))
{
close();
return false;
}
// Pass the stream to the reader
SoundFileReader::Info info;
if (!m_reader->open(*file, info))
{
close();
return false;
}
// Retrieve the attributes of the open sound file
m_sampleCount = info.sampleCount;
m_channelCount = info.channelCount;
m_sampleRate = info.sampleRate;
return true;
}
////////////////////////////////////////////////////////////
bool InputSoundFile::openFromMemory(const void* data, std::size_t sizeInBytes)
{
// If the file is already open, first close it
close();
// Find a suitable reader for the file type
m_reader = SoundFileFactory::createReaderFromMemory(data, sizeInBytes);
if (!m_reader)
{
err() << "Failed to open sound file from memory (format not supported)" << std::endl;
return false;
}
// Wrap the memory file into a stream
MemoryInputStream* memory = new MemoryInputStream;
m_stream = memory;
m_streamOwned = true;
// Open it
memory->open(data, sizeInBytes);
// Pass the stream to the reader
SoundFileReader::Info info;
if (!m_reader->open(*memory, info))
{
close();
return false;
}
// Retrieve the attributes of the open sound file
m_sampleCount = info.sampleCount;
m_channelCount = info.channelCount;
m_sampleRate = info.sampleRate;
return true;
}
////////////////////////////////////////////////////////////
bool InputSoundFile::openFromStream(InputStream& stream)
{
// If the file is already open, first close it
close();
// Find a suitable reader for the file type
m_reader = SoundFileFactory::createReaderFromStream(stream);
if (!m_reader)
{
err() << "Failed to open sound file from stream (format not supported)" << std::endl;
return false;
}
// store the stream
m_stream = &stream;
m_streamOwned = false;
// Don't forget to reset the stream to its beginning before re-opening it
if (stream.seek(0) != 0)
{
err() << "Failed to open sound file from stream (cannot restart stream)" << std::endl;
return false;
}
// Pass the stream to the reader
SoundFileReader::Info info;
if (!m_reader->open(stream, info))
{
close();
return false;
}
// Retrieve the attributes of the open sound file
m_sampleCount = info.sampleCount;
m_channelCount = info.channelCount;
m_sampleRate = info.sampleRate;
return true;
}
////////////////////////////////////////////////////////////
Uint64 InputSoundFile::getSampleCount() const
{
return m_sampleCount;
}
////////////////////////////////////////////////////////////
unsigned int InputSoundFile::getChannelCount() const
{
return m_channelCount;
}
////////////////////////////////////////////////////////////
unsigned int InputSoundFile::getSampleRate() const
{
return m_sampleRate;
}
////////////////////////////////////////////////////////////
Time InputSoundFile::getDuration() const
{
return seconds(static_cast<float>(m_sampleCount) / m_channelCount / m_sampleRate);
}
////////////////////////////////////////////////////////////
void InputSoundFile::seek(Uint64 sampleOffset)
{
if (m_reader)
m_reader->seek(sampleOffset);
}
////////////////////////////////////////////////////////////
void InputSoundFile::seek(Time timeOffset)
{
seek(static_cast<Uint64>(timeOffset.asSeconds() * m_sampleRate * m_channelCount));
}
////////////////////////////////////////////////////////////
Uint64 InputSoundFile::read(Int16* samples, Uint64 maxCount)
{
if (m_reader && samples && maxCount)
return m_reader->read(samples, maxCount);
else
return 0;
}
////////////////////////////////////////////////////////////
void InputSoundFile::close()
{
// Destroy the reader
delete m_reader;
m_reader = NULL;
// Destroy the stream if we own it
if (m_streamOwned)
{
delete m_stream;
m_stream = NULL;
m_streamOwned = false;
}
// Reset the sound file attributes
m_sampleCount = 0;
m_channelCount = 0;
m_sampleRate = 0;
}
} // namespace sf

View file

@ -27,7 +27,6 @@
////////////////////////////////////////////////////////////
#include <SFML/Audio/Music.hpp>
#include <SFML/Audio/ALCheck.hpp>
#include <SFML/Audio/SoundFile.hpp>
#include <SFML/System/Lock.hpp>
#include <SFML/System/Err.hpp>
#include <fstream>
@ -37,7 +36,7 @@ namespace sf
{
////////////////////////////////////////////////////////////
Music::Music() :
m_file (new priv::SoundFile),
m_file (),
m_duration()
{
@ -49,8 +48,6 @@ Music::~Music()
{
// We must stop before destroying the file
stop();
delete m_file;
}
@ -61,7 +58,7 @@ bool Music::openFromFile(const std::string& filename)
stop();
// Open the underlying sound file
if (!m_file->openRead(filename))
if (!m_file.openFromFile(filename))
return false;
// Perform common initializations
@ -78,7 +75,7 @@ bool Music::openFromMemory(const void* data, std::size_t sizeInBytes)
stop();
// Open the underlying sound file
if (!m_file->openRead(data, sizeInBytes))
if (!m_file.openFromMemory(data, sizeInBytes))
return false;
// Perform common initializations
@ -95,7 +92,7 @@ bool Music::openFromStream(InputStream& stream)
stop();
// Open the underlying sound file
if (!m_file->openRead(stream))
if (!m_file.openFromStream(stream))
return false;
// Perform common initializations
@ -119,7 +116,7 @@ bool Music::onGetData(SoundStream::Chunk& data)
// Fill the chunk parameters
data.samples = &m_samples[0];
data.sampleCount = m_file->read(&m_samples[0], m_samples.size());
data.sampleCount = static_cast<std::size_t>(m_file.read(&m_samples[0], m_samples.size()));
// Check if we have reached the end of the audio file
return data.sampleCount == m_samples.size();
@ -131,7 +128,7 @@ void Music::onSeek(Time timeOffset)
{
Lock lock(m_mutex);
m_file->seek(timeOffset);
m_file.seek(timeOffset);
}
@ -139,13 +136,13 @@ void Music::onSeek(Time timeOffset)
void Music::initialize()
{
// Compute the music duration
m_duration = seconds(static_cast<float>(m_file->getSampleCount()) / m_file->getSampleRate() / m_file->getChannelCount());
m_duration = m_file.getDuration();
// Resize the internal buffer so that it can contain 1 second of audio samples
m_samples.resize(m_file->getSampleRate() * m_file->getChannelCount());
m_samples.resize(m_file.getSampleRate() * m_file.getChannelCount());
// Initialize the stream
SoundStream::initialize(m_file->getChannelCount(), m_file->getSampleRate());
SoundStream::initialize(m_file.getChannelCount(), m_file.getSampleRate());
}
} // namespace sf

View file

@ -0,0 +1,92 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/OutputSoundFile.hpp>
#include <SFML/Audio/SoundFileWriter.hpp>
#include <SFML/Audio/SoundFileFactory.hpp>
#include <SFML/System/Err.hpp>
namespace sf
{
////////////////////////////////////////////////////////////
OutputSoundFile::OutputSoundFile() :
m_writer(NULL)
{
}
////////////////////////////////////////////////////////////
OutputSoundFile::~OutputSoundFile()
{
// Close the file in case it was open
close();
}
////////////////////////////////////////////////////////////
bool OutputSoundFile::openFromFile(const std::string& filename, unsigned int sampleRate, unsigned int channelCount)
{
// If the file is already open, first close it
close();
// Find a suitable writer for the file type
m_writer = SoundFileFactory::createWriterFromFilename(filename);
if (!m_writer)
{
err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl;
return false;
}
// Pass the stream to the reader
if (!m_writer->open(filename, sampleRate, channelCount))
{
close();
return false;
}
return true;
}
////////////////////////////////////////////////////////////
void OutputSoundFile::write(const Int16* samples, Uint64 count)
{
if (m_writer && samples && count)
m_writer->write(samples, count);
}
////////////////////////////////////////////////////////////
void OutputSoundFile::close()
{
// Destroy the reader
delete m_writer;
m_writer = NULL;
}
} // namespace sf

View file

@ -26,7 +26,8 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundBuffer.hpp>
#include <SFML/Audio/SoundFile.hpp>
#include <SFML/Audio/InputSoundFile.hpp>
#include <SFML/Audio/OutputSoundFile.hpp>
#include <SFML/Audio/Sound.hpp>
#include <SFML/Audio/AudioDevice.hpp>
#include <SFML/Audio/ALCheck.hpp>
@ -77,8 +78,8 @@ SoundBuffer::~SoundBuffer()
////////////////////////////////////////////////////////////
bool SoundBuffer::loadFromFile(const std::string& filename)
{
priv::SoundFile file;
if (file.openRead(filename))
InputSoundFile file;
if (file.openFromFile(filename))
return initialize(file);
else
return false;
@ -88,8 +89,8 @@ bool SoundBuffer::loadFromFile(const std::string& filename)
////////////////////////////////////////////////////////////
bool SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes)
{
priv::SoundFile file;
if (file.openRead(data, sizeInBytes))
InputSoundFile file;
if (file.openFromMemory(data, sizeInBytes))
return initialize(file);
else
return false;
@ -99,8 +100,8 @@ bool SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes)
////////////////////////////////////////////////////////////
bool SoundBuffer::loadFromStream(InputStream& stream)
{
priv::SoundFile file;
if (file.openRead(stream))
InputSoundFile file;
if (file.openFromStream(stream))
return initialize(file);
else
return false;
@ -108,7 +109,7 @@ bool SoundBuffer::loadFromStream(InputStream& stream)
////////////////////////////////////////////////////////////
bool SoundBuffer::loadFromSamples(const Int16* samples, std::size_t sampleCount, unsigned int channelCount, unsigned int sampleRate)
bool SoundBuffer::loadFromSamples(const Int16* samples, Uint64 sampleCount, unsigned int channelCount, unsigned int sampleRate)
{
if (samples && sampleCount && channelCount && sampleRate)
{
@ -137,8 +138,8 @@ bool SoundBuffer::loadFromSamples(const Int16* samples, std::size_t sampleCount,
bool SoundBuffer::saveToFile(const std::string& filename) const
{
// Create the sound file in write mode
priv::SoundFile file;
if (file.openWrite(filename, getChannelCount(), getSampleRate()))
OutputSoundFile file;
if (file.openFromFile(filename, getSampleRate(), getChannelCount()))
{
// Write the samples to the opened file
file.write(&m_samples[0], m_samples.size());
@ -160,7 +161,7 @@ const Int16* SoundBuffer::getSamples() const
////////////////////////////////////////////////////////////
std::size_t SoundBuffer::getSampleCount() const
Uint64 SoundBuffer::getSampleCount() const
{
return m_samples.size();
}
@ -208,15 +209,15 @@ SoundBuffer& SoundBuffer::operator =(const SoundBuffer& right)
////////////////////////////////////////////////////////////
bool SoundBuffer::initialize(priv::SoundFile& file)
bool SoundBuffer::initialize(InputSoundFile& file)
{
// Retrieve the sound parameters
std::size_t sampleCount = file.getSampleCount();
Uint64 sampleCount = file.getSampleCount();
unsigned int channelCount = file.getChannelCount();
unsigned int sampleRate = file.getSampleRate();
// Read the samples from the provided file
m_samples.resize(sampleCount);
m_samples.resize(static_cast<std::size_t>(sampleCount));
if (file.read(&m_samples[0], sampleCount) == sampleCount)
{
// Update the internal buffer with the new samples

View file

@ -1,231 +0,0 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_SOUNDFILE_HPP
#define SFML_SOUNDFILE_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/NonCopyable.hpp>
#include <SFML/System/Time.hpp>
#include <sndfile.h>
#include <string>
namespace sf
{
class InputStream;
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Provide read and write access to sound files
///
////////////////////////////////////////////////////////////
class SoundFile : NonCopyable
{
public:
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
SoundFile();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~SoundFile();
////////////////////////////////////////////////////////////
/// \brief Get the total number of audio samples in the file
///
/// \return Number of samples
///
////////////////////////////////////////////////////////////
std::size_t getSampleCount() const;
////////////////////////////////////////////////////////////
/// \brief Get the number of channels used by the sound
///
/// \return Number of channels (1 = mono, 2 = stereo)
///
////////////////////////////////////////////////////////////
unsigned int getChannelCount() const;
////////////////////////////////////////////////////////////
/// \brief Get the sample rate of the sound
///
/// \return Sample rate, in samples per second
///
////////////////////////////////////////////////////////////
unsigned int getSampleRate() const;
////////////////////////////////////////////////////////////
/// \brief Open a sound file for reading
///
/// \param filename Path of the sound file to load
///
/// \return True if the file was successfully opened
///
////////////////////////////////////////////////////////////
bool openRead(const std::string& filename);
////////////////////////////////////////////////////////////
/// \brief Open a sound file in memory for reading
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \return True if the file was successfully opened
///
////////////////////////////////////////////////////////////
bool openRead(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Open a sound file from a custom stream for reading
///
/// \param stream Source stream to read from
///
/// \return True if the file was successfully opened
///
////////////////////////////////////////////////////////////
bool openRead(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief a the sound file for writing
///
/// \param filename Path of the sound file to write
/// \param channelCount Number of channels in the sound
/// \param sampleRate Sample rate of the sound
///
/// \return True if the file was successfully opened
///
////////////////////////////////////////////////////////////
bool openWrite(const std::string& filename, unsigned int channelCount, unsigned int sampleRate);
////////////////////////////////////////////////////////////
/// \brief Read audio samples from the loaded sound
///
/// \param data Pointer to the sample array to fill
/// \param sampleCount Number of samples to read
///
/// \return Number of samples actually read (may be less than \a sampleCount)
///
////////////////////////////////////////////////////////////
std::size_t read(Int16* data, std::size_t sampleCount);
////////////////////////////////////////////////////////////
/// \brief Write audio samples to the file
///
/// \param data Pointer to the sample array to write
/// \param sampleCount Number of samples to write
///
////////////////////////////////////////////////////////////
void write(const Int16* data, std::size_t sampleCount);
////////////////////////////////////////////////////////////
/// \brief Change the current read position in the file
///
/// \param timeOffset New playing position, from the beginning of the file
///
////////////////////////////////////////////////////////////
void seek(Time timeOffset);
private:
////////////////////////////////////////////////////////////
/// \brief Initialize the internal state of the sound file
///
/// This function is called by all the openRead functions.
///
/// \param fileInfo Information about the loaded sound file
///
////////////////////////////////////////////////////////////
void initialize(SF_INFO fileInfo);
////////////////////////////////////////////////////////////
/// \brief Get the internal format of an audio file according to
/// its filename extension
///
/// \param filename Filename to check
///
/// \return Internal format matching the filename (-1 if no match)
///
////////////////////////////////////////////////////////////
static int getFormatFromFilename(const std::string& filename);
////////////////////////////////////////////////////////////
/// \brief Data and callbacks for opening from memory
///
////////////////////////////////////////////////////////////
struct Memory
{
const char* begin;
const char* current;
sf_count_t size;
static sf_count_t getLength(void* user);
static sf_count_t read(void* ptr, sf_count_t count, void* user);
static sf_count_t seek(sf_count_t offset, int whence, void* user);
static sf_count_t tell(void* user);
};
////////////////////////////////////////////////////////////
/// \brief Data and callbacks for opening from stream
///
////////////////////////////////////////////////////////////
struct Stream
{
InputStream* source;
Int64 size;
static sf_count_t getLength(void* user);
static sf_count_t read(void* ptr, sf_count_t count, void* user);
static sf_count_t seek(sf_count_t offset, int whence, void* user);
static sf_count_t tell(void* user);
};
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
SNDFILE* m_file; ///< File descriptor
Memory m_memory; ///< Memory reading info
Stream m_stream; ///< Stream reading info
std::size_t m_sampleCount; ///< Total number of samples in the file
unsigned int m_channelCount; ///< Number of channels used by the sound
unsigned int m_sampleRate; ///< Number of samples per second
#ifdef SFML_SYSTEM_ANDROID
void* m_resourceStream; ///< Asset file streamer (if loaded from file)
#endif
};
} // namespace priv
} // namespace sf
#endif // SFML_SOUNDFILE_HPP

View file

@ -0,0 +1,142 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileFactory.hpp>
#include <SFML/Audio/SoundFileReaderOgg.hpp>
#include <SFML/Audio/SoundFileWriterOgg.hpp>
#include <SFML/Audio/SoundFileReaderWav.hpp>
#include <SFML/Audio/SoundFileWriterWav.hpp>
#include <SFML/System/FileInputStream.hpp>
#include <SFML/System/MemoryInputStream.hpp>
namespace
{
// register all the built-in readers and writers if not already done
void ensureDefaultReadersWritersRegistered()
{
static bool registered = false;
if (!registered)
{
sf::SoundFileFactory::registerReader<sf::priv::SoundFileReaderOgg>();
sf::SoundFileFactory::registerWriter<sf::priv::SoundFileWriterOgg>();
sf::SoundFileFactory::registerReader<sf::priv::SoundFileReaderWav>();
sf::SoundFileFactory::registerWriter<sf::priv::SoundFileWriterWav>();
registered = true;
}
}
}
namespace sf
{
SoundFileFactory::ReaderFactoryArray SoundFileFactory::s_readers;
SoundFileFactory::WriterFactoryArray SoundFileFactory::s_writers;
////////////////////////////////////////////////////////////
SoundFileReader* SoundFileFactory::createReaderFromFilename(const std::string& filename)
{
// Register the built-in readers/writers on first call
ensureDefaultReadersWritersRegistered();
// Wrap the input file into a file stream
FileInputStream stream;
if (!stream.open(filename))
return NULL;
// Test the filename in all the registered factories
for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it)
{
stream.seek(0);
if (it->check(stream))
return it->create();
}
// No suitable reader found
return NULL;
}
////////////////////////////////////////////////////////////
SoundFileReader* SoundFileFactory::createReaderFromMemory(const void* data, std::size_t sizeInBytes)
{
// Register the built-in readers/writers on first call
ensureDefaultReadersWritersRegistered();
// Wrap the memory file into a file stream
MemoryInputStream stream;
stream.open(data, sizeInBytes);
// Test the filename in all the registered factories
for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it)
{
stream.seek(0);
if (it->check(stream))
return it->create();
}
// No suitable reader found
return NULL;
}
////////////////////////////////////////////////////////////
SoundFileReader* SoundFileFactory::createReaderFromStream(InputStream& stream)
{
// Register the built-in readers/writers on first call
ensureDefaultReadersWritersRegistered();
// Test the filename in all the registered factories
for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it)
{
if (it->check(stream))
return it->create();
}
// No suitable reader found
return NULL;
}
////////////////////////////////////////////////////////////
SoundFileWriter* SoundFileFactory::createWriterFromFilename(const std::string& filename)
{
// Register the built-in readers/writers on first call
ensureDefaultReadersWritersRegistered();
// Test the filename in all the registered factories
for (WriterFactoryArray::const_iterator it = s_writers.begin(); it != s_writers.end(); ++it)
{
if (it->check(filename))
return it->create();
}
// No suitable writer found
return NULL;
}
} // namespace sf

View file

@ -0,0 +1,179 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileReaderOgg.hpp>
#include <SFML/System/MemoryInputStream.hpp>
#include <SFML/System/Err.hpp>
#include <algorithm>
#include <cctype>
#include <cassert>
namespace
{
size_t read(void* ptr, size_t size, size_t nmemb, void* data)
{
sf::InputStream* stream = static_cast<sf::InputStream*>(data);
return static_cast<std::size_t>(stream->read(ptr, size * nmemb));
}
int seek(void* data, ogg_int64_t offset, int whence)
{
sf::InputStream* stream = static_cast<sf::InputStream*>(data);
switch (whence)
{
case SEEK_SET:
break;
case SEEK_CUR:
offset += stream->tell();
break;
case SEEK_END:
offset = stream->getSize() - offset;
}
return static_cast<int>(stream->seek(offset));
}
long tell(void* data)
{
sf::InputStream* stream = static_cast<sf::InputStream*>(data);
return static_cast<long>(stream->tell());
}
static ov_callbacks callbacks = {&read, &seek, NULL, &tell};
}
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
bool SoundFileReaderOgg::check(InputStream& stream)
{
OggVorbis_File file;
if (ov_test_callbacks(&stream, &file, NULL, 0, callbacks) == 0)
{
ov_clear(&file);
return true;
}
else
{
return false;
}
}
////////////////////////////////////////////////////////////
SoundFileReaderOgg::SoundFileReaderOgg() :
m_vorbis (),
m_channelCount(0)
{
m_vorbis.datasource = NULL;
}
////////////////////////////////////////////////////////////
SoundFileReaderOgg::~SoundFileReaderOgg()
{
close();
}
////////////////////////////////////////////////////////////
bool SoundFileReaderOgg::open(InputStream& stream, Info& info)
{
// Open the Vorbis stream
int status = ov_open_callbacks(&stream, &m_vorbis, NULL, 0, callbacks);
if (status < 0)
{
err() << "Failed to open Vorbis file for reading" << std::endl;
return false;
}
// Retrieve the music attributes
vorbis_info* vorbisInfo = ov_info(&m_vorbis, -1);
info.channelCount = vorbisInfo->channels;
info.sampleRate = vorbisInfo->rate;
info.sampleCount = static_cast<std::size_t>(ov_pcm_total(&m_vorbis, -1) * vorbisInfo->channels);
// We must keep the channel count for the seek function
m_channelCount = info.channelCount;
return true;
}
////////////////////////////////////////////////////////////
void SoundFileReaderOgg::seek(Uint64 sampleOffset)
{
assert(m_vorbis.datasource);
ov_pcm_seek(&m_vorbis, sampleOffset / m_channelCount);
}
////////////////////////////////////////////////////////////
Uint64 SoundFileReaderOgg::read(Int16* samples, Uint64 maxCount)
{
assert(m_vorbis.datasource);
// Try to read the requested number of samples, stop only on error or end of file
Uint64 count = 0;
while (count < maxCount)
{
int bytesToRead = static_cast<int>(maxCount - count) * sizeof(Int16);
long bytesRead = ov_read(&m_vorbis, reinterpret_cast<char*>(samples), bytesToRead, 0, 2, 1, NULL);
if (bytesRead > 0)
{
long samplesRead = bytesRead / sizeof(Int16);
count += samplesRead;
samples += samplesRead;
}
else
{
// error or end of file
break;
}
}
return count;
}
////////////////////////////////////////////////////////////
void SoundFileReaderOgg::close()
{
if (m_vorbis.datasource)
{
ov_clear(&m_vorbis);
m_vorbis.datasource = NULL;
m_channelCount = 0;
}
}
} // namespace priv
} // namespace sf

View file

@ -0,0 +1,124 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_SOUNDFILEREADEROGG_HPP
#define SFML_SOUNDFILEREADEROGG_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileReader.hpp>
#include <vorbis/vorbisfile.h>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Implementation of sound file reader that handles ogg/vorbis files
///
////////////////////////////////////////////////////////////
class SoundFileReaderOgg : public SoundFileReader
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if this reader can handle a file given by an input stream
///
/// \param stream Source stream to check
///
/// \return True if the file is supported by this reader
///
////////////////////////////////////////////////////////////
static bool check(InputStream& stream);
public :
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
SoundFileReaderOgg();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~SoundFileReaderOgg();
////////////////////////////////////////////////////////////
/// \brief Open a sound file for reading
///
/// \param stream Source stream to read from
/// \param info Structure to fill with the properties of the loaded sound
///
/// \return True if the file was successfully opened
///
////////////////////////////////////////////////////////////
virtual bool open(InputStream& stream, Info& info);
////////////////////////////////////////////////////////////
/// \brief Change the current read position to the given sample offset
///
/// If the given offset exceeds to total number of samples,
/// this function must jump to the end of the file.
///
/// \param sampleOffset Index of the sample to jump to, relative to the beginning
///
////////////////////////////////////////////////////////////
virtual void seek(Uint64 sampleOffset);
////////////////////////////////////////////////////////////
/// \brief Read audio samples from the open file
///
/// \param samples Pointer to the sample array to fill
/// \param maxCount Maximum number of samples to read
///
/// \return Number of samples actually read (may be less than \a maxCount)
///
////////////////////////////////////////////////////////////
virtual Uint64 read(Int16* samples, Uint64 maxCount);
private:
////////////////////////////////////////////////////////////
/// \brief Close the open Vorbis file
///
////////////////////////////////////////////////////////////
void close();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
OggVorbis_File m_vorbis; // ogg/vorbis file handle
unsigned int m_channelCount; // number of channels of the open sound file
};
} // namespace priv
} // namespace sf
#endif // SFML_SOUNDFILEREADEROGG_HPP

View file

@ -0,0 +1,266 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileReaderWav.hpp>
#include <SFML/System/InputStream.hpp>
#include <SFML/System/Err.hpp>
#include <algorithm>
#include <cctype>
#include <cassert>
namespace
{
// The following functions read integers as little endian and
// return them in the host byte order
bool decode(sf::InputStream& stream, sf::Uint8& value)
{
return stream.read(&value, sizeof(value)) == sizeof(value);
}
bool decode(sf::InputStream& stream, sf::Int16& value)
{
unsigned char bytes[sizeof(value)];
if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes))
return false;
value = bytes[0] | (bytes[1] << 8);
return true;
}
bool decode(sf::InputStream& stream, sf::Uint16& value)
{
unsigned char bytes[sizeof(value)];
if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes))
return false;
value = bytes[0] | (bytes[1] << 8);
return true;
}
bool decode(sf::InputStream& stream, sf::Uint32& value)
{
unsigned char bytes[sizeof(value)];
if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes))
return false;
value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
return true;
}
const sf::Uint64 mainChunkSize = 12;
}
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
bool SoundFileReaderWav::check(InputStream& stream)
{
char header[mainChunkSize];
if (stream.read(header, sizeof(header)) < sizeof(header))
return false;
return (header[0] == 'R') && (header[1] == 'I') && (header[2] == 'F') && (header[3] == 'F')
&& (header[8] == 'W') && (header[9] == 'A') && (header[10] == 'V') && (header[11] == 'E');
}
////////////////////////////////////////////////////////////
SoundFileReaderWav::SoundFileReaderWav() :
m_stream (NULL),
m_bytesPerSample(0),
m_dataStart (0)
{
}
////////////////////////////////////////////////////////////
bool SoundFileReaderWav::open(InputStream& stream, Info& info)
{
m_stream = &stream;
if (!parseHeader(info))
{
err() << "Failed to open WAV sound file (invalid or unsupported file)" << std::endl;
return false;
}
return true;
}
////////////////////////////////////////////////////////////
void SoundFileReaderWav::seek(Uint64 sampleOffset)
{
assert(m_stream);
m_stream->seek(m_dataStart + sampleOffset * m_bytesPerSample);
}
////////////////////////////////////////////////////////////
Uint64 SoundFileReaderWav::read(Int16* samples, Uint64 maxCount)
{
assert(m_stream);
Uint64 count = 0;
while (count < maxCount)
{
switch (m_bytesPerSample)
{
case 1:
{
Uint8 sample = 0;
if (decode(*m_stream, sample))
*samples++ = (static_cast<Int16>(sample) - 128) << 8;
else
return count;
break;
}
case 2:
{
Int16 sample = 0;
if (decode(*m_stream, sample))
*samples++ = sample;
else
return count;
break;
}
}
++count;
}
return count;
}
////////////////////////////////////////////////////////////
bool SoundFileReaderWav::parseHeader(Info& info)
{
assert(m_stream);
// If we are here, it means that the first part of the header
// (the format) has already been checked
char mainChunk[mainChunkSize];
if (m_stream->read(mainChunk, sizeof(mainChunk)) != sizeof(mainChunk))
return false;
// Parse all the sub-chunks
bool dataChunkFound = false;
while (!dataChunkFound)
{
// Parse the sub-chunk id and size
char subChunkId[4];
if (m_stream->read(subChunkId, sizeof(subChunkId)) != sizeof(subChunkId))
return false;
Uint32 subChunkSize = 0;
if (!decode(*m_stream, subChunkSize))
return false;
// Check which chunk it is
if ((subChunkId[0] == 'f') && (subChunkId[1] == 'm') && (subChunkId[2] == 't') && (subChunkId[3] == ' '))
{
// "fmt" chunk
// Audio format
Uint16 format = 0;
if (!decode(*m_stream, format))
return false;
if (format != 1) // PCM
return false;
// Channel count
Uint16 channelCount = 0;
if (!decode(*m_stream, channelCount))
return false;
info.channelCount = channelCount;
// Sample rate
Uint32 sampleRate = 0;
if (!decode(*m_stream, sampleRate))
return false;
info.sampleRate = sampleRate;
// Byte rate
Uint32 byteRate = 0;
if (!decode(*m_stream, byteRate))
return false;
// Block align
Uint16 blockAlign = 0;
if (!decode(*m_stream, blockAlign))
return false;
// Bits per sample
Uint16 bitsPerSample = 0;
if (!decode(*m_stream, bitsPerSample))
return false;
m_bytesPerSample = bitsPerSample / 8;
// Skip potential extra information (should not exist for PCM)
if (subChunkSize > 16)
{
char buffer[1024];
if (m_stream->read(buffer, subChunkSize - 16) != subChunkSize - 16)
return false;
}
}
else if ((subChunkId[0] == 'd') && (subChunkId[1] == 'a') && (subChunkId[2] == 't') && (subChunkId[3] == 'a'))
{
// "data" chunk
// Compute the total number of samples
info.sampleCount = subChunkSize / info.channelCount / m_bytesPerSample;
// Store the starting position of samples in the file
m_dataStart = m_stream->tell();
dataChunkFound = true;
}
else
{
// unknown chunk, skip it
char buffer[1024];
if (m_stream->read(buffer, subChunkSize) != subChunkSize)
return false;
}
}
return true;
}
} // namespace priv
} // namespace sf

View file

@ -0,0 +1,121 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_SOUNDFILEREADERWAV_HPP
#define SFML_SOUNDFILEREADERWAV_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileReader.hpp>
#include <string>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Implementation of sound file reader that handles wav files
///
////////////////////////////////////////////////////////////
class SoundFileReaderWav : public SoundFileReader
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if this reader can handle a file given by an input stream
///
/// \param stream Source stream to check
///
/// \return True if the file is supported by this reader
///
////////////////////////////////////////////////////////////
static bool check(InputStream& stream);
public :
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
SoundFileReaderWav();
////////////////////////////////////////////////////////////
/// \brief Open a sound file for reading
///
/// \param stream Stream to open
/// \param info Structure to fill with the attributes of the loaded sound
///
////////////////////////////////////////////////////////////
virtual bool open(sf::InputStream& stream, Info& info);
////////////////////////////////////////////////////////////
/// \brief Change the current read position to the given sample offset
///
/// If the given offset exceeds to total number of samples,
/// this function must jump to the end of the file.
///
/// \param sampleOffset Index of the sample to jump to, relative to the beginning
///
////////////////////////////////////////////////////////////
virtual void seek(Uint64 sampleOffset);
////////////////////////////////////////////////////////////
/// \brief Read audio samples from the open file
///
/// \param samples Pointer to the sample array to fill
/// \param maxCount Maximum number of samples to read
///
/// \return Number of samples actually read (may be less than \a maxCount)
///
////////////////////////////////////////////////////////////
virtual Uint64 read(Int16* samples, Uint64 maxCount);
private:
////////////////////////////////////////////////////////////
/// \brief Read the header of the open file
///
/// \param info Attributes of the sound file
///
/// \return True on success, false on error
///
////////////////////////////////////////////////////////////
bool parseHeader(Info& info);
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
InputStream* m_stream; ///< Source stream to read from
unsigned int m_bytesPerSample; ///< Size of a sample, in bytes
Uint64 m_dataStart; ///< Starting position of the audio data in the open file
};
} // namespace priv
} // namespace sf
#endif // SFML_SOUNDFILEREADERWAV_HPP

View file

@ -0,0 +1,206 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileWriterOgg.hpp>
#include <SFML/System/Err.hpp>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <cassert>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
bool SoundFileWriterOgg::check(const std::string& filename)
{
std::string extension = filename.substr(filename.find_last_of(".") + 1);
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
return extension == "ogg";
}
////////////////////////////////////////////////////////////
SoundFileWriterOgg::SoundFileWriterOgg() :
m_channelCount(0),
m_file (),
m_ogg (),
m_vorbis (),
m_state ()
{
}
////////////////////////////////////////////////////////////
SoundFileWriterOgg::~SoundFileWriterOgg()
{
close();
}
////////////////////////////////////////////////////////////
bool SoundFileWriterOgg::open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount)
{
// Save the channel count
m_channelCount = channelCount;
// Initialize the ogg/vorbis stream
ogg_stream_init(&m_ogg, std::rand());
vorbis_info_init(&m_vorbis);
// Setup the encoder: VBR, automatic bitrate management
// Quality is in range [-1 .. 1], 0.4 gives ~128 kbps for a 44 KHz stereo sound
int status = vorbis_encode_init_vbr(&m_vorbis, channelCount, sampleRate, 0.4f);
if (status < 0)
{
err() << "Failed to write ogg/vorbis file \"" << filename << "\" (unsupported bitrate)" << std::endl;
close();
return false;
}
vorbis_analysis_init(&m_state, &m_vorbis);
// Open the file after the vorbis setup is ok
m_file.open(filename.c_str(), std::ios::binary);
if (!m_file)
{
err() << "Failed to write ogg/vorbis file \"" << filename << "\" (cannot open file)" << std::endl;
close();
return false;
}
// Generate header metadata (leave it empty)
vorbis_comment comment;
vorbis_comment_init(&comment);
// Generate the header packets
ogg_packet header, headerComm, headerCode;
status = vorbis_analysis_headerout(&m_state, &comment, &header, &headerComm, &headerCode);
vorbis_comment_clear(&comment);
if (status < 0)
{
err() << "Failed to write ogg/vorbis file \"" << filename << "\" (cannot generate the headers)" << std::endl;
close();
return false;
}
// Write the header packets to the ogg stream
ogg_stream_packetin(&m_ogg, &header);
ogg_stream_packetin(&m_ogg, &headerComm);
ogg_stream_packetin(&m_ogg, &headerCode);
// This ensures the actual audio data will start on a new page, as per spec
ogg_page page;
while (ogg_stream_flush(&m_ogg, &page) > 0)
{
m_file.write(reinterpret_cast<const char*>(page.header), page.header_len);
m_file.write(reinterpret_cast<const char*>(page.body), page.body_len);
}
return true;
}
////////////////////////////////////////////////////////////
void SoundFileWriterOgg::write(const Int16* samples, Uint64 count)
{
// Prepare a buffer to hold our samples
int frameCount = static_cast<int>(count / m_channelCount);
float** buffer = vorbis_analysis_buffer(&m_state, frameCount);
assert(buffer);
// Write the samples to the buffer, converted to float
for (int i = 0; i < frameCount; ++i)
for (unsigned int j = 0; j < m_channelCount; ++j)
buffer[j][i] = *samples++ / 32767.0f;
// Tell the library how many samples we've written
vorbis_analysis_wrote(&m_state, frameCount);
// Flush any produced block
flushBlocks();
}
////////////////////////////////////////////////////////////
void SoundFileWriterOgg::flushBlocks()
{
// Let the library divide uncompressed data into blocks, and process them
vorbis_block block;
vorbis_block_init(&m_state, &block);
while (vorbis_analysis_blockout(&m_state, &block) == 1)
{
// Let the automatic bitrate management do its job
vorbis_analysis(&block, NULL);
vorbis_bitrate_addblock(&block);
// Get new packets from the bitrate management engine
ogg_packet packet;
while (vorbis_bitrate_flushpacket(&m_state, &packet))
{
// Write the packet to the ogg stream
ogg_stream_packetin(&m_ogg, &packet);
// If the stream produced new pages, write them to the output file
ogg_page page;
while (ogg_stream_flush(&m_ogg, &page) > 0)
{
m_file.write(reinterpret_cast<const char*>(page.header), page.header_len);
m_file.write(reinterpret_cast<const char*>(page.body), page.body_len);
}
}
}
// Clear the allocated block
vorbis_block_clear(&block);
}
////////////////////////////////////////////////////////////
void SoundFileWriterOgg::close()
{
if (m_file.is_open())
{
// Submit an empty packet to mark the end of stream
vorbis_analysis_wrote(&m_state, 0);
flushBlocks();
// Close the file
m_file.close();
}
// Clear all the ogg/vorbis structures
ogg_stream_clear(&m_ogg);
vorbis_dsp_clear(&m_state);
vorbis_info_clear(&m_vorbis);
}
} // namespace priv
} // namespace sf

View file

@ -0,0 +1,122 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_SOUNDFILEWRITEROGG_HPP
#define SFML_SOUNDFILEWRITEROGG_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileWriter.hpp>
#include <vorbis/vorbisenc.h>
#include <fstream>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Implementation of sound file writer that handles ogg files
///
////////////////////////////////////////////////////////////
class SoundFileWriterOgg : public SoundFileWriter
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if this writer can handle a file on disk
///
/// \param filename Path of the sound file to check
///
/// \return True if the file can be written by this writer
///
////////////////////////////////////////////////////////////
static bool check(const std::string& filename);
public :
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
SoundFileWriterOgg();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~SoundFileWriterOgg();
////////////////////////////////////////////////////////////
/// \brief Open a sound file for writing
///
/// \param filename Path of the file to open
/// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels of the sound
///
/// \return True if the file was successfully opened
///
////////////////////////////////////////////////////////////
virtual bool open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount);
////////////////////////////////////////////////////////////
/// \brief Write audio samples to the open file
///
/// \param samples Pointer to the sample array to write
/// \param count Number of samples to write
///
////////////////////////////////////////////////////////////
virtual void write(const Int16* samples, Uint64 count);
private:
////////////////////////////////////////////////////////////
/// \brief Flush blocks produced by the ogg stream, if any
///
////////////////////////////////////////////////////////////
void flushBlocks();
////////////////////////////////////////////////////////////
/// \brief Close the file
///
////////////////////////////////////////////////////////////
void close();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
unsigned int m_channelCount; // channel count of the sound being written
std::ofstream m_file; // output file
ogg_stream_state m_ogg; // ogg stream
vorbis_info m_vorbis; // vorbis handle
vorbis_dsp_state m_state; // current encoding state
};
} // namespace priv
} // namespace sf
#endif // SFML_SOUNDFILEWRITEROGG_HPP

View file

@ -0,0 +1,207 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileWriterWav.hpp>
#include <SFML/System/Err.hpp>
#include <algorithm>
#include <cctype>
#include <cassert>
namespace
{
// The following functions takes integers in host byte order
// and writes them to a stream as little endian
void encode(std::ostream& stream, sf::Int16 value)
{
unsigned char bytes[] =
{
static_cast<unsigned char>(value & 0xFF),
static_cast<unsigned char>(value >> 8)
};
stream.write(reinterpret_cast<const char*>(bytes), sizeof(bytes));
}
void encode(std::ostream& stream, sf::Uint16 value)
{
unsigned char bytes[] =
{
static_cast<unsigned char>(value & 0xFF),
static_cast<unsigned char>(value >> 8)
};
stream.write(reinterpret_cast<const char*>(bytes), sizeof(bytes));
}
void encode(std::ostream& stream, sf::Uint32 value)
{
unsigned char bytes[] =
{
static_cast<unsigned char>(value & 0x000000FF),
static_cast<unsigned char>((value & 0x0000FF00) >> 8),
static_cast<unsigned char>((value & 0x00FF0000) >> 16),
static_cast<unsigned char>((value & 0xFF000000) >> 24),
};
stream.write(reinterpret_cast<const char*>(bytes), sizeof(bytes));
}
}
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
bool SoundFileWriterWav::check(const std::string& filename)
{
std::string extension = filename.substr(filename.find_last_of(".") + 1);
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
return extension == "wav";
}
////////////////////////////////////////////////////////////
SoundFileWriterWav::SoundFileWriterWav() :
m_file (),
m_sampleCount (0),
m_channelCount(0)
{
}
////////////////////////////////////////////////////////////
SoundFileWriterWav::~SoundFileWriterWav()
{
close();
}
////////////////////////////////////////////////////////////
bool SoundFileWriterWav::open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount)
{
// Open the file
m_file.open(filename.c_str(), std::ios::binary);
if (!m_file)
{
err() << "Failed to open WAV sound file \"" << filename << "\" for writing" << std::endl;
return false;
}
// Write the header
if (!writeHeader(sampleRate, channelCount))
{
err() << "Failed to write header of WAV sound file \"" << filename << "\"" << std::endl;
return false;
}
// Save the channel count
m_channelCount = channelCount;
return true;
}
////////////////////////////////////////////////////////////
void SoundFileWriterWav::write(const Int16* samples, Uint64 count)
{
assert(m_file.good());
m_sampleCount += count;
while (count--)
encode(m_file, *samples++);
}
////////////////////////////////////////////////////////////
bool SoundFileWriterWav::writeHeader(unsigned int sampleRate, unsigned int channelCount)
{
assert(m_file.good());
// Write the main chunk ID
char mainChunkId[4] = {'R', 'I', 'F', 'F'};
m_file.write(mainChunkId, sizeof(mainChunkId));
// Write the main chunk header
Uint32 mainChunkSize = 0; // placeholder, will be written later
encode(m_file, mainChunkSize);
char mainChunkFormat[4] = {'W', 'A', 'V', 'E'};
m_file.write(mainChunkFormat, sizeof(mainChunkFormat));
// Write the sub-chunk 1 ("format") id and size
char fmtChunkId[4] = {'f', 'm', 't', ' '};
m_file.write(fmtChunkId, sizeof(fmtChunkId));
Uint32 fmtChunkSize = 16;
encode(m_file, fmtChunkSize);
// Write the format (PCM)
Uint16 format = 1;
encode(m_file, format);
// Write the sound attributes
encode(m_file, static_cast<Uint16>(channelCount));
encode(m_file, static_cast<Uint32>(sampleRate));
Uint32 byteRate = sampleRate * channelCount * 2;
encode(m_file, byteRate);
Uint16 blockAlign = channelCount * 2;
encode(m_file, blockAlign);
Uint16 bitsPerSample = 16;
encode(m_file, bitsPerSample);
// Write the sub-chunk 2 ("data") id and size
char dataChunkId[4] = {'d', 'a', 't', 'a'};
m_file.write(dataChunkId, sizeof(dataChunkId));
Uint32 dataChunkSize = 0; // placeholder, will be written later
encode(m_file, dataChunkSize);
return true;
}
////////////////////////////////////////////////////////////
void SoundFileWriterWav::close()
{
// If the file is open, finalize the header and close it
if (m_file.is_open())
{
m_file.flush();
// Update the main chunk size and data sub-chunk size
Uint32 dataChunkSize = static_cast<Uint32>(m_sampleCount * m_channelCount * 2);
Uint32 mainChunkSize = dataChunkSize + 36;
m_file.seekp(4);
encode(m_file, mainChunkSize);
m_file.seekp(40);
encode(m_file, dataChunkSize);
m_file.close();
}
}
} // namespace priv
} // namespace sf

View file

@ -0,0 +1,125 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_SOUNDFILEWRITERWAV_HPP
#define SFML_SOUNDFILEWRITERWAV_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Audio/SoundFileWriter.hpp>
#include <fstream>
#include <string>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Implementation of sound file writer that handles wav files
///
////////////////////////////////////////////////////////////
class SoundFileWriterWav : public SoundFileWriter
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if this writer can handle a file on disk
///
/// \param filename Path of the sound file to check
///
/// \return True if the file can be written by this writer
///
////////////////////////////////////////////////////////////
static bool check(const std::string& filename);
public :
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
SoundFileWriterWav();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~SoundFileWriterWav();
////////////////////////////////////////////////////////////
/// \brief Open a sound file for writing
///
/// \param filename Path of the file to open
/// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels of the sound
///
/// \return True if the file was successfully opened
///
////////////////////////////////////////////////////////////
virtual bool open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount);
////////////////////////////////////////////////////////////
/// \brief Write audio samples to the open file
///
/// \param samples Pointer to the sample array to write
/// \param count Number of samples to write
///
////////////////////////////////////////////////////////////
virtual void write(const Int16* samples, Uint64 count);
private:
////////////////////////////////////////////////////////////
/// \brief Write the header of the open file
///
/// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels of the sound
///
/// \return True on success, false on error
///
////////////////////////////////////////////////////////////
bool writeHeader(unsigned int sampleRate, unsigned int channelCount);
////////////////////////////////////////////////////////////
/// \brief Close the file
///
////////////////////////////////////////////////////////////
void close();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
std::ofstream m_file; ///< File stream to write to
Uint64 m_sampleCount; ///< Total number of samples written to the file
unsigned int m_channelCount; ///< Number of channels of the sound
};
} // namespace priv
} // namespace sf
#endif // SFML_SOUNDFILEWRITERWAV_HPP

View file

@ -35,6 +35,10 @@ set(SRC
${INCROOT}/Vector2.inl
${INCROOT}/Vector3.hpp
${INCROOT}/Vector3.inl
${SRCROOT}/FileInputStream.cpp
${INCROOT}/FileInputStream.hpp
${SRCROOT}/MemoryInputStream.cpp
${INCROOT}/MemoryInputStream.hpp
)
source_group("" FILES ${SRC})

View file

@ -0,0 +1,76 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/FileInputStream.hpp>
namespace sf
{
////////////////////////////////////////////////////////////
bool FileInputStream::open(const std::string& filename)
{
m_file.open(filename.c_str(), std::ios::binary);
return m_file.good();
}
////////////////////////////////////////////////////////////
Int64 FileInputStream::read(void* data, Int64 size)
{
m_file.read(static_cast<char*>(data), size);
return m_file.gcount();
}
////////////////////////////////////////////////////////////
Int64 FileInputStream::seek(Int64 position)
{
if (m_file.eof())
m_file.clear();
m_file.seekg(position);
return tell();
}
////////////////////////////////////////////////////////////
Int64 FileInputStream::tell()
{
return m_file.tellg();
}
////////////////////////////////////////////////////////////
Int64 FileInputStream::getSize()
{
std::ifstream::pos_type pos = m_file.tellg();
m_file.seekg(0, std::ios::end);
std::ifstream::pos_type size = m_file.tellg();
m_file.seekg(pos);
return size;
}
} // namespace sf

View file

@ -0,0 +1,101 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/MemoryInputStream.hpp>
#include <cstring>
namespace sf
{
////////////////////////////////////////////////////////////
MemoryInputStream::MemoryInputStream() :
m_data (NULL),
m_size (0),
m_offset(0)
{
}
////////////////////////////////////////////////////////////
void MemoryInputStream::open(const void* data, std::size_t sizeInBytes)
{
m_data = static_cast<const char*>(data);
m_size = sizeInBytes;
m_offset = 0;
}
////////////////////////////////////////////////////////////
Int64 MemoryInputStream::read(void* data, Int64 size)
{
if (!m_data)
return -1;
Int64 endPosition = m_offset + size;
Int64 count = endPosition <= m_size ? size : m_size - m_offset;
if (count > 0)
{
std::memcpy(data, m_data + m_offset, static_cast<std::size_t>(count));
m_offset += count;
}
return count;
}
////////////////////////////////////////////////////////////
Int64 MemoryInputStream::seek(Int64 position)
{
if (!m_data)
return -1;
m_offset = position < m_size ? position : m_size;
return m_offset;
}
////////////////////////////////////////////////////////////
Int64 MemoryInputStream::tell()
{
if (!m_data)
return -1;
return m_offset;
}
////////////////////////////////////////////////////////////
Int64 MemoryInputStream::getSize()
{
if (!m_data)
return -1;
return m_size;
}
} // namespace sf