mirror of
https://github.com/SFML/SFML.git
synced 2024-11-25 12:51:05 +08:00
Added Opus sound file support, added SoundFileReaderOpus and FindOpus cmake Module
This commit is contained in:
parent
37ac80dbe5
commit
15bb2ef28e
43
cmake/Modules/FindOpus.cmake
Normal file
43
cmake/Modules/FindOpus.cmake
Normal file
@ -0,0 +1,43 @@
|
||||
# This file was taken from Unvanquished,
|
||||
# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
|
||||
# It's licensed under the terms of the 3-clause OpenBSD license.
|
||||
# Modifications Copyright 2014-2015 the openage authors.
|
||||
# See copying.md for further legal info.
|
||||
|
||||
# - Find opus library
|
||||
# Find the native Opus headers and libraries.
|
||||
# This module defines
|
||||
# OPUS_INCLUDE_DIRS - where to find opus/opus.h, opus/opusfile.h, etc
|
||||
# OPUS_LIBRARIES - List of libraries when using libopus
|
||||
# OPUS_FOUND - True if opus is found.
|
||||
|
||||
# find the opusfile header, defines our api.
|
||||
find_path(OPUS_INCLUDE_DIR
|
||||
NAMES opus/opusfile.h
|
||||
DOC "Opus include directory"
|
||||
)
|
||||
mark_as_advanced(OPUS_INCLUDE_DIR)
|
||||
|
||||
# look for libopusfile, the highlevel container-aware api.
|
||||
find_library(OPUSFILE_LIBRARY
|
||||
NAMES opusfile
|
||||
DOC "Path to OpusFile library"
|
||||
)
|
||||
mark_as_advanced(OPUSFILE_LIBRARY)
|
||||
|
||||
# find libopus, the core codec component.
|
||||
find_library(OPUS_LIBRARY
|
||||
NAMES opus
|
||||
DOC "Path to Opus library"
|
||||
)
|
||||
mark_as_advanced(OPUS_LIBRARY)
|
||||
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set OPUSFILE_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Opus DEFAULT_MSG OPUSFILE_LIBRARY OPUS_LIBRARY OPUS_INCLUDE_DIR)
|
||||
|
||||
# export the variables
|
||||
set(OPUS_LIBRARIES "${OPUSFILE_LIBRARY}" "${OPUS_LIBRARY}")
|
||||
set(OPUS_INCLUDE_DIRS "${OPUS_INCLUDE_DIR}" "${OPUS_INCLUDE_DIR}/opus")
|
@ -48,6 +48,8 @@ set(CODECS_SRC
|
||||
${SRCROOT}/SoundFileReaderMp3.cpp
|
||||
${SRCROOT}/SoundFileReaderOgg.hpp
|
||||
${SRCROOT}/SoundFileReaderOgg.cpp
|
||||
${SRCROOT}/SoundFileReaderOpus.hpp
|
||||
${SRCROOT}/SoundFileReaderOpus.cpp
|
||||
${SRCROOT}/SoundFileReaderWav.hpp
|
||||
${SRCROOT}/SoundFileReaderWav.cpp
|
||||
${INCROOT}/SoundFileWriter.hpp
|
||||
@ -77,6 +79,7 @@ endif()
|
||||
# find external libraries
|
||||
find_package(Vorbis REQUIRED)
|
||||
find_package(FLAC REQUIRED)
|
||||
find_package(Opus REQUIRED)
|
||||
|
||||
# define the sfml-audio target
|
||||
sfml_add_library(Audio
|
||||
|
@ -29,9 +29,11 @@
|
||||
#include <SFML/Audio/SoundFileReaderFlac.hpp>
|
||||
#include <SFML/Audio/SoundFileReaderMp3.hpp>
|
||||
#include <SFML/Audio/SoundFileReaderOgg.hpp>
|
||||
#include <SFML/Audio/SoundFileReaderOpus.hpp>
|
||||
#include <SFML/Audio/SoundFileReaderWav.hpp>
|
||||
#include <SFML/Audio/SoundFileWriterFlac.hpp>
|
||||
#include <SFML/Audio/SoundFileWriterOgg.hpp>
|
||||
//#include <SFML/Audio/SoundFileWriterOpus.hpp>
|
||||
#include <SFML/Audio/SoundFileWriterWav.hpp>
|
||||
|
||||
#include <SFML/System/Err.hpp>
|
||||
@ -144,6 +146,7 @@ SoundFileFactory::ReaderFactoryMap& SoundFileFactory::getReaderFactoryMap()
|
||||
static ReaderFactoryMap result{{&priv::createReader<priv::SoundFileReaderFlac>, &priv::SoundFileReaderFlac::check},
|
||||
{&priv::createReader<priv::SoundFileReaderMp3>, &priv::SoundFileReaderMp3::check},
|
||||
{&priv::createReader<priv::SoundFileReaderOgg>, &priv::SoundFileReaderOgg::check},
|
||||
{&priv::createReader<priv::SoundFileReaderOpus>, &priv::SoundFileReaderOpus::check},
|
||||
{&priv::createReader<priv::SoundFileReaderWav>, &priv::SoundFileReaderWav::check}};
|
||||
|
||||
return result;
|
||||
|
189
src/SFML/Audio/SoundFileReaderOpus.cpp
Normal file
189
src/SFML/Audio/SoundFileReaderOpus.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2016 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.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Audio/SoundFileReaderOpus.hpp>
|
||||
#include <SFML/System/MemoryInputStream.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
|
||||
namespace
|
||||
{
|
||||
int read(void* data, unsigned char* ptr, int bytes)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(data);
|
||||
return static_cast<int>(stream->read(ptr, bytes));
|
||||
}
|
||||
|
||||
int seek(void* data, opus_int64 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 value expected from libopusfile: 0 - Success and -1 - Failure
|
||||
return static_cast<int>(stream->seek(offset)) >= 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
opus_int64 tell(void* data)
|
||||
{
|
||||
sf::InputStream* stream = static_cast<sf::InputStream*>(data);
|
||||
return static_cast<opus_int64>(stream->tell());
|
||||
}
|
||||
|
||||
static OpusFileCallbacks callbacks = {&read, &seek, &tell, NULL};
|
||||
}
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundFileReaderOpus::check(InputStream& stream)
|
||||
{
|
||||
int error = 0;
|
||||
OggOpusFile* file = op_test_callbacks(&stream, &callbacks, NULL, 0, &error);
|
||||
if (error == 0)
|
||||
{
|
||||
op_free(file);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileReaderOpus::SoundFileReaderOpus() :
|
||||
m_opus (NULL),
|
||||
m_channelCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileReaderOpus::~SoundFileReaderOpus()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundFileReaderOpus::open(InputStream& stream, Info& info)
|
||||
{
|
||||
// Open the Opus stream
|
||||
int status = 0;
|
||||
m_opus = op_open_callbacks(&stream, &callbacks, NULL, 0, &status);
|
||||
if (status != 0)
|
||||
{
|
||||
err() << "Failed to open Opus file for reading" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retrieve the music attributes
|
||||
const OpusHead* opusHead = op_head(m_opus, -1);
|
||||
info.channelCount = opusHead->channel_count;
|
||||
info.sampleRate = opusHead->input_sample_rate;
|
||||
info.sampleCount = static_cast<std::size_t>(op_pcm_total(m_opus, -1) * opusHead->channel_count);
|
||||
// We must keep the channel count for the seek function
|
||||
m_channelCount = info.channelCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SoundFileReaderOpus::seek(Uint64 sampleOffset)
|
||||
{
|
||||
assert(m_opus != NULL);
|
||||
|
||||
op_pcm_seek(m_opus, sampleOffset / m_channelCount);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Uint64 SoundFileReaderOpus::read(Int16* samples, Uint64 maxCount)
|
||||
{
|
||||
assert(m_opus != NULL);
|
||||
|
||||
int samplesToRead;
|
||||
// Try to read the requested number of samples, stop only on error or end of file
|
||||
Uint64 count = 0;
|
||||
while (maxCount > 0)
|
||||
{
|
||||
// since maxCount is uint64 we have to ensure that samplesToRead is <= INT_MAX (int overflow)
|
||||
if (maxCount > INT_MAX)
|
||||
{
|
||||
samplesToRead = INT_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
samplesToRead = maxCount;
|
||||
}
|
||||
// op_read returns number of SAMPLES read PER CHANNEL
|
||||
int samplesRead = op_read(m_opus, samples, samplesToRead, NULL) * m_channelCount;
|
||||
if (samplesRead > 0)
|
||||
{
|
||||
maxCount -= samplesRead;
|
||||
count += samplesRead;
|
||||
samples += samplesRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
// error or end of file
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SoundFileReaderOpus::close()
|
||||
{
|
||||
if (m_opus != NULL)
|
||||
{
|
||||
op_free(m_opus);
|
||||
m_channelCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
124
src/SFML/Audio/SoundFileReaderOpus.hpp
Normal file
124
src/SFML/Audio/SoundFileReaderOpus.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2016 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_SOUNDFILEREADEROPUS_HPP
|
||||
#define SFML_SOUNDFILEREADEROPUS_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Audio/SoundFileReader.hpp>
|
||||
#include <opus/opusfile.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Implementation of sound file reader that handles Opus files
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SoundFileReaderOpus : 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
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
SoundFileReaderOpus();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~SoundFileReaderOpus();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \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 Opus file
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void close();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
OggOpusFile* m_opus; // opus file handle
|
||||
unsigned int m_channelCount; // number of channels of the open sound file
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_SOUNDFILEREADEROPUS_HPP
|
Loading…
Reference in New Issue
Block a user