music_vorbis.c

Go to the documentation of this file.
00001 /*
00002  Copyright (C) 2007 Will Glynn
00003 
00004  Derived from music.c:
00005  Copyright (C) 2005 Michael K. McCarty & Fritz Bronner
00006  
00007  This program is free software; you can redistribute it and/or modify
00008  it under the terms of the GNU General Public License as published by
00009  the Free Software Foundation; either version 2 of the License, or
00010  (at your option) any later version.
00011  
00012  This program is distributed in the hope that it will be useful,
00013  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  GNU General Public License for more details.
00016  
00017  You should have received a copy of the GNU General Public License
00018  along with this program; if not, write to the Free Software
00019  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  */
00021 
00022 #include "race.h"
00023 #include "Buzz_inc.h"
00024 #include "mmfile.h"
00025 #include "pace.h"
00026 #include "utils.h"
00027 
00028 // A map of music_tracks to filenames
00029 struct music_key {
00030     enum music_track track;
00031     char *name;
00032 } music_key[] = {
00033     { M_ASSEMBLY, "assembly" },
00034     { M_ASTTRNG, "asttrng" },
00035     { M_BADNEWS, "badnews" },
00036     { M_DRUMSM, "drumsm" },
00037     { M_ELEPHANT, "elephant" },
00038     { M_FILLER, "filler" },
00039     { M_FUTURE, "future" },
00040     { M_GOOD, "good" },
00041     { M_HARDWARE, "hardware" },
00042     { M_HISTORY, "history" },
00043     { M_INTEL, "intel" },
00044     { M_INTELLEG, "intelleg" },
00045     { M_INTERLUD, "interlud" },
00046     { M_LIFTOFF, "liftoff" },
00047     { M_MISSPLAN, "missplan" },
00048     { M_NEW1950, "new1950" },
00049     { M_NEW1970, "new1970" },
00050     { M_PRES, "pres" },
00051     { M_PRGMTRG, "prgmtrg" },
00052     { M_RD, "r&d" },
00053     { M_SOVTYP, "sovtyp" },
00054     { M_SUCCESS, "success" },
00055     { M_SVFUN, "svfun" },
00056     { M_SVLOGO, "svlogo" },
00057     { M_SVPORT, "svport2" },
00058     { M_THEME, "theme" },
00059     { M_UNSUCC, "unsucc" },
00060     { M_USFUN, "usfun" },
00061     { M_USMIL, "usmil" },
00062     { M_USPORT, "usport2" },
00063     { M_USSRMIL, "ussrmil" },
00064     { M_VICTORY, "victory" },
00065     { M_MAX_MUSIC, NULL },
00066 };
00067 
00068 // This structure defines each track
00069 struct music_file {
00070     // Pointer to the audio buffer, once loaded from disk
00071     char * buf;
00072     size_t buf_size;
00073     
00074     // Can this track be played? i.e., does it exist?
00075     int unplayable;
00076     
00077     // Is this track playing?
00078     int playing;
00079     
00080     // The SDL audio chunk describing this track
00081     struct audio_chunk chunk;
00082 };
00083 struct music_file music_files[M_MAX_MUSIC];
00084 
00085 // Ensure that the specified music track is in memory, loading it if required
00086 void music_load(enum music_track track)
00087 {
00088     char fname[20] = "";
00089     int i;
00090     ssize_t bytes;
00091     
00092     // Check to see if the track is already loaded or known broken; if so, we're already done
00093     if (music_files[track].buf != NULL || music_files[track].unplayable)
00094         return;
00095 
00096     // Find the name for this track
00097     for (i = 0; music_key[i].track != M_MAX_MUSIC; i++) {
00098         if (music_key[i].track == track && music_key[i].name) {
00099             snprintf(fname, sizeof(fname), "%s.OGG", music_key[track].name);
00100             break;
00101         }
00102     }
00103     
00104     // Bail out if this track isn't known
00105     if (strlen(fname) == 0) {
00106         music_files[track].unplayable = 1;
00107         return;     
00108     }
00109     
00110     // Load the file
00111     bytes = load_audio_file(fname, &music_files[track].buf, &music_files[track].buf_size);
00112 
00113     // Handle failure gracefully
00114     if (bytes < 0) {
00115         free(music_files[track].buf);
00116         music_files[track].unplayable = 1;
00117         return;
00118     }
00119     
00120     // XXX: Trim the last two seconds from the audio file, since it's broken
00121     // This should really be done on the Vorbis files, rather than in the player
00122     if (bytes > 2 * 11025) {
00123         music_files[track].buf_size -= 2 * 11025;
00124         music_files[track].buf = xrealloc(music_files[track].buf, music_files[track].buf_size);
00125     }
00126 }
00127 
00128 // Start playing the given track
00129 void music_start_loop(enum music_track track, int loop)
00130 {
00131     // Load the track as necessary
00132     music_load(track);
00133     
00134     // Ensure that this track is playable
00135     if (music_files[track].unplayable)
00136         return;
00137     
00138     // Ignore requests to play a track that's already playing
00139     if (music_files[track].playing)
00140         return;
00141     
00142     // Initialize the audio chunk
00143     music_files[track].chunk.data = music_files[track].buf;
00144     music_files[track].chunk.size = music_files[track].buf_size;
00145     music_files[track].chunk.loop = loop;
00146     
00147     // XXX: Stop the existing music, since we need the music channel
00148     // This should be changed to dynamic channel allocation, to allow layering music tracks
00149     music_stop();
00150     
00151     // Play the track, and indicate that it's playing
00152     play(&music_files[track].chunk, AV_MUSIC_CHANNEL);
00153     music_files[track].playing = 1;
00154 }
00155 
00156 // Stop a specific track
00157 void music_stop_track(enum music_track track)
00158 {
00159     if (music_files[track].playing) {
00160         // XXX: stop the global music channel
00161         // This should be assigned on a per-track basis
00162         av_silence(AV_MUSIC_CHANNEL);
00163         
00164         music_files[track].playing = 0;
00165     }   
00166 }
00167 
00168 // Stop all tracks
00169 void music_stop()
00170 {
00171     int i;
00172     
00173     // Iterate through the list and stop any playing tracks by calling music_stop_track()
00174     for (i = 0; i < M_MAX_MUSIC; i ++) {
00175         if (music_files[i].playing) {
00176             music_stop_track(i);
00177         }
00178     }
00179 }
00180 
00181 int music_is_playing()
00182 {
00183     int i;
00184     for (i = 0; i < M_MAX_MUSIC; i ++) {
00185         if (music_files[i].playing) {
00186             return 1;
00187         }
00188     }
00189     
00190     return 0;
00191 }
00192 
00193 int music_is_track_playing(enum music_track track)
00194 {
00195     return music_files[track].playing;
00196 }
00197 
00198 void music_pump()
00199 {
00200     // TODO: Check to see that all the tracks we think are playing actually are
00201     // This doesn't apply to looped tracks, since those keep playing forever
00202 }
00203 
00204 void music_set_mute(int muted)
00205 {
00206     MuteChannel(AV_MUSIC_CHANNEL, muted);
00207 }

Generated on Fri Sep 28 00:35:45 2007 for raceintospace by  doxygen 1.5.3