Adonthell 0.4
|
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 }