mirror of
https://github.com/SFML/SFML.git
synced 2024-11-24 20:31:05 +08:00
Remove default empty state of sf::Music
This commit is contained in:
parent
e7d67cfa2a
commit
52ce862a00
@ -46,9 +46,7 @@ void playSound()
|
|||||||
void playMusic(const std::filesystem::path& filename)
|
void playMusic(const std::filesystem::path& filename)
|
||||||
{
|
{
|
||||||
// Load an ogg music file
|
// Load an ogg music file
|
||||||
sf::Music music;
|
auto music = sf::Music::openFromFile("resources" / filename).value();
|
||||||
if (!music.openFromFile("resources" / filename))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Display music information
|
// Display music information
|
||||||
std::cout << filename << ":" << '\n'
|
std::cout << filename << ":" << '\n'
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -114,20 +115,23 @@ public:
|
|||||||
m_listener.setFillColor(sf::Color::Red);
|
m_listener.setFillColor(sf::Color::Red);
|
||||||
|
|
||||||
// Load the music file
|
// Load the music file
|
||||||
if (!m_music.openFromFile(resourcesDir() / "doodle_pop.ogg"))
|
if (!(m_music = sf::Music::openFromFile(resourcesDir() / "doodle_pop.ogg")))
|
||||||
|
{
|
||||||
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
|
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
// Set the music to loop
|
// Set the music to loop
|
||||||
m_music.setLoop(true);
|
m_music->setLoop(true);
|
||||||
|
|
||||||
// Set attenuation to a nice value
|
// Set attenuation to a nice value
|
||||||
m_music.setAttenuation(0.04f);
|
m_music->setAttenuation(0.04f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpdate(float /*time*/, float x, float y) override
|
void onUpdate(float /*time*/, float x, float y) override
|
||||||
{
|
{
|
||||||
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
|
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
|
||||||
m_music.setPosition({m_position.x, m_position.y, 0.f});
|
m_music->setPosition({m_position.x, m_position.y, 0.f});
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
|
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
|
||||||
@ -145,19 +149,19 @@ public:
|
|||||||
// Synchronize listener audio position with graphical position
|
// Synchronize listener audio position with graphical position
|
||||||
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
|
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
|
||||||
|
|
||||||
m_music.play();
|
m_music->play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onStop() override
|
void onStop() override
|
||||||
{
|
{
|
||||||
m_music.stop();
|
m_music->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf::CircleShape m_listener{20.f};
|
sf::CircleShape m_listener{20.f};
|
||||||
sf::CircleShape m_soundShape{20.f};
|
sf::CircleShape m_soundShape{20.f};
|
||||||
sf::Vector2f m_position;
|
sf::Vector2f m_position;
|
||||||
sf::Music m_music;
|
std::optional<sf::Music> m_music;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -173,20 +177,23 @@ public:
|
|||||||
m_volumeText(getFont(), "Volume: " + std::to_string(m_volume))
|
m_volumeText(getFont(), "Volume: " + std::to_string(m_volume))
|
||||||
{
|
{
|
||||||
// Load the music file
|
// Load the music file
|
||||||
if (!m_music.openFromFile(resourcesDir() / "doodle_pop.ogg"))
|
if (!(m_music = sf::Music::openFromFile(resourcesDir() / "doodle_pop.ogg")))
|
||||||
|
{
|
||||||
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
|
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
// Set the music to loop
|
// Set the music to loop
|
||||||
m_music.setLoop(true);
|
m_music->setLoop(true);
|
||||||
|
|
||||||
// We don't care about attenuation in this effect
|
// We don't care about attenuation in this effect
|
||||||
m_music.setAttenuation(0.f);
|
m_music->setAttenuation(0.f);
|
||||||
|
|
||||||
// Set initial pitch
|
// Set initial pitch
|
||||||
m_music.setPitch(m_pitch);
|
m_music->setPitch(m_pitch);
|
||||||
|
|
||||||
// Set initial volume
|
// Set initial volume
|
||||||
m_music.setVolume(m_volume);
|
m_music->setVolume(m_volume);
|
||||||
|
|
||||||
m_pitchText.setPosition({windowWidth / 2.f - 120.f, windowHeight / 2.f - 80.f});
|
m_pitchText.setPosition({windowWidth / 2.f - 120.f, windowHeight / 2.f - 80.f});
|
||||||
m_volumeText.setPosition({windowWidth / 2.f - 120.f, windowHeight / 2.f - 30.f});
|
m_volumeText.setPosition({windowWidth / 2.f - 120.f, windowHeight / 2.f - 30.f});
|
||||||
@ -197,8 +204,8 @@ public:
|
|||||||
m_pitch = std::clamp(2.f * x, 0.f, 2.f);
|
m_pitch = std::clamp(2.f * x, 0.f, 2.f);
|
||||||
m_volume = std::clamp(100.f * (1.f - y), 0.f, 100.f);
|
m_volume = std::clamp(100.f * (1.f - y), 0.f, 100.f);
|
||||||
|
|
||||||
m_music.setPitch(m_pitch);
|
m_music->setPitch(m_pitch);
|
||||||
m_music.setVolume(m_volume);
|
m_music->setVolume(m_volume);
|
||||||
|
|
||||||
m_pitchText.setString("Pitch: " + std::to_string(m_pitch));
|
m_pitchText.setString("Pitch: " + std::to_string(m_pitch));
|
||||||
m_volumeText.setString("Volume: " + std::to_string(m_volume));
|
m_volumeText.setString("Volume: " + std::to_string(m_volume));
|
||||||
@ -216,20 +223,20 @@ public:
|
|||||||
// so that the music is right on top of the listener
|
// so that the music is right on top of the listener
|
||||||
sf::Listener::setPosition({0.f, 0.f, 0.f});
|
sf::Listener::setPosition({0.f, 0.f, 0.f});
|
||||||
|
|
||||||
m_music.play();
|
m_music->play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onStop() override
|
void onStop() override
|
||||||
{
|
{
|
||||||
m_music.stop();
|
m_music->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float m_pitch{1.f};
|
float m_pitch{1.f};
|
||||||
float m_volume{100.f};
|
float m_volume{100.f};
|
||||||
sf::Text m_pitchText;
|
sf::Text m_pitchText;
|
||||||
sf::Text m_volumeText;
|
sf::Text m_volumeText;
|
||||||
sf::Music m_music;
|
std::optional<sf::Music> m_music;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -276,20 +283,23 @@ public:
|
|||||||
makeCone(m_soundConeInner, innerConeAngle);
|
makeCone(m_soundConeInner, innerConeAngle);
|
||||||
|
|
||||||
// Load the music file
|
// Load the music file
|
||||||
if (!m_music.openFromFile(resourcesDir() / "doodle_pop.ogg"))
|
if (!(m_music = sf::Music::openFromFile(resourcesDir() / "doodle_pop.ogg")))
|
||||||
|
{
|
||||||
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
|
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
// Set the music to loop
|
// Set the music to loop
|
||||||
m_music.setLoop(true);
|
m_music->setLoop(true);
|
||||||
|
|
||||||
// Set attenuation factor
|
// Set attenuation factor
|
||||||
m_music.setAttenuation(m_attenuation);
|
m_music->setAttenuation(m_attenuation);
|
||||||
|
|
||||||
// Set direction to face "downwards"
|
// Set direction to face "downwards"
|
||||||
m_music.setDirection({0.f, 1.f, 0.f});
|
m_music->setDirection({0.f, 1.f, 0.f});
|
||||||
|
|
||||||
// Set cone
|
// Set cone
|
||||||
m_music.setCone({innerConeAngle, outerConeAngle, 0.f});
|
m_music->setCone({innerConeAngle, outerConeAngle, 0.f});
|
||||||
|
|
||||||
m_text.setString(
|
m_text.setString(
|
||||||
"Attenuation factor dampens full volume of sound while within inner cone based on distance to "
|
"Attenuation factor dampens full volume of sound while within inner cone based on distance to "
|
||||||
@ -304,7 +314,7 @@ public:
|
|||||||
void onUpdate(float /*time*/, float x, float y) override
|
void onUpdate(float /*time*/, float x, float y) override
|
||||||
{
|
{
|
||||||
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
|
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
|
||||||
m_music.setPosition({m_position.x, m_position.y, 0.f});
|
m_music->setPosition({m_position.x, m_position.y, 0.f});
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
|
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
|
||||||
@ -326,22 +336,22 @@ public:
|
|||||||
// Synchronize listener audio position with graphical position
|
// Synchronize listener audio position with graphical position
|
||||||
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
|
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
|
||||||
|
|
||||||
m_music.play();
|
m_music->play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onStop() override
|
void onStop() override
|
||||||
{
|
{
|
||||||
m_music.stop();
|
m_music->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sf::CircleShape m_listener{20.f};
|
sf::CircleShape m_listener{20.f};
|
||||||
sf::CircleShape m_soundShape{20.f};
|
sf::CircleShape m_soundShape{20.f};
|
||||||
sf::ConvexShape m_soundConeOuter;
|
sf::ConvexShape m_soundConeOuter;
|
||||||
sf::ConvexShape m_soundConeInner;
|
sf::ConvexShape m_soundConeInner;
|
||||||
sf::Text m_text;
|
sf::Text m_text;
|
||||||
sf::Vector2f m_position;
|
sf::Vector2f m_position;
|
||||||
sf::Music m_music;
|
std::optional<sf::Music> m_music;
|
||||||
|
|
||||||
float m_attenuation{0.01f};
|
float m_attenuation{0.01f};
|
||||||
};
|
};
|
||||||
@ -626,7 +636,7 @@ public:
|
|||||||
void onUpdate([[maybe_unused]] float time, float x, float y) override
|
void onUpdate([[maybe_unused]] float time, float x, float y) override
|
||||||
{
|
{
|
||||||
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
|
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
|
||||||
m_music.setPosition({m_position.x, m_position.y, 0.f});
|
m_music->setPosition({m_position.x, m_position.y, 0.f});
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
|
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
|
||||||
@ -646,12 +656,12 @@ public:
|
|||||||
// Synchronize listener audio position with graphical position
|
// Synchronize listener audio position with graphical position
|
||||||
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
|
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
|
||||||
|
|
||||||
m_music.play();
|
m_music->play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onStop() override
|
void onStop() override
|
||||||
{
|
{
|
||||||
m_music.stop();
|
m_music->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -667,19 +677,22 @@ protected:
|
|||||||
m_instructions.setPosition({windowWidth / 2.f - 250.f, windowHeight * 3.f / 4.f});
|
m_instructions.setPosition({windowWidth / 2.f - 250.f, windowHeight * 3.f / 4.f});
|
||||||
|
|
||||||
// Load the music file
|
// Load the music file
|
||||||
if (!m_music.openFromFile(resourcesDir() / "doodle_pop.ogg"))
|
if (!(m_music = sf::Music::openFromFile(resourcesDir() / "doodle_pop.ogg")))
|
||||||
|
{
|
||||||
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
|
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
// Set the music to loop
|
// Set the music to loop
|
||||||
m_music.setLoop(true);
|
m_music->setLoop(true);
|
||||||
|
|
||||||
// Set attenuation to a nice value
|
// Set attenuation to a nice value
|
||||||
m_music.setAttenuation(0.0f);
|
m_music->setAttenuation(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
sf::Music& getMusic()
|
sf::Music& getMusic()
|
||||||
{
|
{
|
||||||
return m_music;
|
return *m_music;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<bool>& getEnabled() const
|
const std::shared_ptr<bool>& getEnabled() const
|
||||||
@ -696,13 +709,13 @@ private:
|
|||||||
m_enabledText.setString(*m_enabled ? "Processing: Enabled" : "Processing: Disabled");
|
m_enabledText.setString(*m_enabled ? "Processing: Enabled" : "Processing: Disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
sf::CircleShape m_listener{20.f};
|
sf::CircleShape m_listener{20.f};
|
||||||
sf::CircleShape m_soundShape{20.f};
|
sf::CircleShape m_soundShape{20.f};
|
||||||
sf::Vector2f m_position;
|
sf::Vector2f m_position;
|
||||||
sf::Music m_music;
|
std::optional<sf::Music> m_music;
|
||||||
std::shared_ptr<bool> m_enabled{std::make_shared<bool>(true)};
|
std::shared_ptr<bool> m_enabled{std::make_shared<bool>(true)};
|
||||||
sf::Text m_enabledText;
|
sf::Text m_enabledText;
|
||||||
sf::Text m_instructions;
|
sf::Text m_instructions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,6 +40,31 @@ namespace sf
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class SFML_AUDIO_API AudioResource
|
class SFML_AUDIO_API AudioResource
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource(const AudioResource&) = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource& operator=(const AudioResource&) = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource(AudioResource&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource& operator=(AudioResource&&) noexcept = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Default constructor
|
/// \brief Default constructor
|
||||||
@ -51,7 +76,7 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
const std::shared_ptr<void> m_device; //!< Sound device
|
std::shared_ptr<void> m_device; //!< Sound device
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -29,12 +29,11 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Audio/Export.hpp>
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
#include <SFML/Audio/InputSoundFile.hpp>
|
|
||||||
#include <SFML/Audio/SoundStream.hpp>
|
#include <SFML/Audio/SoundStream.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <mutex>
|
#include <memory>
|
||||||
#include <vector>
|
#include <optional>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -44,6 +43,7 @@ namespace sf
|
|||||||
{
|
{
|
||||||
class Time;
|
class Time;
|
||||||
class InputStream;
|
class InputStream;
|
||||||
|
class InputSoundFile;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Streamed music played from an audio file
|
/// \brief Streamed music played from an audio file
|
||||||
@ -72,6 +72,18 @@ public:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
~Music() override;
|
~Music() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Music(Music&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Music& operator=(Music&&) noexcept;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Open a music from an audio file
|
/// \brief Open a music from an audio file
|
||||||
///
|
///
|
||||||
@ -86,12 +98,12 @@ public:
|
|||||||
///
|
///
|
||||||
/// \param filename Path of the music file to open
|
/// \param filename Path of the music file to open
|
||||||
///
|
///
|
||||||
/// \return True if loading succeeded, false if it failed
|
/// \return Music if loading succeeded, `std::nullopt` if it failed
|
||||||
///
|
///
|
||||||
/// \see openFromMemory, openFromStream
|
/// \see openFromMemory, openFromStream
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
[[nodiscard]] bool openFromFile(const std::filesystem::path& filename);
|
[[nodiscard]] static std::optional<Music> openFromFile(const std::filesystem::path& filename);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Open a music from an audio file in memory
|
/// \brief Open a music from an audio file in memory
|
||||||
@ -109,12 +121,12 @@ 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 loading succeeded, false if it failed
|
/// \return Music if loading succeeded, `std::nullopt` if it failed
|
||||||
///
|
///
|
||||||
/// \see openFromFile, openFromStream
|
/// \see openFromFile, openFromStream
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
[[nodiscard]] bool openFromMemory(const void* data, std::size_t sizeInBytes);
|
[[nodiscard]] static std::optional<Music> openFromMemory(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Open a music from an audio file in a custom stream
|
/// \brief Open a music from an audio file in a custom stream
|
||||||
@ -130,12 +142,12 @@ public:
|
|||||||
///
|
///
|
||||||
/// \param stream Source stream to read from
|
/// \param stream Source stream to read from
|
||||||
///
|
///
|
||||||
/// \return True if loading succeeded, false if it failed
|
/// \return Music if loading succeeded, `std::nullopt` if it failed
|
||||||
///
|
///
|
||||||
/// \see openFromFile, openFromMemory
|
/// \see openFromFile, openFromMemory
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
[[nodiscard]] bool openFromStream(InputStream& stream);
|
[[nodiscard]] static std::optional<Music> openFromStream(InputStream& stream);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Get the total duration of the music
|
/// \brief Get the total duration of the music
|
||||||
@ -219,11 +231,17 @@ protected:
|
|||||||
std::optional<std::uint64_t> onLoop() override;
|
std::optional<std::uint64_t> onLoop() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Try opening the music file from an optional input sound file
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::optional<Music> tryOpenFromFile(std::optional<InputSoundFile>&& optFile);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Initialize the internal state after loading a new music
|
/// \brief Initialize the internal state after loading a new music
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void initialize();
|
explicit Music(InputSoundFile&& file);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Helper to convert an sf::Time to a sample position
|
/// \brief Helper to convert an sf::Time to a sample position
|
||||||
@ -248,10 +266,8 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::optional<InputSoundFile> m_file; //!< The streamed music file
|
struct Impl;
|
||||||
std::vector<std::int16_t> m_samples; //!< Temporary buffer of samples
|
std::unique_ptr<Impl> m_impl; //!< Implementation details
|
||||||
std::recursive_mutex m_mutex; //!< Mutex protecting the data
|
|
||||||
Span<std::uint64_t> m_loopSpan; //!< Loop Range Specifier
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -149,10 +149,20 @@ public:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Copy constructor
|
/// \brief Copy constructor
|
||||||
///
|
///
|
||||||
/// \param copy Instance to copy
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundSource(const SoundSource&) = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
SoundSource(const SoundSource& copy) = default;
|
SoundSource(SoundSource&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundSource& operator=(SoundSource&&) noexcept = default;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Destructor
|
/// \brief Destructor
|
||||||
|
@ -67,6 +67,18 @@ public:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
~SoundStream() override;
|
~SoundStream() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundStream(SoundStream&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundStream& operator=(SoundStream&&) noexcept;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Start or resume playing the audio stream
|
/// \brief Start or resume playing the audio stream
|
||||||
///
|
///
|
||||||
@ -286,7 +298,7 @@ private:
|
|||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
struct Impl;
|
struct Impl;
|
||||||
const std::unique_ptr<Impl> m_impl; //!< Implementation details
|
std::unique_ptr<Impl> m_impl; //!< Implementation details
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/InputSoundFile.hpp>
|
||||||
#include <SFML/Audio/Music.hpp>
|
#include <SFML/Audio/Music.hpp>
|
||||||
|
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
@ -34,85 +35,92 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Music::Impl
|
||||||
|
{
|
||||||
|
InputSoundFile file; //!< The streamed music file
|
||||||
|
std::vector<std::int16_t> samples; //!< Temporary buffer of samples
|
||||||
|
std::recursive_mutex mutex; //!< Mutex protecting the data
|
||||||
|
Span<std::uint64_t> loopSpan; //!< Loop Range Specifier
|
||||||
|
|
||||||
|
explicit Impl(InputSoundFile&& theFile) :
|
||||||
|
file(std::move(theFile)),
|
||||||
|
|
||||||
|
// Resize the internal buffer so that it can contain 1 second of audio samples
|
||||||
|
samples(file.getSampleRate() * file.getChannelCount()),
|
||||||
|
|
||||||
|
// Compute the music positions
|
||||||
|
loopSpan{0u, file.getSampleCount()}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Music::~Music()
|
Music::~Music()
|
||||||
{
|
{
|
||||||
// We must stop before destroying the file
|
// We must stop before destroying the file
|
||||||
stop();
|
if (m_impl != nullptr)
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Music::openFromFile(const std::filesystem::path& filename)
|
Music::Music(Music&&) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Music& Music::operator=(Music&&) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::optional<Music> Music::tryOpenFromFile(std::optional<InputSoundFile>&& optFile)
|
||||||
{
|
{
|
||||||
// First stop the music if it was already running
|
if (!optFile.has_value())
|
||||||
stop();
|
return std::nullopt;
|
||||||
|
|
||||||
// Open the underlying sound file
|
// TODO: apply RVO here via passkey idiom
|
||||||
m_file = sf::InputSoundFile::openFromFile(filename);
|
return Music(std::move(*optFile));
|
||||||
if (!m_file)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Perform common initializations
|
|
||||||
initialize();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Music::openFromMemory(const void* data, std::size_t sizeInBytes)
|
std::optional<Music> Music::openFromFile(const std::filesystem::path& filename)
|
||||||
{
|
{
|
||||||
// First stop the music if it was already running
|
return tryOpenFromFile(InputSoundFile::openFromFile(filename));
|
||||||
stop();
|
|
||||||
|
|
||||||
// Open the underlying sound file
|
|
||||||
m_file = sf::InputSoundFile::openFromMemory(data, sizeInBytes);
|
|
||||||
if (!m_file)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Perform common initializations
|
|
||||||
initialize();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Music::openFromStream(InputStream& stream)
|
std::optional<Music> Music::openFromMemory(const void* data, std::size_t sizeInBytes)
|
||||||
{
|
{
|
||||||
// First stop the music if it was already running
|
return tryOpenFromFile(InputSoundFile::openFromMemory(data, sizeInBytes));
|
||||||
stop();
|
}
|
||||||
|
|
||||||
// Open the underlying sound file
|
|
||||||
m_file = sf::InputSoundFile::openFromStream(stream);
|
|
||||||
if (!m_file)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Perform common initializations
|
////////////////////////////////////////////////////////////
|
||||||
initialize();
|
std::optional<Music> Music::openFromStream(InputStream& stream)
|
||||||
|
{
|
||||||
return true;
|
return tryOpenFromFile(InputSoundFile::openFromStream(stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Time Music::getDuration() const
|
Time Music::getDuration() const
|
||||||
{
|
{
|
||||||
assert(m_file && "Music::getDuration() Cannot get duration until music is opened");
|
return m_impl->file.getDuration();
|
||||||
return m_file->getDuration();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Music::TimeSpan Music::getLoopPoints() const
|
Music::TimeSpan Music::getLoopPoints() const
|
||||||
{
|
{
|
||||||
return TimeSpan{samplesToTime(m_loopSpan.offset), samplesToTime(m_loopSpan.length)};
|
return TimeSpan{samplesToTime(m_impl->loopSpan.offset), samplesToTime(m_impl->loopSpan.length)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -122,8 +130,7 @@ 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
|
||||||
assert(m_file && "Music::setLoopPoints() Cannot set loop points unit music is opened");
|
if (getChannelCount() == 0 || m_impl->file.getSampleCount() == 0)
|
||||||
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;
|
||||||
@ -136,11 +143,12 @@ 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_impl->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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (samplePoints.length == 0)
|
if (samplePoints.length == 0)
|
||||||
{
|
{
|
||||||
err() << "LoopPoints length val must be nonzero." << std::endl;
|
err() << "LoopPoints length val must be nonzero." << std::endl;
|
||||||
@ -148,10 +156,10 @@ 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_impl->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_impl->loopSpan.offset && samplePoints.length == m_impl->loopSpan.length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// When we apply this change, we need to "reset" this instance and its buffer
|
// When we apply this change, we need to "reset" this instance and its buffer
|
||||||
@ -164,7 +172,7 @@ void Music::setLoopPoints(TimeSpan timePoints)
|
|||||||
stop();
|
stop();
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
m_loopSpan = samplePoints;
|
m_impl->loopSpan = samplePoints;
|
||||||
|
|
||||||
// Restore
|
// Restore
|
||||||
if (oldPos != Time::Zero)
|
if (oldPos != Time::Zero)
|
||||||
@ -179,80 +187,71 @@ 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_impl->mutex);
|
||||||
|
|
||||||
const std::lock_guard lock(m_mutex);
|
std::size_t toFill = m_impl->samples.size();
|
||||||
|
std::uint64_t currentOffset = m_impl->file.getSampleOffset();
|
||||||
std::size_t toFill = m_samples.size();
|
const std::uint64_t loopEnd = m_impl->loopSpan.offset + m_impl->loopSpan.length;
|
||||||
std::uint64_t currentOffset = m_file->getSampleOffset();
|
|
||||||
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.
|
||||||
// This will trip an "onLoop()" call from the underlying SoundStream,
|
// This will trip an "onLoop()" call from the underlying SoundStream,
|
||||||
// and we can then take action.
|
// and we can then take action.
|
||||||
if (getLoop() && (m_loopSpan.length != 0) && (currentOffset <= loopEnd) && (currentOffset + toFill > loopEnd))
|
if (getLoop() && (m_impl->loopSpan.length != 0) && (currentOffset <= loopEnd) && (currentOffset + toFill > loopEnd))
|
||||||
toFill = static_cast<std::size_t>(loopEnd - currentOffset);
|
toFill = static_cast<std::size_t>(loopEnd - currentOffset);
|
||||||
|
|
||||||
// Fill the chunk parameters
|
// Fill the chunk parameters
|
||||||
data.samples = m_samples.data();
|
data.samples = m_impl->samples.data();
|
||||||
data.sampleCount = static_cast<std::size_t>(m_file->read(m_samples.data(), toFill));
|
data.sampleCount = static_cast<std::size_t>(m_impl->file.read(m_impl->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_impl->file.getSampleCount()) &&
|
||||||
(currentOffset != loopEnd || m_loopSpan.length == 0);
|
(currentOffset != loopEnd || m_impl->loopSpan.length == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
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_impl->mutex);
|
||||||
|
m_impl->file.seek(timeOffset);
|
||||||
const std::lock_guard lock(m_mutex);
|
|
||||||
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_impl->mutex);
|
||||||
const std::uint64_t currentOffset = m_file->getSampleOffset();
|
const std::uint64_t currentOffset = m_impl->file.getSampleOffset();
|
||||||
if (getLoop() && (m_loopSpan.length != 0) && (currentOffset == m_loopSpan.offset + m_loopSpan.length))
|
|
||||||
|
if (getLoop() && (m_impl->loopSpan.length != 0) && (currentOffset == m_impl->loopSpan.offset + m_impl->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_impl->file.seek(m_impl->loopSpan.offset);
|
||||||
return m_file->getSampleOffset();
|
return m_impl->file.getSampleOffset();
|
||||||
}
|
}
|
||||||
else if (getLoop() && (currentOffset >= m_file->getSampleCount()))
|
|
||||||
|
if (getLoop() && (currentOffset >= m_impl->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_impl->file.seek(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void Music::initialize()
|
Music::Music(InputSoundFile&& file) : m_impl(std::make_unique<Impl>(std::move(file)))
|
||||||
{
|
{
|
||||||
// Compute the music positions
|
|
||||||
m_loopSpan.offset = 0;
|
|
||||||
m_loopSpan.length = m_file->getSampleCount();
|
|
||||||
|
|
||||||
// Resize the internal buffer so that it can contain 1 second of audio samples
|
|
||||||
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_impl->file.getChannelCount(), m_impl->file.getSampleRate(), m_impl->file.getChannelMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::uint64_t Music::timeToSamples(Time position) const
|
std::uint64_t Music::timeToSamples(Time position) const
|
||||||
{
|
{
|
||||||
|
@ -233,6 +233,14 @@ SoundStream::SoundStream() : m_impl(std::make_unique<Impl>(this))
|
|||||||
SoundStream::~SoundStream() = default;
|
SoundStream::~SoundStream() = default;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundStream::SoundStream(SoundStream&&) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundStream& SoundStream::operator=(SoundStream&&) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void SoundStream::initialize(unsigned int channelCount, unsigned int sampleRate, const std::vector<SoundChannel>& channelMap)
|
void SoundStream::initialize(unsigned int channelCount, unsigned int sampleRate, const std::vector<SoundChannel>& channelMap)
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
static_assert(!std::is_constructible_v<sf::AudioResource>);
|
static_assert(!std::is_constructible_v<sf::AudioResource>);
|
||||||
static_assert(std::is_copy_constructible_v<sf::AudioResource>);
|
static_assert(std::is_copy_constructible_v<sf::AudioResource>);
|
||||||
static_assert(!std::is_copy_assignable_v<sf::AudioResource>);
|
static_assert(std::is_copy_assignable_v<sf::AudioResource>);
|
||||||
static_assert(std::is_nothrow_move_constructible_v<sf::AudioResource>);
|
static_assert(std::is_nothrow_move_constructible_v<sf::AudioResource>);
|
||||||
static_assert(!std::is_nothrow_move_assignable_v<sf::AudioResource>);
|
static_assert(std::is_nothrow_move_assignable_v<sf::AudioResource>);
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
#include <AudioUtil.hpp>
|
#include <AudioUtil.hpp>
|
||||||
#include <SystemUtil.hpp>
|
#include <SystemUtil.hpp>
|
||||||
#include <array>
|
|
||||||
#include <fstream>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -18,8 +16,8 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
{
|
{
|
||||||
STATIC_CHECK(!std::is_copy_constructible_v<sf::Music>);
|
STATIC_CHECK(!std::is_copy_constructible_v<sf::Music>);
|
||||||
STATIC_CHECK(!std::is_copy_assignable_v<sf::Music>);
|
STATIC_CHECK(!std::is_copy_assignable_v<sf::Music>);
|
||||||
STATIC_CHECK(!std::is_nothrow_move_constructible_v<sf::Music>);
|
STATIC_CHECK(std::is_nothrow_move_constructible_v<sf::Music>);
|
||||||
STATIC_CHECK(!std::is_nothrow_move_assignable_v<sf::Music>);
|
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::Music>);
|
||||||
STATIC_CHECK(std::has_virtual_destructor_v<sf::Music>);
|
STATIC_CHECK(std::has_virtual_destructor_v<sf::Music>);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,39 +32,16 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
CHECK(timeSpan.length == sf::Time::Zero);
|
CHECK(timeSpan.length == sf::Time::Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Construction")
|
|
||||||
{
|
|
||||||
const sf::Music music;
|
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
|
||||||
CHECK(offset == sf::Time::Zero);
|
|
||||||
CHECK(length == sf::Time::Zero);
|
|
||||||
CHECK(music.getChannelCount() == 0);
|
|
||||||
CHECK(music.getSampleRate() == 0);
|
|
||||||
CHECK(music.getStatus() == sf::Music::Status::Stopped);
|
|
||||||
CHECK(music.getPlayingOffset() == sf::Time::Zero);
|
|
||||||
CHECK(!music.getLoop());
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("openFromFile()")
|
SECTION("openFromFile()")
|
||||||
{
|
{
|
||||||
sf::Music music;
|
|
||||||
|
|
||||||
SECTION("Invalid file")
|
SECTION("Invalid file")
|
||||||
{
|
{
|
||||||
REQUIRE(!music.openFromFile("does/not/exist.wav"));
|
CHECK(!sf::Music::openFromFile("does/not/exist.wav"));
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
|
||||||
CHECK(offset == sf::Time::Zero);
|
|
||||||
CHECK(length == sf::Time::Zero);
|
|
||||||
CHECK(music.getChannelCount() == 0);
|
|
||||||
CHECK(music.getSampleRate() == 0);
|
|
||||||
CHECK(music.getStatus() == sf::Music::Status::Stopped);
|
|
||||||
CHECK(music.getPlayingOffset() == sf::Time::Zero);
|
|
||||||
CHECK(!music.getLoop());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Valid file")
|
SECTION("Valid file")
|
||||||
{
|
{
|
||||||
REQUIRE(music.openFromFile("Audio/ding.mp3"));
|
const auto music = sf::Music::openFromFile("Audio/ding.mp3").value();
|
||||||
CHECK(music.getDuration() == sf::microseconds(1990884));
|
CHECK(music.getDuration() == sf::microseconds(1990884));
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
CHECK(offset == sf::Time::Zero);
|
CHECK(offset == sf::Time::Zero);
|
||||||
@ -82,25 +57,17 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
SECTION("openFromMemory()")
|
SECTION("openFromMemory()")
|
||||||
{
|
{
|
||||||
std::vector<std::byte> memory;
|
std::vector<std::byte> memory;
|
||||||
sf::Music music;
|
|
||||||
|
|
||||||
SECTION("Invalid buffer")
|
SECTION("Invalid buffer")
|
||||||
{
|
{
|
||||||
REQUIRE(!music.openFromMemory(memory.data(), memory.size()));
|
CHECK(!sf::Music::openFromMemory(memory.data(), memory.size()));
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
|
||||||
CHECK(offset == sf::Time::Zero);
|
|
||||||
CHECK(length == sf::Time::Zero);
|
|
||||||
CHECK(music.getChannelCount() == 0);
|
|
||||||
CHECK(music.getSampleRate() == 0);
|
|
||||||
CHECK(music.getStatus() == sf::Music::Status::Stopped);
|
|
||||||
CHECK(music.getPlayingOffset() == sf::Time::Zero);
|
|
||||||
CHECK(!music.getLoop());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Valid buffer")
|
SECTION("Valid buffer")
|
||||||
{
|
{
|
||||||
memory = loadIntoMemory("Audio/ding.flac");
|
memory = loadIntoMemory("Audio/ding.flac");
|
||||||
REQUIRE(music.openFromMemory(memory.data(), memory.size()));
|
|
||||||
|
const auto music = sf::Music::openFromMemory(memory.data(), memory.size()).value();
|
||||||
CHECK(music.getDuration() == sf::microseconds(1990884));
|
CHECK(music.getDuration() == sf::microseconds(1990884));
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
CHECK(offset == sf::Time::Zero);
|
CHECK(offset == sf::Time::Zero);
|
||||||
@ -116,25 +83,17 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
SECTION("openFromStream()")
|
SECTION("openFromStream()")
|
||||||
{
|
{
|
||||||
sf::FileInputStream stream;
|
sf::FileInputStream stream;
|
||||||
sf::Music music;
|
|
||||||
|
|
||||||
SECTION("Invalid stream")
|
SECTION("Invalid stream")
|
||||||
{
|
{
|
||||||
CHECK(!music.openFromStream(stream));
|
CHECK(!sf::Music::openFromStream(stream));
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
|
||||||
CHECK(offset == sf::Time::Zero);
|
|
||||||
CHECK(length == sf::Time::Zero);
|
|
||||||
CHECK(music.getChannelCount() == 0);
|
|
||||||
CHECK(music.getSampleRate() == 0);
|
|
||||||
CHECK(music.getStatus() == sf::Music::Status::Stopped);
|
|
||||||
CHECK(music.getPlayingOffset() == sf::Time::Zero);
|
|
||||||
CHECK(!music.getLoop());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Valid stream")
|
SECTION("Valid stream")
|
||||||
{
|
{
|
||||||
REQUIRE(stream.open("Audio/doodle_pop.ogg"));
|
REQUIRE(stream.open("Audio/doodle_pop.ogg"));
|
||||||
REQUIRE(music.openFromStream(stream));
|
|
||||||
|
const auto music = sf::Music::openFromStream(stream).value();
|
||||||
CHECK(music.getDuration() == sf::microseconds(24002176));
|
CHECK(music.getDuration() == sf::microseconds(24002176));
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
CHECK(offset == sf::Time::Zero);
|
CHECK(offset == sf::Time::Zero);
|
||||||
@ -149,8 +108,7 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
|
|
||||||
SECTION("play/pause/stop")
|
SECTION("play/pause/stop")
|
||||||
{
|
{
|
||||||
sf::Music music;
|
auto music = sf::Music::openFromFile("Audio/ding.mp3").value();
|
||||||
REQUIRE(music.openFromFile("Audio/ding.mp3"));
|
|
||||||
|
|
||||||
// Wait for background thread to start
|
// Wait for background thread to start
|
||||||
music.play();
|
music.play();
|
||||||
@ -173,8 +131,7 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
|
|||||||
|
|
||||||
SECTION("setLoopPoints()")
|
SECTION("setLoopPoints()")
|
||||||
{
|
{
|
||||||
sf::Music music;
|
auto music = sf::Music::openFromFile("Audio/killdeer.wav").value();
|
||||||
REQUIRE(music.openFromFile("Audio/killdeer.wav"));
|
|
||||||
music.setLoopPoints({sf::seconds(1), sf::seconds(2)});
|
music.setLoopPoints({sf::seconds(1), sf::seconds(2)});
|
||||||
const auto [offset, length] = music.getLoopPoints();
|
const auto [offset, length] = music.getLoopPoints();
|
||||||
CHECK(offset == sf::seconds(1));
|
CHECK(offset == sf::seconds(1));
|
||||||
|
@ -44,7 +44,7 @@ TEST_CASE("[Audio] sf::SoundSource", runAudioDeviceTests())
|
|||||||
STATIC_CHECK(std::is_copy_assignable_v<sf::SoundSource>);
|
STATIC_CHECK(std::is_copy_assignable_v<sf::SoundSource>);
|
||||||
STATIC_CHECK(!std::is_move_constructible_v<sf::SoundSource>);
|
STATIC_CHECK(!std::is_move_constructible_v<sf::SoundSource>);
|
||||||
STATIC_CHECK(std::is_move_assignable_v<sf::SoundSource>);
|
STATIC_CHECK(std::is_move_assignable_v<sf::SoundSource>);
|
||||||
STATIC_CHECK(!std::is_nothrow_move_assignable_v<sf::SoundSource>);
|
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::SoundSource>);
|
||||||
STATIC_CHECK(std::has_virtual_destructor_v<sf::SoundSource>);
|
STATIC_CHECK(std::has_virtual_destructor_v<sf::SoundSource>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ TEST_CASE("[Audio] sf::SoundStream", runAudioDeviceTests())
|
|||||||
STATIC_CHECK(!std::is_copy_constructible_v<sf::SoundStream>);
|
STATIC_CHECK(!std::is_copy_constructible_v<sf::SoundStream>);
|
||||||
STATIC_CHECK(!std::is_copy_assignable_v<sf::SoundStream>);
|
STATIC_CHECK(!std::is_copy_assignable_v<sf::SoundStream>);
|
||||||
STATIC_CHECK(!std::is_nothrow_move_constructible_v<sf::SoundStream>);
|
STATIC_CHECK(!std::is_nothrow_move_constructible_v<sf::SoundStream>);
|
||||||
STATIC_CHECK(!std::is_nothrow_move_assignable_v<sf::SoundStream>);
|
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::SoundStream>);
|
||||||
STATIC_CHECK(std::has_virtual_destructor_v<sf::SoundStream>);
|
STATIC_CHECK(std::has_virtual_destructor_v<sf::SoundStream>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ int main()
|
|||||||
{
|
{
|
||||||
// Audio
|
// Audio
|
||||||
[[maybe_unused]] const sf::SoundBufferRecorder soundBufferRecorder;
|
[[maybe_unused]] const sf::SoundBufferRecorder soundBufferRecorder;
|
||||||
[[maybe_unused]] const sf::Music music;
|
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
[[maybe_unused]] const sf::Color color;
|
[[maybe_unused]] const sf::Color color;
|
||||||
|
Loading…
Reference in New Issue
Block a user