Back to index

extremetuxracer  0.5beta
audio_data.cpp
Go to the documentation of this file.
00001 /* 
00002  * PPRacer 
00003  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00004  *
00005  * Copyright (C) 1999-2001 Jasmin F. Patry
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (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 "audio_data.h"
00023 #include "audio.h"
00024 
00025 #if defined(HAVE_SDL_MIXER)
00026 
00027 #include "SDL.h"
00028 #include "SDL_mixer.h"
00029 
00030 #include <string>
00031 #include <list>
00032 #include <map>
00033 
00034 #define SOUNDFILE_MISSING_WARNING_LEVEL 10
00035 #define SOUNDFILE_BUSY_WARNING_LEVEL 10
00036 
00037 typedef struct {
00038     Mix_Chunk *data;    /* sound data */
00039     int ref_ctr;        /* reference counter */
00040 } sound_record_t;
00041 
00042 typedef struct {
00043     Mix_Music *data;    /* music data */
00044     int ref_ctr;        /* reference counter */
00045     bool playing;     /* is this music playing? */
00046 } music_record_t;
00047 
00048 //static hash_table_t sound_hash_;
00049 static std::map<std::string,sound_record_t> soundTable;
00050 
00051 //static hash_table_t music_hash_;
00052 static std::map<std::string,music_record_t> musicTable;
00053 
00054 static bool sound_dirty_ = false;
00055 static bool music_dirty_ = false;
00056 
00057 
00058 /* Name:          init_sound_data
00059    Description:   initializes audio module
00060    Precondition:  none
00061    Postcondition: audio module initialized
00062    Return value:  none
00063    Author:        jfpatry
00064    Created:       2000-08-13
00065    Last Modified: 2000-08-13
00066 */
00067 void 
00068 init_audio_data()
00069 {
00070 }
00071 
00072 /* Name:          load_sound
00073    Description:   Loads a sound from a file
00074    Precondition:  name, filename != null
00075    Return value:  true if successful, false otherwise
00076    Modified args: 
00077    Author:        jfpatry
00078    Created:       2000-08-13
00079    Last Modified: 2000-08-13
00080 */
00081 bool
00082 load_sound( const char *name, const char *filename ) 
00083 { 
00084     char *data_ptr;
00085     char *record_ptr;
00086     char *temp_record_ptr;
00087     int ref_ctr = 0;
00088 
00089     check_assertion( name != NULL, "null name" );
00090     check_assertion( filename != NULL, "null filename" );
00091 
00092     if ( ! is_audio_open() ) {
00093               return false;
00094     }
00095 
00096        std::map<std::string,sound_record_t>::iterator soundit;
00097        
00098        if((soundit=soundTable.find(name))!=soundTable.end()){
00099               print_debug( DEBUG_SOUND, "Overwriting sound name %s", name );
00100                             
00101               ref_ctr = soundit->second.ref_ctr;
00102               soundTable.erase(soundit);
00103        }
00104        
00105        data_ptr = (char*) Mix_LoadWAV( filename );
00106 
00107     if ( data_ptr == NULL ) {
00108               print_warning( SOUNDFILE_MISSING_WARNING_LEVEL, 
00109                      "FAILED to load sound file %s: %s", 
00110                      filename, Mix_GetError() );
00111               return false;
00112     }
00113 
00114     print_debug( DEBUG_SOUND, "Successfully loaded sound file %s", 
00115                filename );
00116 
00117        
00118        sound_record_t *srec = &soundTable[name];
00119               
00120        srec->data = (Mix_Chunk*) data_ptr;
00121        srec->ref_ctr = ref_ctr;
00122        record_ptr = (char*) srec;  
00123        
00124 
00125     /* Make sure it's there */
00126     /*
00127        check_assertion( get_hash_entry( hash, name, (void*) &temp_record_ptr ) &&
00128                    ( record_ptr == temp_record_ptr ), 
00129                    "failed addition to hash table" );
00130     */
00131        temp_record_ptr = NULL; /* to prevent warnings when assert turned off */
00132 
00133        sound_dirty_ = true;
00134 
00135     return true;
00136 }
00137 
00138 /* Name:          load_music
00139    Description:   Loads music from a file
00140    Precondition:  name, filename != null
00141    Return value:  true if successful, false otherwise
00142    Modified args: 
00143    Author:        jfpatry
00144    Created:       2000-08-13
00145    Last Modified: 2000-08-13
00146 */
00147 bool
00148 load_music( const char *name, const char *filename ) 
00149 { 
00150        char *data_ptr;
00151     char *record_ptr;
00152     char *temp_record_ptr;
00153     int ref_ctr = 0;
00154 
00155     check_assertion( name != NULL, "null name" );
00156     check_assertion( filename != NULL, "null filename" );
00157 
00158     if ( ! is_audio_open() ) {
00159        return false;
00160     }
00161    
00162        std::map<std::string,music_record_t>::iterator musicit;
00163               
00164        if((musicit=musicTable.find(name))!=musicTable.end()){
00165               if ( musicit->second.playing ) {
00166                      print_warning( SOUNDFILE_BUSY_WARNING_LEVEL, 
00167                             "Can't overwrite music name %s since "
00168                             "it is playing", name );
00169                      return false;
00170               }
00171               ref_ctr = musicit->second.ref_ctr;
00172               musicTable.erase(musicit);
00173        }
00174        /*
00175     if ( get_hash_entry( hash, name, (hash_entry_t*) &record_ptr ) ) {
00176               print_debug( DEBUG_SOUND, "Overwriting music name %s", name );
00177 
00178               // Need to save ref_ctr
00179               music_record_t *mrec = (music_record_t*)record_ptr;
00180               if ( mrec->playing ) {
00181                      // Can't overwrite since music is playing 
00182                      print_warning( SOUNDFILE_BUSY_WARNING_LEVEL, 
00183                             "Can't overwrite music name %s since "
00184                             "it is playing", name );
00185                      return false;
00186               }
00187               ref_ctr = mrec->ref_ctr;
00188               del_hash_entry( hash, name, NULL );
00189     }
00190        */
00191        
00192        data_ptr = (char*) Mix_LoadMUS( filename );
00193 
00194     if ( data_ptr == NULL ) {
00195        print_warning( SOUNDFILE_MISSING_WARNING_LEVEL, 
00196                      "FAILED to load music file %s: %s", 
00197                      filename, Mix_GetError() );
00198        return false;
00199     }
00200 
00201     print_debug( DEBUG_SOUND, "Successfully loaded music file %s", 
00202                filename );
00203 
00204        music_record_t *mrec = (music_record_t*)malloc(sizeof(music_record_t));
00205        mrec->data = (Mix_Music*) data_ptr;
00206        mrec->ref_ctr = ref_ctr;
00207        mrec->playing = false;
00208 
00209        record_ptr = (char*) mrec;
00210 
00211     musicTable[name] = *mrec;
00212 
00213     /* Make sure it's there */
00214     /*check_assertion( get_hash_entry( hash, name, (void*) &temp_record_ptr ) &&
00215                    ( record_ptr == temp_record_ptr ), 
00216                    "failed addition to hash table" );
00217     */
00218        temp_record_ptr = NULL; /* to prevent warnings when assert turned off */
00219 
00220 
00221        music_dirty_ = true;
00222     
00223     return true;
00224        
00225 }
00226 
00227 
00228 /* Name:          get_sound_data
00229    Description:   returns the Mix_Chunk for the sound _name_
00230    Precondition:  name != NULL
00231    Return value:  true if entry for name exists, false otherwise
00232    Modified args: data if non-NULL
00233    Author:        jfpatry
00234    Created:       2000-08-13
00235    Last Modified: 2000-08-13
00236 */
00237 bool
00238 get_sound_data( char *name, Mix_Chunk **data )
00239 {
00240     std::map<std::string,sound_record_t>::iterator srec;
00241        if((srec=soundTable.find(name))==soundTable.end()){
00242               return false;
00243        }
00244 
00245     if ( data ) {
00246               *data = srec->second.data;
00247     }
00248     return true;
00249 }
00250 
00251 /* Name:          get_music_data
00252    Description:   returns the Mix_Music for the music _name_
00253    Precondition:  name != NULL
00254    Return value:  true if entry for name exists, false otherwise
00255    Modified args: data if non-NULL
00256    Author:        jfpatry
00257    Created:       2000-08-13
00258    Last Modified: 2000-08-13
00259 */
00260 bool
00261 get_music_data( char *name, Mix_Music **data )
00262 {
00263        std::map<std::string,music_record_t>::iterator mrec;
00264        if((mrec=musicTable.find(name))==musicTable.end()){
00265               return false;
00266        }
00267 
00268     if ( data ) {
00269               *data = mrec->second.data;
00270     }
00271     return true;
00272 }
00273 
00274 
00290 void
00291 set_music_playing_status( char *name, bool playing )
00292 {
00293        std::map<std::string,music_record_t>::iterator mrec;
00294 
00295        if((mrec=musicTable.find(name))==musicTable.end()){
00296               check_assertion(0, "couldn't find music" );
00297        }
00298        
00299     mrec->second.playing = playing;
00300 }
00301 
00302 
00313 bool
00314 get_music_playing_status( char *name )
00315 {
00316        std::map<std::string,music_record_t>::iterator mrec;
00317 
00318        if((mrec=musicTable.find(name))==musicTable.end()){
00319               check_assertion(0, "couldn't find music" );
00320        }
00321        
00322     return mrec->second.playing;
00323 }
00324 
00325 
00326 /* Name:          incr_sound_data_ref_ctr
00327    Description:   Increments the reference count for sound _name_
00328    Precondition:  name != NULL, entry for name exists
00329    Return value:  
00330    Modified args: 
00331    Author:        jfpatry
00332    Created:       2000-08-13
00333    Last Modified: 2000-08-13
00334 */
00335 void incr_sound_data_ref_ctr( const char *name ) 
00336 {
00337        std::map<std::string,sound_record_t>::iterator srec;
00338        if((srec=soundTable.find(name))==soundTable.end()){
00339               //check_assertion( found, "hashtable entry not found" );
00340        }
00341        
00342        srec->second.ref_ctr++;
00343        print_debug( DEBUG_SOUND, "incremented reference counter of sound %s "
00344                "to %d", name, srec->second.ref_ctr );
00345 }
00346 
00347 
00348 /* Name:          decr_sound_data_ref_ctr
00349    Description:   Decrements the reference count for sound _name_
00350    Precondition:  name != NULL, entry for name exists
00351    Return value:  
00352    Modified args: 
00353    Author:        jfpatry
00354    Created:       2000-08-13
00355    Last Modified: 2000-08-13
00356 */
00357 void decr_sound_data_ref_ctr( const char *name ) 
00358 {
00359        std::map<std::string,sound_record_t>::iterator srec;
00360        if((srec=soundTable.find(name))==soundTable.end()){
00361               //check_assertion( found, "hashtable entry not found" );
00362        }
00363        
00364        srec->second.ref_ctr--;
00365        print_debug( DEBUG_SOUND, "decremented reference counter of sound %s "
00366                "to %d", name, srec->second.ref_ctr );
00367 }
00368 
00369 /* Name:          incr_music_data_ref_ctr
00370    Description:   Increments the reference count for music _name_
00371    Precondition:  name != NULL, entry for name exists
00372    Return value:  
00373    Modified args: 
00374    Author:        jfpatry
00375    Created:       2000-08-13
00376    Last Modified: 2000-08-13
00377 */
00378 void incr_music_data_ref_ctr( const char *name ) 
00379 {
00380        std::map<std::string,music_record_t>::iterator mrec;
00381 
00382        if((mrec=musicTable.find(name))==musicTable.end()){
00383               check_assertion(0, "couldn't find music" );
00384        }
00385     mrec->second.ref_ctr++;
00386 
00387     print_debug( DEBUG_SOUND, "incremented reference counter of music %s "
00388                "to %d", name, mrec->second.ref_ctr );
00389 }
00390 
00391 /* Name:          decr_music_data_ref_ctr
00392    Description:   Decrements the reference count for music _name_
00393    Precondition:  name != NULL, entry for name exists
00394    Return value:  
00395    Modified args: 
00396    Author:        jfpatry
00397    Created:       2000-08-13
00398    Last Modified: 2000-08-13
00399 */
00400 void decr_music_data_ref_ctr( const char *name ) 
00401 {
00402        std::map<std::string,music_record_t>::iterator mrec;
00403 
00404        if((mrec=musicTable.find(name))==musicTable.end()){
00405               check_assertion(0, "couldn't find music" );
00406        }
00407 
00408     mrec->second.ref_ctr--;
00409 
00410     print_debug( DEBUG_SOUND, "decremented reference counter of music %s "
00411                "to %d", name, mrec->second.ref_ctr );
00412 }
00413 
00414 /* Name:          delete_unused_audio_data
00415    Description:   Frees all sound and music data with reference counts == 0
00416    Precondition:  
00417    Return value:  
00418    Modified args: 
00419    Author:        jfpatry
00420    Created:       2000-08-13
00421    Last Modified: 2000-08-13
00422 */
00423 void delete_unused_audio_data()
00424 {
00425        std::list<char*> keysToDelete;
00426 
00427     // clean sounds first
00428        std::map<std::string,sound_record_t>::iterator sit;
00429 
00430        for(sit=soundTable.begin(); sit!=soundTable.end(); sit++){
00431               if ( sit->second.ref_ctr == 0 ) {
00432               Mix_FreeChunk( sit->second.data );
00433                      soundTable.erase(sit);
00434               }      
00435        }
00436        
00437     // clean music
00438        std::map<std::string,music_record_t>::iterator mit;
00439 
00440        for(mit=musicTable.begin(); mit!=musicTable.end(); mit++){
00441               if ( mit->second.ref_ctr == 0 ) {
00442                      // we shouldn't be playing music with ref cnt of 0
00443                      check_assertion( mit->second.playing == false, 
00444                           "playing music with reference count of 0" );
00445                      Mix_FreeMusic( mit->second.data );
00446                      musicTable.erase(mit);
00447               }
00448        }
00449 }
00450 
00451 
00452 /* Name:          is_sound_data_dirty
00453 
00454    Description: Returns true if new sound data has been loaded since
00455    last call to mark_sound_data_clean()
00456 
00457    Precondition:  
00458    Return value:  true iff sound data dirty
00459    Modified args: 
00460    Author:        jfpatry
00461    Created:       2000-08-13
00462    Last Modified: 2000-08-13
00463 */
00464 bool
00465 is_sound_data_dirty()
00466 {
00467     //check_assertion( initialized_, "audio_data module not initialized" );
00468 
00469     return sound_dirty_;
00470 }
00471 
00472 /* Name:          is_music_data_dirty
00473 
00474    Description: Returns true if new music data has been loaded since
00475    last call to mark_music_data_clean()
00476 
00477    Precondition:  
00478    Return value:  true iff music data dirty
00479    Modified args: 
00480    Author:        jfpatry
00481    Created:       2000-08-13
00482    Last Modified: 2000-08-13
00483 */
00484 bool
00485 is_music_data_dirty()
00486 {
00487 //    check_assertion( initialized_, "audio_data module not initialized" );
00488 
00489     return music_dirty_;
00490 }
00491 
00492 
00493 /* Name:          mark_sound_data_clean
00494    Description:   Mark sound data as clean
00495    Precondition:  
00496    Return value:  
00497    Modified args: 
00498    Author:        jfpatry
00499    Created:       2000-08-13
00500    Last Modified: 2000-08-13
00501 */
00502 void
00503 mark_sound_data_clean()
00504 {
00505 //    check_assertion( initialized_, "audio_data module not initialized" );
00506 
00507     sound_dirty_ = false;
00508 }
00509 
00510 
00511 /* Name:          mark_music_data_clean
00512    Description:   Mark music data as clean
00513    Precondition:  
00514    Return value:  
00515    Modified args: 
00516    Author:        jfpatry
00517    Created:       2000-08-13
00518    Last Modified: 2000-08-13
00519 */
00520 void
00521 mark_music_data_clean()
00522 {
00523 //    check_assertion( initialized_, "audio_data module not initialized" );
00524 
00525     music_dirty_ = false;
00526 }
00527 
00528 
00529 /* Name:          load_sound_cb
00530    Description:   Tcl callback for tux_sound_load
00531    Precondition:  
00532    Return value:  Tcl error status
00533    Modified args: 
00534    Author:        jfpatry
00535    Created:       2000-08-13
00536    Last Modified: 2000-09-02
00537 */
00538 static int load_sound_cb( ClientData cd, Tcl_Interp *ip, 
00539                        int argc, CONST84 char *argv[]) 
00540 {
00541     Tcl_Obj *result;
00542 
00543 //    check_assertion( initialized_, "audio_data module not initialized" );
00544 
00545     if ( argc != 3 ) {
00546         Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n", 
00547                       "Usage: ", argv[0], " <name> <sound file>",
00548                       (char *)0 );
00549         return TCL_ERROR;
00550     } 
00551 
00552     result = Tcl_NewBooleanObj( load_sound( argv[1], argv[2] ) );
00553     Tcl_SetObjResult( ip, result );
00554     return TCL_OK;
00555 } 
00556 
00557 /* Name:          load_music_cb
00558    Description:   Tcl callback for tux_music_load
00559    Precondition:  
00560    Return value:  Tcl error status
00561    Modified args: 
00562    Author:        jfpatry
00563    Created:       2000-08-13
00564    Last Modified: 2000-09-02
00565 */
00566 static int load_music_cb( ClientData cd, Tcl_Interp *ip, 
00567                        int argc, CONST84 char *argv[]) 
00568 {
00569     Tcl_Obj *result;
00570 
00571 //    check_assertion( initialized_, "audio_data module not initialized" );
00572 
00573     if ( argc != 3 ) {
00574         Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n", 
00575                       "Usage: ", argv[0], " <name> <sound file>",
00576                       (char *)0 );
00577         return TCL_ERROR;
00578     } 
00579 
00580     result = Tcl_NewBooleanObj( load_music( argv[1], argv[2] ) );
00581     Tcl_SetObjResult( ip, result );
00582     return TCL_OK;
00583 } 
00584 
00585 
00586 /* Name:          register_sound_data_tcl_callbacks
00587    Description:   register sound data tcl callbacks ;)
00588    Precondition:  
00589    Return value:  
00590    Modified args: 
00591    Author:        jfpatry
00592    Created:       2000-08-13
00593    Last Modified: 2000-08-13
00594 */
00595 void register_sound_data_tcl_callbacks( Tcl_Interp *ip )
00596 {
00597     Tcl_CreateCommand (ip, "tux_load_sound", load_sound_cb,  0,0);
00598     Tcl_CreateCommand (ip, "tux_load_music", load_music_cb,  0,0);
00599 }
00600 
00601 #else
00602 
00603 void 
00604 init_audio_data()
00605 {
00606 }
00607 
00608 bool 
00609 load_sound( char *name, char *filename ) 
00610 { 
00611     return true;
00612 }
00613 
00614 bool 
00615 load_music( char *name, char *filename ) 
00616 { 
00617     return true;
00618 }
00619 
00620 bool
00621 get_sound_data( char *name, Mix_Chunk **data )
00622 {
00623     return false;
00624 }
00625 
00626 bool
00627 get_music_data( char *name, Mix_Music **data )
00628 {
00629     return false;
00630 }
00631 
00632 void
00633 set_music_playing_status( char *name, bool playing )
00634 {
00635 }
00636 
00637 
00638 bool
00639 get_music_playing_status( char *name )
00640 {
00641     return false;
00642 }
00643 
00644 void incr_sound_data_ref_ctr( char *name ) 
00645 {
00646 }
00647 
00648 void decr_sound_data_ref_ctr( char *name ) 
00649 {
00650 }
00651 
00652 void incr_music_data_ref_ctr( char *name ) 
00653 {
00654 }
00655 
00656 void decr_music_data_ref_ctr( char *name ) 
00657 {
00658 }
00659  
00660 void delete_unused_audio_data()
00661 {
00662 }
00663 
00664 bool
00665 is_sound_data_dirty()
00666 {
00667     return false;
00668 }
00669 
00670 bool
00671 is_music_data_dirty()
00672 {
00673     return false;
00674 }
00675 
00676 void
00677 mark_sound_data_clean()
00678 {
00679 }
00680 
00681 void
00682 mark_music_data_clean()
00683 {
00684 }
00685 
00686 
00687 static int load_sound_cb( ClientData cd, Tcl_Interp *ip, 
00688                        int argc, CONST84 char *argv[]) 
00689 {
00690     Tcl_Obj *result;
00691 
00692     result = Tcl_NewBooleanObj( 1 );
00693     Tcl_SetObjResult( ip, result );
00694     return TCL_OK;
00695 } 
00696 
00697 static int load_music_cb( ClientData cd, Tcl_Interp *ip, 
00698                        int argc, CONST84 char *argv[]) 
00699 {
00700     Tcl_Obj *result;
00701 
00702     result = Tcl_NewBooleanObj( 1 );
00703     Tcl_SetObjResult( ip, result );
00704     return TCL_OK;
00705 } 
00706 
00707 
00708 void register_sound_data_tcl_callbacks( Tcl_Interp *ip )
00709 {
00710     Tcl_CreateCommand (ip, "tux_load_sound", load_sound_cb,  0,0);
00711     Tcl_CreateCommand (ip, "tux_load_music", load_music_cb,  0,0);
00712 }
00713 
00714 #endif /* defined(HAVE_SDL_MIXER) */