mirror of
https://github.com/SFML/SFML.git
synced 2024-11-25 04:41:05 +08:00
Remove default empty state of sf::InputSoundFile
and sf::OutputSoundFile
This commit is contained in:
parent
53ade4baf1
commit
e9fadbbcb3
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@ -64,10 +65,10 @@ public:
|
|||||||
///
|
///
|
||||||
/// \param filename Path of the sound file to load
|
/// \param filename Path of the sound file to load
|
||||||
///
|
///
|
||||||
/// \return True if the file was successfully opened
|
/// \return Input sound file if the file was successfully opened, otherwise `std::nullopt`
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
[[nodiscard]] bool openFromFile(const std::filesystem::path& filename);
|
[[nodiscard]] static std::optional<InputSoundFile> openFromFile(const std::filesystem::path& filename);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Open a sound file in memory for reading
|
/// \brief Open a sound file in memory for reading
|
||||||
@ -78,10 +79,10 @@ public:
|
|||||||
/// \param data Pointer to the file data in memory
|
/// \param data Pointer to the file data in memory
|
||||||
/// \param sizeInBytes Size of the data to load, in bytes
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
///
|
///
|
||||||
/// \return True if the file was successfully opened
|
/// \return Input sound file if the file was successfully opened, otherwise `std::nullopt`
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
[[nodiscard]] bool openFromMemory(const void* data, std::size_t sizeInBytes);
|
[[nodiscard]] static std::optional<InputSoundFile> openFromMemory(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Open a sound file from a custom stream for reading
|
/// \brief Open a sound file from a custom stream for reading
|
||||||
@ -91,10 +92,10 @@ public:
|
|||||||
///
|
///
|
||||||
/// \param stream Source stream to read from
|
/// \param stream Source stream to read from
|
||||||
///
|
///
|
||||||
/// \return True if the file was successfully opened
|
/// \return Input sound file if the file was successfully opened, otherwise `std::nullopt`
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
[[nodiscard]] bool openFromStream(InputStream& stream);
|
[[nodiscard]] static std::optional<InputSoundFile> openFromStream(InputStream& stream);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Get the total number of audio samples in the file
|
/// \brief Get the total number of audio samples in the file
|
||||||
@ -211,6 +212,14 @@ public:
|
|||||||
void close();
|
void close();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Useful for implementing close()
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
InputSoundFile() = default;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Deleter for input streams that only conditionally deletes
|
/// \brief Deleter for input streams that only conditionally deletes
|
||||||
///
|
///
|
||||||
@ -228,6 +237,16 @@ private:
|
|||||||
bool owned{true};
|
bool owned{true};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Constructor from reader, stream, and attributes
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
InputSoundFile(std::unique_ptr<SoundFileReader>&& reader,
|
||||||
|
std::unique_ptr<InputStream, StreamDeleter>&& stream,
|
||||||
|
std::uint64_t sampleCount,
|
||||||
|
unsigned int sampleRate,
|
||||||
|
std::vector<SoundChannel>&& channelMap);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -248,10 +248,10 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
InputSoundFile m_file; //!< The streamed music file
|
std::optional<InputSoundFile> m_file; //!< The streamed music file
|
||||||
std::vector<std::int16_t> m_samples; //!< Temporary buffer of samples
|
std::vector<std::int16_t> m_samples; //!< Temporary buffer of samples
|
||||||
std::recursive_mutex m_mutex; //!< Mutex protecting the data
|
std::recursive_mutex m_mutex; //!< Mutex protecting the data
|
||||||
Span<std::uint64_t> m_loopSpan; //!< Loop Range Specifier
|
Span<std::uint64_t> m_loopSpan; //!< Loop Range Specifier
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -58,13 +59,14 @@ public:
|
|||||||
/// \param channelCount Number of channels in the sound
|
/// \param channelCount Number of channels in the sound
|
||||||
/// \param channelMap Map of position in sample frame to sound channel
|
/// \param channelMap Map of position in sample frame to sound channel
|
||||||
///
|
///
|
||||||
/// \return True if the file was successfully opened
|
/// \return Output sound file if the file was successfully opened
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
[[nodiscard]] bool openFromFile(const std::filesystem::path& filename,
|
[[nodiscard]] static std::optional<OutputSoundFile> openFromFile(
|
||||||
unsigned int sampleRate,
|
const std::filesystem::path& filename,
|
||||||
unsigned int channelCount,
|
unsigned int sampleRate,
|
||||||
const std::vector<SoundChannel>& channelMap);
|
unsigned int channelCount,
|
||||||
|
const std::vector<SoundChannel>& channelMap);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Write audio samples to the file
|
/// \brief Write audio samples to the file
|
||||||
@ -82,6 +84,12 @@ public:
|
|||||||
void close();
|
void close();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Constructor from writer
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit OutputSoundFile(std::unique_ptr<SoundFileWriter>&& writer);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -65,51 +65,36 @@ void InputSoundFile::StreamDeleter::operator()(InputStream* ptr) const
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool InputSoundFile::openFromFile(const std::filesystem::path& filename)
|
std::optional<InputSoundFile> InputSoundFile::openFromFile(const std::filesystem::path& filename)
|
||||||
{
|
{
|
||||||
// If the file is already open, first close it
|
|
||||||
close();
|
|
||||||
|
|
||||||
// Find a suitable reader for the file type
|
// Find a suitable reader for the file type
|
||||||
auto reader = SoundFileFactory::createReaderFromFilename(filename);
|
auto reader = SoundFileFactory::createReaderFromFilename(filename);
|
||||||
if (!reader)
|
if (!reader)
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
// Wrap the file into a stream
|
// Wrap the file into a stream
|
||||||
auto file = std::make_unique<FileInputStream>();
|
auto file = std::make_unique<FileInputStream>();
|
||||||
|
|
||||||
// Open it
|
// Open it
|
||||||
if (!file->open(filename))
|
if (!file->open(filename))
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
// Pass the stream to the reader
|
// Pass the stream to the reader
|
||||||
const auto info = reader->open(*file);
|
auto info = reader->open(*file);
|
||||||
if (!info)
|
if (!info)
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
// Take ownership of successfully opened reader and stream
|
return InputSoundFile(std::move(reader), std::move(file), info->sampleCount, info->sampleRate, std::move(info->channelMap));
|
||||||
m_reader = std::move(reader);
|
|
||||||
m_stream = std::move(file);
|
|
||||||
|
|
||||||
// Retrieve the attributes of the open sound file
|
|
||||||
m_sampleCount = info->sampleCount;
|
|
||||||
m_sampleRate = info->sampleRate;
|
|
||||||
m_channelMap = info->channelMap;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool InputSoundFile::openFromMemory(const void* data, std::size_t sizeInBytes)
|
std::optional<InputSoundFile> 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
|
// Find a suitable reader for the file type
|
||||||
auto reader = SoundFileFactory::createReaderFromMemory(data, sizeInBytes);
|
auto reader = SoundFileFactory::createReaderFromMemory(data, sizeInBytes);
|
||||||
if (!reader)
|
if (!reader)
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
// Wrap the memory file into a stream
|
// Wrap the memory file into a stream
|
||||||
auto memory = std::make_unique<MemoryInputStream>();
|
auto memory = std::make_unique<MemoryInputStream>();
|
||||||
@ -118,56 +103,35 @@ bool InputSoundFile::openFromMemory(const void* data, std::size_t sizeInBytes)
|
|||||||
memory->open(data, sizeInBytes);
|
memory->open(data, sizeInBytes);
|
||||||
|
|
||||||
// Pass the stream to the reader
|
// Pass the stream to the reader
|
||||||
const auto info = reader->open(*memory);
|
auto info = reader->open(*memory);
|
||||||
if (!info)
|
if (!info)
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
// Take ownership of successfully opened reader and stream
|
return InputSoundFile(std::move(reader), std::move(memory), info->sampleCount, info->sampleRate, std::move(info->channelMap));
|
||||||
m_reader = std::move(reader);
|
|
||||||
m_stream = std::move(memory);
|
|
||||||
|
|
||||||
// Retrieve the attributes of the open sound file
|
|
||||||
m_sampleCount = info->sampleCount;
|
|
||||||
m_sampleRate = info->sampleRate;
|
|
||||||
m_channelMap = info->channelMap;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool InputSoundFile::openFromStream(InputStream& stream)
|
std::optional<InputSoundFile> InputSoundFile::openFromStream(InputStream& stream)
|
||||||
{
|
{
|
||||||
// If the file is already open, first close it
|
|
||||||
close();
|
|
||||||
|
|
||||||
// Find a suitable reader for the file type
|
// Find a suitable reader for the file type
|
||||||
auto reader = SoundFileFactory::createReaderFromStream(stream);
|
auto reader = SoundFileFactory::createReaderFromStream(stream);
|
||||||
if (!reader)
|
if (!reader)
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
// Don't forget to reset the stream to its beginning before re-opening it
|
// Don't forget to reset the stream to its beginning before re-opening it
|
||||||
if (stream.seek(0) != 0)
|
if (stream.seek(0) != 0)
|
||||||
{
|
{
|
||||||
err() << "Failed to open sound file from stream (cannot restart stream)" << std::endl;
|
err() << "Failed to open sound file from stream (cannot restart stream)" << std::endl;
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass the stream to the reader
|
// Pass the stream to the reader
|
||||||
const auto info = reader->open(stream);
|
auto info = reader->open(stream);
|
||||||
if (!info)
|
if (!info)
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
// Take ownership of reader and store a reference to the stream without taking ownership
|
return InputSoundFile(std::move(reader), {&stream, false}, info->sampleCount, info->sampleRate, std::move(info->channelMap));
|
||||||
m_reader = std::move(reader);
|
|
||||||
m_stream = {&stream, false};
|
|
||||||
|
|
||||||
// Retrieve the attributes of the open sound file
|
|
||||||
m_sampleCount = info->sampleCount;
|
|
||||||
m_sampleRate = info->sampleRate;
|
|
||||||
m_channelMap = info->channelMap;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -268,4 +232,19 @@ void InputSoundFile::close()
|
|||||||
m_channelMap.clear();
|
m_channelMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
InputSoundFile::InputSoundFile(std::unique_ptr<SoundFileReader>&& reader,
|
||||||
|
std::unique_ptr<InputStream, StreamDeleter>&& stream,
|
||||||
|
std::uint64_t sampleCount,
|
||||||
|
unsigned int sampleRate,
|
||||||
|
std::vector<SoundChannel>&& channelMap) :
|
||||||
|
m_reader(std::move(reader)),
|
||||||
|
m_stream(std::move(stream)),
|
||||||
|
m_sampleCount(sampleCount),
|
||||||
|
m_sampleRate(sampleRate),
|
||||||
|
m_channelMap(std::move(channelMap))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
@ -52,7 +54,8 @@ bool Music::openFromFile(const std::filesystem::path& filename)
|
|||||||
stop();
|
stop();
|
||||||
|
|
||||||
// Open the underlying sound file
|
// Open the underlying sound file
|
||||||
if (!m_file.openFromFile(filename))
|
m_file = sf::InputSoundFile::openFromFile(filename);
|
||||||
|
if (!m_file)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Perform common initializations
|
// Perform common initializations
|
||||||
@ -69,7 +72,8 @@ bool Music::openFromMemory(const void* data, std::size_t sizeInBytes)
|
|||||||
stop();
|
stop();
|
||||||
|
|
||||||
// Open the underlying sound file
|
// Open the underlying sound file
|
||||||
if (!m_file.openFromMemory(data, sizeInBytes))
|
m_file = sf::InputSoundFile::openFromMemory(data, sizeInBytes);
|
||||||
|
if (!m_file)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Perform common initializations
|
// Perform common initializations
|
||||||
@ -86,7 +90,8 @@ bool Music::openFromStream(InputStream& stream)
|
|||||||
stop();
|
stop();
|
||||||
|
|
||||||
// Open the underlying sound file
|
// Open the underlying sound file
|
||||||
if (!m_file.openFromStream(stream))
|
m_file = sf::InputSoundFile::openFromStream(stream);
|
||||||
|
if (!m_file)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Perform common initializations
|
// Perform common initializations
|
||||||
@ -99,7 +104,8 @@ bool Music::openFromStream(InputStream& stream)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Time Music::getDuration() const
|
Time Music::getDuration() const
|
||||||
{
|
{
|
||||||
return m_file.getDuration();
|
assert(m_file && "Music::getDuration() Cannot get duration until music is opened");
|
||||||
|
return m_file->getDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -116,7 +122,8 @@ void Music::setLoopPoints(TimeSpan timePoints)
|
|||||||
Span<std::uint64_t> samplePoints{timeToSamples(timePoints.offset), timeToSamples(timePoints.length)};
|
Span<std::uint64_t> samplePoints{timeToSamples(timePoints.offset), timeToSamples(timePoints.length)};
|
||||||
|
|
||||||
// Check our state. This averts a divide-by-zero. GetChannelCount() is cheap enough to use often
|
// Check our state. This averts a divide-by-zero. GetChannelCount() is cheap enough to use often
|
||||||
if (getChannelCount() == 0 || m_file.getSampleCount() == 0)
|
assert(m_file && "Music::setLoopPoints() Cannot set loop points unit music is opened");
|
||||||
|
if (getChannelCount() == 0 || m_file->getSampleCount() == 0)
|
||||||
{
|
{
|
||||||
err() << "Music is not in a valid state to assign Loop Points." << std::endl;
|
err() << "Music is not in a valid state to assign Loop Points." << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -129,7 +136,7 @@ void Music::setLoopPoints(TimeSpan timePoints)
|
|||||||
samplePoints.length -= (samplePoints.length % getChannelCount());
|
samplePoints.length -= (samplePoints.length % getChannelCount());
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if (samplePoints.offset >= m_file.getSampleCount())
|
if (samplePoints.offset >= m_file->getSampleCount())
|
||||||
{
|
{
|
||||||
err() << "LoopPoints offset val must be in range [0, Duration)." << std::endl;
|
err() << "LoopPoints offset val must be in range [0, Duration)." << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -141,7 +148,7 @@ void Music::setLoopPoints(TimeSpan timePoints)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clamp End Point
|
// Clamp End Point
|
||||||
samplePoints.length = std::min(samplePoints.length, m_file.getSampleCount() - samplePoints.offset);
|
samplePoints.length = std::min(samplePoints.length, m_file->getSampleCount() - samplePoints.offset);
|
||||||
|
|
||||||
// If this change has no effect, we can return without touching anything
|
// If this change has no effect, we can return without touching anything
|
||||||
if (samplePoints.offset == m_loopSpan.offset && samplePoints.length == m_loopSpan.length)
|
if (samplePoints.offset == m_loopSpan.offset && samplePoints.length == m_loopSpan.length)
|
||||||
@ -172,10 +179,12 @@ void Music::setLoopPoints(TimeSpan timePoints)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Music::onGetData(SoundStream::Chunk& data)
|
bool Music::onGetData(SoundStream::Chunk& data)
|
||||||
{
|
{
|
||||||
|
assert(m_file && "Music::onGetData() Cannot perform operation until music is opened");
|
||||||
|
|
||||||
const std::lock_guard lock(m_mutex);
|
const std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
std::size_t toFill = m_samples.size();
|
std::size_t toFill = m_samples.size();
|
||||||
std::uint64_t currentOffset = m_file.getSampleOffset();
|
std::uint64_t currentOffset = m_file->getSampleOffset();
|
||||||
const std::uint64_t loopEnd = m_loopSpan.offset + m_loopSpan.length;
|
const std::uint64_t loopEnd = m_loopSpan.offset + m_loopSpan.length;
|
||||||
|
|
||||||
// If the loop end is enabled and imminent, request less data.
|
// If the loop end is enabled and imminent, request less data.
|
||||||
@ -186,11 +195,11 @@ bool Music::onGetData(SoundStream::Chunk& data)
|
|||||||
|
|
||||||
// Fill the chunk parameters
|
// Fill the chunk parameters
|
||||||
data.samples = m_samples.data();
|
data.samples = m_samples.data();
|
||||||
data.sampleCount = static_cast<std::size_t>(m_file.read(m_samples.data(), toFill));
|
data.sampleCount = static_cast<std::size_t>(m_file->read(m_samples.data(), toFill));
|
||||||
currentOffset += data.sampleCount;
|
currentOffset += data.sampleCount;
|
||||||
|
|
||||||
// Check if we have stopped obtaining samples or reached either the EOF or the loop end point
|
// Check if we have stopped obtaining samples or reached either the EOF or the loop end point
|
||||||
return (data.sampleCount != 0) && (currentOffset < m_file.getSampleCount()) &&
|
return (data.sampleCount != 0) && (currentOffset < m_file->getSampleCount()) &&
|
||||||
(currentOffset != loopEnd || m_loopSpan.length == 0);
|
(currentOffset != loopEnd || m_loopSpan.length == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,28 +207,32 @@ bool Music::onGetData(SoundStream::Chunk& data)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void Music::onSeek(Time timeOffset)
|
void Music::onSeek(Time timeOffset)
|
||||||
{
|
{
|
||||||
|
assert(m_file && "Music::onSeek() Cannot perform operation until music is opened");
|
||||||
|
|
||||||
const std::lock_guard lock(m_mutex);
|
const std::lock_guard lock(m_mutex);
|
||||||
m_file.seek(timeOffset);
|
m_file->seek(timeOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::optional<std::uint64_t> Music::onLoop()
|
std::optional<std::uint64_t> Music::onLoop()
|
||||||
{
|
{
|
||||||
|
assert(m_file && "Music::onLoop() Cannot perform operation until music is opened");
|
||||||
|
|
||||||
// Called by underlying SoundStream so we can determine where to loop.
|
// Called by underlying SoundStream so we can determine where to loop.
|
||||||
const std::lock_guard lock(m_mutex);
|
const std::lock_guard lock(m_mutex);
|
||||||
const std::uint64_t currentOffset = m_file.getSampleOffset();
|
const std::uint64_t currentOffset = m_file->getSampleOffset();
|
||||||
if (getLoop() && (m_loopSpan.length != 0) && (currentOffset == m_loopSpan.offset + m_loopSpan.length))
|
if (getLoop() && (m_loopSpan.length != 0) && (currentOffset == m_loopSpan.offset + m_loopSpan.length))
|
||||||
{
|
{
|
||||||
// Looping is enabled, and either we're at the loop end, or we're at the EOF
|
// Looping is enabled, and either we're at the loop end, or we're at the EOF
|
||||||
// when it's equivalent to the loop end (loop end takes priority). Send us to loop begin
|
// when it's equivalent to the loop end (loop end takes priority). Send us to loop begin
|
||||||
m_file.seek(m_loopSpan.offset);
|
m_file->seek(m_loopSpan.offset);
|
||||||
return static_cast<std::int64_t>(m_file.getSampleOffset());
|
return static_cast<std::int64_t>(m_file->getSampleOffset());
|
||||||
}
|
}
|
||||||
else if (getLoop() && (currentOffset >= m_file.getSampleCount()))
|
else if (getLoop() && (currentOffset >= m_file->getSampleCount()))
|
||||||
{
|
{
|
||||||
// If we're at the EOF, reset to 0
|
// If we're at the EOF, reset to 0
|
||||||
m_file.seek(0);
|
m_file->seek(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -231,13 +244,13 @@ void Music::initialize()
|
|||||||
{
|
{
|
||||||
// Compute the music positions
|
// Compute the music positions
|
||||||
m_loopSpan.offset = 0;
|
m_loopSpan.offset = 0;
|
||||||
m_loopSpan.length = m_file.getSampleCount();
|
m_loopSpan.length = m_file->getSampleCount();
|
||||||
|
|
||||||
// Resize the internal buffer so that it can contain 1 second of audio samples
|
// 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
|
// Initialize the stream
|
||||||
SoundStream::initialize(m_file.getChannelCount(), m_file.getSampleRate(), m_file.getChannelMap());
|
SoundStream::initialize(m_file->getChannelCount(), m_file->getSampleRate(), m_file->getChannelMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -33,27 +33,24 @@
|
|||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool OutputSoundFile::openFromFile(const std::filesystem::path& filename,
|
std::optional<OutputSoundFile> OutputSoundFile::openFromFile(
|
||||||
unsigned int sampleRate,
|
const std::filesystem::path& filename,
|
||||||
unsigned int channelCount,
|
unsigned int sampleRate,
|
||||||
const std::vector<SoundChannel>& channelMap)
|
unsigned int channelCount,
|
||||||
|
const std::vector<SoundChannel>& channelMap)
|
||||||
{
|
{
|
||||||
// If the file is already open, first close it
|
|
||||||
close();
|
|
||||||
|
|
||||||
// Find a suitable writer for the file type
|
// Find a suitable writer for the file type
|
||||||
m_writer = SoundFileFactory::createWriterFromFilename(filename);
|
auto writer = SoundFileFactory::createWriterFromFilename(filename);
|
||||||
if (!m_writer)
|
if (!writer)
|
||||||
return false;
|
return std::nullopt;
|
||||||
|
|
||||||
// Pass the stream to the reader
|
// Pass the stream to the reader
|
||||||
if (!m_writer->open(filename, sampleRate, channelCount, channelMap))
|
if (!writer->open(filename, sampleRate, channelCount, channelMap))
|
||||||
{
|
{
|
||||||
close();
|
return std::nullopt;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return OutputSoundFile(std::move(writer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -72,4 +69,10 @@ void OutputSoundFile::close()
|
|||||||
m_writer.reset();
|
m_writer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
OutputSoundFile::OutputSoundFile(std::unique_ptr<SoundFileWriter>&& writer) : m_writer(std::move(writer))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -70,9 +70,8 @@ SoundBuffer::~SoundBuffer()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::optional<SoundBuffer> SoundBuffer::loadFromFile(const std::filesystem::path& filename)
|
std::optional<SoundBuffer> SoundBuffer::loadFromFile(const std::filesystem::path& filename)
|
||||||
{
|
{
|
||||||
InputSoundFile file;
|
if (auto file = InputSoundFile::openFromFile(filename))
|
||||||
if (file.openFromFile(filename))
|
return initialize(*file);
|
||||||
return initialize(file);
|
|
||||||
else
|
else
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -81,9 +80,8 @@ std::optional<SoundBuffer> SoundBuffer::loadFromFile(const std::filesystem::path
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::optional<SoundBuffer> SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes)
|
std::optional<SoundBuffer> SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes)
|
||||||
{
|
{
|
||||||
InputSoundFile file;
|
if (auto file = InputSoundFile::openFromMemory(data, sizeInBytes))
|
||||||
if (file.openFromMemory(data, sizeInBytes))
|
return initialize(*file);
|
||||||
return initialize(file);
|
|
||||||
else
|
else
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -92,9 +90,8 @@ std::optional<SoundBuffer> SoundBuffer::loadFromMemory(const void* data, std::si
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::optional<SoundBuffer> SoundBuffer::loadFromStream(InputStream& stream)
|
std::optional<SoundBuffer> SoundBuffer::loadFromStream(InputStream& stream)
|
||||||
{
|
{
|
||||||
InputSoundFile file;
|
if (auto file = InputSoundFile::openFromStream(stream))
|
||||||
if (file.openFromStream(stream))
|
return initialize(*file);
|
||||||
return initialize(file);
|
|
||||||
else
|
else
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -136,11 +133,10 @@ std::optional<SoundBuffer> SoundBuffer::loadFromSamples(
|
|||||||
bool SoundBuffer::saveToFile(const std::filesystem::path& filename) const
|
bool SoundBuffer::saveToFile(const std::filesystem::path& filename) const
|
||||||
{
|
{
|
||||||
// Create the sound file in write mode
|
// Create the sound file in write mode
|
||||||
OutputSoundFile file;
|
if (auto file = OutputSoundFile::openFromFile(filename, getSampleRate(), getChannelCount(), getChannelMap()))
|
||||||
if (file.openFromFile(filename, getSampleRate(), getChannelCount(), getChannelMap()))
|
|
||||||
{
|
{
|
||||||
// Write the samples to the opened file
|
// Write the samples to the opened file
|
||||||
file.write(m_samples.data(), m_samples.size());
|
file->write(m_samples.data(), m_samples.size());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -15,37 +15,25 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
{
|
{
|
||||||
SECTION("Type traits")
|
SECTION("Type traits")
|
||||||
{
|
{
|
||||||
|
STATIC_CHECK(!std::is_default_constructible_v<sf::InputSoundFile>);
|
||||||
STATIC_CHECK(!std::is_copy_constructible_v<sf::InputSoundFile>);
|
STATIC_CHECK(!std::is_copy_constructible_v<sf::InputSoundFile>);
|
||||||
STATIC_CHECK(!std::is_copy_assignable_v<sf::InputSoundFile>);
|
STATIC_CHECK(!std::is_copy_assignable_v<sf::InputSoundFile>);
|
||||||
STATIC_CHECK(std::is_nothrow_move_constructible_v<sf::InputSoundFile>);
|
STATIC_CHECK(std::is_nothrow_move_constructible_v<sf::InputSoundFile>);
|
||||||
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::InputSoundFile>);
|
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::InputSoundFile>);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Construction")
|
|
||||||
{
|
|
||||||
const sf::InputSoundFile inputSoundFile;
|
|
||||||
CHECK(inputSoundFile.getSampleCount() == 0);
|
|
||||||
CHECK(inputSoundFile.getChannelCount() == 0);
|
|
||||||
CHECK(inputSoundFile.getSampleRate() == 0);
|
|
||||||
CHECK(inputSoundFile.getDuration() == sf::Time::Zero);
|
|
||||||
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
|
|
||||||
CHECK(inputSoundFile.getSampleOffset() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("openFromFile()")
|
SECTION("openFromFile()")
|
||||||
{
|
{
|
||||||
sf::InputSoundFile inputSoundFile;
|
|
||||||
|
|
||||||
SECTION("Invalid file")
|
SECTION("Invalid file")
|
||||||
{
|
{
|
||||||
CHECK(!inputSoundFile.openFromFile("does/not/exist.wav"));
|
CHECK(!sf::InputSoundFile::openFromFile("does/not/exist.wav"));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Valid file")
|
SECTION("Valid file")
|
||||||
{
|
{
|
||||||
SECTION("flac")
|
SECTION("flac")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.flac"));
|
const auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 1);
|
CHECK(inputSoundFile.getChannelCount() == 1);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
||||||
@ -56,7 +44,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("mp3")
|
SECTION("mp3")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.mp3"));
|
const auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.mp3").value();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 1);
|
CHECK(inputSoundFile.getChannelCount() == 1);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
||||||
@ -67,7 +55,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("ogg")
|
SECTION("ogg")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/doodle_pop.ogg"));
|
const auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/doodle_pop.ogg").value();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 2'116'992);
|
CHECK(inputSoundFile.getSampleCount() == 2'116'992);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 2);
|
CHECK(inputSoundFile.getChannelCount() == 2);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
||||||
@ -78,7 +66,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("wav")
|
SECTION("wav")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/killdeer.wav"));
|
const auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/killdeer.wav").value();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 112'941);
|
CHECK(inputSoundFile.getSampleCount() == 112'941);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 1);
|
CHECK(inputSoundFile.getChannelCount() == 1);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 22'050);
|
CHECK(inputSoundFile.getSampleRate() == 22'050);
|
||||||
@ -91,9 +79,8 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("openFromMemory()")
|
SECTION("openFromMemory()")
|
||||||
{
|
{
|
||||||
const auto memory = loadIntoMemory("Audio/killdeer.wav");
|
const auto memory = loadIntoMemory("Audio/killdeer.wav");
|
||||||
sf::InputSoundFile inputSoundFile;
|
const auto inputSoundFile = sf::InputSoundFile::openFromMemory(memory.data(), memory.size()).value();
|
||||||
REQUIRE(inputSoundFile.openFromMemory(memory.data(), memory.size()));
|
|
||||||
CHECK(inputSoundFile.getSampleCount() == 112'941);
|
CHECK(inputSoundFile.getSampleCount() == 112'941);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 1);
|
CHECK(inputSoundFile.getChannelCount() == 1);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 22'050);
|
CHECK(inputSoundFile.getSampleRate() == 22'050);
|
||||||
@ -104,12 +91,11 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("openFromStream()")
|
SECTION("openFromStream()")
|
||||||
{
|
{
|
||||||
sf::InputSoundFile inputSoundFile;
|
|
||||||
sf::FileInputStream stream;
|
sf::FileInputStream stream;
|
||||||
|
|
||||||
SECTION("Invalid stream")
|
SECTION("Invalid stream")
|
||||||
{
|
{
|
||||||
CHECK(!inputSoundFile.openFromStream(stream));
|
CHECK(!sf::InputSoundFile::openFromStream(stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Valid stream")
|
SECTION("Valid stream")
|
||||||
@ -117,7 +103,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
SECTION("flac")
|
SECTION("flac")
|
||||||
{
|
{
|
||||||
REQUIRE(stream.open("Audio/ding.flac"));
|
REQUIRE(stream.open("Audio/ding.flac"));
|
||||||
REQUIRE(inputSoundFile.openFromStream(stream));
|
const auto inputSoundFile = sf::InputSoundFile::openFromStream(stream).value();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 1);
|
CHECK(inputSoundFile.getChannelCount() == 1);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
||||||
@ -129,7 +115,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
SECTION("mp3")
|
SECTION("mp3")
|
||||||
{
|
{
|
||||||
REQUIRE(stream.open("Audio/ding.mp3"));
|
REQUIRE(stream.open("Audio/ding.mp3"));
|
||||||
REQUIRE(inputSoundFile.openFromStream(stream));
|
const auto inputSoundFile = sf::InputSoundFile::openFromStream(stream).value();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 1);
|
CHECK(inputSoundFile.getChannelCount() == 1);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
||||||
@ -141,7 +127,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
SECTION("ogg")
|
SECTION("ogg")
|
||||||
{
|
{
|
||||||
REQUIRE(stream.open("Audio/doodle_pop.ogg"));
|
REQUIRE(stream.open("Audio/doodle_pop.ogg"));
|
||||||
REQUIRE(inputSoundFile.openFromStream(stream));
|
const auto inputSoundFile = sf::InputSoundFile::openFromStream(stream).value();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 2'116'992);
|
CHECK(inputSoundFile.getSampleCount() == 2'116'992);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 2);
|
CHECK(inputSoundFile.getChannelCount() == 2);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
CHECK(inputSoundFile.getSampleRate() == 44'100);
|
||||||
@ -153,7 +139,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
SECTION("wav")
|
SECTION("wav")
|
||||||
{
|
{
|
||||||
REQUIRE(stream.open("Audio/killdeer.wav"));
|
REQUIRE(stream.open("Audio/killdeer.wav"));
|
||||||
REQUIRE(inputSoundFile.openFromStream(stream));
|
const auto inputSoundFile = sf::InputSoundFile::openFromStream(stream).value();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 112'941);
|
CHECK(inputSoundFile.getSampleCount() == 112'941);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 1);
|
CHECK(inputSoundFile.getChannelCount() == 1);
|
||||||
CHECK(inputSoundFile.getSampleRate() == 22'050);
|
CHECK(inputSoundFile.getSampleRate() == 22'050);
|
||||||
@ -166,11 +152,9 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("seek(std::uint64_t)")
|
SECTION("seek(std::uint64_t)")
|
||||||
{
|
{
|
||||||
sf::InputSoundFile inputSoundFile;
|
|
||||||
|
|
||||||
SECTION("flac")
|
SECTION("flac")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.flac"));
|
auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value();
|
||||||
inputSoundFile.seek(1'000);
|
inputSoundFile.seek(1'000);
|
||||||
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(22'675));
|
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(22'675));
|
||||||
CHECK(inputSoundFile.getSampleOffset() == 1'000);
|
CHECK(inputSoundFile.getSampleOffset() == 1'000);
|
||||||
@ -178,7 +162,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("mp3")
|
SECTION("mp3")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.mp3"));
|
auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.mp3").value();
|
||||||
inputSoundFile.seek(1'000);
|
inputSoundFile.seek(1'000);
|
||||||
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(22'675));
|
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(22'675));
|
||||||
CHECK(inputSoundFile.getSampleOffset() == 1'000);
|
CHECK(inputSoundFile.getSampleOffset() == 1'000);
|
||||||
@ -186,7 +170,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("ogg")
|
SECTION("ogg")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/doodle_pop.ogg"));
|
auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/doodle_pop.ogg").value();
|
||||||
inputSoundFile.seek(1'000);
|
inputSoundFile.seek(1'000);
|
||||||
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(11'337));
|
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(11'337));
|
||||||
CHECK(inputSoundFile.getSampleOffset() == 1'000);
|
CHECK(inputSoundFile.getSampleOffset() == 1'000);
|
||||||
@ -194,7 +178,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("wav")
|
SECTION("wav")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/killdeer.wav"));
|
auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/killdeer.wav").value();
|
||||||
inputSoundFile.seek(1'000);
|
inputSoundFile.seek(1'000);
|
||||||
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(45'351));
|
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(45'351));
|
||||||
CHECK(inputSoundFile.getSampleOffset() == 1'000);
|
CHECK(inputSoundFile.getSampleOffset() == 1'000);
|
||||||
@ -203,8 +187,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("seek(Time)")
|
SECTION("seek(Time)")
|
||||||
{
|
{
|
||||||
sf::InputSoundFile inputSoundFile;
|
auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value();
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.flac"));
|
|
||||||
inputSoundFile.seek(sf::milliseconds(100));
|
inputSoundFile.seek(sf::milliseconds(100));
|
||||||
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
CHECK(inputSoundFile.getSampleCount() == 87'798);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 1);
|
CHECK(inputSoundFile.getChannelCount() == 1);
|
||||||
@ -216,21 +199,15 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("read()")
|
SECTION("read()")
|
||||||
{
|
{
|
||||||
sf::InputSoundFile inputSoundFile;
|
auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value();
|
||||||
std::array<std::int16_t, 4> samples{};
|
|
||||||
|
|
||||||
SECTION("Unloaded file")
|
|
||||||
{
|
|
||||||
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.flac"));
|
|
||||||
|
|
||||||
SECTION("Null address")
|
SECTION("Null address")
|
||||||
{
|
{
|
||||||
CHECK(inputSoundFile.read(nullptr, 10) == 0);
|
CHECK(inputSoundFile.read(nullptr, 10) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<std::int16_t, 4> samples{};
|
||||||
|
|
||||||
SECTION("Zero count")
|
SECTION("Zero count")
|
||||||
{
|
{
|
||||||
CHECK(inputSoundFile.read(samples.data(), 0) == 0);
|
CHECK(inputSoundFile.read(samples.data(), 0) == 0);
|
||||||
@ -240,7 +217,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
{
|
{
|
||||||
SECTION("flac")
|
SECTION("flac")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.flac"));
|
inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value();
|
||||||
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
||||||
CHECK(samples == std::array<std::int16_t, 4>{0, 1, -1, 4});
|
CHECK(samples == std::array<std::int16_t, 4>{0, 1, -1, 4});
|
||||||
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
||||||
@ -249,7 +226,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("mp3")
|
SECTION("mp3")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.mp3"));
|
inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.mp3").value();
|
||||||
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
||||||
CHECK(samples == std::array<std::int16_t, 4>{0, -2, 0, 2});
|
CHECK(samples == std::array<std::int16_t, 4>{0, -2, 0, 2});
|
||||||
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
||||||
@ -258,7 +235,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("ogg")
|
SECTION("ogg")
|
||||||
{
|
{
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/doodle_pop.ogg"));
|
inputSoundFile = sf::InputSoundFile::openFromFile("Audio/doodle_pop.ogg").value();
|
||||||
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
||||||
CHECK(samples == std::array<std::int16_t, 4>{-827, -985, -1168, -1319});
|
CHECK(samples == std::array<std::int16_t, 4>{-827, -985, -1168, -1319});
|
||||||
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
|
||||||
@ -274,8 +251,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
|
|||||||
|
|
||||||
SECTION("close()")
|
SECTION("close()")
|
||||||
{
|
{
|
||||||
sf::InputSoundFile inputSoundFile;
|
auto inputSoundFile = sf::InputSoundFile::openFromFile("Audio/ding.flac").value();
|
||||||
REQUIRE(inputSoundFile.openFromFile("Audio/ding.flac"));
|
|
||||||
inputSoundFile.close();
|
inputSoundFile.close();
|
||||||
CHECK(inputSoundFile.getSampleCount() == 0);
|
CHECK(inputSoundFile.getSampleCount() == 0);
|
||||||
CHECK(inputSoundFile.getChannelCount() == 0);
|
CHECK(inputSoundFile.getChannelCount() == 0);
|
||||||
|
@ -37,7 +37,6 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
SECTION("Construction")
|
SECTION("Construction")
|
||||||
{
|
{
|
||||||
const sf::Music music;
|
const sf::Music music;
|
||||||
CHECK(music.getDuration() == sf::Time::Zero);
|
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
CHECK(offset == sf::Time::Zero);
|
CHECK(offset == sf::Time::Zero);
|
||||||
CHECK(length == sf::Time::Zero);
|
CHECK(length == sf::Time::Zero);
|
||||||
@ -55,7 +54,6 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
SECTION("Invalid file")
|
SECTION("Invalid file")
|
||||||
{
|
{
|
||||||
REQUIRE(!music.openFromFile("does/not/exist.wav"));
|
REQUIRE(!music.openFromFile("does/not/exist.wav"));
|
||||||
CHECK(music.getDuration() == sf::Time::Zero);
|
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
CHECK(offset == sf::Time::Zero);
|
CHECK(offset == sf::Time::Zero);
|
||||||
CHECK(length == sf::Time::Zero);
|
CHECK(length == sf::Time::Zero);
|
||||||
@ -89,7 +87,6 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
SECTION("Invalid buffer")
|
SECTION("Invalid buffer")
|
||||||
{
|
{
|
||||||
REQUIRE(!music.openFromMemory(memory.data(), memory.size()));
|
REQUIRE(!music.openFromMemory(memory.data(), memory.size()));
|
||||||
CHECK(music.getDuration() == sf::Time::Zero);
|
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
CHECK(offset == sf::Time::Zero);
|
CHECK(offset == sf::Time::Zero);
|
||||||
CHECK(length == sf::Time::Zero);
|
CHECK(length == sf::Time::Zero);
|
||||||
@ -124,7 +121,6 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
SECTION("Invalid stream")
|
SECTION("Invalid stream")
|
||||||
{
|
{
|
||||||
CHECK(!music.openFromStream(stream));
|
CHECK(!music.openFromStream(stream));
|
||||||
CHECK(music.getDuration() == sf::Time::Zero);
|
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
CHECK(offset == sf::Time::Zero);
|
CHECK(offset == sf::Time::Zero);
|
||||||
CHECK(length == sf::Time::Zero);
|
CHECK(length == sf::Time::Zero);
|
||||||
@ -178,32 +174,15 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
SECTION("setLoopPoints()")
|
SECTION("setLoopPoints()")
|
||||||
{
|
{
|
||||||
sf::Music music;
|
sf::Music music;
|
||||||
|
REQUIRE(music.openFromFile("Audio/killdeer.wav"));
|
||||||
SECTION("No file")
|
music.setLoopPoints({sf::seconds(1), sf::seconds(2)});
|
||||||
{
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
music.setLoopPoints({sf::Time::Zero, sf::Time::Zero});
|
CHECK(offset == sf::seconds(1));
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
CHECK(length == sf::seconds(2));
|
||||||
CHECK(offset == sf::Time::Zero);
|
CHECK(music.getChannelCount() == 1);
|
||||||
CHECK(length == sf::Time::Zero);
|
CHECK(music.getSampleRate() == 22050);
|
||||||
CHECK(music.getChannelCount() == 0);
|
CHECK(music.getStatus() == sf::Music::Status::Stopped);
|
||||||
CHECK(music.getSampleRate() == 0);
|
CHECK(music.getPlayingOffset() == sf::Time::Zero);
|
||||||
CHECK(music.getStatus() == sf::Music::Status::Stopped);
|
CHECK(!music.getLoop());
|
||||||
CHECK(music.getPlayingOffset() == sf::Time::Zero);
|
|
||||||
CHECK(!music.getLoop());
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Loaded file")
|
|
||||||
{
|
|
||||||
REQUIRE(music.openFromFile("Audio/killdeer.wav"));
|
|
||||||
music.setLoopPoints({sf::seconds(1), sf::seconds(2)});
|
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
|
||||||
CHECK(offset == sf::seconds(1));
|
|
||||||
CHECK(length == sf::seconds(2));
|
|
||||||
CHECK(music.getChannelCount() == 1);
|
|
||||||
CHECK(music.getSampleRate() == 22050);
|
|
||||||
CHECK(music.getStatus() == sf::Music::Status::Stopped);
|
|
||||||
CHECK(music.getPlayingOffset() == sf::Time::Zero);
|
|
||||||
CHECK(!music.getLoop());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
static_assert(!std::is_default_constructible_v<sf::OutputSoundFile>);
|
||||||
static_assert(!std::is_copy_constructible_v<sf::OutputSoundFile>);
|
static_assert(!std::is_copy_constructible_v<sf::OutputSoundFile>);
|
||||||
static_assert(!std::is_copy_assignable_v<sf::OutputSoundFile>);
|
static_assert(!std::is_copy_assignable_v<sf::OutputSoundFile>);
|
||||||
static_assert(std::is_nothrow_move_constructible_v<sf::OutputSoundFile>);
|
static_assert(std::is_nothrow_move_constructible_v<sf::OutputSoundFile>);
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Audio
|
// Audio
|
||||||
[[maybe_unused]] const sf::InputSoundFile inputSoundFile;
|
|
||||||
[[maybe_unused]] const sf::SoundBufferRecorder soundBufferRecorder;
|
[[maybe_unused]] const sf::SoundBufferRecorder soundBufferRecorder;
|
||||||
[[maybe_unused]] const sf::Music music;
|
[[maybe_unused]] const sf::Music music;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user