Added support for FLAC audio files
This commit is contained in:
parent
6096d22091
commit
5e0e645f46
22 changed files with 8065 additions and 7 deletions
|
@ -39,15 +39,19 @@ set(CODECS_SRC
|
|||
${INCROOT}/SoundFileFactory.hpp
|
||||
${INCROOT}/SoundFileFactory.inl
|
||||
${INCROOT}/SoundFileReader.hpp
|
||||
${SRCROOT}/SoundFileReaderFlac.hpp
|
||||
${SRCROOT}/SoundFileReaderFlac.cpp
|
||||
${SRCROOT}/SoundFileReaderOgg.hpp
|
||||
${SRCROOT}/SoundFileReaderOgg.cpp
|
||||
${SRCROOT}/SoundFileReaderWav.hpp
|
||||
${SRCROOT}/SoundFileReaderWav.cpp
|
||||
${INCROOT}/SoundFileWriter.hpp
|
||||
${SRCROOT}/SoundFileWriterWav.hpp
|
||||
${SRCROOT}/SoundFileWriterWav.cpp
|
||||
${SRCROOT}/SoundFileWriterFlac.hpp
|
||||
${SRCROOT}/SoundFileWriterFlac.cpp
|
||||
${SRCROOT}/SoundFileWriterOgg.hpp
|
||||
${SRCROOT}/SoundFileWriterOgg.cpp
|
||||
${SRCROOT}/SoundFileWriterWav.hpp
|
||||
${SRCROOT}/SoundFileWriterWav.cpp
|
||||
)
|
||||
source_group("codecs" FILES ${CODECS_SRC})
|
||||
|
||||
|
@ -64,19 +68,23 @@ endif()
|
|||
if(NOT SFML_OS_ANDROID)
|
||||
find_package(OpenAL REQUIRED)
|
||||
find_package(Vorbis REQUIRED)
|
||||
find_package(FLAC REQUIRED)
|
||||
else()
|
||||
find_host_package(OpenAL REQUIRED)
|
||||
find_host_package(Vorbis REQUIRED)
|
||||
find_host_package(FLAC REQUIRED)
|
||||
endif()
|
||||
include_directories(${OPENAL_INCLUDE_DIR})
|
||||
include_directories(${VORBIS_INCLUDE_DIRS})
|
||||
include_directories(${FLAC_INCLUDE_DIR})
|
||||
add_definitions(-DOV_EXCLUDE_STATIC_CALLBACKS) # avoids warnings in vorbisfile.h
|
||||
add_definitions(-DFLAC__NO_DLL)
|
||||
|
||||
# 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} ${VORBIS_LIBRARIES})
|
||||
list(APPEND AUDIO_EXT_LIBS ${OPENAL_LIBRARY} ${VORBIS_LIBRARIES} ${FLAC_LIBRARY})
|
||||
|
||||
# define the sfml-audio target
|
||||
sfml_add_library(sfml-audio
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Audio/SoundFileFactory.hpp>
|
||||
#include <SFML/Audio/SoundFileReaderFlac.hpp>
|
||||
#include <SFML/Audio/SoundFileWriterFlac.hpp>
|
||||
#include <SFML/Audio/SoundFileReaderOgg.hpp>
|
||||
#include <SFML/Audio/SoundFileWriterOgg.hpp>
|
||||
#include <SFML/Audio/SoundFileReaderWav.hpp>
|
||||
|
@ -42,6 +44,8 @@ namespace
|
|||
static bool registered = false;
|
||||
if (!registered)
|
||||
{
|
||||
sf::SoundFileFactory::registerReader<sf::priv::SoundFileReaderFlac>();
|
||||
sf::SoundFileFactory::registerWriter<sf::priv::SoundFileWriterFlac>();
|
||||
sf::SoundFileFactory::registerReader<sf::priv::SoundFileReaderOgg>();
|
||||
sf::SoundFileFactory::registerWriter<sf::priv::SoundFileWriterOgg>();
|
||||
sf::SoundFileFactory::registerReader<sf::priv::SoundFileReaderWav>();
|
||||
|
|
322
src/SFML/Audio/SoundFileReaderFlac.cpp
Normal file
322
src/SFML/Audio/SoundFileReaderFlac.cpp
Normal file
|
@ -0,0 +1,322 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/SoundFileReaderFlac.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
FLAC__StreamDecoderReadStatus read(const FLAC__StreamDecoder*, FLAC__byte buffer[], std::size_t* bytes, void* clientData)
|
||||
{
|
||||
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
|
||||
|
||||
sf::Int64 count = data->stream->read(buffer, *bytes);
|
||||
if (count > 0)
|
||||
{
|
||||
*bytes = static_cast<std::size_t>(count);
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||
}
|
||||
else if (count == 0)
|
||||
{
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderSeekStatus seek(const FLAC__StreamDecoder*, FLAC__uint64 absoluteByteOffset, void* clientData)
|
||||
{
|
||||
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
|
||||
|
||||
sf::Int64 position = data->stream->seek(absoluteByteOffset);
|
||||
if (position >= 0)
|
||||
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
|
||||
else
|
||||
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderTellStatus tell(const FLAC__StreamDecoder*, FLAC__uint64* absoluteByteOffset, void* clientData)
|
||||
{
|
||||
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
|
||||
|
||||
sf::Int64 position = data->stream->tell();
|
||||
if (position >= 0)
|
||||
{
|
||||
*absoluteByteOffset = position;
|
||||
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderLengthStatus length(const FLAC__StreamDecoder*, FLAC__uint64* streamLength, void* clientData)
|
||||
{
|
||||
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
|
||||
|
||||
sf::Int64 count = data->stream->getSize();
|
||||
if (count >= 0)
|
||||
{
|
||||
*streamLength = count;
|
||||
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__bool eof(const FLAC__StreamDecoder*, void* clientData)
|
||||
{
|
||||
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
|
||||
|
||||
return data->stream->tell() == data->stream->getSize();
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderWriteStatus write(const FLAC__StreamDecoder*, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* clientData)
|
||||
{
|
||||
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
|
||||
|
||||
// If there's no output buffer, it means that we are seeking
|
||||
if (!data->buffer)
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
|
||||
// Reserve memory if we're going to use the leftovers buffer
|
||||
unsigned int frameSamples = frame->header.blocksize * frame->header.channels;
|
||||
if (data->remaining < frameSamples)
|
||||
data->leftovers.reserve(static_cast<std::size_t>(frameSamples - data->remaining));
|
||||
|
||||
// Decode the samples
|
||||
for (unsigned i = 0; i < frame->header.blocksize; ++i)
|
||||
{
|
||||
for (unsigned int j = 0; j < frame->header.channels; ++j)
|
||||
{
|
||||
// Decode the current sample
|
||||
sf::Int16 sample = 0;
|
||||
switch (frame->header.bits_per_sample)
|
||||
{
|
||||
case 8:
|
||||
sample = buffer[j][i] << 8;
|
||||
break;
|
||||
case 16:
|
||||
sample = buffer[j][i];
|
||||
break;
|
||||
case 24:
|
||||
sample = buffer[j][i] >> 8;
|
||||
break;
|
||||
case 32:
|
||||
sample = buffer[j][i] >> 16;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (data->remaining > 0)
|
||||
{
|
||||
// There's room in the output buffer, copy the sample there
|
||||
*data->buffer++ = sample;
|
||||
data->remaining--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have decoded all the requested samples, put the sample in a temporary buffer until next call
|
||||
data->leftovers.push_back(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
void metadata(const FLAC__StreamDecoder*, const FLAC__StreamMetadata* meta, void* clientData)
|
||||
{
|
||||
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
|
||||
|
||||
if (meta->type == FLAC__METADATA_TYPE_STREAMINFO)
|
||||
{
|
||||
data->info.sampleCount = meta->data.stream_info.total_samples * meta->data.stream_info.channels;
|
||||
data->info.sampleRate = meta->data.stream_info.sample_rate;
|
||||
data->info.channelCount = meta->data.stream_info.channels;
|
||||
}
|
||||
}
|
||||
|
||||
void error(const FLAC__StreamDecoder*, FLAC__StreamDecoderErrorStatus status, void* clientData)
|
||||
{
|
||||
sf::priv::SoundFileReaderFlac::ClientData* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
|
||||
data->error = true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundFileReaderFlac::check(InputStream& stream)
|
||||
{
|
||||
// Create a decoder
|
||||
FLAC__StreamDecoder* decoder = FLAC__stream_decoder_new();
|
||||
if (!decoder)
|
||||
return false;
|
||||
|
||||
// Initialize the decoder with our callbacks
|
||||
ClientData data;
|
||||
data.stream = &stream;
|
||||
data.error = false;
|
||||
FLAC__stream_decoder_init_stream(decoder, &::read, &::seek, &::tell, &::length, &::eof, &::write, NULL, &::error, &data);
|
||||
|
||||
// Read the header
|
||||
bool valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder) != 0;
|
||||
|
||||
// Destroy the decoder
|
||||
FLAC__stream_decoder_finish(decoder);
|
||||
FLAC__stream_decoder_delete(decoder);
|
||||
|
||||
return valid && !data.error;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileReaderFlac::SoundFileReaderFlac() :
|
||||
m_decoder(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileReaderFlac::~SoundFileReaderFlac()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundFileReaderFlac::open(InputStream& stream, Info& info)
|
||||
{
|
||||
// Create the decoder
|
||||
m_decoder = FLAC__stream_decoder_new();
|
||||
if (!m_decoder)
|
||||
{
|
||||
err() << "Failed to open FLAC file (failed to allocate the decoder)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the decoder with our callbacks
|
||||
m_clientData.stream = &stream;
|
||||
FLAC__stream_decoder_init_stream(m_decoder, &::read, &::seek, &::tell, &::length, &::eof, &::write, &::metadata, &::error, &m_clientData);
|
||||
|
||||
// Read the header
|
||||
if (!FLAC__stream_decoder_process_until_end_of_metadata(m_decoder))
|
||||
{
|
||||
close();
|
||||
err() << "Failed to open FLAC file (failed to read metadata)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retrieve the sound properties
|
||||
info = m_clientData.info; // was filled in the "metadata" callback
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SoundFileReaderFlac::seek(Uint64 sampleOffset)
|
||||
{
|
||||
assert(m_decoder);
|
||||
|
||||
// Reset the callback data (the "write" callback will be called)
|
||||
m_clientData.buffer = NULL;
|
||||
m_clientData.remaining = 0;
|
||||
m_clientData.leftovers.clear();
|
||||
|
||||
FLAC__stream_decoder_seek_absolute(m_decoder, sampleOffset);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Uint64 SoundFileReaderFlac::read(Int16* samples, Uint64 maxCount)
|
||||
{
|
||||
assert(m_decoder);
|
||||
|
||||
// If there are leftovers from previous call, use it first
|
||||
Uint64 left = m_clientData.leftovers.size();
|
||||
if (left > 0)
|
||||
{
|
||||
if (left > maxCount)
|
||||
{
|
||||
// There are more leftovers than needed
|
||||
std::copy(m_clientData.leftovers.begin(), m_clientData.leftovers.end(), samples);
|
||||
std::vector<Int16> leftovers(m_clientData.leftovers.begin() + maxCount, m_clientData.leftovers.end());
|
||||
m_clientData.leftovers.swap(leftovers);
|
||||
return maxCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We can use all the leftovers and decode new frames
|
||||
std::copy(m_clientData.leftovers.begin(), m_clientData.leftovers.end(), samples);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the data that will be used in the callback
|
||||
m_clientData.buffer = samples + left;
|
||||
m_clientData.remaining = maxCount - left;
|
||||
m_clientData.leftovers.clear();
|
||||
|
||||
// Decode frames one by one until we reach the requested sample count, the end of file or an error
|
||||
while (m_clientData.remaining > 0)
|
||||
{
|
||||
// Everything happens in the "write" callback
|
||||
if (!FLAC__stream_decoder_process_single(m_decoder))
|
||||
break;
|
||||
}
|
||||
|
||||
return maxCount - m_clientData.remaining;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SoundFileReaderFlac::close()
|
||||
{
|
||||
if (m_decoder)
|
||||
{
|
||||
FLAC__stream_decoder_finish(m_decoder);
|
||||
FLAC__stream_decoder_delete(m_decoder);
|
||||
m_decoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
140
src/SFML/Audio/SoundFileReaderFlac.hpp
Normal file
140
src/SFML/Audio/SoundFileReaderFlac.hpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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_SOUNDFILEREADERFLAC_HPP
|
||||
#define SFML_SOUNDFILEREADERFLAC_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Audio/SoundFileReader.hpp>
|
||||
#include <flac/stream_decoder.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Implementation of sound file reader that handles FLAC files
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SoundFileReaderFlac : 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
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileReaderFlac();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~SoundFileReaderFlac();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \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);
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Hold the state that is passed to the decoder callbacks
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
struct ClientData
|
||||
{
|
||||
InputStream* stream;
|
||||
SoundFileReader::Info info;
|
||||
Int16* buffer;
|
||||
Uint64 remaining;
|
||||
std::vector<Int16> leftovers;
|
||||
bool error;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Close the open FLAC file
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void close();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
FLAC__StreamDecoder* m_decoder; ///< FLAC decoder
|
||||
ClientData m_clientData; ///< Structure passed to the decoder callbacks
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_SOUNDFILEREADERFLAC_HPP
|
|
@ -37,7 +37,7 @@ namespace sf
|
|||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Implementation of sound file reader that handles ogg/vorbis files
|
||||
/// \brief Implementation of sound file reader that handles OGG/Vorbis files
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SoundFileReaderOgg : public SoundFileReader
|
||||
|
|
133
src/SFML/Audio/SoundFileWriterFlac.cpp
Normal file
133
src/SFML/Audio/SoundFileWriterFlac.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/SoundFileWriterFlac.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundFileWriterFlac::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 == "flac";
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileWriterFlac::SoundFileWriterFlac() :
|
||||
m_encoder (NULL),
|
||||
m_channelCount(0),
|
||||
m_samples32 ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileWriterFlac::~SoundFileWriterFlac()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundFileWriterFlac::open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount)
|
||||
{
|
||||
// Create the encoder
|
||||
m_encoder = FLAC__stream_encoder_new();
|
||||
if (!m_encoder)
|
||||
{
|
||||
err() << "Failed to write flac file \"" << filename << "\" (failed to allocate encoder)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup the encoder
|
||||
FLAC__stream_encoder_set_channels(m_encoder, channelCount);
|
||||
FLAC__stream_encoder_set_bits_per_sample(m_encoder, 16);
|
||||
FLAC__stream_encoder_set_sample_rate(m_encoder, sampleRate);
|
||||
|
||||
// Initialize the output stream
|
||||
if (FLAC__stream_encoder_init_file(m_encoder, filename.c_str(), NULL, NULL) != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
|
||||
{
|
||||
err() << "Failed to write flac file \"" << filename << "\" (failed to open the file)" << std::endl;
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the channel count
|
||||
m_channelCount = channelCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SoundFileWriterFlac::write(const Int16* samples, Uint64 count)
|
||||
{
|
||||
while (count > 0)
|
||||
{
|
||||
// Make sure that we don't process too many samples at once
|
||||
unsigned int frames = std::min(static_cast<unsigned int>(count / m_channelCount), 10000u);
|
||||
|
||||
// Convert the samples to 32-bits
|
||||
m_samples32.assign(samples, samples + frames * m_channelCount);
|
||||
|
||||
// Write them to the FLAC stream
|
||||
FLAC__stream_encoder_process_interleaved(m_encoder, &m_samples32[0], frames);
|
||||
|
||||
// Next chunk
|
||||
count -= m_samples32.size();
|
||||
samples += m_samples32.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SoundFileWriterFlac::close()
|
||||
{
|
||||
if (m_encoder)
|
||||
{
|
||||
// Close the output stream
|
||||
FLAC__stream_encoder_finish(m_encoder);
|
||||
|
||||
// Destroy the encoder
|
||||
FLAC__stream_encoder_delete(m_encoder);
|
||||
m_encoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
114
src/SFML/Audio/SoundFileWriterFlac.hpp
Normal file
114
src/SFML/Audio/SoundFileWriterFlac.hpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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_SOUNDFILEWRITERFLAC_HPP
|
||||
#define SFML_SOUNDFILEWRITERFLAC_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Audio/SoundFileWriter.hpp>
|
||||
#include <flac/stream_encoder.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Implementation of sound file writer that handles FLAC files
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SoundFileWriterFlac : 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
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileWriterFlac();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~SoundFileWriterFlac();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \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 Close the file
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void close();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
FLAC__StreamEncoder* m_encoder; ///< FLAC stream encoder
|
||||
unsigned int m_channelCount; ///< Number of channels
|
||||
std::vector<Int32> m_samples32; ///< Conversion buffer
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_SOUNDFILEWRITERFLAC_HPP
|
|
@ -38,7 +38,7 @@ namespace sf
|
|||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Implementation of sound file writer that handles ogg files
|
||||
/// \brief Implementation of sound file writer that handles OGG/Vorbis files
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SoundFileWriterOgg : public SoundFileWriter
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue