Implement mixer music

This commit is contained in:
Dmitry Marakasov 2015-08-31 18:38:29 +03:00
parent 8155dc8158
commit f3511a1a71
10 changed files with 544 additions and 3 deletions

View File

@ -111,6 +111,7 @@ SET(LIBRARY_SOURCES
SDL2pp/Chunk.cc
SDL2pp/Exception.cc
SDL2pp/Mixer.cc
SDL2pp/Music.cc
SDL2pp/Point.cc
SDL2pp/RWops.cc
SDL2pp/Rect.cc
@ -132,6 +133,7 @@ SET(LIBRARY_HEADERS
SDL2pp/ContainerRWops.hh
SDL2pp/Exception.hh
SDL2pp/Mixer.hh
SDL2pp/Music.hh
SDL2pp/Optional.hh
SDL2pp/Point.hh
SDL2pp/RWops.hh

View File

@ -21,6 +21,7 @@
#include <SDL2pp/Mixer.hh>
#include <SDL2pp/Chunk.hh>
#include <SDL2pp/Music.hh>
#include <SDL2pp/Exception.hh>
namespace SDL2pp {
@ -35,7 +36,7 @@ Mixer::~Mixer() {
Mix_CloseAudio();
}
Mixer::Mixer(Mixer&& other) noexcept : open_(other.open_) {
Mixer::Mixer(Mixer&& other) noexcept : open_(other.open_), current_music_hook_(std::move(other.current_music_hook_)) {
other.open_ = false;
}
@ -45,6 +46,7 @@ Mixer& Mixer::operator=(Mixer&& other) noexcept {
if (open_)
Mix_CloseAudio();
open_ = other.open_;
current_music_hook_ = std::move(other.current_music_hook_);
other.open_ = false;
return *this;
}
@ -129,4 +131,77 @@ Mix_Fading Mixer::GetChannelFading(int which) const {
return Mix_FadingChannel(which);
}
void Mixer::PlayMusic(const Music& music, int loops) {
if (Mix_PlayMusic(music.Get(), loops) == -1)
throw Exception("Mix_PlayMusic");
}
void Mixer::FadeInMusic(const Music& music, int loops, int ms) {
if (Mix_FadeInMusic(music.Get(), loops, ms) == -1)
throw Exception("Mix_FadeInMusic");
}
int Mixer::SetMusicVolume(int volume) {
return Mix_VolumeMusic(volume);
}
int Mixer::GetMusicVolume() const {
return Mix_VolumeMusic(-1);
}
void Mixer::PauseMusic() {
Mix_PauseMusic();
}
void Mixer::ResumeMusic() {
Mix_ResumeMusic();
}
void Mixer::RewindMusic() {
Mix_RewindMusic();
}
void Mixer::SetMusicPosition(double position) {
if (Mix_SetMusicPosition(position) == -1)
throw Exception("Mix_SetMusicPosition");
}
void Mixer::HaltMusic() {
Mix_HaltMusic();
}
bool Mixer::FadeOutMusic(int ms) {
return Mix_FadeOutMusic(ms);
}
bool Mixer::IsMusicPlaying() const {
return Mix_PlayingMusic();
}
bool Mixer::IsMusicPaused() const {
return Mix_PausedMusic();
}
Mix_Fading Mixer::GetMusicFading() const {
return Mix_FadingMusic();
}
void Mixer::SetMusicFinishedHandler(MusicFinishedHandler music_finished) {
Mix_HookMusicFinished(music_finished);
}
void Mixer::SetMusicHook(MusicHook&& hook) {
if (!hook) {
Mix_HookMusic(nullptr, nullptr);
current_music_hook_.reset(nullptr);
return;
}
current_music_hook_.reset(new MusicHook(std::move(hook)));
Mix_HookMusic([](void *udata, Uint8 *stream, int len) {
static_cast<std::function<void(Uint8 *stream, int len)>*>(udata)->operator()(stream, len);
}, current_music_hook_.get());
}
}

View File

@ -22,11 +22,16 @@
#ifndef SDL2PP_MIXER_HH
#define SDL2PP_MIXER_HH
#include <functional>
#include <SDL2/SDL_stdinc.h>
#include <SDL2/SDL_mixer.h>
namespace SDL2pp {
class Chunk;
class Music;
////////////////////////////////////////////////////////////
/// \brief SDL_mixer's audio mixer
@ -43,9 +48,13 @@ class Chunk;
class Mixer {
public:
typedef void (*ChannelFinishedHandler)(int); ///< Function type for channel finished callback
typedef void (*MusicFinishedHandler)(); ///< Function type for music finished callback
typedef std::function<void(Uint8 *stream, int len)> MusicHook; ///< Custom music hook
private:
bool open_;
std::unique_ptr<MusicHook> current_music_hook_;
public:
////////////////////////////////////////////////////////////
@ -363,7 +372,165 @@ public:
Mix_Fading GetChannelFading(int which) const;
// TODO: Groups
// TODO: Music
////////////////////////////////////////////////////////////
/// \brief Play music
///
/// \param[in] music Music to play
/// \param[in] loops number of times to play through the music.
/// 0 plays the music zero times...
/// -1 plays the music forever
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC57
///
////////////////////////////////////////////////////////////
void PlayMusic(const Music& music, int loops = -1);
////////////////////////////////////////////////////////////
/// \brief Play music, with looping, and fade in
///
/// \param[in] music Music to play
/// \param[in] loops number of times to play through the music.
/// 0 plays the music zero times...
/// -1 plays the music forever
/// \param[in] ms Milliseconds for the fade-in effect to complete
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC57
///
////////////////////////////////////////////////////////////
void FadeInMusic(const Music& music, int loops = -1, int ms = 0);
////////////////////////////////////////////////////////////
/// \brief Set music volume
///
/// \param[in] volume The volume to use from 0 to MIX_MAX_VOLUME(128)
///
/// \returns The previous volume setting
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC61
///
////////////////////////////////////////////////////////////
int SetMusicVolume(int volume);
////////////////////////////////////////////////////////////
/// \brief Get music volume
///
/// \returns Current volume setting
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC61
///
////////////////////////////////////////////////////////////
int GetMusicVolume() const;
////////////////////////////////////////////////////////////
/// \brief Pause music
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC62
///
////////////////////////////////////////////////////////////
void PauseMusic();
////////////////////////////////////////////////////////////
/// \brief Resume paused music
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC63
///
////////////////////////////////////////////////////////////
void ResumeMusic();
////////////////////////////////////////////////////////////
/// \brief Rewind music to beginning
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC64
///
////////////////////////////////////////////////////////////
void RewindMusic();
////////////////////////////////////////////////////////////
/// \brief Set position of playback in stream
///
/// \param[in] position Posistion to play from
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC65
///
////////////////////////////////////////////////////////////
void SetMusicPosition(double position);
////////////////////////////////////////////////////////////
/// \brief Stop music playback
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC67
///
////////////////////////////////////////////////////////////
void HaltMusic();
////////////////////////////////////////////////////////////
/// \brief Stop music, with fade out
///
/// \param[in] ms Milliseconds of time that the fade-out effect
/// should take to go to silence, starting now.
///
/// \returns True in success, false on failure
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC68
///
////////////////////////////////////////////////////////////
bool FadeOutMusic(int ms);
////////////////////////////////////////////////////////////
/// \brief Test whether music is playing
///
/// \returns True if music is actively playing
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC71
///
////////////////////////////////////////////////////////////
bool IsMusicPlaying() const;
////////////////////////////////////////////////////////////
/// \brief Test whether music is paused
///
/// \returns True if music is paused
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC72
///
////////////////////////////////////////////////////////////
bool IsMusicPaused() const;
////////////////////////////////////////////////////////////
/// \brief Get status of current music fade activity
///
/// \returns The fading status
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC73
///
////////////////////////////////////////////////////////////
Mix_Fading GetMusicFading() const;
////////////////////////////////////////////////////////////
/// \brief Set a callback for when music stops
///
/// \param[in] music_finished Function to call when music stops
///
/// \note Since Mix_HookMusicFinished doesn't take any custom data
/// pointer, unfortunately there's no safe way of using
/// std::function here.
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC69
///
////////////////////////////////////////////////////////////
void SetMusicFinishedHandler(MusicFinishedHandler music_finished);
////////////////////////////////////////////////////////////
/// \brief Hook for a custom music player
///
/// \param[in] hook Music player mixer function
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC60
///
////////////////////////////////////////////////////////////
void SetMusicHook(MusicHook&& hook);
// TODO: Effects
};

62
SDL2pp/Music.cc Normal file
View File

@ -0,0 +1,62 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2015 Dmitry Marakasov <amdmi3@amdmi3.ru>
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.
*/
#include <SDL2pp/Music.hh>
#include <SDL2pp/Exception.hh>
namespace SDL2pp {
Music::Music(Mix_Music* music) : music_(music) {
}
Music::Music(const std::string& file) {
if ((music_ = Mix_LoadMUS(file.c_str())) == nullptr)
throw Exception("Mix_LoadMUS");
}
Music::~Music() {
if (music_ != nullptr)
Mix_FreeMusic(music_);
}
Music::Music(Music&& other) noexcept : music_(other.music_) {
other.music_ = nullptr;
}
Music& Music::operator=(Music&& other) noexcept {
if (&other == this)
return *this;
if (music_ != nullptr)
Mix_FreeMusic(music_);
music_ = other.music_;
other.music_ = nullptr;
return *this;
}
Mix_Music* Music::Get() const {
return music_;
}
Mix_MusicType Music::GetType() const {
return Mix_GetMusicType(music_);
}
}

125
SDL2pp/Music.hh Normal file
View File

@ -0,0 +1,125 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2015 Dmitry Marakasov <amdmi3@amdmi3.ru>
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 SDL2PP_MUSIC_HH
#define SDL2PP_MUSIC_HH
#include <string>
#include <SDL2/SDL_mixer.h>
namespace SDL2pp {
////////////////////////////////////////////////////////////
/// \brief SDL_mixer music data
///
/// \ingroup mixer
///
/// \headerfile SDL2pp/Music.hh
///
////////////////////////////////////////////////////////////
class Music {
private:
Mix_Music* music_; ///< Managed Mix_Music object
public:
////////////////////////////////////////////////////////////
/// \brief Construct from existing Mix_Music pointer
///
/// \param[in] chunk Existing Mix_Music to manage
///
////////////////////////////////////////////////////////////
Music(Mix_Music* music);
////////////////////////////////////////////////////////////
/// \brief Load music file
///
/// \param[in] file Name of music file to use
///
/// \throws SDL2pp::Exception
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC55
///
////////////////////////////////////////////////////////////
Music(const std::string& file);
////////////////////////////////////////////////////////////
/// \brief Destructor
///
/// \see https://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer.html#SEC56
///
////////////////////////////////////////////////////////////
~Music();
////////////////////////////////////////////////////////////
/// \brief Move constructor
///
/// \param[in] other SDL2pp::Music object to move data from
///
////////////////////////////////////////////////////////////
Music(Music&& other) noexcept;
////////////////////////////////////////////////////////////
/// \brief Move assignment operator
///
/// \param[in] other SDL2pp::Music object to move data from
///
/// \returns Reference to self
///
////////////////////////////////////////////////////////////
Music& operator=(Music&& other) noexcept;
////////////////////////////////////////////////////////////
/// \brief Deleted copy constructor
///
/// This class is not copyable
///
////////////////////////////////////////////////////////////
Music(const Music& other) = delete;
////////////////////////////////////////////////////////////
/// \brief Deleted assignment operator
///
/// This class is not copyable
///
////////////////////////////////////////////////////////////
Music& operator=(const Music& other) = delete;
////////////////////////////////////////////////////////////
/// \brief Get pointer to managed Mix_Music object
///
/// \returns Pointer to managed Mix_Music object
///
////////////////////////////////////////////////////////////
Mix_Music* Get() const;
////////////////////////////////////////////////////////////
/// \brief Get the music encoding type
///
/// \returns The type of music
///
////////////////////////////////////////////////////////////
Mix_MusicType GetType() const;
};
}
#endif

View File

@ -125,6 +125,7 @@
#ifdef SDL2PP_WITH_MIXER
# include <SDL2pp/Chunk.hh>
# include <SDL2pp/Mixer.hh>
# include <SDL2pp/Music.hh>
# include <SDL2pp/SDLMixer.hh>
#endif

View File

@ -31,4 +31,10 @@ ENDIF(SDL2PP_WITH_TTF)
IF(SDL2PP_WITH_MIXER)
ADD_EXECUTABLE(mixer mixer.cc)
TARGET_LINK_LIBRARIES(mixer SDL2pp)
ADD_EXECUTABLE(mixer_music mixer_music.cc)
TARGET_LINK_LIBRARIES(mixer_music SDL2pp)
ADD_EXECUTABLE(mixer_music_sine mixer_music_sine.cc)
TARGET_LINK_LIBRARIES(mixer_music_sine SDL2pp)
ENDIF(SDL2PP_WITH_MIXER)

View File

@ -38,7 +38,7 @@ int main() try {
Chunk sound(TESTDATA_DIR "/test.ogg");
mixer.ChannelFinished([](int channel){
mixer.SetChannelFinishedHandler([](int channel){
std::cerr << "Channel " << channel << " finished playback" << std::endl;
});

49
examples/mixer_music.cc Normal file
View File

@ -0,0 +1,49 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2015 Dmitry Marakasov <amdmi3@amdmi3.ru>
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.
*/
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <SDL2pp/SDL.hh>
#include <SDL2pp/SDLMixer.hh>
#include <SDL2pp/Mixer.hh>
#include <SDL2pp/Music.hh>
using namespace SDL2pp;
int main() try {
SDL sdl(SDL_INIT_AUDIO);
SDLMixer mixerlib(MIX_INIT_OGG);
Mixer mixer(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 4096);
Music music(TESTDATA_DIR "/test.ogg");
mixer.FadeInMusic(music, -1, 2000);
SDL_Delay(5000);
return 0;
} catch (std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}

View File

@ -0,0 +1,54 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2013-2015 Dmitry Marakasov <amdmi3@amdmi3.ru>
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.
*/
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2pp/SDL.hh>
#include <SDL2pp/Mixer.hh>
using namespace SDL2pp;
int main() try {
SDL sdl(SDL_INIT_AUDIO);
Mixer mixer(MIX_DEFAULT_FREQUENCY, AUDIO_S16SYS, 1, 4096);
float frequency = 2093.00f; // C7 tone
int64_t nsample = 0;
// Open audio device
mixer.SetMusicHook([&nsample, frequency](Uint8* stream, int len) {
// fill provided buffer with sine wave
for (Uint8* ptr = stream; ptr < stream + len; ptr += 2)
*(Uint16*)ptr = (Uint16)(32766.0f * sin(nsample++ / (float)MIX_DEFAULT_FREQUENCY * frequency));
}
);
// Play for 1 second, after which everything is stopped and closed
SDL_Delay(1000);
return 0;
} catch (std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}