• Main Page
  • Related Pages
  • Classes
  • Files
  • File List
  • File Members

audio.cc

00001 /*
00002    $Id: audio.cc,v 1.32 2003/01/16 11:22:45 ksterker Exp $
00003 
00004    Copyright (C) 2000 Andrew Henderson <hendersa@db.erau.edu>
00005    Copyright (C) 2002 Kai Sterker <kaisterker@linuxgames.com>
00006    Part of the Adonthell Project http://adonthell.linuxgames.com
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #include <string.h>
00017 #include <stdlib.h>
00018 #include <stdio.h>
00019 #include "SDL.h"
00020 #include "audio.h"
00021 
00022 // #include "audio_loop.h"
00023 
00024 bool audio::audio_initialized = false;
00025 
00026 int audio::background_volume;
00027 int audio::effects_volume;
00028 #ifdef OGG_MUSIC
00029 // loop_info *audio::loop[NUM_MUSIC];
00030 #endif
00031 Mix_Music *audio::music[NUM_MUSIC];
00032 string audio::music_file[NUM_MUSIC];
00033 Mix_Chunk *audio::sounds[NUM_WAVES];
00034 int audio::current_background;
00035 int audio::last_background;
00036 bool audio::background_paused;
00037 int audio::audio_rate;
00038 Uint16 audio::buffer_size;
00039 Uint16 audio::audio_format;
00040 int audio::audio_channels;
00041 
00042 // python schedule stuff
00043 py_object audio::schedule;
00044 bool audio::schedule_active = 0;
00045 PyObject *audio::schedule_args = NULL;
00046 
00047 
00048 void audio::init (config *myconfig) {
00049   int i;  // Generic counter variable
00050 
00051   // Sample rate: 11025, 22050 or 44100 Hz
00052   switch( myconfig->audio_sample_rate ) {
00053     case 0: {
00054       audio_rate = 11025;
00055       break; }
00056     case 1: {
00057       audio_rate = 22050;
00058       break; }
00059     default: {
00060       audio_rate = 44100;
00061       break; }
00062   }
00063   
00064   // Output in signed 8/16-bit form
00065   audio_format = myconfig->audio_resolution == 0 ? AUDIO_S8 : AUDIO_S16; 
00066 
00067   // 1 is mono, 2 is stereo
00068   audio_channels = myconfig->audio_channels == 0 ? 1 : 2;  
00069 
00070   // 100... scales to percentages ;>
00071   background_volume = myconfig->audio_volume;   
00072 
00073   buffer_size = 4096;        // Audio buffer size
00074   effects_volume = 128;      // Still figuring this one out...
00075   current_background = -1;   // No song currently playing
00076   last_background = -1;      // No song played so far
00077   background_paused = false; // Music isn't paused
00078   audio_initialized = false; // No audio connection yet
00079   schedule_active = false;   // No schedule file yet
00080   
00081   // Mark all slots in sound and music arrays as empty
00082   for (i = 0; i < NUM_WAVES; i++) sounds[i] = NULL;
00083   for (i = 0; i < NUM_MUSIC; i++) {
00084       music[i] = NULL; 
00085       music_file[i] = "";
00086   }
00087   
00088   // Try opening the audio device at our defaults
00089   i = Mix_OpenAudio(audio_rate, audio_format, audio_channels, buffer_size);
00090 
00091   // Now see what we got when opening the audio device
00092   // If we COULDN'T open the audio...
00093   if ( i < 0 ) {
00094     fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
00095     fprintf(stderr, "Audio will not be used.\n");
00096 
00097   // If we COULD open the audio...
00098   } else {
00099     audio_initialized = true;
00100     Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
00101     set_background_volume (background_volume);
00102   }
00103 }
00104 
00105 void audio::cleanup(void) 
00106 {
00107     int i;
00108     // No music is queued to play
00109     current_background = -1;
00110 
00111     // Null out those tunes and sound effects
00112     for (i = 0; i < NUM_WAVES; i++) 
00113     {
00114         unload_wave(i);
00115         sounds[i] = NULL;
00116     }
00117     
00118     for (i = 0; i < NUM_MUSIC; i++) 
00119     {
00120         unload_background(i);
00121         music[i] = NULL;
00122         music_file[i] = "";
00123     }
00124 
00125     // Clean audio schedule
00126     schedule.clear ();
00127   
00128     // Close out audio connection
00129     if (audio_initialized == true)
00130     {
00131         Mix_CloseAudio();
00132         audio_initialized = false;
00133     }
00134 }
00135 
00136 int audio::load_background(int slot, char *filename) {
00137 
00138   if (!audio_initialized) return (0);
00139 
00140   // Check for bad input
00141   if ((slot >= NUM_MUSIC) || (slot < 0)) {
00142     fprintf(stderr, "Error: Tried to put music in invalid slot.\n");
00143     return(0);
00144   }
00145 
00146   //  Check if the file exists at all...
00147   FILE *f = fopen (filename, "r");
00148   if (!f) {
00149     fprintf(stderr, "Error: No such file: %s.\n", filename);
00150     return 0;
00151   }
00152   fclose (f);   
00153 
00154   // Music already occupies that slot
00155   if (music[slot] != NULL)
00156       unload_background (slot);
00157 
00158   // No music in slot, load new tune in, ...
00159   music[slot] = Mix_LoadMUS(filename);
00160   music_file[slot] = filename;
00161 
00162 #ifdef OGG_MUSIC
00163   // read loop points and ...
00164   // loop[slot] = new loop_info (&music[slot]->ogg_data.ogg->vf);
00165   
00166   // ... enable looping
00167   // music[slot]->ogg_data.ogg->vf.callbacks.read_func = &ogg_read_callback;
00168 #endif
00169   return(1);
00170 }
00171 
00172 void audio::unload_background (int slot)
00173 {
00174     if (music[slot] == NULL) return;
00175 
00176     // If we are unloading background music from the slot
00177     // the current background music is in...
00178     if (current_background == slot)
00179     {
00180         last_background = current_background;
00181         current_background = -1;
00182 
00183         // Just a precaution
00184         Mix_HaltMusic();
00185         Mix_ResumeMusic ();
00186     }
00187 
00188     Mix_FreeMusic (music[slot]);
00189     music[slot] = NULL;
00190     music_file[slot] = "";
00191 
00192 #ifdef OGG_MUSIC
00193     // delete loop[slot];
00194 #endif
00195 }
00196 
00197 void audio::pause_music(void) {
00198   Mix_PauseMusic();
00199 }
00200 
00201 void audio::unpause_music(void) {
00202   Mix_ResumeMusic();
00203 }
00204 
00205 // Accepts a percentage of the maximum volume level
00206 // and clips out of bounds values to 0-100.
00207 void audio::set_background_volume(int volume) {
00208 
00209   // Check for bad input
00210   if (volume < 0) {
00211     background_volume = 0;
00212   } else if (volume > 100) {
00213     background_volume = 100;
00214   } else
00215     background_volume = volume;
00216 
00217   // Scales 0-100% to 0-128
00218   Mix_VolumeMusic(int(background_volume * 1.28));
00219 }
00220 
00221 // This should be done better, but I'll wait until
00222 // I have enough sound effects to play with ;>
00223 int audio::load_wave(int slot, char *filename) {
00224 
00225   if (!audio_initialized) return(1);
00226  
00227   // Check for bad input
00228   if ((slot >= NUM_WAVES) || (slot < 0)) {
00229     fprintf(stderr, "Error: Tried to put wave in invalid slot.\n");
00230     return(1);
00231   } else {
00232       //  Check if the file exists at all...
00233       FILE *f = fopen (filename, "r");
00234       if (!f)  
00235       {
00236           sounds[slot] = NULL; 
00237           return 1;
00238       }
00239       
00240       fclose (f);   
00241       
00242       sounds[slot] = Mix_LoadWAV(filename);
00243   }
00244   return(0);
00245 }
00246 
00247 void audio::unload_wave(int wave) {
00248   if (sounds[wave] != NULL) {
00249     Mix_FreeChunk(sounds[wave]);
00250     sounds[wave] = NULL;
00251   }
00252 }
00253 
00254 void audio::play_wave(int channel, int slot) {
00255   if ((slot > -1) && (slot < NUM_CHANNELS))
00256     if (sounds[slot] != NULL) Mix_PlayChannel(channel, sounds[slot], 0);
00257 }
00258 
00259 void audio::play_background(int slot) {
00260   if (music[slot] != NULL) {
00261     current_background = slot;
00262     Mix_PlayMusic(music[current_background], 0);
00263   }
00264 }
00265 
00266 void audio::fade_out_background(int time) {
00267     if (Mix_PlayingMusic ())
00268     {
00269         Mix_FadeOutMusic(time);
00270         last_background = current_background;
00271         current_background = -1;
00272     }
00273 #ifdef OGG_MUSIC
00274     // music[current_background]->ogg_data.ogg->vf.callbacks.read_func = &fread_wrap;
00275 #endif
00276 }
00277 
00278 void audio::fade_in_background(int slot, int time) {
00279   if (music[slot] != NULL) {
00280     current_background = slot;
00281     Mix_FadeInMusic(music[slot], 0, time);
00282   }
00283 }
00284 
00285 // Temporary convience function for testing
00286 void audio::change_background(int slot, int time) {
00287   fade_out_background(time);
00288   fade_in_background(slot, time);
00289 }
00290 
00291 #ifdef OGG_MUSIC
00292 // OggVorbis_File* audio::get_vorbisfile ()
00293 // {
00294 //     return &music[current_background]->ogg_data.ogg->vf;
00295 // }
00296 #endif
00297 
00298 // set audio schedule
00299 void audio::set_schedule (string file, PyObject * args)
00300 {     
00301     // Clears the schedule
00302     schedule.clear ();
00303     Py_XDECREF (schedule_args);
00304     schedule_args = NULL;
00305 
00306     // Set new schedule
00307     if (file != "")
00308     {
00309         schedule_args = args; 
00310         Py_XINCREF (schedule_args); 
00311         schedule.create_instance ("schedules.audio." + file, file, args);
00312     }
00313 }
00314 
00315 // run the audio control schedule
00316 void audio::run_schedule ()
00317 {
00318     PyObject *song = Py_BuildValue ("(i)", last_background);
00319     if (schedule_active) schedule.call_method ("music_finished", song);
00320     Py_DECREF (song);
00321 }
00322 
00323 // save state
00324 s_int8 audio::put_state (ogzstream& file)
00325 {
00326     // currently playing
00327     current_background >> file;
00328 
00329     // music file
00330     if (current_background != -1) music_file[current_background] >> file;
00331 
00332     // Save the schedule script state
00333     schedule.class_name () >> file;
00334     if (schedule_args) 
00335     {
00336         true >> file; 
00337         python::put_tuple (schedule_args, file);
00338     }
00339     else false >> file; 
00340     is_schedule_activated () >> file;
00341     
00342     return 1;
00343 }
00344 
00345 // get state
00346 s_int8 audio::get_state (igzstream& file)
00347 {
00348     string song, script;
00349     bool have_args;
00350     
00351     // current background
00352     last_background << file;
00353 
00354     // if song was playing, see which it is
00355     if (last_background != -1)
00356     {
00357         song << file;
00358 
00359         // ... and resume playing
00360         if (load_background (last_background, (char *) song.c_str ()))
00361             play_background (last_background);
00362     }
00363 
00364     // Restore the schedule script state
00365     PyObject * args = NULL; 
00366     script << file;
00367     
00368     have_args << file;
00369     if (have_args) args = python::get_tuple (file); 
00370     set_schedule (script, args);      
00371     Py_XDECREF (args); 
00372     
00373     schedule_active << file;
00374 
00375     return 1;
00376 }

Generated on Fri Mar 18 2011 for Adonthell by  doxygen 1.7.1