sdlmixer.cpp

Go to the documentation of this file.
00001 /*
00002   libwt - Vassilis Virvilis Toolkit - a widget library
00003   Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm>
00004  
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Lesser General Public
00007   License as published by the Free Software Foundation; either
00008   version 2.1 of the License, or (at your option) any later version.
00009   
00010   This library is distributed in the hope that it will be useful,
00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013   Lesser General Public License for more details.
00014   
00015   You should have received a copy of the GNU Lesser General Public
00016   License along with this library; if not, write to the
00017   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018   Boston, MA  02111-1307, SA.
00019 */
00020 
00021 #include <SDL/SDL.h>
00022 
00023 #include <boost/assign/list_of.hpp> // for 'map_list_of()'
00024 
00025 #include "sdlmixer.h"
00026 #include <wt/trace.h>
00027 
00028 namespace Wt {
00029 
00030 Factory<Audio, SDLMixer> SDLMixer::factory;
00031 
00032 FlagMap SDLMixer::fadingTypeMap;
00033 FlagMap SDLMixer::musicTypeMap;
00034 
00035 SDLMixer::SDLMixer()
00036         : Audio() {
00037 
00038     // we can't reliably initialize staticly since we have to make
00039     // sure the enumeration is initialized first and this depends
00040     // from the linking order (static initialization fiasco)
00041     fadingTypeMap = boost::assign::map_list_of
00042                     (MIX_NO_FADING, FadingType::None)
00043                     (MIX_FADING_OUT, FadingType::Out)
00044                     (MIX_FADING_IN, FadingType::In);
00045 
00046     musicTypeMap = boost::assign::map_list_of
00047                    (MUS_NONE, MusicType::None)
00048                    (MUS_CMD, MusicType::Cmd)
00049                    (MUS_WAV, MusicType::WAV)
00050                    (MUS_MOD, MusicType::MOD)
00051                    (MUS_MID, MusicType::MID)
00052                    (MUS_OGG, MusicType::OGG)
00053                    (MUS_MP3, MusicType::MP3);
00054 
00055     adjustAllocatedChannels<SDLMixer>(0, Mix_AllocateChannels(-1));
00056     Mix_ChannelFinished(onChannelFinish);
00057     Mix_HookMusicFinished(onMusicFinish);
00058 }
00059 
00060 SDLMixer::~SDLMixer() {
00061     trace("sdlmixer", "Entering Destructor for SDLMixer\n");
00062     allocateChannels(0);
00063     Mix_CloseAudio();
00064 }
00065 
00066 Audio* SDLMixer::load() {
00067     trace("sdlmixer", "Initializing SDL audio...\n");
00068     if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
00069         trace("sdlmixer", "Initialize SDL audio: %s\n", SDL_GetError());
00070         goto fail;
00071     }
00072 
00073     int audio_rate, audio_channels;
00074     Uint16 audio_format;
00075     int chunksize;
00076 
00077     audio_format = MIX_DEFAULT_FORMAT;
00078     audio_channels = MIX_DEFAULT_CHANNELS;
00079 
00080     //undef this (HIFI) to reduce CPU by a 5%
00081     audio_rate = MIX_DEFAULT_FREQUENCY;
00082     chunksize = 1024;
00083     //audio_rate = 44100;
00084     //chunksize = 2048;
00085 
00086     /* Open the audio device */
00087     if (Mix_OpenAudio(audio_rate, audio_format,
00088                       audio_channels, chunksize) < 0) {
00089         trace("sdlmixer", "Initializing SDLMixer failed: %s\n", SDL_GetError());
00090         SDL_QuitSubSystem(SDL_INIT_AUDIO);
00091         goto fail;
00092     }
00093 
00094     Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
00095     trace("sdlmixer") << "Opened audio at "<< audio_rate <<
00096     " Hz " << (audio_format & 0xFF) << "bit " <<
00097     ((audio_channels > 1) ? "stereo" : "mono") << std::endl;
00098 
00099     trace("audio", "SDLMixer initialization...ok\n");
00100     return new SDLMixer();
00101 
00102 fail:
00103     trace("audio", "SDLMixer initialization...fail\n");
00104     return 0;
00105 }
00106 
00107 Audio::Chunk* SDLMixer::loadChunk(const std::string& filename) const {
00108     Mix_Chunk *chunk = Mix_LoadWAV(filename.c_str());
00109     return (chunk) ? new SDLMixer::Chunk(chunk) : 0;
00110 }
00111 
00112 int SDLMixer::allocateChannels(int num_channels) {
00113     const int oldnum = numChannels();
00114     assert(Mix_AllocateChannels(-1) == oldnum);
00115 
00116     if (num_channels == oldnum || num_channels < 0)
00117         return oldnum;
00118 
00119     adjustAllocatedChannels<SDLMixer>(oldnum,
00120                                       Mix_AllocateChannels(num_channels));
00121 
00122     return numChannels();
00123 }
00124 
00125 void SDLMixer::pause() {
00126     Mix_Pause(-1);
00127 }
00128 
00129 void SDLMixer::resume() {
00130     Mix_Resume(-1);
00131 }
00132 
00133 void SDLMixer::stop(int ms) {
00134     (ms) ? Mix_ExpireChannel(-1, ms) :
00135     Mix_HaltChannel(-1);
00136 }
00137 
00138 void SDLMixer::fadeOut(int ms) {
00139     Mix_FadeOutChannel(-1, ms);
00140 }
00141 
00142 int SDLMixer::playingChannels() const {
00143     return Mix_Playing(-1);
00144 }
00145 
00146 int SDLMixer::pausedChannels() const {
00147     return Mix_Paused(-1);
00148 }
00149 
00150 bool SDLMixer::isAvailable() const {
00151     return true;
00152 }
00153 
00154 // ************* SDLMixer::Music *****************
00155 Audio::Music *SDLMixer::loadMusic(const std::string& filename) {
00156     Mix_Music *m = Mix_LoadMUS(filename.c_str());
00157     return (m) ? new Music(m) : 0;
00158 }
00159 
00160 SDLMixer::Music::Music(Mix_Music *music_p)
00161         : Audio::Music(),
00162 music_p(music_p) {
00163     trace("sdlmixer", "SDLMixer::Music::Music() constructor called\n");
00164 }
00165 
00166 SDLMixer::Music::~Music() {
00167     Mix_FreeMusic(music_p);
00168 }
00169 
00170 /// it blocks until any previously music fading out is done
00171 void SDLMixer::playMusic(Audio::Music& music) {
00172     SDLMixer::Music& m = * static_cast<SDLMixer::Music *>(&music);
00173     trace("sdlmixer", "SDLMixer::playMusic() called\n");
00174     Mix_PlayMusic(m, musicLoops - 1);
00175 }
00176 
00177 void SDLMixer::fadeInMusic(Audio::Music& music, int ms) {
00178     SDLMixer::Music& m = * static_cast<SDLMixer::Music *>(&music);
00179     Mix_FadeInMusic(m, musicLoops - 1, ms);
00180 }
00181 
00182 void SDLMixer::fadeOutMusic(int ms) {
00183     Mix_FadeOutMusic(ms);
00184 }
00185 
00186 void SDLMixer::setMusicVolume(int volume) {
00187     SDLMixer& self = * static_cast<SDLMixer *>(instance());
00188     int hwvol = self.HWVolume(volume);
00189     Mix_VolumeMusic(hwvol);
00190 }
00191 
00192 void SDLMixer::pauseMusic() {
00193     Mix_PauseMusic();
00194 }
00195 
00196 void SDLMixer::rewindMusic() {
00197     Mix_RewindMusic();
00198 }
00199 
00200 bool SDLMixer::setMusicPosition(double start_sec) {
00201     return !Mix_SetMusicPosition(start_sec);
00202 }
00203 
00204 void SDLMixer::stopMusic() {
00205     Mix_HaltMusic();
00206 }
00207 
00208 bool SDLMixer::playingMusic() const {
00209     return Mix_PlayingMusic();
00210 }
00211 
00212 bool SDLMixer::pausedMusic() const {
00213     return Mix_PausedMusic();
00214 }
00215 
00216 int SDLMixer::musicFading() const {
00217     return fadingTypeMap[Mix_FadingMusic()];
00218 }
00219 
00220 int SDLMixer::Music::type() const {
00221     return musicTypeMap[Mix_GetMusicType(music_p)];
00222 }
00223 
00224 int SDLMixer::minHWVolume() const {
00225     return 0;
00226 }
00227 
00228 int SDLMixer::maxHWVolume() const {
00229     return MIX_MAX_VOLUME;
00230 }
00231 
00232 void SDLMixer::onChannelFinish(int channel_id) {
00233     Audio::onChannelFinish(channel_id);
00234     // if this function is called  SDLMixer is running
00235     // so all static casts are safe
00236     SDLMixer& self = * static_cast<SDLMixer *>(instance());
00237     SDLMixer::Channel *channel =
00238         static_cast<SDLMixer::Channel *>(self.channels[channel_id]);
00239     SDLMixer::Chunk *chunk = static_cast<SDLMixer::Chunk *>(channel->chunk());
00240     channel->chunk_p = 0;
00241     chunk->channel_id = -1;
00242 }
00243 
00244 // ********* SDLMixer::Chunk ***************
00245 
00246 SDLMixer::Chunk::Chunk(Mix_Chunk *mix_chunk_p)
00247         : Audio::Chunk(),
00248         chunk_p(mix_chunk_p, Deleter()),
00249 channel_id(-1) {
00250     trace("sdlmixer",
00251           "SDLMixer::Chunk Creating chunk %p (%p)\n", this, mix_chunk_p);
00252     setVolume(Audio::maxVolume);
00253 }
00254 
00255 SDLMixer::Chunk::~Chunk() {
00256     trace("sdlmixer",
00257           "SDLMixer::~Chunk Stoping chunk %p (%p)\n",
00258           this, chunk_p.get());
00259     stop();
00260 }
00261 
00262 void SDLMixer::Chunk::setVolume(int volume) {
00263     SDLMixer& self = * static_cast<SDLMixer *>(instance());
00264     int hwvol = self.HWVolume(volume);
00265     detach();
00266     Mix_VolumeChunk(*this, hwvol);
00267 }
00268 
00269 void SDLMixer::Chunk::play(int duration) {
00270     detach();
00271     channel_id = Mix_PlayChannelTimed(-1, *this, loops - 1, duration);
00272     if (channel_id >= 0)
00273         Audio::Chunk::channel<SDLMixer>()->chunk_p = this;
00274 }
00275 
00276 void SDLMixer::Chunk::fadeIn(int ms, int duration) {
00277     detach();
00278     channel_id = Mix_FadeInChannelTimed(-1, *this, loops - 1, ms, duration);
00279     if (channel_id >= 0)
00280         Audio::Chunk::channel<SDLMixer>()->chunk_p = this;
00281 }
00282 
00283 void SDLMixer::Chunk::fadeOut(int ms) {
00284     if (channel_id < 0)
00285         return;
00286     Mix_FadeOutChannel(channel_id, ms);
00287 }
00288 
00289 void SDLMixer::Chunk::pause() {
00290     if (channel_id < 0)
00291         return;
00292     Mix_Pause(channel_id);
00293 }
00294 
00295 void SDLMixer::Chunk::resume() {
00296     if (channel_id < 0)
00297         return;
00298     Mix_Resume(channel_id);
00299 }
00300 
00301 void SDLMixer::Chunk::stop(int ms) {
00302     if (channel_id < 0)
00303         return;
00304     (ms) ? Mix_ExpireChannel(channel_id, ms) :
00305     Mix_HaltChannel(channel_id);
00306 }
00307 
00308 bool SDLMixer::Chunk::playing() const {
00309     return (channel_id < 0) ? false : Mix_Playing(channel_id);
00310 }
00311 
00312 bool SDLMixer::Chunk::paused() const {
00313     return (channel_id < 0) ? false : Mix_Paused(channel_id);
00314 }
00315 
00316 Audio::Channel *SDLMixer::Chunk::channel() const {
00317     SDLMixer& self = * static_cast<SDLMixer *>(instance());
00318     return (channel_id < 0) ? 0 : self.channels[channel_id];
00319 }
00320 
00321 static Mix_Chunk *clone_chunk(const Mix_Chunk *chunk_p) {
00322     Mix_Chunk *new_chunk_p = static_cast<Mix_Chunk *>(malloc(sizeof(Mix_Chunk)));
00323     *new_chunk_p = *chunk_p;
00324     new_chunk_p->allocated = 0;
00325     trace("sdlmixer", "clone_chunk %p --> %p\n", chunk_p, new_chunk_p);
00326     return new_chunk_p;
00327 }
00328 
00329 void SDLMixer::Chunk::Deleter::operator()(Mix_Chunk *c) {
00330     trace("sdlmixer",
00331           "SDLMixer::Chunk::Deleter Deleting Mix_Chunk (%p)\n", c);
00332     Mix_FreeChunk(c);
00333 }
00334 
00335 Audio::Chunk *SDLMixer::Chunk::clone() const {
00336     trace("sdlmixer", "SDLMixer::Chunk::clone %p\n", this);
00337     return new Chunk(clone_chunk(*this));
00338 }
00339 
00340 void SDLMixer::Chunk::detach() {
00341     trace("sdlmixer", "SDLMixer::Chunk::detach %p\n", this);
00342     //avoid detaching if we are the only client for this Sound
00343     if (!chunk_p.unique()) {
00344         trace("sdlmixer", "SDLMixer::Chunk::detaching %p\n", this);
00345         chunk_p.reset(clone_chunk(*this), Deleter());
00346     }
00347 }
00348 
00349 // ********* SDLMixer::Channel ***************
00350 
00351 SDLMixer::Channel::Channel(int id) :
00352         Audio::Channel(),
00353         chunk_p(0),
00354 channel_id(id) {}
00355 
00356 void SDLMixer::Channel::setVolume(int volume) {
00357     SDLMixer& self = * static_cast<SDLMixer *>(instance());
00358     int hwvol = self.HWVolume(volume);
00359     Mix_Volume(channel_id, hwvol);
00360 }
00361 
00362 void SDLMixer::Channel::play(Audio::Chunk& chunk, int duration) {
00363     trace("sdlmixer", "SDLMixer::Channel::play()\n");
00364     SDLMixer::Chunk& c = * static_cast<SDLMixer::Chunk *>(&chunk);
00365     int status = Mix_PlayChannelTimed(channel_id, c,
00366                                       loops - 1, duration);
00367     if (!status)
00368         chunk_p = &c;
00369 }
00370 
00371 void SDLMixer::Channel::fadeIn(Audio::Chunk& chunk, int ms, int duration) {
00372     SDLMixer::Chunk& c = * static_cast<SDLMixer::Chunk *>(&chunk);
00373     int status = Mix_FadeInChannelTimed(channel_id, c,
00374                                         loops - 1, ms, duration);
00375     if (!status)
00376         chunk_p = &c;
00377 }
00378 
00379 void SDLMixer::Channel::fadeOut(int ms) {
00380     Mix_FadeOutChannel(channel_id, ms);
00381 }
00382 
00383 void SDLMixer::Channel::pause() {
00384     Mix_Pause(channel_id);
00385 }
00386 
00387 void SDLMixer::Channel::resume() {
00388     Mix_Resume(channel_id);
00389 }
00390 
00391 void SDLMixer::Channel::stop(int ms) {
00392     (ms) ? Mix_ExpireChannel(channel_id, ms) :
00393     Mix_HaltChannel(channel_id);
00394 }
00395 
00396 bool SDLMixer::Channel::playing() const {
00397     return Mix_Playing(channel_id);
00398 }
00399 
00400 bool SDLMixer::Channel::paused() const {
00401     return Mix_Paused(channel_id);
00402 }
00403 
00404 int SDLMixer::Channel::fading() const {
00405     return fadingTypeMap[Mix_FadingChannel(channel_id)];
00406 }
00407 
00408 Audio::Chunk *SDLMixer::Channel::chunk() const {
00409     return chunk_p;
00410 }
00411 
00412 } // namespace Wt

Generated Fri Jul 28 19:23:00 2006.
Copyright © 1998-2003 by the respective authors.

This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.