From 2e4ceb5bae05c712f7bdda6ea1bcb75c7e2bfb14 Mon Sep 17 00:00:00 2001 From: Cruel Date: Sat, 22 Aug 2015 22:26:59 -0400 Subject: [PATCH] Initial SFML audio port --- include/cpp3ds/Audio.hpp | 12 +- include/cpp3ds/Audio/InputSoundFile.hpp | 255 ++++++++++ include/cpp3ds/Audio/Music.hpp | 220 +++++++++ include/cpp3ds/Audio/OutputSoundFile.hpp | 133 ++++++ include/cpp3ds/Audio/Sound.hpp | 269 +++++++++++ include/cpp3ds/Audio/SoundBuffer.hpp | 362 ++++++++++++++ include/cpp3ds/Audio/SoundBufferRecorder.hpp | 137 ++++++ include/cpp3ds/Audio/SoundFileFactory.hpp | 196 ++++++++ include/cpp3ds/Audio/SoundFileFactory.inl | 100 ++++ include/cpp3ds/Audio/SoundFileReader.hpp | 161 +++++++ include/cpp3ds/Audio/SoundFileReaderOgg.hpp | 124 +++++ include/cpp3ds/Audio/SoundFileReaderWav.hpp | 121 +++++ include/cpp3ds/Audio/SoundFileWriter.hpp | 125 +++++ include/cpp3ds/Audio/SoundFileWriterOgg.hpp | 122 +++++ include/cpp3ds/Audio/SoundFileWriterWav.hpp | 125 +++++ include/cpp3ds/Audio/SoundRecorder.hpp | 362 ++++++++++++++ include/cpp3ds/Audio/SoundSource.hpp | 285 +++++++++++ include/cpp3ds/Audio/SoundStream.hpp | 385 +++++++++++++++ src/cpp3ds/Audio/InputSoundFile.cpp | 257 ++++++++++ src/cpp3ds/Audio/Music.cpp | 148 ++++++ src/cpp3ds/Audio/OutputSoundFile.cpp | 92 ++++ src/cpp3ds/Audio/Sound.cpp | 211 ++++++++ src/cpp3ds/Audio/SoundBuffer.cpp | 299 ++++++++++++ src/cpp3ds/Audio/SoundBufferRecorder.cpp | 68 +++ src/cpp3ds/Audio/SoundFileFactory.cpp | 155 ++++++ src/cpp3ds/Audio/SoundFileReaderOgg.cpp | 178 +++++++ src/cpp3ds/Audio/SoundFileReaderWav.cpp | 285 +++++++++++ src/cpp3ds/Audio/SoundFileWriterOgg.cpp | 206 ++++++++ src/cpp3ds/Audio/SoundFileWriterWav.cpp | 207 ++++++++ src/cpp3ds/Audio/SoundRecorder.cpp | 274 +++++++++++ src/cpp3ds/Audio/SoundSource.cpp | 157 ++++++ src/cpp3ds/Audio/SoundStream.cpp | 477 +++++++++++++++++++ src/emu3ds/Audio/InputSoundFile.cpp | 138 ++++++ src/emu3ds/Audio/Sound.cpp | 154 ++++++ src/emu3ds/Audio/SoundBuffer.cpp | 196 ++++++++ 35 files changed, 6990 insertions(+), 6 deletions(-) create mode 100644 include/cpp3ds/Audio/InputSoundFile.hpp create mode 100644 include/cpp3ds/Audio/Music.hpp create mode 100644 include/cpp3ds/Audio/OutputSoundFile.hpp create mode 100644 include/cpp3ds/Audio/Sound.hpp create mode 100644 include/cpp3ds/Audio/SoundBuffer.hpp create mode 100644 include/cpp3ds/Audio/SoundBufferRecorder.hpp create mode 100644 include/cpp3ds/Audio/SoundFileFactory.hpp create mode 100644 include/cpp3ds/Audio/SoundFileFactory.inl create mode 100644 include/cpp3ds/Audio/SoundFileReader.hpp create mode 100644 include/cpp3ds/Audio/SoundFileReaderOgg.hpp create mode 100644 include/cpp3ds/Audio/SoundFileReaderWav.hpp create mode 100644 include/cpp3ds/Audio/SoundFileWriter.hpp create mode 100644 include/cpp3ds/Audio/SoundFileWriterOgg.hpp create mode 100644 include/cpp3ds/Audio/SoundFileWriterWav.hpp create mode 100644 include/cpp3ds/Audio/SoundRecorder.hpp create mode 100644 include/cpp3ds/Audio/SoundSource.hpp create mode 100644 include/cpp3ds/Audio/SoundStream.hpp create mode 100644 src/cpp3ds/Audio/InputSoundFile.cpp create mode 100644 src/cpp3ds/Audio/Music.cpp create mode 100644 src/cpp3ds/Audio/OutputSoundFile.cpp create mode 100644 src/cpp3ds/Audio/Sound.cpp create mode 100644 src/cpp3ds/Audio/SoundBuffer.cpp create mode 100644 src/cpp3ds/Audio/SoundBufferRecorder.cpp create mode 100644 src/cpp3ds/Audio/SoundFileFactory.cpp create mode 100644 src/cpp3ds/Audio/SoundFileReaderOgg.cpp create mode 100644 src/cpp3ds/Audio/SoundFileReaderWav.cpp create mode 100644 src/cpp3ds/Audio/SoundFileWriterOgg.cpp create mode 100644 src/cpp3ds/Audio/SoundFileWriterWav.cpp create mode 100644 src/cpp3ds/Audio/SoundRecorder.cpp create mode 100644 src/cpp3ds/Audio/SoundSource.cpp create mode 100644 src/cpp3ds/Audio/SoundStream.cpp create mode 100644 src/emu3ds/Audio/InputSoundFile.cpp create mode 100644 src/emu3ds/Audio/Sound.cpp create mode 100644 src/emu3ds/Audio/SoundBuffer.cpp diff --git a/include/cpp3ds/Audio.hpp b/include/cpp3ds/Audio.hpp index 67d92a9..cd93b4b 100644 --- a/include/cpp3ds/Audio.hpp +++ b/include/cpp3ds/Audio.hpp @@ -3,12 +3,12 @@ #include //#include -//#include -//#include -//#include -//#include -//#include -//#include +#include +#include +#include +#include +#include +#include #endif diff --git a/include/cpp3ds/Audio/InputSoundFile.hpp b/include/cpp3ds/Audio/InputSoundFile.hpp new file mode 100644 index 0000000..90a7925 --- /dev/null +++ b/include/cpp3ds/Audio/InputSoundFile.hpp @@ -0,0 +1,255 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_INPUTSOUNDFILE_HPP +#define CPP3DS_INPUTSOUNDFILE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#ifdef EMULATION +#include +#endif +#include +#include +#include + + +namespace cpp3ds +{ +class InputStream; +class SoundFileReader; + +//////////////////////////////////////////////////////////// +/// \brief Provide read access to sound files +/// +//////////////////////////////////////////////////////////// +class InputSoundFile : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + InputSoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~InputSoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file from the disk for reading + /// + /// The supported audio formats are: WAV, OGG/Vorbis, FLAC. + /// + /// \param filename Path of the sound file to load + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openFromFile(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file in memory for reading + /// + /// The supported audio formats are: WAV, OGG/Vorbis, FLAC. + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openFromMemory(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file from a custom stream for reading + /// + /// The supported audio formats are: WAV, OGG/Vorbis, FLAC. + /// + /// \param stream Source stream to read from + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Open the sound file from the disk for writing + /// + /// \param filename Path of the sound file to write + /// \param channelCount Number of channels in the sound + /// \param sampleRate Sample rate of the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openForWriting(const std::string& filename, unsigned int channelCount, unsigned int sampleRate); + + //////////////////////////////////////////////////////////// + /// \brief Get the total number of audio samples in the file + /// + /// \return Number of samples + /// + //////////////////////////////////////////////////////////// + Uint64 getSampleCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of channels used by the sound + /// + /// \return Number of channels (1 = mono, 2 = stereo) + /// + //////////////////////////////////////////////////////////// + unsigned int getChannelCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the sample rate of the sound + /// + /// \return Sample rate, in samples per second + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the total duration of the sound file + /// + /// This function is provided for convenience, the duration is + /// deduced from the other sound file attributes. + /// + /// \return Duration of the sound file + /// + //////////////////////////////////////////////////////////// + Time getDuration() const; + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given sample offset + /// + /// This function takes a sample offset to provide maximum + /// precision. If you need to jump to a given time, use the + /// other overload. + /// + /// If the given offset exceeds to total number of samples, + /// this function jumps to the end of the sound file. + /// + /// \param sampleOffset Index of the sample to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + void seek(Uint64 sampleOffset); + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given time offset + /// + /// Using a time offset is handy but imprecise. If you need an accurate + /// result, consider using the overload which takes a sample offset. + /// + /// If the given time exceeds to total duration, this function jumps + /// to the end of the sound file. + /// + /// \param timeOffset Time to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + void seek(Time timeOffset); + + //////////////////////////////////////////////////////////// + /// \brief Read audio samples from the open file + /// + /// \param samples Pointer to the sample array to fill + /// \param maxCount Maximum number of samples to read + /// + /// \return Number of samples actually read (may be less than \a maxCount) + /// + //////////////////////////////////////////////////////////// + Uint64 read(Int16* samples, Uint64 maxCount); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Close the current file + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SoundFileReader* m_reader; ///< Reader that handles I/O on the file's format + InputStream* m_stream; ///< Input stream used to access the file's data + bool m_streamOwned; ///< Is the stream internal or external? + Uint64 m_sampleCount; ///< Total number of samples in the file + unsigned int m_channelCount; ///< Number of channels of the sound + unsigned int m_sampleRate; ///< Number of samples per second + #ifdef EMULATION + sf::InputSoundFile m_inputSoundFile; + #endif +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_INPUTSOUNDFILE_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::InputSoundFile +/// \ingroup audio +/// +/// This class decodes audio samples from a sound file. It is +/// used internally by higher-level classes such as cpp3ds::SoundBuffer +/// and cpp3ds::Music, but can also be useful if you want to process +/// or analyze audio files without playing them, or if you want to +/// implement your own version of cpp3ds::Music with more specific +/// features. +/// +/// Usage example: +/// \code +/// // Open a sound file +/// cpp3ds::InputSoundFile file; +/// if (!file.openFromFile("music.ogg")) +/// /* error */; +/// +/// // Print the sound attributes +/// std::cout << "duration: " << file.getDuration().asSeconds() << std::endl; +/// std::cout << "channels: " << file.getChannelCount() << std::endl; +/// std::cout << "sample rate: " << file.getSampleRate() << std::endl; +/// std::cout << "sample count: " << file.getSampleCount() << std::endl; +/// +/// // Read and process batches of samples until the end of file is reached +/// cpp3ds::Int16 samples[1024]; +/// cpp3ds::Uint64 count; +/// do +/// { +/// count = file.read(samples, 1024); +/// +/// // process, analyze, play, convert, or whatever +/// // you want to do with the samples... +/// } +/// while (count > 0); +/// \endcode +/// +/// \see cpp3ds::SoundFileReader, cpp3ds::OutputSoundFile +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/Music.hpp b/include/cpp3ds/Audio/Music.hpp new file mode 100644 index 0000000..9e2e6ae --- /dev/null +++ b/include/cpp3ds/Audio/Music.hpp @@ -0,0 +1,220 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_MUSIC_HPP +#define CPP3DS_MUSIC_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace cpp3ds +{ +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Streamed music played from an audio file +/// +//////////////////////////////////////////////////////////// +class Music : public SoundStream +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Music(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~Music(); + + //////////////////////////////////////////////////////////// + /// \brief Open a music from an audio file + /// + /// This function doesn't start playing the music (call play() + /// to do so). + /// See the documentation of cpp3ds::InputSoundFile for the list + /// of supported formats. + /// + /// \param filename Path of the music file to open + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see openFromMemory, openFromStream + /// + //////////////////////////////////////////////////////////// + bool openFromFile(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Open a music from an audio file in memory + /// + /// This function doesn't start playing the music (call play() + /// to do so). + /// See the documentation of cpp3ds::InputSoundFile for the list + /// of supported formats. + /// Since the music is not loaded completely but rather streamed + /// continuously, the \a data must remain available as long as the + /// music is playing (i.e. you can't deallocate it right after calling + /// this function). + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see openFromFile, openFromStream + /// + //////////////////////////////////////////////////////////// + bool openFromMemory(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Open a music from an audio file in a custom stream + /// + /// This function doesn't start playing the music (call play() + /// to do so). + /// See the documentation of cpp3ds::InputSoundFile for the list + /// of supported formats. + /// Since the music is not loaded completely but rather streamed + /// continuously, the \a stream must remain alive as long as the + /// music is playing (i.e. you can't destroy it right after calling + /// this function). + /// + /// \param stream Source stream to read from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see openFromFile, openFromMemory + /// + //////////////////////////////////////////////////////////// + bool openFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Get the total duration of the music + /// + /// \return Music duration + /// + //////////////////////////////////////////////////////////// + Time getDuration() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Request a new chunk of audio samples from the stream source + /// + /// This function fills the chunk from the next samples + /// to read from the audio file. + /// + /// \param data Chunk of data to fill + /// + /// \return True to continue playback, false to stop + /// + //////////////////////////////////////////////////////////// + virtual bool onGetData(Chunk& data); + + //////////////////////////////////////////////////////////// + /// \brief Change the current playing position in the stream source + /// + /// \param timeOffset New playing position, from the beginning of the music + /// + //////////////////////////////////////////////////////////// + virtual void onSeek(Time timeOffset); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Initialize the internal state after loading a new music + /// + //////////////////////////////////////////////////////////// + void initialize(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + InputSoundFile m_file; ///< The streamed music file + Time m_duration; ///< Music duration + std::vector m_samples; ///< Temporary buffer of samples + Mutex m_mutex; ///< Mutex protecting the data +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_MUSIC_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::Music +/// \ingroup audio +/// +/// Musics are sounds that are streamed rather than completely +/// loaded in memory. This is especially useful for compressed +/// musics that usually take hundreds of MB when they are +/// uncompressed: by streaming it instead of loading it entirely, +/// you avoid saturating the memory and have almost no loading delay. +/// +/// Apart from that, a cpp3ds::Music has almost the same features as +/// the cpp3ds::SoundBuffer / cpp3ds::Sound pair: you can play/pause/stop +/// it, request its parameters (channels, sample rate), change +/// the way it is played (pitch, volume, 3D position, ...), etc. +/// +/// As a sound stream, a music is played in its own thread in order +/// not to block the rest of the program. This means that you can +/// leave the music alone after calling play(), it will manage itself +/// very well. +/// +/// Usage example: +/// \code +/// // Declare a new music +/// cpp3ds::Music music; +/// +/// // Open it from an audio file +/// if (!music.openFromFile("music.ogg")) +/// { +/// // error... +/// } +/// +/// // Change some parameters +/// music.setPosition(0, 1, 10); // change its 3D position +/// music.setPitch(2); // increase the pitch +/// music.setVolume(50); // reduce the volume +/// music.setLoop(true); // make it loop +/// +/// // Play it +/// music.play(); +/// \endcode +/// +/// \see cpp3ds::Sound, cpp3ds::SoundStream +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/OutputSoundFile.hpp b/include/cpp3ds/Audio/OutputSoundFile.hpp new file mode 100644 index 0000000..d0e507f --- /dev/null +++ b/include/cpp3ds/Audio/OutputSoundFile.hpp @@ -0,0 +1,133 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_OUTPUTSOUNDFILE_HPP +#define CPP3DS_OUTPUTSOUNDFILE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace cpp3ds +{ +class SoundFileWriter; + +//////////////////////////////////////////////////////////// +/// \brief Provide write access to sound files +/// +//////////////////////////////////////////////////////////// +class OutputSoundFile : NonCopyable +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + OutputSoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// Closes the file if it was still open. + /// + //////////////////////////////////////////////////////////// + ~OutputSoundFile(); + + //////////////////////////////////////////////////////////// + /// \brief Open the sound file from the disk for writing + /// + /// The supported audio formats are: WAV, OGG/Vorbis, FLAC. + /// + /// \param filename Path of the sound file to write + /// \param sampleRate Sample rate of the sound + /// \param channelCount Number of channels in the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + bool openFromFile(const std::string& filename, unsigned int sampleRate, unsigned int channelCount); + + //////////////////////////////////////////////////////////// + /// \brief Write audio samples to the file + /// + /// \param samples Pointer to the sample array to write + /// \param count Number of samples to write + /// + //////////////////////////////////////////////////////////// + void write(const Int16* samples, Uint64 count); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Close the current file + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SoundFileWriter* m_writer; ///< Writer that handles I/O on the file's format +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_OUTPUTSOUNDFILE_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::OutputSoundFile +/// \ingroup audio +/// +/// This class encodes audio samples to a sound file. It is +/// used internally by higher-level classes such as cpp3ds::SoundBuffer, +/// but can also be useful if you want to create audio files from +/// custom data sources, like generated audio samples. +/// +/// Usage example: +/// \code +/// // Create a sound file, ogg/vorbis format, 44100 Hz, stereo +/// cpp3ds::OutputSoundFile file; +/// if (!file.openFromFile("music.ogg", 44100, 2)) +/// /* error */; +/// +/// while (...) +/// { +/// // Read or generate audio samples from your custom source +/// std::vector samples = ...; +/// +/// // Write them to the file +/// file.write(samples.data(), samples.size()); +/// } +/// \endcode +/// +/// \see cpp3ds::SoundFileWriter, cpp3ds::InputSoundFile +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/Sound.hpp b/include/cpp3ds/Audio/Sound.hpp new file mode 100644 index 0000000..9193c4a --- /dev/null +++ b/include/cpp3ds/Audio/Sound.hpp @@ -0,0 +1,269 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUND_HPP +#define CPP3DS_SOUND_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#ifdef EMULATION +#include +#endif +#include +#include +#include + + +namespace cpp3ds +{ +class SoundBuffer; + +//////////////////////////////////////////////////////////// +/// \brief Regular sound that can be played in the audio environment +/// +//////////////////////////////////////////////////////////// +class Sound : public SoundSource +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Sound(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the sound with a buffer + /// + /// \param buffer Sound buffer containing the audio data to play with the sound + /// + //////////////////////////////////////////////////////////// + explicit Sound(const SoundBuffer& buffer); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + Sound(const Sound& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~Sound(); + + //////////////////////////////////////////////////////////// + /// \brief Start or resume playing the sound + /// + /// This function starts the stream if it was stopped, resumes + /// it if it was paused, and restarts it from beginning if it + /// was it already playing. + /// This function uses its own thread so that it doesn't block + /// the rest of the program while the sound is played. + /// + /// \see pause, stop + /// + //////////////////////////////////////////////////////////// + void play(); + + //////////////////////////////////////////////////////////// + /// \brief Pause the sound + /// + /// This function pauses the sound if it was playing, + /// otherwise (sound already paused or stopped) it has no effect. + /// + /// \see play, stop + /// + //////////////////////////////////////////////////////////// + void pause(); + + //////////////////////////////////////////////////////////// + /// \brief stop playing the sound + /// + /// This function stops the sound if it was playing or paused, + /// and does nothing if it was already stopped. + /// It also resets the playing position (unlike pause()). + /// + /// \see play, pause + /// + //////////////////////////////////////////////////////////// + void stop(); + + //////////////////////////////////////////////////////////// + /// \brief Set the source buffer containing the audio data to play + /// + /// It is important to note that the sound buffer is not copied, + /// thus the cpp3ds::SoundBuffer instance must remain alive as long + /// as it is attached to the sound. + /// + /// \param buffer Sound buffer to attach to the sound + /// + /// \see getBuffer + /// + //////////////////////////////////////////////////////////// + void setBuffer(const SoundBuffer& buffer); + + //////////////////////////////////////////////////////////// + /// \brief Set whether or not the sound should loop after reaching the end + /// + /// If set, the sound will restart from beginning after + /// reaching the end and so on, until it is stopped or + /// setLoop(false) is called. + /// The default looping state for sound is false. + /// + /// \param loop True to play in loop, false to play once + /// + /// \see getLoop + /// + //////////////////////////////////////////////////////////// + void setLoop(bool loop); + + //////////////////////////////////////////////////////////// + /// \brief Change the current playing position of the sound + /// + /// The playing position can be changed when the sound is + /// either paused or playing. + /// + /// \param timeOffset New playing position, from the beginning of the sound + /// + /// \see getPlayingOffset + /// + //////////////////////////////////////////////////////////// + void setPlayingOffset(Time timeOffset); + + //////////////////////////////////////////////////////////// + /// \brief Get the audio buffer attached to the sound + /// + /// \return Sound buffer attached to the sound (can be NULL) + /// + //////////////////////////////////////////////////////////// + const SoundBuffer* getBuffer() const; + + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the sound is in loop mode + /// + /// \return True if the sound is looping, false otherwise + /// + /// \see setLoop + /// + //////////////////////////////////////////////////////////// + bool getLoop() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the current playing position of the sound + /// + /// \return Current playing position, from the beginning of the sound + /// + /// \see setPlayingOffset + /// + //////////////////////////////////////////////////////////// + Time getPlayingOffset() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the current status of the sound (stopped, paused, playing) + /// + /// \return Current status of the sound + /// + //////////////////////////////////////////////////////////// + Status getStatus() const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + Sound& operator =(const Sound& right); + + //////////////////////////////////////////////////////////// + /// \brief Reset the internal buffer of the sound + /// + /// This function is for internal use only, you don't have + /// to use it. It is called by the cpp3ds::SoundBuffer that + /// this sound uses, when it is destroyed in order to prevent + /// the sound from using a dead buffer. + /// + //////////////////////////////////////////////////////////// + void resetBuffer(); + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + const SoundBuffer* m_buffer; ///< Sound buffer bound to the source + int m_currentChannel; ///< Current CSND channel for this sound + bool m_loop; + #ifdef EMULATION + sf::Sound m_sound; + #endif +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUND_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::Sound +/// \ingroup audio +/// +/// cpp3ds::Sound is the class to use to play sounds. +/// It provides: +/// \li Control (play, pause, stop) +/// \li Ability to modify output parameters in real-time (pitch, volume, ...) +/// \li 3D spatial features (position, attenuation, ...). +/// +/// cpp3ds::Sound is perfect for playing short sounds that can +/// fit in memory and require no latency, like foot steps or +/// gun shots. For longer sounds, like background musics +/// or long speeches, rather see cpp3ds::Music (which is based +/// on streaming). +/// +/// In order to work, a sound must be given a buffer of audio +/// data to play. Audio data (samples) is stored in cpp3ds::SoundBuffer, +/// and attached to a sound with the setBuffer() function. +/// The buffer object attached to a sound must remain alive +/// as long as the sound uses it. Note that multiple sounds +/// can use the same sound buffer at the same time. +/// +/// Usage example: +/// \code +/// cpp3ds::SoundBuffer buffer; +/// buffer.loadFromFile("sound.wav"); +/// +/// cpp3ds::Sound sound; +/// sound.setBuffer(buffer); +/// sound.play(); +/// \endcode +/// +/// \see cpp3ds::SoundBuffer, cpp3ds::Music +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/SoundBuffer.hpp b/include/cpp3ds/Audio/SoundBuffer.hpp new file mode 100644 index 0000000..91569b7 --- /dev/null +++ b/include/cpp3ds/Audio/SoundBuffer.hpp @@ -0,0 +1,362 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDBUFFER_HPP +#define CPP3DS_SOUNDBUFFER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#ifdef EMULATION +#include +#endif +#include +#include +#include +#include + + +namespace cpp3ds +{ +class Sound; +class InputSoundFile; +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Storage for audio samples defining a sound +/// +//////////////////////////////////////////////////////////// +class SoundBuffer +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SoundBuffer(); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + SoundBuffer(const SoundBuffer& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~SoundBuffer(); + + //////////////////////////////////////////////////////////// + /// \brief Load the sound buffer from a file + /// + /// See the documentation of cpp3ds::InputSoundFile for the list + /// of supported formats. + /// + /// \param filename Path of the sound file to load + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromMemory, loadFromStream, loadFromSamples, saveToFile + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Load the sound buffer from a file in memory + /// + /// See the documentation of cpp3ds::InputSoundFile for the list + /// of supported formats. + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromStream, loadFromSamples + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const void* data, std::size_t sizeInBytes); + + bool loadFromResource(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Load the sound buffer from a custom stream + /// + /// See the documentation of cpp3ds::InputSoundFile for the list + /// of supported formats. + /// + /// \param stream Source stream to read from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory, loadFromSamples + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Load the sound buffer from an array of audio samples + /// + /// The assumed format of the audio samples is 16 bits signed integer + /// (cpp3ds::Int16). + /// + /// \param samples Pointer to the array of samples in memory + /// \param sampleCount Number of samples in the array + /// \param channelCount Number of channels (1 = mono, 2 = stereo, ...) + /// \param sampleRate Sample rate (number of samples to play per second) + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory, saveToFile + /// + //////////////////////////////////////////////////////////// + bool loadFromSamples(const Int16* samples, Uint64 sampleCount, unsigned int channelCount, unsigned int sampleRate); + + //////////////////////////////////////////////////////////// + /// \brief Save the sound buffer to an audio file + /// + /// See the documentation of cpp3ds::OutputSoundFile for the list + /// of supported formats. + /// + /// \param filename Path of the sound file to write + /// + /// \return True if saving succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory, loadFromSamples + /// + //////////////////////////////////////////////////////////// + bool saveToFile(const std::string& filename) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the array of audio samples stored in the buffer + /// + /// The format of the returned samples is 16 bits signed integer + /// (cpp3ds::Int16). The total number of samples in this array + /// is given by the getSampleCount() function. + /// + /// \return Read-only pointer to the array of sound samples + /// + /// \see getSampleCount + /// + //////////////////////////////////////////////////////////// + const Int16* getSamples() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of samples stored in the buffer + /// + /// The array of samples can be accessed with the getSamples() + /// function. + /// + /// \return Number of samples + /// + /// \see getSamples + /// + //////////////////////////////////////////////////////////// + Uint64 getSampleCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the sample rate of the sound + /// + /// The sample rate is the number of samples played per second. + /// The higher, the better the quality (for example, 44100 + /// samples/s is CD quality). + /// + /// \return Sample rate (number of samples per second) + /// + /// \see getChannelCount, getDuration + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of channels used by the sound + /// + /// If the sound is mono then the number of channels will + /// be 1, 2 for stereo, etc. + /// + /// \return Number of channels + /// + /// \see getSampleRate, getDuration + /// + //////////////////////////////////////////////////////////// + unsigned int getChannelCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the total duration of the sound + /// + /// \return Sound duration + /// + /// \see getSampleRate, getChannelCount + /// + //////////////////////////////////////////////////////////// + Time getDuration() const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + SoundBuffer& operator =(const SoundBuffer& right); + +private: + + friend class Sound; + + //////////////////////////////////////////////////////////// + /// \brief Initialize the internal state after loading a new sound + /// + /// \param file Sound file providing access to the new loaded sound + /// + /// \return True on successful initialization, false on failure + /// + //////////////////////////////////////////////////////////// + bool initialize(InputSoundFile& file); + + //////////////////////////////////////////////////////////// + /// \brief Update the internal buffer with the cached audio samples + /// + /// \param channelCount Number of channels + /// \param sampleRate Sample rate (number of samples per second) + /// + /// \return True on success, false if any error happened + /// + //////////////////////////////////////////////////////////// + bool update(unsigned int channelCount, unsigned int sampleRate); + + //////////////////////////////////////////////////////////// + /// \brief Add a sound to the list of sounds that use this buffer + /// + /// \param sound Sound instance to attach + /// + //////////////////////////////////////////////////////////// + void attachSound(Sound* sound) const; + + //////////////////////////////////////////////////////////// + /// \brief Remove a sound from the list of sounds that use this buffer + /// + /// \param sound Sound instance to detach + /// + //////////////////////////////////////////////////////////// + void detachSound(Sound* sound) const; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::set SoundList; ///< Set of unique sound instances + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + unsigned int m_buffer; ///< OpenAL buffer identifier + Int16* m_samples; ///< Samples buffer + Uint64 m_sampleCount; + Time m_duration; ///< Sound duration + mutable SoundList m_sounds; ///< List of sounds that are using this buffer + + unsigned int m_sampleRate; + unsigned int m_channelCount; + #ifdef EMULATION + sf::SoundBuffer m_soundBuffer; + #endif +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDBUFFER_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::SoundBuffer +/// \ingroup audio +/// +/// A sound buffer holds the data of a sound, which is +/// an array of audio samples. A sample is a 16 bits signed integer +/// that defines the amplitude of the sound at a given time. +/// The sound is then reconstituted by playing these samples at +/// a high rate (for example, 44100 samples per second is the +/// standard rate used for playing CDs). In short, audio samples +/// are like texture pixels, and a cpp3ds::SoundBuffer is similar to +/// a cpp3ds::Texture. +/// +/// A sound buffer can be loaded from a file (see loadFromFile() +/// for the complete list of supported formats), from memory, from +/// a custom stream (see cpp3ds::InputStream) or directly from an array +/// of samples. It can also be saved back to a file. +/// +/// Sound buffers alone are not very useful: they hold the audio data +/// but cannot be played. To do so, you need to use the cpp3ds::Sound class, +/// which provides functions to play/pause/stop the sound as well as +/// changing the way it is outputted (volume, pitch, 3D position, ...). +/// This separation allows more flexibility and better performances: +/// indeed a cpp3ds::SoundBuffer is a heavy resource, and any operation on it +/// is slow (often too slow for real-time applications). On the other +/// side, a cpp3ds::Sound is a lightweight object, which can use the audio data +/// of a sound buffer and change the way it is played without actually +/// modifying that data. Note that it is also possible to bind +/// several cpp3ds::Sound instances to the same cpp3ds::SoundBuffer. +/// +/// It is important to note that the cpp3ds::Sound instance doesn't +/// copy the buffer that it uses, it only keeps a reference to it. +/// Thus, a cpp3ds::SoundBuffer must not be destructed while it is +/// used by a cpp3ds::Sound (i.e. never write a function that +/// uses a local cpp3ds::SoundBuffer instance for loading a sound). +/// +/// Usage example: +/// \code +/// // Declare a new sound buffer +/// cpp3ds::SoundBuffer buffer; +/// +/// // Load it from a file +/// if (!buffer.loadFromFile("sound.wav")) +/// { +/// // error... +/// } +/// +/// // Create a sound source and bind it to the buffer +/// cpp3ds::Sound sound1; +/// sound1.setBuffer(buffer); +/// +/// // Play the sound +/// sound1.play(); +/// +/// // Create another sound source bound to the same buffer +/// cpp3ds::Sound sound2; +/// sound2.setBuffer(buffer); +/// +/// // Play it with a higher pitch -- the first sound remains unchanged +/// sound2.setPitch(2); +/// sound2.play(); +/// \endcode +/// +/// \see cpp3ds::Sound, cpp3ds::SoundBufferRecorder +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/SoundBufferRecorder.hpp b/include/cpp3ds/Audio/SoundBufferRecorder.hpp new file mode 100644 index 0000000..7a40c3d --- /dev/null +++ b/include/cpp3ds/Audio/SoundBufferRecorder.hpp @@ -0,0 +1,137 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDBUFFERRECORDER_HPP +#define CPP3DS_SOUNDBUFFERRECORDER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized SoundRecorder which stores the captured +/// audio data into a sound buffer +/// +//////////////////////////////////////////////////////////// +class SoundBufferRecorder : public SoundRecorder +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Get the sound buffer containing the captured audio data + /// + /// The sound buffer is valid only after the capture has ended. + /// This function provides a read-only access to the internal + /// sound buffer, but it can be copied if you need to + /// make any modification to it. + /// + /// \return Read-only access to the sound buffer + /// + //////////////////////////////////////////////////////////// + const SoundBuffer& getBuffer() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Start capturing audio data + /// + /// \return True to start the capture, or false to abort it + /// + //////////////////////////////////////////////////////////// + virtual bool onStart(); + + //////////////////////////////////////////////////////////// + /// \brief Process a new chunk of recorded samples + /// + /// \param samples Pointer to the new chunk of recorded samples + /// \param sampleCount Number of samples pointed by \a samples + /// + /// \return True to continue the capture, or false to stop it + /// + //////////////////////////////////////////////////////////// + virtual bool onProcessSamples(const Int16* samples, std::size_t sampleCount); + + //////////////////////////////////////////////////////////// + /// \brief Stop capturing audio data + /// + //////////////////////////////////////////////////////////// + virtual void onStop(); + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector m_samples; ///< Temporary sample buffer to hold the recorded data + SoundBuffer m_buffer; ///< Sound buffer that will contain the recorded data +}; + +} // namespace cpp3ds + +#endif // CPP3DS_SOUNDBUFFERRECORDER_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::SoundBufferRecorder +/// \ingroup audio +/// +/// cpp3ds::SoundBufferRecorder allows to access a recorded sound +/// through a cpp3ds::SoundBuffer, so that it can be played, saved +/// to a file, etc. +/// +/// It has the same simple interface as its base class (start(), stop()) +/// and adds a function to retrieve the recorded sound buffer +/// (getBuffer()). +/// +/// As usual, don't forget to call the isAvailable() function +/// before using this class (see cpp3ds::SoundRecorder for more details +/// about this). +/// +/// Usage example: +/// \code +/// if (cpp3ds::SoundBufferRecorder::isAvailable()) +/// { +/// // Record some audio data +/// cpp3ds::SoundBufferRecorder recorder; +/// recorder.start(); +/// ... +/// recorder.stop(); +/// +/// // Get the buffer containing the captured audio data +/// const cpp3ds::SoundBuffer& buffer = recorder.getBuffer(); +/// +/// // Save it to a file (for example...) +/// buffer.saveToFile("my_record.ogg"); +/// } +/// \endcode +/// +/// \see cpp3ds::SoundRecorder +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/SoundFileFactory.hpp b/include/cpp3ds/Audio/SoundFileFactory.hpp new file mode 100644 index 0000000..0ce5ce3 --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileFactory.hpp @@ -0,0 +1,196 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDFILEFACTORY_HPP +#define CPP3DS_SOUNDFILEFACTORY_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace cpp3ds +{ +class InputStream; +class SoundFileReader; +class SoundFileWriter; + +//////////////////////////////////////////////////////////// +/// \brief Manages and instantiates sound file readers and writers +/// +//////////////////////////////////////////////////////////// +class SoundFileFactory +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Register a new reader + /// + /// \see unregisterReader + /// + //////////////////////////////////////////////////////////// + template + static void registerReader(); + + //////////////////////////////////////////////////////////// + /// \brief Unregister a reader + /// + /// \see registerReader + /// + //////////////////////////////////////////////////////////// + template + static void unregisterReader(); + + //////////////////////////////////////////////////////////// + /// \brief Register a new writer + /// + /// \see unregisterWriter + /// + //////////////////////////////////////////////////////////// + template + static void registerWriter(); + + //////////////////////////////////////////////////////////// + /// \brief Unregister a writer + /// + /// \see registerWriter + /// + //////////////////////////////////////////////////////////// + template + static void unregisterWriter(); + + //////////////////////////////////////////////////////////// + /// \brief Instantiate the right reader for the given file on disk + /// + /// It's up to the caller to release the returned reader + /// + /// \param filename Path of the sound file + /// + /// \return A new sound file reader that can read the given file, or null if no reader can handle it + /// + /// \see createReaderFromMemory, createReaderFromStream + /// + //////////////////////////////////////////////////////////// + static SoundFileReader* createReaderFromFilename(const std::string& filename); + + //////////////////////////////////////////////////////////// + /// \brief Instantiate the right codec for the given file in memory + /// + /// It's up to the caller to release the returned reader + /// + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Total size of the file data, in bytes + /// + /// \return A new sound file codec that can read the given file, or null if no codec can handle it + /// + /// \see createReaderFromFilename, createReaderFromStream + /// + //////////////////////////////////////////////////////////// + static SoundFileReader* createReaderFromMemory(const void* data, std::size_t sizeInBytes); + + //////////////////////////////////////////////////////////// + /// \brief Instantiate the right codec for the given file in stream + /// + /// It's up to the caller to release the returned reader + /// + /// \param stream Source stream to read from + /// + /// \return A new sound file codec that can read the given file, or null if no codec can handle it + /// + /// \see createReaderFromFilename, createReaderFromMemory + /// + //////////////////////////////////////////////////////////// + static SoundFileReader* createReaderFromStream(InputStream& stream); + + //////////////////////////////////////////////////////////// + /// \brief Instantiate the right writer for the given file on disk + /// + /// It's up to the caller to release the returned writer + /// + /// \param filename Path of the sound file + /// + /// \return A new sound file writer that can write given file, or null if no writer can handle it + /// + //////////////////////////////////////////////////////////// + static SoundFileWriter* createWriterFromFilename(const std::string& filename); + +private: + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + struct ReaderFactory + { + bool (*check)(InputStream&); + SoundFileReader* (*create)(); + }; + typedef std::vector ReaderFactoryArray; + + struct WriterFactory + { + bool (*check)(const std::string&); + SoundFileWriter* (*create)(); + }; + typedef std::vector WriterFactoryArray; + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static ReaderFactoryArray s_readers; ///< List of all registered readers + static WriterFactoryArray s_writers; ///< List of all registered writers +}; + +} // namespace cpp3ds + +#include + +#endif // CPP3DS_SOUNDFILEFACTORY_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::SoundFileFactory +/// \ingroup audio +/// +/// This class is where all the sound file readers and writers are +/// registered. You should normally only need to use its registration +/// and unregistration functions; readers/writers creation and manipulation +/// are wrapped into the higher-level classes cpp3ds::InputSoundFile and +/// cpp3ds::OutputSoundFile. +/// +/// To register a new reader (writer) use the cpp3ds::SoundFileFactory::registerReader +/// (registerWriter) static function. You don't have to call the unregisterReader +/// (unregisterWriter) function, unless you want to unregister a format before your +/// application ends (typically, when a plugin is unloaded). +/// +/// Usage example: +/// \code +/// cpp3ds::SoundFileFactory::registerReader(); +/// cpp3ds::SoundFileFactory::registerWriter(); +/// \endcode +/// +/// \see cpp3ds::InputSoundFile, cpp3ds::OutputSoundFile, cpp3ds::SoundFileReader, cpp3ds::SoundFileWriter +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/SoundFileFactory.inl b/include/cpp3ds/Audio/SoundFileFactory.inl new file mode 100644 index 0000000..fa1b61c --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileFactory.inl @@ -0,0 +1,100 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + + +namespace cpp3ds +{ +namespace priv +{ + template SoundFileReader* createReader() {return new T;} + template SoundFileWriter* createWriter() {return new T;} +} + +//////////////////////////////////////////////////////////// +template +void SoundFileFactory::registerReader() +{ + // Make sure the same class won't be registered twice + unregisterReader(); + + // Create a new factory with the functions provided by the class + ReaderFactory factory; + factory.check = &T::check; + factory.create = &priv::createReader; + + // Add it + s_readers.push_back(factory); +} + + +//////////////////////////////////////////////////////////// +template +void SoundFileFactory::unregisterReader() +{ + // Remove the instance(s) of the reader from the array of factories + for (ReaderFactoryArray::iterator it = s_readers.begin(); it != s_readers.end(); ) + { + if (it->create == &priv::createReader) + it = s_readers.erase(it); + else + ++it; + } +} + +//////////////////////////////////////////////////////////// +template +void SoundFileFactory::registerWriter() +{ + // Make sure the same class won't be registered twice + unregisterWriter(); + + // Create a new factory with the functions provided by the class + WriterFactory factory; + factory.check = &T::check; + factory.create = &priv::createWriter; + + // Add it + s_writers.push_back(factory); +} + + +//////////////////////////////////////////////////////////// +template +void SoundFileFactory::unregisterWriter() +{ + // Remove the instance(s) of the writer from the array of factories + for (WriterFactoryArray::iterator it = s_writers.begin(); it != s_writers.end(); ) + { + if (it->create == &priv::createWriter) + it = s_writers.erase(it); + else + ++it; + } +} + +} // namespace cpp3ds diff --git a/include/cpp3ds/Audio/SoundFileReader.hpp b/include/cpp3ds/Audio/SoundFileReader.hpp new file mode 100644 index 0000000..0432e44 --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileReader.hpp @@ -0,0 +1,161 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDFILEREADER_HPP +#define CPP3DS_SOUNDFILEREADER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace cpp3ds +{ +class InputStream; + +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for sound file decoding +/// +//////////////////////////////////////////////////////////// +class SoundFileReader +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Structure holding the audio properties of a sound file + /// + //////////////////////////////////////////////////////////// + struct Info + { + Uint64 sampleCount; ///< Total number of samples in the file + unsigned int channelCount; ///< Number of channels of the sound + unsigned int sampleRate; ///< Samples rate of the sound, in samples per second + }; + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundFileReader() {} + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for reading + /// + /// The provided stream reference is valid as long as the + /// SoundFileReader is alive, so it is safe to use/store it + /// during the whole lifetime of the reader. + /// + /// \param stream Source stream to read from + /// \param info Structure to fill with the properties of the loaded sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + virtual bool open(InputStream& stream, Info& info) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given sample offset + /// + /// If the given offset exceeds to total number of samples, + /// this function must jump to the end of the file. + /// + /// \param sampleOffset Index of the sample to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + virtual void seek(Uint64 sampleOffset) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Read audio samples from the open file + /// + /// \param samples Pointer to the sample array to fill + /// \param maxCount Maximum number of samples to read + /// + /// \return Number of samples actually read (may be less than \a maxCount) + /// + //////////////////////////////////////////////////////////// + virtual Uint64 read(Int16* samples, Uint64 maxCount) = 0; +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDFILEREADER_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::SoundFileReader +/// \ingroup audio +/// +/// This class allows users to read audio file formats not natively +/// supported by cpp3ds, and thus extend the set of supported readable +/// audio formats. +/// +/// A valid sound file reader must override the open, seek and write functions, +/// as well as providing a static check function; the latter is used by +/// cpp3ds to find a suitable writer for a given input file. +/// +/// To register a new reader, use the cpp3ds::SoundFileFactory::registerReader +/// template function. +/// +/// Usage example: +/// \code +/// class MySoundFileReader : public cpp3ds::SoundFileReader +/// { +/// public: +/// +/// static bool check(cpp3ds::InputStream& stream) +/// { +/// // typically, read the first few header bytes and check fields that identify the format +/// // return true if the reader can handle the format +/// } +/// +/// virtual bool open(cpp3ds::InputStream& stream, Info& info) +/// { +/// // read the sound file header and fill the sound attributes +/// // (channel count, sample count and sample rate) +/// // return true on success +/// } +/// +/// virtual void seek(cpp3ds::Uint64 sampleOffset) +/// { +/// // advance to the sampleOffset-th sample from the beginning of the sound +/// } +/// +/// virtual cpp3ds::Uint64 read(cpp3ds::Int16* samples, cpp3ds::Uint64 maxCount) +/// { +/// // read up to 'maxCount' samples into the 'samples' array, +/// // convert them (for example from normalized float) if they are not stored +/// // as 16-bits signed integers in the file +/// // return the actual number of samples read +/// } +/// }; +/// +/// cpp3ds::SoundFileFactory::registerReader(); +/// \endcode +/// +/// \see cpp3ds::InputSoundFile, cpp3ds::SoundFileFactory, cpp3ds::SoundFileWriter +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/SoundFileReaderOgg.hpp b/include/cpp3ds/Audio/SoundFileReaderOgg.hpp new file mode 100644 index 0000000..9b30e67 --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileReaderOgg.hpp @@ -0,0 +1,124 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDFILEREADEROGG_HPP +#define CPP3DS_SOUNDFILEREADEROGG_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief Implementation of sound file reader that handles OGG/Vorbis files +/// +//////////////////////////////////////////////////////////// +class SoundFileReaderOgg : public SoundFileReader +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Check if this reader can handle a file given by an input stream + /// + /// \param stream Source stream to check + /// + /// \return True if the file is supported by this reader + /// + //////////////////////////////////////////////////////////// + static bool check(InputStream& stream); + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SoundFileReaderOgg(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~SoundFileReaderOgg(); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for reading + /// + /// \param stream Source stream to read from + /// \param info Structure to fill with the properties of the loaded sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + virtual bool open(InputStream& stream, Info& info); + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given sample offset + /// + /// If the given offset exceeds to total number of samples, + /// this function must jump to the end of the file. + /// + /// \param sampleOffset Index of the sample to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + virtual void seek(Uint64 sampleOffset); + + //////////////////////////////////////////////////////////// + /// \brief Read audio samples from the open file + /// + /// \param samples Pointer to the sample array to fill + /// \param maxCount Maximum number of samples to read + /// + /// \return Number of samples actually read (may be less than \a maxCount) + /// + //////////////////////////////////////////////////////////// + virtual Uint64 read(Int16* samples, Uint64 maxCount); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Close the open Vorbis file + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + OggVorbis_File m_vorbis; // ogg/vorbis file handle + unsigned int m_channelCount; // number of channels of the open sound file +}; + +} // namespace priv + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDFILEREADEROGG_HPP diff --git a/include/cpp3ds/Audio/SoundFileReaderWav.hpp b/include/cpp3ds/Audio/SoundFileReaderWav.hpp new file mode 100644 index 0000000..30e5a3b --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileReaderWav.hpp @@ -0,0 +1,121 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDFILEREADERWAV_HPP +#define CPP3DS_SOUNDFILEREADERWAV_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief Implementation of sound file reader that handles wav files +/// +//////////////////////////////////////////////////////////// +class SoundFileReaderWav : public SoundFileReader +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Check if this reader can handle a file given by an input stream + /// + /// \param stream Source stream to check + /// + /// \return True if the file is supported by this reader + /// + //////////////////////////////////////////////////////////// + static bool check(InputStream& stream); + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SoundFileReaderWav(); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for reading + /// + /// \param stream Stream to open + /// \param info Structure to fill with the attributes of the loaded sound + /// + //////////////////////////////////////////////////////////// + virtual bool open(cpp3ds::InputStream& stream, Info& info); + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given sample offset + /// + /// If the given offset exceeds to total number of samples, + /// this function must jump to the end of the file. + /// + /// \param sampleOffset Index of the sample to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + virtual void seek(Uint64 sampleOffset); + + //////////////////////////////////////////////////////////// + /// \brief Read audio samples from the open file + /// + /// \param samples Pointer to the sample array to fill + /// \param maxCount Maximum number of samples to read + /// + /// \return Number of samples actually read (may be less than \a maxCount) + /// + //////////////////////////////////////////////////////////// + virtual Uint64 read(Int16* samples, Uint64 maxCount); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Read the header of the open file + /// + /// \param info Attributes of the sound file + /// + /// \return True on success, false on error + /// + //////////////////////////////////////////////////////////// + bool parseHeader(Info& info); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + InputStream* m_stream; ///< Source stream to read from + unsigned int m_bytesPerSample; ///< Size of a sample, in bytes + Uint64 m_dataStart; ///< Starting position of the audio data in the open file +}; + +} // namespace priv + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDFILEREADERWAV_HPP diff --git a/include/cpp3ds/Audio/SoundFileWriter.hpp b/include/cpp3ds/Audio/SoundFileWriter.hpp new file mode 100644 index 0000000..c44661a --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileWriter.hpp @@ -0,0 +1,125 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDFILEWRITER_HPP +#define CPP3DS_SOUNDFILEWRITER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for sound file encoding +/// +//////////////////////////////////////////////////////////// +class SoundFileWriter +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundFileWriter() {} + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for writing + /// + /// \param filename Path of the file to open + /// \param sampleRate Sample rate of the sound + /// \param channelCount Number of channels of the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + virtual bool open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Write audio samples to the open file + /// + /// \param samples Pointer to the sample array to write + /// \param count Number of samples to write + /// + //////////////////////////////////////////////////////////// + virtual void write(const Int16* samples, Uint64 count) = 0; +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDFILEWRITER_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::SoundFileWriter +/// \ingroup audio +/// +/// This class allows users to write audio file formats not natively +/// supported by cpp3ds, and thus extend the set of supported writable +/// audio formats. +/// +/// A valid sound file writer must override the open and write functions, +/// as well as providing a static check function; the latter is used by +/// cpp3ds to find a suitable writer for a given filename. +/// +/// To register a new writer, use the cpp3ds::SoundFileFactory::registerWriter +/// template function. +/// +/// Usage example: +/// \code +/// class MySoundFileWriter : public cpp3ds::SoundFileWriter +/// { +/// public: +/// +/// static bool check(const std::string& filename) +/// { +/// // typically, check the extension +/// // return true if the writer can handle the format +/// } +/// +/// virtual bool open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount) +/// { +/// // open the file 'filename' for writing, +/// // write the given sample rate and channel count to the file header +/// // return true on success +/// } +/// +/// virtual void write(const cpp3ds::Int16* samples, cpp3ds::Uint64 count) +/// { +/// // write 'count' samples stored at address 'samples', +/// // convert them (for example to normalized float) if the format requires it +/// } +/// }; +/// +/// cpp3ds::SoundFileFactory::registerWriter(); +/// \endcode +/// +/// \see cpp3ds::OutputSoundFile, cpp3ds::SoundFileFactory, cpp3ds::SoundFileReader +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/SoundFileWriterOgg.hpp b/include/cpp3ds/Audio/SoundFileWriterOgg.hpp new file mode 100644 index 0000000..6602129 --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileWriterOgg.hpp @@ -0,0 +1,122 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDFILEWRITEROGG_HPP +#define CPP3DS_SOUNDFILEWRITEROGG_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief Implementation of sound file writer that handles OGG/Vorbis files +/// +//////////////////////////////////////////////////////////// +class SoundFileWriterOgg : public SoundFileWriter +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Check if this writer can handle a file on disk + /// + /// \param filename Path of the sound file to check + /// + /// \return True if the file can be written by this writer + /// + //////////////////////////////////////////////////////////// + static bool check(const std::string& filename); + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SoundFileWriterOgg(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~SoundFileWriterOgg(); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for writing + /// + /// \param filename Path of the file to open + /// \param sampleRate Sample rate of the sound + /// \param channelCount Number of channels of the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + virtual bool open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount); + + //////////////////////////////////////////////////////////// + /// \brief Write audio samples to the open file + /// + /// \param samples Pointer to the sample array to write + /// \param count Number of samples to write + /// + //////////////////////////////////////////////////////////// + virtual void write(const Int16* samples, Uint64 count); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Flush blocks produced by the ogg stream, if any + /// + //////////////////////////////////////////////////////////// + void flushBlocks(); + + //////////////////////////////////////////////////////////// + /// \brief Close the file + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + unsigned int m_channelCount; // channel count of the sound being written + std::ofstream m_file; // output file + ogg_stream_state m_ogg; // ogg stream + vorbis_info m_vorbis; // vorbis handle + vorbis_dsp_state m_state; // current encoding state +}; + +} // namespace priv + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDFILEWRITEROGG_HPP diff --git a/include/cpp3ds/Audio/SoundFileWriterWav.hpp b/include/cpp3ds/Audio/SoundFileWriterWav.hpp new file mode 100644 index 0000000..5125803 --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileWriterWav.hpp @@ -0,0 +1,125 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDFILEWRITERWAV_HPP +#define CPP3DS_SOUNDFILEWRITERWAV_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief Implementation of sound file writer that handles wav files +/// +//////////////////////////////////////////////////////////// +class SoundFileWriterWav : public SoundFileWriter +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Check if this writer can handle a file on disk + /// + /// \param filename Path of the sound file to check + /// + /// \return True if the file can be written by this writer + /// + //////////////////////////////////////////////////////////// + static bool check(const std::string& filename); + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SoundFileWriterWav(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~SoundFileWriterWav(); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for writing + /// + /// \param filename Path of the file to open + /// \param sampleRate Sample rate of the sound + /// \param channelCount Number of channels of the sound + /// + /// \return True if the file was successfully opened + /// + //////////////////////////////////////////////////////////// + virtual bool open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount); + + //////////////////////////////////////////////////////////// + /// \brief Write audio samples to the open file + /// + /// \param samples Pointer to the sample array to write + /// \param count Number of samples to write + /// + //////////////////////////////////////////////////////////// + virtual void write(const Int16* samples, Uint64 count); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Write the header of the open file + /// + /// \param sampleRate Sample rate of the sound + /// \param channelCount Number of channels of the sound + /// + /// \return True on success, false on error + /// + //////////////////////////////////////////////////////////// + bool writeHeader(unsigned int sampleRate, unsigned int channelCount); + + //////////////////////////////////////////////////////////// + /// \brief Close the file + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::ofstream m_file; ///< File stream to write to + Uint64 m_sampleCount; ///< Total number of samples written to the file + unsigned int m_channelCount; ///< Number of channels of the sound +}; + +} // namespace priv + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDFILEWRITERWAV_HPP diff --git a/include/cpp3ds/Audio/SoundRecorder.hpp b/include/cpp3ds/Audio/SoundRecorder.hpp new file mode 100644 index 0000000..7651dd7 --- /dev/null +++ b/include/cpp3ds/Audio/SoundRecorder.hpp @@ -0,0 +1,362 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDRECORDER_HPP +#define CPP3DS_SOUNDRECORDER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for capturing sound data +/// +//////////////////////////////////////////////////////////// +class SoundRecorder +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundRecorder(); + + //////////////////////////////////////////////////////////// + /// \brief Start the capture + /// + /// The \a sampleRate parameter defines the number of audio samples + /// captured per second. The higher, the better the quality + /// (for example, 44100 samples/sec is CD quality). + /// This function uses its own thread so that it doesn't block + /// the rest of the program while the capture runs. + /// Please note that only one capture can happen at the same time. + /// You can select which capture device will be used, by passing + /// the name to the setDevice() method. If none was selected + /// before, the default capture device will be used. You can get a + /// list of the names of all available capture devices by calling + /// getAvailableDevices(). + /// + /// \param sampleRate Desired capture rate, in number of samples per second + /// + /// \return True, if start of capture was successful + /// + /// \see stop, getAvailableDevices + /// + //////////////////////////////////////////////////////////// + bool start(unsigned int sampleRate = 44100); + + //////////////////////////////////////////////////////////// + /// \brief Stop the capture + /// + /// \see start + /// + //////////////////////////////////////////////////////////// + void stop(); + + //////////////////////////////////////////////////////////// + /// \brief Get the sample rate + /// + /// The sample rate defines the number of audio samples + /// captured per second. The higher, the better the quality + /// (for example, 44100 samples/sec is CD quality). + /// + /// \return Sample rate, in samples per second + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a list of the names of all availabe audio capture devices + /// + /// This function returns a vector of strings, containing + /// the names of all availabe audio capture devices. + /// + /// \return A vector of strings containing the names + /// + //////////////////////////////////////////////////////////// + static std::vector getAvailableDevices(); + + //////////////////////////////////////////////////////////// + /// \brief Get the name of the default audio capture device + /// + /// This function returns the name of the default audio + /// capture device. If none is available, an empty string + /// is returned. + /// + /// \return The name of the default audio capture device + /// + //////////////////////////////////////////////////////////// + static std::string getDefaultDevice(); + + //////////////////////////////////////////////////////////// + /// \brief Set the audio capture device + /// + /// This function sets the audio capture device to the device + /// with the given \a name. It can be called on the fly (i.e: + /// while recording). If you do so while recording and + /// opening the device fails, it stops the recording. + /// + /// \param name The name of the audio capture device + /// + /// \return True, if it was able to set the requested device + /// + /// \see getAvailableDevices, getDefaultDevice + /// + //////////////////////////////////////////////////////////// + bool setDevice(const std::string& name); + + //////////////////////////////////////////////////////////// + /// \brief Get the name of the current audio capture device + /// + /// \return The name of the current audio capture device + /// + //////////////////////////////////////////////////////////// + const std::string& getDevice() const; + + //////////////////////////////////////////////////////////// + /// \brief Check if the system supports audio capture + /// + /// This function should always be called before using + /// the audio capture features. If it returns false, then + /// any attempt to use cpp3ds::SoundRecorder or one of its derived + /// classes will fail. + /// + /// \return True if audio capture is supported, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isAvailable(); + +protected : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor is only meant to be called by derived classes. + /// + //////////////////////////////////////////////////////////// + SoundRecorder(); + + //////////////////////////////////////////////////////////// + /// \brief Set the processing interval + /// + /// The processing interval controls the period + /// between calls to the onProcessSamples function. You may + /// want to use a small interval if you want to process the + /// recorded data in real time, for example. + /// + /// Note: this is only a hint, the actual period may vary. + /// So don't rely on this parameter to implement precise timing. + /// + /// The default processing interval is 100 ms. + /// + /// \param interval Processing interval + /// + //////////////////////////////////////////////////////////// + void setProcessingInterval(cpp3ds::Time interval); + + //////////////////////////////////////////////////////////// + /// \brief Start capturing audio data + /// + /// This virtual function may be overriden by a derived class + /// if something has to be done every time a new capture + /// starts. If not, this function can be ignored; the default + /// implementation does nothing. + /// + /// \return True to start the capture, or false to abort it + /// + //////////////////////////////////////////////////////////// + virtual bool onStart(); + + //////////////////////////////////////////////////////////// + /// \brief Process a new chunk of recorded samples + /// + /// This virtual function is called every time a new chunk of + /// recorded data is available. The derived class can then do + /// whatever it wants with it (storing it, playing it, sending + /// it over the network, etc.). + /// + /// \param samples Pointer to the new chunk of recorded samples + /// \param sampleCount Number of samples pointed by \a samples + /// + /// \return True to continue the capture, or false to stop it + /// + //////////////////////////////////////////////////////////// + virtual bool onProcessSamples(const Int16* samples, std::size_t sampleCount) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Stop capturing audio data + /// + /// This virtual function may be overriden by a derived class + /// if something has to be done every time the capture + /// ends. If not, this function can be ignored; the default + /// implementation does nothing. + /// + //////////////////////////////////////////////////////////// + virtual void onStop(); + +private : + + //////////////////////////////////////////////////////////// + /// \brief Function called as the entry point of the thread + /// + /// This function starts the recording loop, and returns + /// only when the capture is stopped. + /// + //////////////////////////////////////////////////////////// + void record(); + + //////////////////////////////////////////////////////////// + /// \brief Get the new available audio samples and process them + /// + /// This function is called continuously during the + /// capture loop. It retrieves the captured samples and + /// forwards them to the derived class. + /// + //////////////////////////////////////////////////////////// + void processCapturedSamples(); + + //////////////////////////////////////////////////////////// + /// \brief Clean up the recorder's internal resources + /// + /// This function is called when the capture stops. + /// + //////////////////////////////////////////////////////////// + void cleanup(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Thread m_thread; ///< Thread running the background recording task + std::vector m_samples; ///< Buffer to store captured samples + unsigned int m_sampleRate; ///< Sample rate + cpp3ds::Time m_processingInterval; ///< Time period between calls to onProcessSamples + bool m_isCapturing; ///< Capturing state + std::string m_deviceName; ///< Name of the audio capture device +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDRECORDER_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::SoundRecorder +/// \ingroup audio +/// +/// cpp3ds::SoundBuffer provides a simple interface to access +/// the audio recording capabilities of the computer +/// (the microphone). As an abstract base class, it only cares +/// about capturing sound samples, the task of making something +/// useful with them is left to the derived class. Note that +/// cpp3ds provides a built-in specialization for saving the +/// captured data to a sound buffer (see cpp3ds::SoundBufferRecorder). +/// +/// A derived class has only one virtual function to override: +/// \li onProcessSamples provides the new chunks of audio samples while the capture happens +/// +/// Moreover, two additionnal virtual functions can be overriden +/// as well if necessary: +/// \li onStart is called before the capture happens, to perform custom initializations +/// \li onStop is called after the capture ends, to perform custom cleanup +/// +/// A derived class can also control the frequency of the onProcessSamples +/// calls, with the setProcessingInterval protected function. The default +/// interval is chosen so that recording thread doesn't consume too much +/// CPU, but it can be changed to a smaller value if you need to process +/// the recorded data in real time, for example. +/// +/// The audio capture feature may not be supported or activated +/// on every platform, thus it is recommended to check its +/// availability with the isAvailable() function. If it returns +/// false, then any attempt to use an audio recorder will fail. +/// +/// If you have multiple sound input devices connected to your +/// computer (for example: microphone, external soundcard, webcam mic, ...) +/// you can get a list of all available devices throught the +/// getAvailableDevices() function. You can then select a device +/// by calling setDevice() with the appropiate device. Otherwise +/// the default capturing device will be used. +/// +/// It is important to note that the audio capture happens in a +/// separate thread, so that it doesn't block the rest of the +/// program. In particular, the onProcessSamples virtual function +/// (but not onStart and not onStop) will be called +/// from this separate thread. It is important to keep this in +/// mind, because you may have to take care of synchronization +/// issues if you share data between threads. +/// +/// Usage example: +/// \code +/// class CustomRecorder : public cpp3ds::SoundRecorder +/// { +/// virtual bool onStart() // optional +/// { +/// // Initialize whatever has to be done before the capture starts +/// ... +/// +/// // Return true to start playing +/// return true; +/// } +/// +/// virtual bool onProcessSamples(const Int16* samples, std::size_t sampleCount) +/// { +/// // Do something with the new chunk of samples (store them, send them, ...) +/// ... +/// +/// // Return true to continue playing +/// return true; +/// } +/// +/// virtual void onStop() // optional +/// { +/// // Clean up whatever has to be done after the capture ends +/// ... +/// } +/// } +/// +/// // Usage +/// if (CustomRecorder::isAvailable()) +/// { +/// CustomRecorder recorder; +/// +/// if (!recorder.start()) +/// return -1; +/// +/// ... +/// recorder.stop(); +/// } +/// \endcode +/// +/// \see cpp3ds::SoundBufferRecorder +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/SoundSource.hpp b/include/cpp3ds/Audio/SoundSource.hpp new file mode 100644 index 0000000..a721067 --- /dev/null +++ b/include/cpp3ds/Audio/SoundSource.hpp @@ -0,0 +1,285 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDSOURCE_HPP +#define CPP3DS_SOUNDSOURCE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +/// \brief Base class defining a sound's properties +/// +//////////////////////////////////////////////////////////// +class SoundSource +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Enumeration of the sound source states + /// + //////////////////////////////////////////////////////////// + enum Status + { + Stopped, ///< Sound is not playing + Paused, ///< Sound is paused + Playing ///< Sound is playing + }; + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + SoundSource(const SoundSource& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundSource(); + + //////////////////////////////////////////////////////////// + /// \brief Set the pitch of the sound + /// + /// The pitch represents the perceived fundamental frequency + /// of a sound; thus you can make a sound more acute or grave + /// by changing its pitch. A side effect of changing the pitch + /// is to modify the playing speed of the sound as well. + /// The default value for the pitch is 1. + /// + /// \param pitch New pitch to apply to the sound + /// + /// \see getPitch + /// + //////////////////////////////////////////////////////////// + void setPitch(float pitch); + + //////////////////////////////////////////////////////////// + /// \brief Set the volume of the sound + /// + /// The volume is a value between 0 (mute) and 100 (full volume). + /// The default value for the volume is 100. + /// + /// \param volume Volume of the sound + /// + /// \see getVolume + /// + //////////////////////////////////////////////////////////// + void setVolume(float volume); + + //////////////////////////////////////////////////////////// + /// \brief Set the 3D position of the sound in the audio scene + /// + /// Only sounds with one channel (mono sounds) can be + /// spatialized. + /// The default position of a sound is (0, 0, 0). + /// + /// \param x X coordinate of the position of the sound in the scene + /// \param y Y coordinate of the position of the sound in the scene + /// \param z Z coordinate of the position of the sound in the scene + /// + /// \see getPosition + /// + //////////////////////////////////////////////////////////// + void setPosition(float x, float y, float z); + + //////////////////////////////////////////////////////////// + /// \brief Set the 3D position of the sound in the audio scene + /// + /// Only sounds with one channel (mono sounds) can be + /// spatialized. + /// The default position of a sound is (0, 0, 0). + /// + /// \param position Position of the sound in the scene + /// + /// \see getPosition + /// + //////////////////////////////////////////////////////////// + void setPosition(const Vector3f& position); + + //////////////////////////////////////////////////////////// + /// \brief Make the sound's position relative to the listener or absolute + /// + /// Making a sound relative to the listener will ensure that it will always + /// be played the same way regardless the position of the listener. + /// This can be useful for non-spatialized sounds, sounds that are + /// produced by the listener, or sounds attached to it. + /// The default value is false (position is absolute). + /// + /// \param relative True to set the position relative, false to set it absolute + /// + /// \see isRelativeToListener + /// + //////////////////////////////////////////////////////////// + void setRelativeToListener(bool relative); + + //////////////////////////////////////////////////////////// + /// \brief Set the minimum distance of the sound + /// + /// The "minimum distance" of a sound is the maximum + /// distance at which it is heard at its maximum volume. Further + /// than the minimum distance, it will start to fade out according + /// to its attenuation factor. A value of 0 ("inside the head + /// of the listener") is an invalid value and is forbidden. + /// The default value of the minimum distance is 1. + /// + /// \param distance New minimum distance of the sound + /// + /// \see getMinDistance, setAttenuation + /// + //////////////////////////////////////////////////////////// + void setMinDistance(float distance); + + //////////////////////////////////////////////////////////// + /// \brief Set the attenuation factor of the sound + /// + /// The attenuation is a multiplicative factor which makes + /// the sound more or less loud according to its distance + /// from the listener. An attenuation of 0 will produce a + /// non-attenuated sound, i.e. its volume will always be the same + /// whether it is heard from near or from far. On the other hand, + /// an attenuation value such as 100 will make the sound fade out + /// very quickly as it gets further from the listener. + /// The default value of the attenuation is 1. + /// + /// \param attenuation New attenuation factor of the sound + /// + /// \see getAttenuation, setMinDistance + /// + //////////////////////////////////////////////////////////// + void setAttenuation(float attenuation); + + //////////////////////////////////////////////////////////// + /// \brief Get the pitch of the sound + /// + /// \return Pitch of the sound + /// + /// \see setPitch + /// + //////////////////////////////////////////////////////////// + float getPitch() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the volume of the sound + /// + /// \return Volume of the sound, in the range [0, 100] + /// + /// \see setVolume + /// + //////////////////////////////////////////////////////////// + float getVolume() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the 3D position of the sound in the audio scene + /// + /// \return Position of the sound + /// + /// \see setPosition + /// + //////////////////////////////////////////////////////////// + Vector3f getPosition() const; + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the sound's position is relative to the + /// listener or is absolute + /// + /// \return True if the position is relative, false if it's absolute + /// + /// \see setRelativeToListener + /// + //////////////////////////////////////////////////////////// + bool isRelativeToListener() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the minimum distance of the sound + /// + /// \return Minimum distance of the sound + /// + /// \see setMinDistance, getAttenuation + /// + //////////////////////////////////////////////////////////// + float getMinDistance() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the attenuation factor of the sound + /// + /// \return Attenuation factor of the sound + /// + /// \see setAttenuation, getMinDistance + /// + //////////////////////////////////////////////////////////// + float getAttenuation() const; + +protected : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor is meant ot be called by derived classes only. + /// + //////////////////////////////////////////////////////////// + SoundSource(); + + //////////////////////////////////////////////////////////// + /// \brief Get the current status of the sound (stopped, paused, playing) + /// + /// \return Current status of the sound + /// + //////////////////////////////////////////////////////////// + Status getStatus() const; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// +// unsigned int m_source; ///< OpenAL source identifier +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDSOURCE_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::SoundSource +/// \ingroup audio +/// +/// cpp3ds::SoundSource is not meant to be used directly, it +/// only serves as a common base for all audio objects +/// that can live in the audio environment. +/// +/// It defines several properties for the sound: pitch, +/// volume, position, attenuation, etc. All of them can be +/// changed at any time with no impact on performances. +/// +/// \see cpp3ds::Sound, cpp3ds::SoundStream +/// +//////////////////////////////////////////////////////////// diff --git a/include/cpp3ds/Audio/SoundStream.hpp b/include/cpp3ds/Audio/SoundStream.hpp new file mode 100644 index 0000000..1b47cdb --- /dev/null +++ b/include/cpp3ds/Audio/SoundStream.hpp @@ -0,0 +1,385 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDSTREAM_HPP +#define CPP3DS_SOUNDSTREAM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +/// \brief Abstract base class for streamed audio sources +/// +//////////////////////////////////////////////////////////// +class SoundStream : public SoundSource +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Structure defining a chunk of audio data to stream + /// + //////////////////////////////////////////////////////////// + struct Chunk + { + const Int16* samples; ///< Pointer to the audio samples + std::size_t sampleCount; ///< Number of samples pointed by Samples + }; + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + virtual ~SoundStream(); + + //////////////////////////////////////////////////////////// + /// \brief Start or resume playing the audio stream + /// + /// This function starts the stream if it was stopped, resumes + /// it if it was paused, and restarts it from the beginning if + /// it was already playing. + /// This function uses its own thread so that it doesn't block + /// the rest of the program while the stream is played. + /// + /// \see pause, stop + /// + //////////////////////////////////////////////////////////// + void play(); + + //////////////////////////////////////////////////////////// + /// \brief Pause the audio stream + /// + /// This function pauses the stream if it was playing, + /// otherwise (stream already paused or stopped) it has no effect. + /// + /// \see play, stop + /// + //////////////////////////////////////////////////////////// + void pause(); + + //////////////////////////////////////////////////////////// + /// \brief Stop playing the audio stream + /// + /// This function stops the stream if it was playing or paused, + /// and does nothing if it was already stopped. + /// It also resets the playing position (unlike pause()). + /// + /// \see play, pause + /// + //////////////////////////////////////////////////////////// + void stop(); + + //////////////////////////////////////////////////////////// + /// \brief Return the number of channels of the stream + /// + /// 1 channel means a mono sound, 2 means stereo, etc. + /// + /// \return Number of channels + /// + //////////////////////////////////////////////////////////// + unsigned int getChannelCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the stream sample rate of the stream + /// + /// The sample rate is the number of audio samples played per + /// second. The higher, the better the quality. + /// + /// \return Sample rate, in number of samples per second + /// + //////////////////////////////////////////////////////////// + unsigned int getSampleRate() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the current status of the stream (stopped, paused, playing) + /// + /// \return Current status + /// + //////////////////////////////////////////////////////////// + Status getStatus() const; + + //////////////////////////////////////////////////////////// + /// \brief Change the current playing position of the stream + /// + /// The playing position can be changed when the stream is + /// either paused or playing. Changing the playing position + /// when the stream is stopped has no effect, since playing + /// the stream would reset its position. + /// + /// \param timeOffset New playing position, from the beginning of the stream + /// + /// \see getPlayingOffset + /// + //////////////////////////////////////////////////////////// + void setPlayingOffset(Time timeOffset); + + //////////////////////////////////////////////////////////// + /// \brief Get the current playing position of the stream + /// + /// \return Current playing position, from the beginning of the stream + /// + /// \see setPlayingOffset + /// + //////////////////////////////////////////////////////////// + Time getPlayingOffset() const; + + //////////////////////////////////////////////////////////// + /// \brief Set whether or not the stream should loop after reaching the end + /// + /// If set, the stream will restart from beginning after + /// reaching the end and so on, until it is stopped or + /// setLoop(false) is called. + /// The default looping state for streams is false. + /// + /// \param loop True to play in loop, false to play once + /// + /// \see getLoop + /// + //////////////////////////////////////////////////////////// + void setLoop(bool loop); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the stream is in loop mode + /// + /// \return True if the stream is looping, false otherwise + /// + /// \see setLoop + /// + //////////////////////////////////////////////////////////// + bool getLoop() const; + +protected: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor is only meant to be called by derived classes. + /// + //////////////////////////////////////////////////////////// + SoundStream(); + + //////////////////////////////////////////////////////////// + /// \brief Define the audio stream parameters + /// + /// This function must be called by derived classes as soon + /// as they know the audio settings of the stream to play. + /// Any attempt to manipulate the stream (play(), ...) before + /// calling this function will fail. + /// It can be called multiple times if the settings of the + /// audio stream change, but only when the stream is stopped. + /// + /// \param channelCount Number of channels of the stream + /// \param sampleRate Sample rate, in samples per second + /// + //////////////////////////////////////////////////////////// + void initialize(unsigned int channelCount, unsigned int sampleRate); + + //////////////////////////////////////////////////////////// + /// \brief Request a new chunk of audio samples from the stream source + /// + /// This function must be overridden by derived classes to provide + /// the audio samples to play. It is called continuously by the + /// streaming loop, in a separate thread. + /// The source can choose to stop the streaming loop at any time, by + /// returning false to the caller. + /// If you return true (i.e. continue streaming) it is important that + /// the returned array of samples is not empty; this would stop the stream + /// due to an internal limitation. + /// + /// \param data Chunk of data to fill + /// + /// \return True to continue playback, false to stop + /// + //////////////////////////////////////////////////////////// + virtual bool onGetData(Chunk& data) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Change the current playing position in the stream source + /// + /// This function must be overridden by derived classes to + /// allow random seeking into the stream source. + /// + /// \param timeOffset New playing position, relative to the beginning of the stream + /// + //////////////////////////////////////////////////////////// + virtual void onSeek(Time timeOffset) = 0; + +private: + + //////////////////////////////////////////////////////////// + /// \brief Function called as the entry point of the thread + /// + /// This function starts the streaming loop, and returns + /// only when the sound is stopped. + /// + //////////////////////////////////////////////////////////// + void streamData(); + + //////////////////////////////////////////////////////////// + /// \brief Fill a new buffer with audio samples, and append + /// it to the playing queue + /// + /// This function is called as soon as a buffer has been fully + /// consumed; it fills it again and inserts it back into the + /// playing queue. + /// + /// \param bufferNum Number of the buffer to fill (in [0, BufferCount]) + /// + /// \return True if the stream source has requested to stop, false otherwise + /// + //////////////////////////////////////////////////////////// + bool fillAndPushBuffer(unsigned int bufferNum); + + //////////////////////////////////////////////////////////// + /// \brief Fill the audio buffers and put them all into the playing queue + /// + /// This function is called when playing starts and the + /// playing queue is empty. + /// + /// \return True if the derived class has requested to stop, false otherwise + /// + //////////////////////////////////////////////////////////// + bool fillQueue(); + + //////////////////////////////////////////////////////////// + /// \brief Clear all the audio buffers and empty the playing queue + /// + /// This function is called when the stream is stopped. + /// + //////////////////////////////////////////////////////////// + void clearQueue(); + + enum + { + BufferCount = 3 ///< Number of audio buffers used by the streaming loop + }; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Thread m_thread; ///< Thread running the background tasks + mutable Mutex m_threadMutex; ///< Thread mutex + Status m_threadStartState; ///< State the thread starts in (Playing, Paused, Stopped) + bool m_isStreaming; ///< Streaming state (true = playing, false = stopped) + unsigned int m_buffers[BufferCount]; ///< Sound buffers used to store temporary audio data + unsigned int m_channelCount; ///< Number of channels (1 = mono, 2 = stereo, ...) + unsigned int m_sampleRate; ///< Frequency (samples / second) + Uint32 m_format; ///< Format of the internal sound buffers + bool m_loop; ///< Loop flag (true to loop, false to play once) + Uint64 m_samplesProcessed; ///< Number of buffers processed since beginning of the stream + bool m_endBuffers[BufferCount]; ///< Each buffer is marked as "end buffer" or not, for proper duration calculation +}; + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDSTREAM_HPP + + +//////////////////////////////////////////////////////////// +/// \class cpp3ds::SoundStream +/// \ingroup audio +/// +/// Unlike audio buffers (see cpp3ds::SoundBuffer), audio streams +/// are never completely loaded in memory. Instead, the audio +/// data is acquired continuously while the stream is playing. +/// This behavior allows to play a sound with no loading delay, +/// and keeps the memory consumption very low. +/// +/// Sound sources that need to be streamed are usually big files +/// (compressed audio musics that would eat hundreds of MB in memory) +/// or files that would take a lot of time to be received +/// (sounds played over the network). +/// +/// cpp3ds::SoundStream is a base class that doesn't care about the +/// stream source, which is left to the derived class. cpp3ds provides +/// a built-in specialization for big files (see cpp3ds::Music). +/// No network stream source is provided, but you can write your own +/// by combining this class with the network module. +/// +/// A derived class has to override two virtual functions: +/// \li onGetData fills a new chunk of audio data to be played +/// \li onSeek changes the current playing position in the source +/// +/// It is important to note that each SoundStream is played in its +/// own separate thread, so that the streaming loop doesn't block the +/// rest of the program. In particular, the OnGetData and OnSeek +/// virtual functions may sometimes be called from this separate thread. +/// It is important to keep this in mind, because you may have to take +/// care of synchronization issues if you share data between threads. +/// +/// Usage example: +/// \code +/// class CustomStream : public cpp3ds::SoundStream +/// { +/// public: +/// +/// bool open(const std::string& location) +/// { +/// // Open the source and get audio settings +/// ... +/// unsigned int channelCount = ...; +/// unsigned int sampleRate = ...; +/// +/// // Initialize the stream -- important! +/// initialize(channelCount, sampleRate); +/// } +/// +/// private: +/// +/// virtual bool onGetData(Chunk& data) +/// { +/// // Fill the chunk with audio data from the stream source +/// // (note: must not be empty if you want to continue playing) +/// data.samples = ...; +/// data.sampleCount = ...; +/// +/// // Return true to continue playing +/// return true; +/// } +/// +/// virtual void onSeek(Uint32 timeOffset) +/// { +/// // Change the current position in the stream source +/// ... +/// } +/// } +/// +/// // Usage +/// CustomStream stream; +/// stream.open("path/to/stream"); +/// stream.play(); +/// \endcode +/// +/// \see cpp3ds::Music +/// +//////////////////////////////////////////////////////////// diff --git a/src/cpp3ds/Audio/InputSoundFile.cpp b/src/cpp3ds/Audio/InputSoundFile.cpp new file mode 100644 index 0000000..190e5b8 --- /dev/null +++ b/src/cpp3ds/Audio/InputSoundFile.cpp @@ -0,0 +1,257 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +InputSoundFile::InputSoundFile() : +m_reader (NULL), +m_stream (NULL), +m_streamOwned (false), +m_sampleCount (0), +m_channelCount(0), +m_sampleRate (0) +{ +} + + +//////////////////////////////////////////////////////////// +InputSoundFile::~InputSoundFile() +{ + // Close the file in case it was open + close(); +} + + +//////////////////////////////////////////////////////////// +bool InputSoundFile::openFromFile(const std::string& filename) +{ + // If the file is already open, first close it + close(); + + // Find a suitable reader for the file type + m_reader = SoundFileFactory::createReaderFromFilename(filename); + if (!m_reader) + { + err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl; + return false; + } + + // Wrap the file into a stream + FileInputStream* file = new FileInputStream; + m_stream = file; + m_streamOwned = true; + + // Open it + if (!file->open(filename)) + { + close(); + return false; + } + + // Pass the stream to the reader + SoundFileReader::Info info; + if (!m_reader->open(*file, info)) + { + close(); + return false; + } + + // Retrieve the attributes of the open sound file + m_sampleCount = info.sampleCount; + m_channelCount = info.channelCount; + m_sampleRate = info.sampleRate; + + return true; +} + + +//////////////////////////////////////////////////////////// +bool InputSoundFile::openFromMemory(const void* data, std::size_t sizeInBytes) +{ + // If the file is already open, first close it + close(); + + // Find a suitable reader for the file type + m_reader = SoundFileFactory::createReaderFromMemory(data, sizeInBytes); + if (!m_reader) + { + err() << "Failed to open sound file from memory (format not supported)" << std::endl; + return false; + } + + // Wrap the memory file into a stream + MemoryInputStream* memory = new MemoryInputStream; + m_stream = memory; + m_streamOwned = true; + + // Open it + memory->open(data, sizeInBytes); + + // Pass the stream to the reader + SoundFileReader::Info info; + if (!m_reader->open(*memory, info)) + { + close(); + return false; + } + + // Retrieve the attributes of the open sound file + m_sampleCount = info.sampleCount; + m_channelCount = info.channelCount; + m_sampleRate = info.sampleRate; + + return true; +} + + +//////////////////////////////////////////////////////////// +bool InputSoundFile::openFromStream(InputStream& stream) +{ + // If the file is already open, first close it + close(); + + // Find a suitable reader for the file type + m_reader = SoundFileFactory::createReaderFromStream(stream); + if (!m_reader) + { + err() << "Failed to open sound file from stream (format not supported)" << std::endl; + return false; + } + + // store the stream + m_stream = &stream; + m_streamOwned = false; + + // Don't forget to reset the stream to its beginning before re-opening it + if (stream.seek(0) != 0) + { + err() << "Failed to open sound file from stream (cannot restart stream)" << std::endl; + return false; + } + + // Pass the stream to the reader + SoundFileReader::Info info; + if (!m_reader->open(stream, info)) + { + close(); + return false; + } + + // Retrieve the attributes of the open sound file + m_sampleCount = info.sampleCount; + m_channelCount = info.channelCount; + m_sampleRate = info.sampleRate; + + return true; +} + + +//////////////////////////////////////////////////////////// +Uint64 InputSoundFile::getSampleCount() const +{ + return m_sampleCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int InputSoundFile::getChannelCount() const +{ + return m_channelCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int InputSoundFile::getSampleRate() const +{ + return m_sampleRate; +} + + +//////////////////////////////////////////////////////////// +Time InputSoundFile::getDuration() const +{ + return seconds(static_cast(m_sampleCount) / m_channelCount / m_sampleRate); +} + + +//////////////////////////////////////////////////////////// +void InputSoundFile::seek(Uint64 sampleOffset) +{ + if (m_reader) + m_reader->seek(sampleOffset); +} + + +//////////////////////////////////////////////////////////// +void InputSoundFile::seek(Time timeOffset) +{ + seek(static_cast(timeOffset.asSeconds() * m_sampleRate * m_channelCount)); +} + + +//////////////////////////////////////////////////////////// +Uint64 InputSoundFile::read(Int16* samples, Uint64 maxCount) +{ + if (m_reader && samples && maxCount) + return m_reader->read(samples, maxCount); + else + return 0; +} + + +//////////////////////////////////////////////////////////// +void InputSoundFile::close() +{ + // Destroy the reader + delete m_reader; + m_reader = NULL; + + // Destroy the stream if we own it + if (m_streamOwned) + { + delete m_stream; + m_streamOwned = false; + } + m_stream = NULL; + + // Reset the sound file attributes + m_sampleCount = 0; + m_channelCount = 0; + m_sampleRate = 0; +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/Music.cpp b/src/cpp3ds/Audio/Music.cpp new file mode 100644 index 0000000..627dd0d --- /dev/null +++ b/src/cpp3ds/Audio/Music.cpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +//#include +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +Music::Music() : +m_file (), +m_duration() +{ + +} + + +//////////////////////////////////////////////////////////// +Music::~Music() +{ + // We must stop before destroying the file + stop(); +} + + +//////////////////////////////////////////////////////////// +bool Music::openFromFile(const std::string& filename) +{ + // First stop the music if it was already running + stop(); + + // Open the underlying sound file + if (!m_file.openFromFile(filename)) + return false; + + // Perform common initializations + initialize(); + + return true; +} + + +//////////////////////////////////////////////////////////// +bool Music::openFromMemory(const void* data, std::size_t sizeInBytes) +{ + // First stop the music if it was already running + stop(); + + // Open the underlying sound file + if (!m_file.openFromMemory(data, sizeInBytes)) + return false; + + // Perform common initializations + initialize(); + + return true; +} + + +//////////////////////////////////////////////////////////// +bool Music::openFromStream(InputStream& stream) +{ + // First stop the music if it was already running + stop(); + + // Open the underlying sound file + if (!m_file.openFromStream(stream)) + return false; + + // Perform common initializations + initialize(); + + return true; +} + + +//////////////////////////////////////////////////////////// +Time Music::getDuration() const +{ + return m_duration; +} + + +//////////////////////////////////////////////////////////// +bool Music::onGetData(SoundStream::Chunk& data) +{ + Lock lock(m_mutex); + + // Fill the chunk parameters + data.samples = &m_samples[0]; + data.sampleCount = static_cast(m_file.read(&m_samples[0], m_samples.size())); + + // Check if we have reached the end of the audio file + return data.sampleCount == m_samples.size(); +} + + +//////////////////////////////////////////////////////////// +void Music::onSeek(Time timeOffset) +{ + Lock lock(m_mutex); + + m_file.seek(timeOffset); +} + + +//////////////////////////////////////////////////////////// +void Music::initialize() +{ + // Compute the music duration + m_duration = m_file.getDuration(); + + // Resize the internal buffer so that it can contain 1 second of audio samples + m_samples.resize(m_file.getSampleRate() * m_file.getChannelCount()); + + // Initialize the stream + SoundStream::initialize(m_file.getChannelCount(), m_file.getSampleRate()); +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/OutputSoundFile.cpp b/src/cpp3ds/Audio/OutputSoundFile.cpp new file mode 100644 index 0000000..47cc21b --- /dev/null +++ b/src/cpp3ds/Audio/OutputSoundFile.cpp @@ -0,0 +1,92 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +OutputSoundFile::OutputSoundFile() : +m_writer(NULL) +{ +} + + +//////////////////////////////////////////////////////////// +OutputSoundFile::~OutputSoundFile() +{ + // Close the file in case it was open + close(); +} + + +//////////////////////////////////////////////////////////// +bool OutputSoundFile::openFromFile(const std::string& filename, unsigned int sampleRate, unsigned int channelCount) +{ + // If the file is already open, first close it + close(); + + // Find a suitable writer for the file type + m_writer = SoundFileFactory::createWriterFromFilename(filename); + if (!m_writer) + { + err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl; + return false; + } + + // Pass the stream to the reader + if (!m_writer->open(filename, sampleRate, channelCount)) + { + close(); + return false; + } + + return true; +} + + +//////////////////////////////////////////////////////////// +void OutputSoundFile::write(const Int16* samples, Uint64 count) +{ + if (m_writer && samples && count) + m_writer->write(samples, count); +} + + +//////////////////////////////////////////////////////////// +void OutputSoundFile::close() +{ + // Destroy the reader + delete m_writer; + m_writer = NULL; +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/Sound.cpp b/src/cpp3ds/Audio/Sound.cpp new file mode 100644 index 0000000..f635fc3 --- /dev/null +++ b/src/cpp3ds/Audio/Sound.cpp @@ -0,0 +1,211 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +//#include +#include <3ds.h> +#include +#include + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +Sound::Sound() : +m_buffer(NULL), +m_loop(false) +{ +} + + +//////////////////////////////////////////////////////////// +Sound::Sound(const SoundBuffer& buffer) : +m_buffer(NULL), +m_currentChannel(-1), +m_loop(false) +{ + setBuffer(buffer); +} + + +//////////////////////////////////////////////////////////// +Sound::Sound(const Sound& copy) : +SoundSource(copy), +m_buffer (NULL) +{ + if (copy.m_buffer) + setBuffer(*copy.m_buffer); + setLoop(copy.getLoop()); +} + + +//////////////////////////////////////////////////////////// +Sound::~Sound() +{ + stop(); + if (m_buffer) + m_buffer->detachSound(this); +} + + +//////////////////////////////////////////////////////////// +void Sound::play() +{ + if (!m_buffer || m_buffer->getSampleCount() == 0) + return; + + // 24 possible CSND channels to cycle through (0-7) reserved for DSP + static int channel; + channel++; + channel %= 24; + + u32 flags = SOUND_FORMAT_16BIT; + if (m_loop) + flags |= SOUND_REPEAT; + u32 size = sizeof(Int16) * m_buffer->getSampleCount(); + std::cout << "Playing sound: " << m_buffer->getSampleCount(); + GSPGPU_FlushDataCache(NULL, (u8*)m_buffer->getSamples(), size); + csndPlaySound(channel+8, flags, m_buffer->getSampleRate(), 1.0, 0.0, (u32*)m_buffer->getSamples(), (u32*)m_buffer->getSamples(), size); +} + + +//////////////////////////////////////////////////////////// +void Sound::pause() +{ + +} + + +//////////////////////////////////////////////////////////// +void Sound::stop() +{ + +} + + +//////////////////////////////////////////////////////////// +void Sound::setBuffer(const SoundBuffer& buffer) +{ + // First detach from the previous buffer + if (m_buffer) + { + stop(); + m_buffer->detachSound(this); + } + + // Assign and use the new buffer + m_buffer = &buffer; + m_buffer->attachSound(this); +} + + +//////////////////////////////////////////////////////////// +void Sound::setLoop(bool loop) +{ + m_loop = loop; +} + + +//////////////////////////////////////////////////////////// +void Sound::setPlayingOffset(Time timeOffset) +{ + +} + + +//////////////////////////////////////////////////////////// +const SoundBuffer* Sound::getBuffer() const +{ + return m_buffer; +} + + +//////////////////////////////////////////////////////////// +bool Sound::getLoop() const +{ + return m_loop; +} + + +//////////////////////////////////////////////////////////// +Time Sound::getPlayingOffset() const +{ + return seconds(0); +} + + +//////////////////////////////////////////////////////////// +Sound::Status Sound::getStatus() const +{ + return SoundSource::getStatus(); +} + + +//////////////////////////////////////////////////////////// +Sound& Sound::operator =(const Sound& right) +{ + // Here we don't use the copy-and-swap idiom, because it would mess up + // the list of sound instances contained in the buffers + + // Detach the sound instance from the previous buffer (if any) + if (m_buffer) + { + stop(); + m_buffer->detachSound(this); + m_buffer = NULL; + } + + // Copy the sound attributes + if (right.m_buffer) + setBuffer(*right.m_buffer); + setLoop(right.getLoop()); + setPitch(right.getPitch()); + setVolume(right.getVolume()); + setPosition(right.getPosition()); + setRelativeToListener(right.isRelativeToListener()); + setMinDistance(right.getMinDistance()); + setAttenuation(right.getAttenuation()); + + return *this; +} + + +//////////////////////////////////////////////////////////// +void Sound::resetBuffer() +{ + // First stop the sound in case it is playing + stop(); + + // Detach the buffer + if (m_buffer) + { + m_buffer->detachSound(this); + m_buffer = NULL; + } +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundBuffer.cpp b/src/cpp3ds/Audio/SoundBuffer.cpp new file mode 100644 index 0000000..ac1384b --- /dev/null +++ b/src/cpp3ds/Audio/SoundBuffer.cpp @@ -0,0 +1,299 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +//#include +//#include +#include +#include +#include <3ds.h> +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +SoundBuffer::SoundBuffer() : +m_buffer (0), +m_sampleCount (0), +m_duration() +{ +} + + +//////////////////////////////////////////////////////////// +SoundBuffer::SoundBuffer(const SoundBuffer& copy) : +m_buffer (0), +m_samples (copy.m_samples), +m_sampleCount (copy.m_sampleCount), +m_duration(copy.m_duration), +m_sounds () // don't copy the attached sounds +{ + // Update the internal buffer with the new samples + update(copy.getChannelCount(), copy.getSampleRate()); +} + + +//////////////////////////////////////////////////////////// +SoundBuffer::~SoundBuffer() +{ + // To prevent the iterator from becoming invalid, move the entire buffer to another + // container. Otherwise calling resetBuffer would result in detachSound being + // called which removes the sound from the internal list. + SoundList sounds; + sounds.swap(m_sounds); + + // Detach the buffer from the sounds that use it (to avoid OpenAL errors) + for (SoundList::const_iterator it = sounds.begin(); it != sounds.end(); ++it) + (*it)->resetBuffer(); + + // Destroy the buffer + if (m_samples) + linearFree(m_samples); +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromFile(const std::string& filename) +{ + InputSoundFile file; + if (file.openFromFile(filename)) + return initialize(file); + else + return false; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromResource(const std::string& filename) +{ + return loadFromMemory(priv::resources[filename].data, priv::resources[filename].size); +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes) +{ + InputSoundFile file; + if (file.openFromMemory(data, sizeInBytes)) + return initialize(file); + else + return false; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromStream(InputStream& stream) +{ + InputSoundFile file; + if (file.openFromStream(stream)) + return initialize(file); + else + return false; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromSamples(const Int16* samples, Uint64 sampleCount, unsigned int channelCount, unsigned int sampleRate) +{ + if (samples && sampleCount && channelCount && sampleRate) + { + // Copy the new audio samples + if (m_samples) + linearFree(m_samples); + m_samples = (Int16*)linearAlloc(sizeof(Int16) * sampleCount); + memcpy(m_samples, samples, sizeof(Int16) * sampleCount); + m_sampleCount = sampleCount; + + // Update the internal buffer with the new samples + return update(channelCount, sampleRate); + } + else + { + // Error... + err() << "Failed to load sound buffer from samples (" + << "array: " << samples << ", " + << "count: " << sampleCount << ", " + << "channels: " << channelCount << ", " + << "samplerate: " << sampleRate << ")" + << std::endl; + + return false; + } +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::saveToFile(const std::string& filename) const +{ + // Create the sound file in write mode + OutputSoundFile file; + if (file.openFromFile(filename, getSampleRate(), getChannelCount())) + { + // Write the samples to the opened file + file.write(m_samples, m_sampleCount); + + return true; + } + else + { + return false; + } +} + + +//////////////////////////////////////////////////////////// +const Int16* SoundBuffer::getSamples() const +{ + return m_sampleCount == 0 ? NULL : m_samples; +} + + +//////////////////////////////////////////////////////////// +Uint64 SoundBuffer::getSampleCount() const +{ + return m_sampleCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundBuffer::getSampleRate() const +{ + return m_sampleRate; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundBuffer::getChannelCount() const +{ + return m_channelCount; +} + + +//////////////////////////////////////////////////////////// +Time SoundBuffer::getDuration() const +{ + return m_duration; +} + + +//////////////////////////////////////////////////////////// +SoundBuffer& SoundBuffer::operator =(const SoundBuffer& right) +{ + SoundBuffer temp(right); + + std::swap(m_samples, temp.m_samples); + std::swap(m_sampleCount, temp.m_sampleCount); + std::swap(m_buffer, temp.m_buffer); + std::swap(m_duration, temp.m_duration); + std::swap(m_sounds, temp.m_sounds); // swap sounds too, so that they are detached when temp is destroyed + + return *this; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::initialize(InputSoundFile& file) +{ + // Retrieve the sound parameters + Uint64 sampleCount = file.getSampleCount(); + unsigned int channelCount = file.getChannelCount(); + unsigned int sampleRate = file.getSampleRate(); + m_channelCount = channelCount; + m_sampleRate = sampleRate; + + // Resize sample array to be filled + if (m_samples) + linearFree(m_samples); + m_samples = (Int16*)linearAlloc(sizeof(Int16) * sampleCount); + + // Read the samples from the provided file + if (file.read(m_samples, sampleCount) == sampleCount) + { + m_sampleCount = sampleCount; + // Update the internal buffer with the new samples + return update(channelCount, sampleRate); + } + else + { + return false; + } +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::update(unsigned int channelCount, unsigned int sampleRate) +{ + // Check parameters + if (!channelCount || !sampleRate || m_sampleCount == 0) + return false; + + // Check if the format is valid + if (channelCount > 1){ + err() << "Failed to load sound buffer (unsupported number of channels: " << channelCount << ")" << std::endl; + return false; + } + + m_channelCount = channelCount; + m_sampleRate = sampleRate; + + // First make a copy of the list of sounds so we can reattach later + SoundList sounds(m_sounds); + + // Detach the buffer from the sounds that use it (to avoid OpenAL errors) + for (SoundList::const_iterator it = sounds.begin(); it != sounds.end(); ++it) + (*it)->resetBuffer(); + + // Compute the duration + m_duration = seconds(static_cast(m_sampleCount) / sampleRate / channelCount); + + // Now reattach the buffer to the sounds that use it + for (SoundList::const_iterator it = sounds.begin(); it != sounds.end(); ++it) + (*it)->setBuffer(*this); + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundBuffer::attachSound(Sound* sound) const +{ + m_sounds.insert(sound); +} + + +//////////////////////////////////////////////////////////// +void SoundBuffer::detachSound(Sound* sound) const +{ + m_sounds.erase(sound); +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundBufferRecorder.cpp b/src/cpp3ds/Audio/SoundBufferRecorder.cpp new file mode 100644 index 0000000..78d107f --- /dev/null +++ b/src/cpp3ds/Audio/SoundBufferRecorder.cpp @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +bool SoundBufferRecorder::onStart() +{ + m_samples.clear(); + m_buffer = SoundBuffer(); + + return true; +} + + +//////////////////////////////////////////////////////////// +bool SoundBufferRecorder::onProcessSamples(const Int16* samples, std::size_t sampleCount) +{ + std::copy(samples, samples + sampleCount, std::back_inserter(m_samples)); + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundBufferRecorder::onStop() +{ + if (!m_samples.empty()) + m_buffer.loadFromSamples(&m_samples[0], m_samples.size(), 1, getSampleRate()); +} + + +//////////////////////////////////////////////////////////// +const SoundBuffer& SoundBufferRecorder::getBuffer() const +{ + return m_buffer; +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundFileFactory.cpp b/src/cpp3ds/Audio/SoundFileFactory.cpp new file mode 100644 index 0000000..89c9d4d --- /dev/null +++ b/src/cpp3ds/Audio/SoundFileFactory.cpp @@ -0,0 +1,155 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#ifdef CPP3DS_ENABLE_FLAC +#include +#include +#endif +#ifdef CPP3DS_ENABLE_OGG +#include +#include +#endif +#include +#include +#include +#include + + +namespace +{ + // Register all the built-in readers and writers if not already done + void ensureDefaultReadersWritersRegistered() + { + static bool registered = false; + if (!registered) + { + #ifdef CPP3DS_ENABLE_FLAC + cpp3ds::SoundFileFactory::registerReader(); + cpp3ds::SoundFileFactory::registerWriter(); + #endif + #ifdef CPP3DS_ENABLE_OGG + cpp3ds::SoundFileFactory::registerReader(); + cpp3ds::SoundFileFactory::registerWriter(); + #endif + cpp3ds::SoundFileFactory::registerReader(); + cpp3ds::SoundFileFactory::registerWriter(); + registered = true; + } + } +} + +namespace cpp3ds +{ +SoundFileFactory::ReaderFactoryArray SoundFileFactory::s_readers; +SoundFileFactory::WriterFactoryArray SoundFileFactory::s_writers; + + +//////////////////////////////////////////////////////////// +SoundFileReader* SoundFileFactory::createReaderFromFilename(const std::string& filename) +{ + // Register the built-in readers/writers on first call + ensureDefaultReadersWritersRegistered(); + + // Wrap the input file into a file stream + FileInputStream stream; + if (!stream.open(filename)) + return NULL; + + // Test the filename in all the registered factories + for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it) + { + stream.seek(0); + if (it->check(stream)) + return it->create(); + } + + // No suitable reader found + return NULL; +} + + +//////////////////////////////////////////////////////////// +SoundFileReader* SoundFileFactory::createReaderFromMemory(const void* data, std::size_t sizeInBytes) +{ + // Register the built-in readers/writers on first call + ensureDefaultReadersWritersRegistered(); + + // Wrap the memory file into a file stream + MemoryInputStream stream; + stream.open(data, sizeInBytes); + + // Test the stream for all the registered factories + for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it) + { + stream.seek(0); + if (it->check(stream)) + return it->create(); + } + + // No suitable reader found + return NULL; +} + + +//////////////////////////////////////////////////////////// +SoundFileReader* SoundFileFactory::createReaderFromStream(InputStream& stream) +{ + // Register the built-in readers/writers on first call + ensureDefaultReadersWritersRegistered(); + + // Test the stream for all the registered factories + for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it) + { + stream.seek(0); + if (it->check(stream)) + return it->create(); + } + + // No suitable reader found + return NULL; +} + + +//////////////////////////////////////////////////////////// +SoundFileWriter* SoundFileFactory::createWriterFromFilename(const std::string& filename) +{ + // Register the built-in readers/writers on first call + ensureDefaultReadersWritersRegistered(); + + // Test the filename in all the registered factories + for (WriterFactoryArray::const_iterator it = s_writers.begin(); it != s_writers.end(); ++it) + { + if (it->check(filename)) + return it->create(); + } + + // No suitable writer found + return NULL; +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundFileReaderOgg.cpp b/src/cpp3ds/Audio/SoundFileReaderOgg.cpp new file mode 100644 index 0000000..9aba217 --- /dev/null +++ b/src/cpp3ds/Audio/SoundFileReaderOgg.cpp @@ -0,0 +1,178 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace +{ + size_t read(void* ptr, size_t size, size_t nmemb, void* data) + { + cpp3ds::InputStream* stream = static_cast(data); + return static_cast(stream->read(ptr, size * nmemb)); + } + + int seek(void* data, ogg_int64_t offset, int whence) + { + cpp3ds::InputStream* stream = static_cast(data); + switch (whence) + { + case SEEK_SET: + break; + case SEEK_CUR: + offset += stream->tell(); + break; + case SEEK_END: + offset = stream->getSize() - offset; + } + return static_cast(stream->seek(offset)); + } + + long tell(void* data) + { + cpp3ds::InputStream* stream = static_cast(data); + return static_cast(stream->tell()); + } + + static ov_callbacks callbacks = {&read, &seek, NULL, &tell}; +} + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +bool SoundFileReaderOgg::check(InputStream& stream) +{ + OggVorbis_File file; + if (ov_test_callbacks(&stream, &file, NULL, 0, callbacks) == 0) + { + ov_clear(&file); + return true; + } + else + { + return false; + } +} + + +//////////////////////////////////////////////////////////// +SoundFileReaderOgg::SoundFileReaderOgg() : +m_vorbis (), +m_channelCount(0) +{ + m_vorbis.datasource = NULL; +} + + +//////////////////////////////////////////////////////////// +SoundFileReaderOgg::~SoundFileReaderOgg() +{ + close(); +} + + +//////////////////////////////////////////////////////////// +bool SoundFileReaderOgg::open(InputStream& stream, Info& info) +{ + // Open the Vorbis stream + int status = ov_open_callbacks(&stream, &m_vorbis, NULL, 0, callbacks); + if (status < 0) { + err() << "Failed to open Vorbis file for reading" << std::endl; + return false; + } + + // Retrieve the music attributes + vorbis_info* vorbisInfo = ov_info(&m_vorbis, -1); + info.channelCount = vorbisInfo->channels; + info.sampleRate = vorbisInfo->rate; + info.sampleCount = static_cast(ov_pcm_total(&m_vorbis, -1) * vorbisInfo->channels); + + // We must keep the channel count for the seek function + m_channelCount = info.channelCount; + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundFileReaderOgg::seek(Uint64 sampleOffset) +{ + assert(m_vorbis.datasource); + + ov_pcm_seek(&m_vorbis, sampleOffset / m_channelCount); +} + + +//////////////////////////////////////////////////////////// +Uint64 SoundFileReaderOgg::read(Int16* samples, Uint64 maxCount) +{ + assert(m_vorbis.datasource); + + // Try to read the requested number of samples, stop only on error or end of file + Uint64 count = 0; + while (count < maxCount) + { + int bytesToRead = static_cast(maxCount - count) * sizeof(Int16); + long bytesRead = ov_read(&m_vorbis, reinterpret_cast(samples), bytesToRead, 0, 2, 1, NULL); + if (bytesRead > 0) + { + long samplesRead = bytesRead / sizeof(Int16); + count += samplesRead; + samples += samplesRead; + } + else + { + // error or end of file + break; + } + } + + return count; +} + + +//////////////////////////////////////////////////////////// +void SoundFileReaderOgg::close() +{ + if (m_vorbis.datasource) + { + ov_clear(&m_vorbis); + m_vorbis.datasource = NULL; + m_channelCount = 0; + } +} + +} // namespace priv + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundFileReaderWav.cpp b/src/cpp3ds/Audio/SoundFileReaderWav.cpp new file mode 100644 index 0000000..4c3b70a --- /dev/null +++ b/src/cpp3ds/Audio/SoundFileReaderWav.cpp @@ -0,0 +1,285 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace +{ + // The following functions read integers as little endian and + // return them in the host byte order + + bool decode(cpp3ds::InputStream& stream, cpp3ds::Uint8& value) + { + return stream.read(&value, sizeof(value)) == sizeof(value); + } + + bool decode(cpp3ds::InputStream& stream, cpp3ds::Int16& value) + { + unsigned char bytes[sizeof(value)]; + if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes)) + return false; + + value = bytes[0] | (bytes[1] << 8); + + return true; + } + + bool decode(cpp3ds::InputStream& stream, cpp3ds::Uint16& value) + { + unsigned char bytes[sizeof(value)]; + if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes)) + return false; + + value = bytes[0] | (bytes[1] << 8); + + return true; + } + + bool decode(cpp3ds::InputStream& stream, cpp3ds::Int32& value) + { + unsigned char bytes[sizeof(value)]; + if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes)) + return false; + + value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); + + return true; + } + + bool decode(cpp3ds::InputStream& stream, cpp3ds::Uint32& value) + { + unsigned char bytes[sizeof(value)]; + if (stream.read(bytes, sizeof(bytes)) != sizeof(bytes)) + return false; + + value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); + + return true; + } + + const cpp3ds::Uint64 mainChunkSize = 12; +} + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +bool SoundFileReaderWav::check(InputStream& stream) +{ + char header[mainChunkSize]; + if (stream.read(header, sizeof(header)) < static_cast(sizeof(header))) + return false; + + return (header[0] == 'R') && (header[1] == 'I') && (header[2] == 'F') && (header[3] == 'F') + && (header[8] == 'W') && (header[9] == 'A') && (header[10] == 'V') && (header[11] == 'E'); +} + + +//////////////////////////////////////////////////////////// +SoundFileReaderWav::SoundFileReaderWav() : +m_stream (NULL), +m_bytesPerSample(0), +m_dataStart (0) +{ +} + + +//////////////////////////////////////////////////////////// +bool SoundFileReaderWav::open(InputStream& stream, Info& info) +{ + m_stream = &stream; + + if (!parseHeader(info)) + { + err() << "Failed to open WAV sound file (invalid or unsupported file)" << std::endl; + return false; + } + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundFileReaderWav::seek(Uint64 sampleOffset) +{ + assert(m_stream); + + m_stream->seek(m_dataStart + sampleOffset * m_bytesPerSample); +} + + +//////////////////////////////////////////////////////////// +Uint64 SoundFileReaderWav::read(Int16* samples, Uint64 maxCount) +{ + assert(m_stream); + + Uint64 count = 0; + while (count < maxCount) + { + switch (m_bytesPerSample) + { + case 1: + { + Uint8 sample = 0; + if (decode(*m_stream, sample)) + *samples++ = (static_cast(sample) - 128) << 8; + else + return count; + break; + } + + case 2: + { + Int16 sample = 0; + if (decode(*m_stream, sample)) + *samples++ = sample; + else + return count; + break; + } + + case 4: + { + Int32 sample = 0; + if (decode(*m_stream, sample)) + *samples++ = sample >> 16; + else + return count; + break; + } + } + + ++count; + } + + return count; +} + + +//////////////////////////////////////////////////////////// +bool SoundFileReaderWav::parseHeader(Info& info) +{ + assert(m_stream); + + // If we are here, it means that the first part of the header + // (the format) has already been checked + char mainChunk[mainChunkSize]; + if (m_stream->read(mainChunk, sizeof(mainChunk)) != sizeof(mainChunk)) + return false; + + // Parse all the sub-chunks + bool dataChunkFound = false; + while (!dataChunkFound) + { + // Parse the sub-chunk id and size + char subChunkId[4]; + if (m_stream->read(subChunkId, sizeof(subChunkId)) != sizeof(subChunkId)) + return false; + Uint32 subChunkSize = 0; + if (!decode(*m_stream, subChunkSize)) + return false; + + // Check which chunk it is + if ((subChunkId[0] == 'f') && (subChunkId[1] == 'm') && (subChunkId[2] == 't') && (subChunkId[3] == ' ')) + { + // "fmt" chunk + + // Audio format + Uint16 format = 0; + if (!decode(*m_stream, format)) + return false; + if (format != 1) // PCM + return false; + + // Channel count + Uint16 channelCount = 0; + if (!decode(*m_stream, channelCount)) + return false; + info.channelCount = channelCount; + + // Sample rate + Uint32 sampleRate = 0; + if (!decode(*m_stream, sampleRate)) + return false; + info.sampleRate = sampleRate; + + // Byte rate + Uint32 byteRate = 0; + if (!decode(*m_stream, byteRate)) + return false; + + // Block align + Uint16 blockAlign = 0; + if (!decode(*m_stream, blockAlign)) + return false; + + // Bits per sample + Uint16 bitsPerSample = 0; + if (!decode(*m_stream, bitsPerSample)) + return false; + m_bytesPerSample = bitsPerSample / 8; + + // Skip potential extra information (should not exist for PCM) + if (subChunkSize > 16) + { + if (m_stream->seek(m_stream->tell() + subChunkSize - 16) == -1) + return false; + } + } + else if ((subChunkId[0] == 'd') && (subChunkId[1] == 'a') && (subChunkId[2] == 't') && (subChunkId[3] == 'a')) + { + // "data" chunk + + // Compute the total number of samples + info.sampleCount = subChunkSize / m_bytesPerSample; + + // Store the starting position of samples in the file + m_dataStart = m_stream->tell(); + + dataChunkFound = true; + } + else + { + // unknown chunk, skip it + if (m_stream->seek(m_stream->tell() + subChunkSize) == -1) + return false; + } + } + + return true; +} + +} // namespace priv + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundFileWriterOgg.cpp b/src/cpp3ds/Audio/SoundFileWriterOgg.cpp new file mode 100644 index 0000000..eabc5d8 --- /dev/null +++ b/src/cpp3ds/Audio/SoundFileWriterOgg.cpp @@ -0,0 +1,206 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +bool SoundFileWriterOgg::check(const std::string& filename) +{ + std::string extension = filename.substr(filename.find_last_of(".") + 1); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + + return extension == "ogg"; +} + + +//////////////////////////////////////////////////////////// +SoundFileWriterOgg::SoundFileWriterOgg() : +m_channelCount(0), +m_file (), +m_ogg (), +m_vorbis (), +m_state () +{ +} + + +//////////////////////////////////////////////////////////// +SoundFileWriterOgg::~SoundFileWriterOgg() +{ + close(); +} + + +//////////////////////////////////////////////////////////// +bool SoundFileWriterOgg::open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount) +{ + // Save the channel count + m_channelCount = channelCount; + + // Initialize the ogg/vorbis stream + ogg_stream_init(&m_ogg, std::rand()); + vorbis_info_init(&m_vorbis); + + // Setup the encoder: VBR, automatic bitrate management + // Quality is in range [-1 .. 1], 0.4 gives ~128 kbps for a 44 KHz stereo sound + int status = vorbis_encode_init_vbr(&m_vorbis, channelCount, sampleRate, 0.4f); + if (status < 0) + { + err() << "Failed to write ogg/vorbis file \"" << filename << "\" (unsupported bitrate)" << std::endl; + close(); + return false; + } + vorbis_analysis_init(&m_state, &m_vorbis); + + // Open the file after the vorbis setup is ok + m_file.open(filename.c_str(), std::ios::binary); + if (!m_file) + { + err() << "Failed to write ogg/vorbis file \"" << filename << "\" (cannot open file)" << std::endl; + close(); + return false; + } + + // Generate header metadata (leave it empty) + vorbis_comment comment; + vorbis_comment_init(&comment); + + // Generate the header packets + ogg_packet header, headerComm, headerCode; + status = vorbis_analysis_headerout(&m_state, &comment, &header, &headerComm, &headerCode); + vorbis_comment_clear(&comment); + if (status < 0) + { + err() << "Failed to write ogg/vorbis file \"" << filename << "\" (cannot generate the headers)" << std::endl; + close(); + return false; + } + + // Write the header packets to the ogg stream + ogg_stream_packetin(&m_ogg, &header); + ogg_stream_packetin(&m_ogg, &headerComm); + ogg_stream_packetin(&m_ogg, &headerCode); + + // This ensures the actual audio data will start on a new page, as per spec + ogg_page page; + while (ogg_stream_flush(&m_ogg, &page) > 0) + { + m_file.write(reinterpret_cast(page.header), page.header_len); + m_file.write(reinterpret_cast(page.body), page.body_len); + } + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundFileWriterOgg::write(const Int16* samples, Uint64 count) +{ + // Prepare a buffer to hold our samples + int frameCount = static_cast(count / m_channelCount); + float** buffer = vorbis_analysis_buffer(&m_state, frameCount); + assert(buffer); + + // Write the samples to the buffer, converted to float + for (int i = 0; i < frameCount; ++i) + for (unsigned int j = 0; j < m_channelCount; ++j) + buffer[j][i] = *samples++ / 32767.0f; + + // Tell the library how many samples we've written + vorbis_analysis_wrote(&m_state, frameCount); + + // Flush any produced block + flushBlocks(); +} + + +//////////////////////////////////////////////////////////// +void SoundFileWriterOgg::flushBlocks() +{ + // Let the library divide uncompressed data into blocks, and process them + vorbis_block block; + vorbis_block_init(&m_state, &block); + while (vorbis_analysis_blockout(&m_state, &block) == 1) + { + // Let the automatic bitrate management do its job + vorbis_analysis(&block, NULL); + vorbis_bitrate_addblock(&block); + + // Get new packets from the bitrate management engine + ogg_packet packet; + while (vorbis_bitrate_flushpacket(&m_state, &packet)) + { + // Write the packet to the ogg stream + ogg_stream_packetin(&m_ogg, &packet); + + // If the stream produced new pages, write them to the output file + ogg_page page; + while (ogg_stream_flush(&m_ogg, &page) > 0) + { + m_file.write(reinterpret_cast(page.header), page.header_len); + m_file.write(reinterpret_cast(page.body), page.body_len); + } + } + } + + // Clear the allocated block + vorbis_block_clear(&block); +} + + +//////////////////////////////////////////////////////////// +void SoundFileWriterOgg::close() +{ + if (m_file.is_open()) + { + // Submit an empty packet to mark the end of stream + vorbis_analysis_wrote(&m_state, 0); + flushBlocks(); + + // Close the file + m_file.close(); + } + + // Clear all the ogg/vorbis structures + ogg_stream_clear(&m_ogg); + vorbis_dsp_clear(&m_state); + vorbis_info_clear(&m_vorbis); +} + +} // namespace priv + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundFileWriterWav.cpp b/src/cpp3ds/Audio/SoundFileWriterWav.cpp new file mode 100644 index 0000000..35d6bfe --- /dev/null +++ b/src/cpp3ds/Audio/SoundFileWriterWav.cpp @@ -0,0 +1,207 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace +{ + // The following functions takes integers in host byte order + // and writes them to a stream as little endian + + void encode(std::ostream& stream, cpp3ds::Int16 value) + { + unsigned char bytes[] = + { + static_cast(value & 0xFF), + static_cast(value >> 8) + }; + stream.write(reinterpret_cast(bytes), sizeof(bytes)); + } + + void encode(std::ostream& stream, cpp3ds::Uint16 value) + { + unsigned char bytes[] = + { + static_cast(value & 0xFF), + static_cast(value >> 8) + }; + stream.write(reinterpret_cast(bytes), sizeof(bytes)); + } + + void encode(std::ostream& stream, cpp3ds::Uint32 value) + { + unsigned char bytes[] = + { + static_cast(value & 0x000000FF), + static_cast((value & 0x0000FF00) >> 8), + static_cast((value & 0x00FF0000) >> 16), + static_cast((value & 0xFF000000) >> 24), + }; + stream.write(reinterpret_cast(bytes), sizeof(bytes)); + } +} + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +bool SoundFileWriterWav::check(const std::string& filename) +{ + std::string extension = filename.substr(filename.find_last_of(".") + 1); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + + return extension == "wav"; +} + + +//////////////////////////////////////////////////////////// +SoundFileWriterWav::SoundFileWriterWav() : +m_file (), +m_sampleCount (0), +m_channelCount(0) +{ +} + + +//////////////////////////////////////////////////////////// +SoundFileWriterWav::~SoundFileWriterWav() +{ + close(); +} + + +//////////////////////////////////////////////////////////// +bool SoundFileWriterWav::open(const std::string& filename, unsigned int sampleRate, unsigned int channelCount) +{ + // Open the file + m_file.open(filename.c_str(), std::ios::binary); + if (!m_file) + { + err() << "Failed to open WAV sound file \"" << filename << "\" for writing" << std::endl; + return false; + } + + // Write the header + if (!writeHeader(sampleRate, channelCount)) + { + err() << "Failed to write header of WAV sound file \"" << filename << "\"" << std::endl; + return false; + } + + // Save the channel count + m_channelCount = channelCount; + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundFileWriterWav::write(const Int16* samples, Uint64 count) +{ + assert(m_file.good()); + + m_sampleCount += count; + + while (count--) + encode(m_file, *samples++); +} + + +//////////////////////////////////////////////////////////// +bool SoundFileWriterWav::writeHeader(unsigned int sampleRate, unsigned int channelCount) +{ + assert(m_file.good()); + + // Write the main chunk ID + char mainChunkId[4] = {'R', 'I', 'F', 'F'}; + m_file.write(mainChunkId, sizeof(mainChunkId)); + + // Write the main chunk header + Uint32 mainChunkSize = 0; // placeholder, will be written later + encode(m_file, mainChunkSize); + char mainChunkFormat[4] = {'W', 'A', 'V', 'E'}; + m_file.write(mainChunkFormat, sizeof(mainChunkFormat)); + + // Write the sub-chunk 1 ("format") id and size + char fmtChunkId[4] = {'f', 'm', 't', ' '}; + m_file.write(fmtChunkId, sizeof(fmtChunkId)); + Uint32 fmtChunkSize = 16; + encode(m_file, fmtChunkSize); + + // Write the format (PCM) + Uint16 format = 1; + encode(m_file, format); + + // Write the sound attributes + encode(m_file, static_cast(channelCount)); + encode(m_file, static_cast(sampleRate)); + Uint32 byteRate = sampleRate * channelCount * 2; + encode(m_file, byteRate); + Uint16 blockAlign = channelCount * 2; + encode(m_file, blockAlign); + Uint16 bitsPerSample = 16; + encode(m_file, bitsPerSample); + + // Write the sub-chunk 2 ("data") id and size + char dataChunkId[4] = {'d', 'a', 't', 'a'}; + m_file.write(dataChunkId, sizeof(dataChunkId)); + Uint32 dataChunkSize = 0; // placeholder, will be written later + encode(m_file, dataChunkSize); + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundFileWriterWav::close() +{ + // If the file is open, finalize the header and close it + if (m_file.is_open()) + { + m_file.flush(); + + // Update the main chunk size and data sub-chunk size + Uint32 dataChunkSize = static_cast(m_sampleCount * m_channelCount * 2); + Uint32 mainChunkSize = dataChunkSize + 36; + m_file.seekp(4); + encode(m_file, mainChunkSize); + m_file.seekp(40); + encode(m_file, dataChunkSize); + + m_file.close(); + } +} + +} // namespace priv + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundRecorder.cpp b/src/cpp3ds/Audio/SoundRecorder.cpp new file mode 100644 index 0000000..ce9ff18 --- /dev/null +++ b/src/cpp3ds/Audio/SoundRecorder.cpp @@ -0,0 +1,274 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +//#include +//#include +#include +#include +#include + + +namespace +{ +// ALCdevice* captureDevice = NULL; +} + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +SoundRecorder::SoundRecorder() : +m_thread (&SoundRecorder::record, this), +m_sampleRate (0), +m_processingInterval(milliseconds(100)), +m_isCapturing (false) +{ + // Set the device name to the default device + m_deviceName = getDefaultDevice(); +} + + +//////////////////////////////////////////////////////////// +SoundRecorder::~SoundRecorder() +{ + // Nothing to do +} + + +//////////////////////////////////////////////////////////// +bool SoundRecorder::start(unsigned int sampleRate) +{ + // Check if the device can do audio capture + if (!isAvailable()) + { + err() << "Failed to start capture: your system cannot capture audio data (call SoundRecorder::isAvailable to check it)" << std::endl; + return false; + } + + // Check that another capture is not already running +// if (captureDevice) +// { +// err() << "Trying to start audio capture, but another capture is already running" << std::endl; +// return false; +// } + + // Open the capture device for capturing 16 bits mono samples +// captureDevice = alcCaptureOpenDevice(m_deviceName.c_str(), sampleRate, AL_FORMAT_MONO16, sampleRate); +// if (!captureDevice) +// { +// err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl; +// return false; +// } + + // Clear the array of samples + m_samples.clear(); + + // Store the sample rate + m_sampleRate = sampleRate; + + // Notify derived class + if (onStart()) + { + // Start the capture +// alcCaptureStart(captureDevice); + + // Start the capture in a new thread, to avoid blocking the main thread + m_isCapturing = true; + m_thread.launch(); + + return true; + } + + return false; +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::stop() +{ + // Stop the capturing thread + m_isCapturing = false; + m_thread.wait(); + + // Notify derived class + onStop(); +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundRecorder::getSampleRate() const +{ + return m_sampleRate; +} + + +//////////////////////////////////////////////////////////// +std::vector SoundRecorder::getAvailableDevices() +{ + std::vector deviceNameList; + + return deviceNameList; +} + + +//////////////////////////////////////////////////////////// +std::string SoundRecorder::getDefaultDevice() +{ +// return alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + return ""; +} + + +//////////////////////////////////////////////////////////// +bool SoundRecorder::setDevice(const std::string& name) +{ + // Store the device name + if (name.empty()) + m_deviceName = getDefaultDevice(); + else + m_deviceName = name; + + if (m_isCapturing) + { + // Stop the capturing thread + m_isCapturing = false; + m_thread.wait(); + + // Open the requested capture device for capturing 16 bits mono samples +// captureDevice = alcCaptureOpenDevice(name.c_str(), m_sampleRate, AL_FORMAT_MONO16, m_sampleRate); +// if (!captureDevice) +// { +// // Notify derived class +// onStop(); +// +// err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl; +// return false; +// } + + // Start the capture +// alcCaptureStart(captureDevice); + + // Start the capture in a new thread, to avoid blocking the main thread + m_isCapturing = true; + m_thread.launch(); + } + + return true; +} + + +//////////////////////////////////////////////////////////// +const std::string& SoundRecorder::getDevice() const +{ + return m_deviceName; +} + + +//////////////////////////////////////////////////////////// +bool SoundRecorder::isAvailable() +{ + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::setProcessingInterval(cpp3ds::Time interval) +{ + m_processingInterval = interval; +} + + +//////////////////////////////////////////////////////////// +bool SoundRecorder::onStart() +{ + // Nothing to do + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::onStop() +{ + // Nothing to do +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::record() +{ + while (m_isCapturing) + { + // Process available samples + processCapturedSamples(); + + // Don't bother the CPU while waiting for more captured data + sleep(m_processingInterval); + } + + // Capture is finished: clean up everything + cleanup(); +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::processCapturedSamples() +{ + // Get the number of samples available +// ALCint samplesAvailable; +// alcGetIntegerv(captureDevice, ALC_CAPTURE_SAMPLES, 1, &samplesAvailable); + +// if (samplesAvailable > 0) +// { +// // Get the recorded samples +// m_samples.resize(samplesAvailable); +// alcCaptureSamples(captureDevice, &m_samples[0], samplesAvailable); +// +// // Forward them to the derived class +// if (!onProcessSamples(&m_samples[0], m_samples.size())) +// { +// // The user wants to stop the capture +// m_isCapturing = false; +// } +// } +} + + +//////////////////////////////////////////////////////////// +void SoundRecorder::cleanup() +{ + // Stop the capture +// alcCaptureStop(captureDevice); + + // Get the samples left in the buffer + processCapturedSamples(); + + // Close the device +// alcCaptureCloseDevice(captureDevice); +// captureDevice = NULL; +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundSource.cpp b/src/cpp3ds/Audio/SoundSource.cpp new file mode 100644 index 0000000..4026ac9 --- /dev/null +++ b/src/cpp3ds/Audio/SoundSource.cpp @@ -0,0 +1,157 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +SoundSource::SoundSource() +{ + +} + + +//////////////////////////////////////////////////////////// +SoundSource::SoundSource(const SoundSource& copy) +{ + setPitch(copy.getPitch()); + setVolume(copy.getVolume()); + setPosition(copy.getPosition()); + setRelativeToListener(copy.isRelativeToListener()); + setMinDistance(copy.getMinDistance()); + setAttenuation(copy.getAttenuation()); +} + + +//////////////////////////////////////////////////////////// +SoundSource::~SoundSource() +{ + +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setPitch(float pitch) +{ + +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setVolume(float volume) +{ + +} + +//////////////////////////////////////////////////////////// +void SoundSource::setPosition(float x, float y, float z) +{ + +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setPosition(const Vector3f& position) +{ + setPosition(position.x, position.y, position.z); +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setRelativeToListener(bool relative) +{ + +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setMinDistance(float distance) +{ + +} + + +//////////////////////////////////////////////////////////// +void SoundSource::setAttenuation(float attenuation) +{ + +} + + +//////////////////////////////////////////////////////////// +float SoundSource::getPitch() const +{ + return 0; +} + + +//////////////////////////////////////////////////////////// +float SoundSource::getVolume() const +{ + return 100; +} + + +//////////////////////////////////////////////////////////// +Vector3f SoundSource::getPosition() const +{ + Vector3f position; + + return position; +} + + +//////////////////////////////////////////////////////////// +bool SoundSource::isRelativeToListener() const +{ + return true; +} + + +//////////////////////////////////////////////////////////// +float SoundSource::getMinDistance() const +{ + return 0; +} + + +//////////////////////////////////////////////////////////// +float SoundSource::getAttenuation() const +{ + return 0; +} + + +//////////////////////////////////////////////////////////// +SoundSource::Status SoundSource::getStatus() const +{ + return Stopped; +} + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundStream.cpp b/src/cpp3ds/Audio/SoundStream.cpp new file mode 100644 index 0000000..078e9a0 --- /dev/null +++ b/src/cpp3ds/Audio/SoundStream.cpp @@ -0,0 +1,477 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +//#include +//#include +#include +#include +#include + +#ifdef _MSC_VER + #pragma warning(disable: 4355) // 'this' used in base member initializer list +#endif + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +SoundStream::SoundStream() : +m_thread (&SoundStream::streamData, this), +m_threadMutex (), +m_threadStartState(Stopped), +m_isStreaming (false), +m_channelCount (0), +m_sampleRate (0), +m_format (0), +m_loop (false), +m_samplesProcessed(0) +{ + +} + + +//////////////////////////////////////////////////////////// +SoundStream::~SoundStream() +{ + // Stop the sound if it was playing + + // Request the thread to terminate + { + Lock lock(m_threadMutex); + m_isStreaming = false; + } + + // Wait for the thread to terminate + m_thread.wait(); +} + + +//////////////////////////////////////////////////////////// +void SoundStream::initialize(unsigned int channelCount, unsigned int sampleRate) +{ + m_channelCount = channelCount; + m_sampleRate = sampleRate; + + // Deduce the format from the number of channels +// m_format = priv::AudioDevice::getFormatFromChannelCount(channelCount); + + // Check if the format is valid + if (m_format == 0) + { + m_channelCount = 0; + m_sampleRate = 0; + err() << "Unsupported number of channels (" << m_channelCount << ")" << std::endl; + } +} + + +//////////////////////////////////////////////////////////// +void SoundStream::play() +{ + // Check if the sound parameters have been set + if (m_format == 0) + { + err() << "Failed to play audio stream: sound parameters have not been initialized (call initialize() first)" << std::endl; + return; + } + + bool isStreaming = false; + Status threadStartState = Stopped; + + { + Lock lock(m_threadMutex); + + isStreaming = m_isStreaming; + threadStartState = m_threadStartState; + } + + + if (isStreaming && (threadStartState == Paused)) + { + // If the sound is paused, resume it + Lock lock(m_threadMutex); + m_threadStartState = Playing; +// alCheck(alSourcePlay(m_source)); + return; + } + else if (isStreaming && (threadStartState == Playing)) + { + // If the sound is playing, stop it and continue as if it was stopped + stop(); + } + + // Move to the beginning + onSeek(Time::Zero); + + // Start updating the stream in a separate thread to avoid blocking the application + m_samplesProcessed = 0; + m_isStreaming = true; + m_threadStartState = Playing; + m_thread.launch(); +} + + +//////////////////////////////////////////////////////////// +void SoundStream::pause() +{ + // Handle pause() being called before the thread has started + { + Lock lock(m_threadMutex); + + if (!m_isStreaming) + return; + + m_threadStartState = Paused; + } + +// alCheck(alSourcePause(m_source)); +} + + +//////////////////////////////////////////////////////////// +void SoundStream::stop() +{ + // Request the thread to terminate + { + Lock lock(m_threadMutex); + m_isStreaming = false; + } + + // Wait for the thread to terminate + m_thread.wait(); + + // Move to the beginning + onSeek(Time::Zero); + + // Reset the playing position + m_samplesProcessed = 0; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundStream::getChannelCount() const +{ + return m_channelCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundStream::getSampleRate() const +{ + return m_sampleRate; +} + + +//////////////////////////////////////////////////////////// +SoundStream::Status SoundStream::getStatus() const +{ + Status status = SoundSource::getStatus(); + + // To compensate for the lag between play() and alSourceplay() + if (status == Stopped) + { + Lock lock(m_threadMutex); + + if (m_isStreaming) + status = m_threadStartState; + } + + return status; +} + + +//////////////////////////////////////////////////////////// +void SoundStream::setPlayingOffset(Time timeOffset) +{ + // Get old playing status + Status oldStatus = getStatus(); + + // Stop the stream + stop(); + + // Let the derived class update the current position + onSeek(timeOffset); + + // Restart streaming + m_samplesProcessed = static_cast(timeOffset.asSeconds() * m_sampleRate * m_channelCount); + + if (oldStatus == Stopped) + return; + + m_isStreaming = true; + m_threadStartState = oldStatus; + m_thread.launch(); +} + + +//////////////////////////////////////////////////////////// +Time SoundStream::getPlayingOffset() const +{ + if (m_sampleRate && m_channelCount) + { + float secs = 0.f; +// ALfloat secs = 0.f; +// alCheck(alGetSourcef(m_source, AL_SEC_OFFSET, &secs)); + + return seconds(secs + static_cast(m_samplesProcessed) / m_sampleRate / m_channelCount); + } + else + { + return Time::Zero; + } +} + + +//////////////////////////////////////////////////////////// +void SoundStream::setLoop(bool loop) +{ + m_loop = loop; +} + + +//////////////////////////////////////////////////////////// +bool SoundStream::getLoop() const +{ + return m_loop; +} + + +//////////////////////////////////////////////////////////// +void SoundStream::streamData() +{ + bool requestStop = false; + + { + Lock lock(m_threadMutex); + + // Check if the thread was launched Stopped + if (m_threadStartState == Stopped) + { + m_isStreaming = false; + return; + } + } + + // Create the buffers +// alCheck(alGenBuffers(BufferCount, m_buffers)); + for (int i = 0; i < BufferCount; ++i) + m_endBuffers[i] = false; + + // Fill the queue + requestStop = fillQueue(); + + // Play the sound +// alCheck(alSourcePlay(m_source)); + + { + Lock lock(m_threadMutex); + + // Check if the thread was launched Paused +// if (m_threadStartState == Paused) +// alCheck(alSourcePause(m_source)); + } + + for (;;) + { + { + Lock lock(m_threadMutex); + if (!m_isStreaming) + break; + } + + // The stream has been interrupted! + if (SoundSource::getStatus() == Stopped) + { + if (!requestStop) + { + // Just continue +// alCheck(alSourcePlay(m_source)); + } + else + { + // End streaming + Lock lock(m_threadMutex); + m_isStreaming = false; + } + } + + // Get the number of buffers that have been processed (i.e. ready for reuse) + int nbProcessed = 0; +// ALint nbProcessed = 0; +// alCheck(alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &nbProcessed)); + + while (nbProcessed--) + { + // Pop the first unused buffer from the queue + int buffer; +// ALuint buffer; +// alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer)); + + // Find its number + unsigned int bufferNum = 0; + for (int i = 0; i < BufferCount; ++i) + if (m_buffers[i] == buffer) + { + bufferNum = i; + break; + } + + // Retrieve its size and add it to the samples count + if (m_endBuffers[bufferNum]) + { + // This was the last buffer: reset the sample count + m_samplesProcessed = 0; + m_endBuffers[bufferNum] = false; + } + else + { + int size, bits; +// ALint size, bits; +// alCheck(alGetBufferi(buffer, AL_SIZE, &size)); +// alCheck(alGetBufferi(buffer, AL_BITS, &bits)); + + // Bits can be 0 if the format or parameters are corrupt, avoid division by zero + if (bits == 0) + { + err() << "Bits in sound stream are 0: make sure that the audio format is not corrupt " + << "and initialize() has been called correctly" << std::endl; + + // Abort streaming (exit main loop) + Lock lock(m_threadMutex); + m_isStreaming = false; + requestStop = true; + break; + } + else + { + m_samplesProcessed += size / (bits / 8); + } + } + + // Fill it and push it back into the playing queue + if (!requestStop) + { + if (fillAndPushBuffer(bufferNum)) + requestStop = true; + } + } + + // Leave some time for the other threads if the stream is still playing + if (SoundSource::getStatus() != Stopped) + sleep(milliseconds(10)); + } + + // Stop the playback +// alCheck(alSourceStop(m_source)); + + // Dequeue any buffer left in the queue + clearQueue(); + + // Delete the buffers +// alCheck(alSourcei(m_source, AL_BUFFER, 0)); +// alCheck(alDeleteBuffers(BufferCount, m_buffers)); +} + + +//////////////////////////////////////////////////////////// +bool SoundStream::fillAndPushBuffer(unsigned int bufferNum) +{ + bool requestStop = false; + + // Acquire audio data + Chunk data = {NULL, 0}; + if (!onGetData(data)) + { + // Mark the buffer as the last one (so that we know when to reset the playing position) + m_endBuffers[bufferNum] = true; + + // Check if the stream must loop or stop + if (m_loop) + { + // Return to the beginning of the stream source + onSeek(Time::Zero); + + // If we previously had no data, try to fill the buffer once again + if (!data.samples || (data.sampleCount == 0)) + { + return fillAndPushBuffer(bufferNum); + } + } + else + { + // Not looping: request stop + requestStop = true; + } + } + + // Fill the buffer if some data was returned + if (data.samples && data.sampleCount) + { + unsigned int buffer = m_buffers[bufferNum]; + + // Fill the buffer +// ALsizei size = static_cast(data.sampleCount) * sizeof(Int16); +// alCheck(alBufferData(buffer, m_format, data.samples, size, m_sampleRate)); + + // Push it into the sound queue +// alCheck(alSourceQueueBuffers(m_source, 1, &buffer)); + } + + return requestStop; +} + + +//////////////////////////////////////////////////////////// +bool SoundStream::fillQueue() +{ + // Fill and enqueue all the available buffers + bool requestStop = false; + for (int i = 0; (i < BufferCount) && !requestStop; ++i) + { + if (fillAndPushBuffer(i)) + requestStop = true; + } + + return requestStop; +} + + +//////////////////////////////////////////////////////////// +void SoundStream::clearQueue() +{ + // Get the number of buffers still in the queue +// ALint nbQueued; +// alCheck(alGetSourcei(m_source, AL_BUFFERS_QUEUED, &nbQueued)); + + // Dequeue them all +// ALuint buffer; +// for (ALint i = 0; i < nbQueued; ++i) +// alCheck(alSourceUnqueueBuffers(m_source, 1, &buffer)); +} + +} // namespace cpp3ds diff --git a/src/emu3ds/Audio/InputSoundFile.cpp b/src/emu3ds/Audio/InputSoundFile.cpp new file mode 100644 index 0000000..abf9043 --- /dev/null +++ b/src/emu3ds/Audio/InputSoundFile.cpp @@ -0,0 +1,138 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +InputSoundFile::InputSoundFile() : +m_reader (NULL), +m_stream (NULL), +m_streamOwned (false), +m_sampleCount (0), +m_channelCount(0), +m_sampleRate (0) +{ +} + + +//////////////////////////////////////////////////////////// +InputSoundFile::~InputSoundFile() +{ +} + + +//////////////////////////////////////////////////////////// +bool InputSoundFile::openFromFile(const std::string& filename) +{ + return m_inputSoundFile.openFromFile(filename); +} + + +//////////////////////////////////////////////////////////// +bool InputSoundFile::openFromMemory(const void* data, std::size_t sizeInBytes) +{ + return m_inputSoundFile.openFromMemory(data, sizeInBytes); +} + + +//////////////////////////////////////////////////////////// +bool InputSoundFile::openFromStream(InputStream& stream) +{ + // TODO: don't cast here + return m_inputSoundFile.openFromStream(reinterpret_cast(stream)); +} + + +//////////////////////////////////////////////////////////// +Uint64 InputSoundFile::getSampleCount() const +{ + return m_sampleCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int InputSoundFile::getChannelCount() const +{ + return m_channelCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int InputSoundFile::getSampleRate() const +{ + return m_sampleRate; +} + + +//////////////////////////////////////////////////////////// +Time InputSoundFile::getDuration() const +{ + return seconds(m_inputSoundFile.getDuration().asSeconds()); +} + + +//////////////////////////////////////////////////////////// +void InputSoundFile::seek(Uint64 sampleOffset) +{ + if (m_reader) + m_reader->seek(sampleOffset); +} + + +//////////////////////////////////////////////////////////// +void InputSoundFile::seek(Time timeOffset) +{ + seek(static_cast(timeOffset.asSeconds() * m_sampleRate * m_channelCount)); +} + + +//////////////////////////////////////////////////////////// +Uint64 InputSoundFile::read(Int16* samples, Uint64 maxCount) +{ + if (m_reader && samples && maxCount) + return m_reader->read(samples, maxCount); + else + return 0; +} + + +//////////////////////////////////////////////////////////// +void InputSoundFile::close() +{ +} + + +} // namespace cpp3ds diff --git a/src/emu3ds/Audio/Sound.cpp b/src/emu3ds/Audio/Sound.cpp new file mode 100644 index 0000000..70a1e5f --- /dev/null +++ b/src/emu3ds/Audio/Sound.cpp @@ -0,0 +1,154 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +Sound::Sound() : + m_buffer(NULL), + m_sound() +{ +} + + +//////////////////////////////////////////////////////////// +Sound::Sound(const SoundBuffer& buffer) : + m_buffer(NULL), + m_sound() +{ + setBuffer(buffer); +} + + +//////////////////////////////////////////////////////////// +Sound::Sound(const Sound& copy) : + SoundSource(copy), + m_buffer (NULL), + m_sound(copy.m_sound) +{ + if (copy.m_buffer) + setBuffer(*copy.m_buffer); + setLoop(copy.getLoop()); +} + + +//////////////////////////////////////////////////////////// +Sound::~Sound() +{ + +} + + +//////////////////////////////////////////////////////////// +void Sound::play() +{ + m_sound.play(); +} + + +//////////////////////////////////////////////////////////// +void Sound::pause() +{ + m_sound.pause(); +} + + +//////////////////////////////////////////////////////////// +void Sound::stop() +{ + m_sound.stop(); +} + + +//////////////////////////////////////////////////////////// +void Sound::setBuffer(const SoundBuffer& buffer) +{ + m_sound.setBuffer(buffer.m_soundBuffer); +} + + +//////////////////////////////////////////////////////////// +void Sound::setLoop(bool loop) +{ + m_sound.setLoop(loop); +} + + +//////////////////////////////////////////////////////////// +void Sound::setPlayingOffset(Time timeOffset) +{ + m_sound.setPlayingOffset(sf::seconds(timeOffset.asSeconds())); +} + + +//////////////////////////////////////////////////////////// +const SoundBuffer* Sound::getBuffer() const +{ + return m_buffer; +} + + +//////////////////////////////////////////////////////////// +bool Sound::getLoop() const +{ + return m_sound.getLoop(); +} + + +//////////////////////////////////////////////////////////// +Time Sound::getPlayingOffset() const +{ + return seconds(m_sound.getPlayingOffset().asSeconds()); +} + + +//////////////////////////////////////////////////////////// +Sound::Status Sound::getStatus() const +{ + return static_cast(m_sound.getStatus()); +} + + +//////////////////////////////////////////////////////////// +Sound& Sound::operator =(const Sound& right) +{ + m_sound = right.m_sound; + + return *this; +} + + +//////////////////////////////////////////////////////////// +void Sound::resetBuffer() +{ + m_sound.resetBuffer(); +} + +} // namespace cpp3ds diff --git a/src/emu3ds/Audio/SoundBuffer.cpp b/src/emu3ds/Audio/SoundBuffer.cpp new file mode 100644 index 0000000..299e227 --- /dev/null +++ b/src/emu3ds/Audio/SoundBuffer.cpp @@ -0,0 +1,196 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include +#include + + +namespace cpp3ds +{ +//////////////////////////////////////////////////////////// +SoundBuffer::SoundBuffer() : +m_buffer (0), +m_duration() +{ +} + + +//////////////////////////////////////////////////////////// +SoundBuffer::SoundBuffer(const SoundBuffer& copy) : +m_buffer (0), +m_samples (copy.m_samples), +m_duration(copy.m_duration), +m_sounds () // don't copy the attached sounds +{ +} + + +//////////////////////////////////////////////////////////// +SoundBuffer::~SoundBuffer() +{ +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromFile(const std::string& filename) +{ + return m_soundBuffer.loadFromFile(filename); +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromResource(const std::string& filename) +{ + return loadFromMemory(priv::resources[filename].data, priv::resources[filename].size); +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromMemory(const void* data, std::size_t sizeInBytes) +{ + return m_soundBuffer.loadFromMemory(data, sizeInBytes); +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromStream(InputStream& stream) +{ + // TODO: casting could break things + return m_soundBuffer.loadFromStream(reinterpret_cast(stream)); +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::loadFromSamples(const Int16* samples, Uint64 sampleCount, unsigned int channelCount, unsigned int sampleRate) +{ + return m_soundBuffer.loadFromSamples(samples, sampleCount, channelCount, sampleRate); +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::saveToFile(const std::string& filename) const +{ + // Create the sound file in write mode + OutputSoundFile file; + if (file.openFromFile(filename, getSampleRate(), getChannelCount())) + { + // Write the samples to the opened file + file.write(&m_samples[0], m_samples.size()); + + return true; + } + else + { + return false; + } +} + + +//////////////////////////////////////////////////////////// +const Int16* SoundBuffer::getSamples() const +{ + return m_soundBuffer.getSamples(); +} + + +//////////////////////////////////////////////////////////// +Uint64 SoundBuffer::getSampleCount() const +{ + return m_soundBuffer.getSampleCount(); +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundBuffer::getSampleRate() const +{ + return m_soundBuffer.getSampleRate(); +} + + +//////////////////////////////////////////////////////////// +unsigned int SoundBuffer::getChannelCount() const +{ + return m_soundBuffer.getChannelCount(); +} + + +//////////////////////////////////////////////////////////// +Time SoundBuffer::getDuration() const +{ + return seconds(m_soundBuffer.getDuration().asSeconds()); +} + + +//////////////////////////////////////////////////////////// +SoundBuffer& SoundBuffer::operator =(const SoundBuffer& right) +{ + SoundBuffer temp(right); + + std::swap(m_samples, temp.m_samples); + std::swap(m_buffer, temp.m_buffer); + std::swap(m_duration, temp.m_duration); + std::swap(m_sounds, temp.m_sounds); // swap sounds too, so that they are detached when temp is destroyed + + return *this; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::initialize(InputSoundFile& file) +{ + return true; +} + + +//////////////////////////////////////////////////////////// +bool SoundBuffer::update(unsigned int channelCount, unsigned int sampleRate) +{ + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundBuffer::attachSound(Sound* sound) const +{ +} + + +//////////////////////////////////////////////////////////// +void SoundBuffer::detachSound(Sound* sound) const +{ +} + +} // namespace cpp3ds