1 #include "ge211_audio.hxx"
2 #include "ge211_resource.hxx"
3 #include "ge211_session.hxx"
13 using namespace detail;
17 static inline int unit_to_volume(
double unit_volume)
19 return int(unit_volume * MIX_MAX_VOLUME);
22 static inline double volume_to_unit(
int int_volume)
24 return int_volume / double(MIX_MAX_VOLUME);
27 Audio_clip::Audio_clip()
29 Session::check_session(
"Audio loading");
34 return mixer.
is_enabled() && real_try_load_(filename, mixer);
39 if (!try_load(filename, mixer))
40 throw Mixer_error::could_not_load(filename);
50 load(filename, mixer);
55 Mix_Music* raw = Mix_LoadMUS_RW(File_resource(filename).release(), 1);
57 ptr_ = {raw, &Mix_FreeMusic};
64 void Music_track::real_clear_()
69 bool Music_track::real_empty_()
const
71 return ptr_ ==
nullptr;
76 load(filename, mixer);
81 Mix_Chunk* raw = Mix_LoadWAV_RW(File_resource(filename).release(), 1);
84 ptr_ = {raw, &Mix_FreeChunk};
91 void Sound_effect::real_clear_()
96 bool Sound_effect::real_empty_()
const
98 return ptr_ ==
nullptr;
102 : enabled_{0 == Mix_OpenAudio(MIX_DEFAULT_FREQUENCY,
106 , channels_(MIX_CHANNELS)
107 , available_effect_channels_(MIX_CHANNELS)
110 warn_sdl() <<
"Could not open audio device";
114 int mix_want = MIX_INIT_OGG | MIX_INIT_MP3;
115 int mix_have = Mix_Init(mix_want);
117 warn_sdl() <<
"Could not initialize audio mixer";
118 }
else if ((mix_have & mix_want) != mix_want) {
119 warn_sdl() <<
"Could not initialize all audio formats";
122 int music_decoders = Mix_GetNumMusicDecoders();
123 info_sdl() <<
"Number of music decoders is " << music_decoders;
124 for (
int i = 0; i < music_decoders; ++i) {
125 info_sdl() <<
" [" << i <<
"] " << Mix_GetMusicDecoder(i);
128 int chunk_decoders = Mix_GetNumChunkDecoders();
129 info_sdl() <<
"Number of chunk decoders is " << chunk_decoders;
130 for (
int i = 0; i < chunk_decoders; ++i) {
131 info_sdl() <<
" [" << i <<
"] " << Mix_GetChunkDecoder(i);
152 switch (music_state_) {
164 current_music_ = std::move(music);
166 if (current_music_) {
175 switch (music_state_) {
181 Mix_FadeInMusicPos(current_music_.ptr_.
get(),
200 switch (music_state_) {
214 music_position_.
pause();
226 switch (music_state_) {
228 music_position_.
reset();
235 "Mixer::rewind_music: must be paused");
249 int Mixer::find_empty_channel_()
const
251 auto iter = std::find_if(channels_.begin(),
253 [](
auto& h) { return h.empty(); });
255 if (iter == channels_.end())
258 return (
int) std::distance(channels_.begin(), iter);
261 void Mixer::poll_channels_()
263 if (!enabled_)
return;
265 if (current_music_) {
266 if (!Mix_PlayingMusic()) {
267 switch (music_state_) {
273 music_position_.
pause();
274 music_position_.
reset();
279 music_position_.
pause();
286 for (
int channel = 0; channel < int(channels_.size()); ++channel) {
287 if (channels_[channel] && !Mix_Playing(channel))
289 unregister_effect_(channel);
297 if (!enabled_)
throw Mixer_error::not_enabled();
300 if (!handle)
throw Mixer_error::out_of_channels();
308 if (!enabled_)
return {};
310 int channel = find_empty_channel_();
311 if (channel < 0)
return {};
313 Mix_Volume(channel, unit_to_volume(volume));
314 Mix_PlayChannel(channel, effect.ptr_.
get(), 0);
316 return register_effect_(channel, std::move(effect));
321 switch (ptr_->state) {
327 Mix_Resume(ptr_->channel);
341 switch (ptr_->state) {
351 Mix_Pause(ptr_->channel);
361 switch (ptr_->state) {
366 ptr_->mixer.unregister_effect_(ptr_->channel);
367 Mix_HaltChannel(ptr_->channel);
371 ptr_->mixer.unregister_effect_(ptr_->channel);
372 Mix_HaltChannel(ptr_->channel);
384 for (
const auto& handle : channels_) {
394 for (
const auto& handle : channels_) {
402 return available_effect_channels_;
406 Mixer::register_effect_(
int channel,
Sound_effect effect)
408 assert(!channels_[channel]);
410 --available_effect_channels_;
411 return channels_[channel];
414 void Mixer::unregister_effect_(
int channel)
416 assert(channels_[channel]);
418 channels_[channel] = {};
419 ++available_effect_channels_;
424 return volume_to_unit(Mix_VolumeMusic(-1));
429 Mix_VolumeMusic(unit_to_volume(unit_value));
434 return ptr_ ==
nullptr;
437 Sound_effect_handle::operator bool()
const
445 : ptr_(std::make_shared<Impl_>(mixer, std::move(effect), channel))
453 return volume_to_unit(Mix_Volume(ptr_->channel, -1));
459 Mix_Volume(ptr_->channel, unit_to_volume(unit_value));