00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 #include "OSDLSound.h"
00028 
00029 #include "OSDLAudio.h"               
00030 #include "OSDLFileTags.h"            
00031 
00032 
00033 #ifdef OSDL_USES_CONFIG_H
00034 #include "OSDLConfig.h"              
00035 #endif // OSDL_USES_CONFIG_H
00036 
00037 
00038 #if OSDL_ARCH_NINTENDO_DS
00039 #include "OSDLConfigForNintendoDS.h" 
00040 #endif // OSDL_ARCH_NINTENDO_DS
00041 
00042 
00043 
00044 #if OSDL_USES_SDL
00045 #include "SDL.h"                     
00046 #endif // OSDL_USES_SDL
00047 
00048 #if OSDL_USES_SDL_MIXER
00049 #include "SDL_mixer.h"               
00050 #endif // OSDL_USES_SDL_MIXER
00051 
00052 
00053 
00054 
00055 
00056 #if OSDL_DEBUG_AUDIO_PLAYBACK
00057 
00058 #define LOG_DEBUG_AUDIO(message)   LogPlug::debug(message)
00059 #define LOG_TRACE_AUDIO(message)   LogPlug::trace(message)
00060 #define LOG_WARNING_AUDIO(message) LogPlug::warning(message)
00061 
00062 #else // OSDL_DEBUG_AUDIO_PLAYBACK
00063 
00064 #define LOG_DEBUG_AUDIO(message)
00065 #define LOG_TRACE_AUDIO(message)
00066 #define LOG_WARNING_AUDIO(message)
00067 
00068 #endif // OSDL_DEBUG_AUDIO_PLAYBACK
00069 
00070 
00071 
00072 using std::string ;
00073 
00074 using Ceylan::System::Millisecond ;
00075 
00076 
00077 using namespace Ceylan::Log ;
00078 using namespace Ceylan::System ;
00079 
00080 using namespace OSDL::Audio ;
00081 
00082 
00083 
00084 
00085 
00113 SoundException::SoundException( const string & reason ) :
00114     AudibleException( reason )
00115 {
00116 
00117 }
00118 
00119 
00120     
00121 SoundException::~SoundException() throw()
00122 {
00123 
00124 }
00125 
00126 
00127 
00128 
00129 
00130 Sound::Sound( const std::string & soundFile, bool preload ) :
00131     Audible(  false ), 
00132     Ceylan::LoadableWithContent<LowLevelSound>( soundFile ),
00133     _dataStream( 0 )
00134 {
00135 
00136     if ( ! AudioModule::IsAudioInitialized() )
00137         throw SoundException( "Sound constructor failed: "
00138             "audio module not already initialized" ) ;
00139              
00140     if ( preload )
00141     {
00142     
00143         try
00144         {
00145         
00146             load() ;
00147             
00148         }
00149         catch( const Ceylan::LoadableException & e )
00150         {
00151         
00152             throw SoundException( "Sound constructor failed while preloading: "
00153                 + e.toString() ) ;
00154         }
00155             
00156     }
00157     
00158 }
00159 
00160 
00161 
00162 Sound::~Sound() throw()
00163 {
00164 
00165     try
00166     {
00167     
00168         if ( hasContent() )
00169             unload() ;
00170     
00171     }
00172     catch( const Ceylan::LoadableException & e )
00173     {
00174         
00175         LogPlug::error( "Sound destructor failed while unloading: " 
00176             + e.toString() ) ;
00177         
00178     }
00179 
00180     
00181     
00182 }
00183 
00184 
00185 
00186 
00187 
00188 
00189 
00190 
00191 
00192 bool Sound::load()
00193 {
00194 
00195     if ( hasContent() )
00196         return false ;
00197 
00198 #if OSDL_ARCH_NINTENDO_DS
00199         
00200 #ifdef OSDL_RUNS_ON_ARM7
00201 
00202     throw Ceylan::LoadableException( "Sound::load failed: "
00203         "not supported on the ARM7" ) ;
00204 
00205 #elif defined(OSDL_RUNS_ON_ARM9)
00206 
00207 
00208     
00209 
00210 
00211 
00212 
00213 
00214 
00215     try
00216     {
00217     
00218         _content = new LowLevelSound() ;
00219         
00220         
00221         
00222         File & soundFile = File::Open( _contentPath ) ;
00223         
00224         
00225         FileTag readTag = soundFile.readUint16() ;
00226         
00227         if ( readTag != SoundTag )
00228             throw Ceylan::LoadableException( 
00229                 "Sound::load: expected sound tag not found ("
00230                 + Ceylan::toString( SoundTag ) + "), read instead "
00231                 + Ceylan::toString( readTag ) + ", which corresponds to: "
00232                 + DescribeFileTag( readTag ) ) ;
00233             
00234         
00235         _content->_frequency = soundFile.readUint16()  ;
00236 
00237 
00238         
00239         SampleFormat readFormat = soundFile.readUint16() ;
00240         
00241         
00242 
00243 
00244 
00245 
00246 
00247 
00248 
00249 
00250 
00251 
00252 
00253 
00254 
00255 
00256 
00257 
00258 
00259 
00260 
00261 
00262 
00263 
00264 
00265         
00266         if ( readFormat == AudioModule::LittleSint16SampleFormat )
00267             _content->_bitDepth = 16 ;
00268         else if ( readFormat == AudioModule::Sint8SampleFormat )
00269             _content->_bitDepth = 8 ;
00270         else if ( readFormat == AudioModule::IMAADPCMSampleFormat )
00271             _content->_bitDepth = 4  ;
00272         else
00273             throw Ceylan::LoadableException( "Sound::load failed: "
00274                 "unexpected bit depth (" + Ceylan::toString( readFormat )
00275                 + ") read from sound file '" + _contentPath + "'" ) ;
00276             
00277                 
00278         
00279         ChannelFormat readMode = soundFile.readUint16() ;
00280         
00281         if ( readMode != AudioModule::Mono
00282                 && readMode != AudioModule::Stereo )
00283             throw Ceylan::LoadableException( "Sound::load failed: "
00284                 "unexpected channel format read from sound file '" 
00285                 + _contentPath + "'" ) ;
00286              
00287         _content->_mode = static_cast<Ceylan::Uint8>( readMode ) ;
00288         
00289         
00290         Ceylan::Uint32 readSize = soundFile.size() - 4*sizeof(Ceylan::Uint16) ;
00291 
00292         LOG_DEBUG_AUDIO( "Sound::load: for '" + _contentPath 
00293             + "', bit depth is " 
00294             + Ceylan::toNumericalString( _content->_bitDepth ) 
00295             + ", channel mode is " 
00296             + Ceylan::toNumericalString( _content->_mode )
00297             + ", frequency is " + Ceylan::toString( _content->_frequency ) 
00298             + " Hz, size of all samples is " + Ceylan::toString( readSize )
00299             + " bytes." ) ;
00300         
00301         _content->_size = readSize ;   
00302             
00303         
00304         _content->_samples = CacheProtectedNew( readSize ) ;   
00305         
00306         soundFile.readExactLength( _content->_samples, readSize ) ;
00307 
00308         
00309         DC_FlushRange( (void*) _content->_samples, readSize ) ;
00310                 
00311         delete & soundFile ;    
00312     
00313     }
00314     catch( const Ceylan::System::SystemException & e )
00315     {
00316     
00317         throw Ceylan::LoadableException( "Sound::load failed: "
00318             + e.toString() ) ;
00319     
00320     }
00321         
00322     _convertedToOutputFormat = true ;
00323     
00324     return true ;
00325             
00326 #endif // OSDL_RUNS_ON_ARM7
00327 
00328 #else // OSDL_ARCH_NINTENDO_DS
00329         
00330 #if OSDL_USES_SDL_MIXER
00331 
00332     
00333 
00334 
00335 
00336 
00337 
00338     if ( hasContent() )
00339         return false ;
00340 
00341     try
00342     {
00343     
00344         
00345         
00346         
00347 
00348 
00349 
00350 
00351 
00352 
00353 
00354     
00355         Ceylan::System::File & soundFile = File::Open( _contentPath ) ;
00356         
00357         
00358 
00359 
00360 
00361         
00362         
00363 
00364         _dataStream = & Utils::createDataStreamFrom( soundFile ) ;
00365 
00366         
00367 
00368 
00369 
00370 
00371 
00372 
00373 
00374 
00375 
00376 
00377 
00378 
00379 
00380 
00381 
00382 
00383 
00384 
00385         _content = ::Mix_LoadWAV_RW( _dataStream,
00386              true ) ;
00387         
00388          
00389         
00390         
00391         
00392     }
00393     catch( const Ceylan::Exception & e )
00394     {
00395     
00396         throw Ceylan::LoadableException( "Sound::load failed: '"
00397             "unable to locate '" + _contentPath + "': " + e.toString() ) ;
00398             
00399     }   
00400     
00401     if ( _content == 0 )
00402         throw Ceylan::LoadableException( "Sound::load failed: "
00403             + string( ::Mix_GetError() ) ) ;
00404     
00405     _convertedToOutputFormat = true ;
00406     
00407     return true ;
00408     
00409 #else // OSDL_USES_SDL_MIXER
00410 
00411     throw Ceylan::LoadableException( 
00412         "Sound::load failed: no SDL_mixer support available." ) ;
00413     
00414 #endif // OSDL_USES_SDL_MIXER
00415 
00416 #endif // OSDL_ARCH_NINTENDO_DS
00417 
00418 }
00419 
00420 
00421 
00422 bool Sound::unload()
00423 {
00424 
00425     if ( ! hasContent() )
00426         return false ;
00427 
00428     
00429 
00430 #if OSDL_ARCH_NINTENDO_DS
00431         
00432 #ifdef OSDL_RUNS_ON_ARM7
00433 
00434     throw Ceylan::LoadableException( "Sound::unload failed: "
00435         "not supported on the ARM7" ) ;
00436 
00437 #elif defined(OSDL_RUNS_ON_ARM9)
00438 
00439     if ( _content->_samples != 0 )
00440         CacheProtectedDelete( _content->_samples ) ;
00441 
00442     delete _content ;
00443 
00444     
00445 #endif // OSDL_RUNS_ON_ARM7
00446 
00447 #else // OSDL_ARCH_NINTENDO_DS
00448     
00449 #if OSDL_USES_SDL_MIXER
00450 
00451     ::Mix_FreeChunk( _content ) ;
00452     
00453 
00454     
00455 
00456 
00457 
00458 
00459 
00460 
00461 
00462 
00463 
00464 
00465 
00466 
00467 
00468 
00469 
00470 
00471 
00472 
00473 
00474     
00475     _dataStream = 0 ;
00476     
00477 #else // OSDL_USES_SDL_MIXER
00478 
00479     throw Ceylan::LoadableException( 
00480         "Sound::unload failed: no SDL_mixer support available." ) ;
00481     
00482 #endif // OSDL_USES_SDL_MIXER
00483 
00484 #endif // OSDL_ARCH_NINTENDO_DS
00485 
00486     _content = 0 ;
00487     
00488     return true ;
00489 
00490 }
00491 
00492 
00493 
00494 
00495 
00496 
00497 
00498 
00499 
00500 Volume Sound::getVolume() const
00501 {
00502 
00503 #if OSDL_USES_SDL_MIXER
00504     
00505     try
00506     {
00507     
00508         if ( hasContent() )
00509             return ::Mix_VolumeChunk( const_cast<LowLevelSound *>( 
00510                 & getExistingContentAsConst() ),  -1 ) ;
00511         else
00512             throw SoundException( 
00513                 "Sound::getVolume failed: no loaded sound available." ) ;
00514                 
00515     }
00516     catch( const Ceylan::LoadableException & e )
00517     {
00518     
00519         throw SoundException( "Sound::getVolume failed: " + e.toString() ) ;
00520         
00521     }
00522             
00523 #else // OSDL_USES_SDL_MIXER
00524 
00525     throw SoundException( 
00526         "Sound::getVolume failed: no SDL_mixer support available." ) ;
00527     
00528 #endif // OSDL_USES_SDL_MIXER
00529 
00530 }
00531 
00532 
00533 
00534 void Sound::setVolume( Volume newVolume )
00535 {
00536 
00537 #if OSDL_USES_SDL_MIXER
00538     
00539     try
00540     {
00541     
00542         if ( hasContent() )
00543             ::Mix_VolumeChunk( & getExistingContent(), 
00544                 static_cast<int>( newVolume ) ) ;
00545         else
00546             throw SoundException( 
00547                 "Sound::setVolume failed: no loaded sound available." ) ;
00548                 
00549     }
00550     catch( const Ceylan::LoadableException & e )
00551     {
00552     
00553         
00554         throw SoundException( "Sound::setVolume failed: " + e.toString() ) ;
00555         
00556     }
00557             
00558 #else // OSDL_USES_SDL_MIXER
00559 
00560     throw SoundException( 
00561         "Sound::setVolume failed: no SDL_mixer support available." ) ;
00562     
00563 #endif // OSDL_USES_SDL_MIXER
00564 
00565 }
00566 
00567 
00568 
00569 
00570 
00571 
00572 
00573 
00574 
00575 
00576 
00577 
00578 void Sound::play( PlaybackCount playCount )
00579 {
00580 
00581 #if OSDL_ARCH_NINTENDO_DS
00582         
00583 #ifdef OSDL_RUNS_ON_ARM7
00584 
00585     throw SoundException( "Sound::play failed: not supported on the ARM7" ) ;
00586 
00587 #elif defined(OSDL_RUNS_ON_ARM9)
00588 
00589 
00590     try
00591     {
00592     
00593         CommandManager::GetExistingCommandManager().playSound( *this ) ;
00594         
00595     }
00596     catch( const CommandException & e )
00597     {
00598     
00599         throw SoundException( "Sound::play failed: " + e.toString() ) ;
00600         
00601     }
00602     
00603         
00604 #endif // OSDL_RUNS_ON_ARM7
00605 
00606 #else // OSDL_ARCH_NINTENDO_DS
00607 
00608     
00609     playReturnChannel( playCount ) ;
00610 
00611 #endif // OSDL_ARCH_NINTENDO_DS
00612 
00613 }
00614 
00615 
00616 
00617 ChannelNumber Sound::playReturnChannel( PlaybackCount playCount ) 
00618 {
00619 
00620 #if OSDL_USES_SDL_MIXER
00621     
00622     if ( ! hasContent() )
00623         throw AudibleException( "Sound::playReturnChannel failed: "
00624             "no loaded sound available." ) ;
00625             
00626     int channelNumber = ::Mix_PlayChannel( 
00627          -1, _content, 
00628         GetLoopsForPlayCount( playCount ) ) ;
00629     
00630     if ( channelNumber == -1 )      
00631         throw SoundException( "Sound::playReturnChannel failed: "
00632             + string( ::Mix_GetError() ) ) ;
00633     else
00634         return static_cast<ChannelNumber>( channelNumber ) ;
00635             
00636 #else // OSDL_USES_SDL_MIXER
00637 
00638     throw SoundException( 
00639         "Sound::playReturnChannel failed: no SDL_mixer support available." ) ;
00640     
00641 #endif // OSDL_USES_SDL_MIXER
00642 
00643 }
00644 
00645 
00646 
00647 void Sound::play( ChannelNumber mixingChannelNumber, PlaybackCount playCount )
00648 {
00649 
00650 #if OSDL_USES_SDL_MIXER
00651 
00652     if ( ! hasContent() )
00653         throw AudibleException( "Sound::play failed: "
00654             "no loaded sound available." ) ;
00655             
00656     if ( ::Mix_PlayChannel( mixingChannelNumber, _content, 
00657             GetLoopsForPlayCount( playCount ) ) == -1 )
00658         throw SoundException( "Sound::play failed: "
00659             + string( ::Mix_GetError() ) ) ;
00660             
00661 #else // OSDL_USES_SDL_MIXER
00662 
00663     throw SoundException( 
00664         "Sound::play failed: no SDL_mixer support available." ) ;
00665     
00666 #endif // OSDL_USES_SDL_MIXER
00667 
00668 }
00669 
00670 
00671 
00672 
00673 
00674 
00675 
00676 
00677 void Sound::playForAtMost( Ceylan::System::Millisecond maxDuration, 
00678     PlaybackCount playCount )
00679 {
00680 
00681     
00682     playForAtMostReturnChannel( maxDuration, playCount ) ;
00683 
00684 }
00685 
00686 
00687 
00688 ChannelNumber Sound::playForAtMostReturnChannel( 
00689     Ceylan::System::Millisecond maxDuration, PlaybackCount playCount ) 
00690 {
00691 
00692 #if OSDL_USES_SDL_MIXER
00693         
00694     if ( ! hasContent() )
00695         throw AudibleException( "Sound::playForAtMostReturnChannel failed: "
00696             "no loaded sound available." ) ;
00697 
00698     int channelNumber = ::Mix_PlayChannelTimed( 
00699          -1, _content, 
00700         GetLoopsForPlayCount( playCount ), maxDuration ) ;
00701         
00702     if ( channelNumber == -1 )      
00703         throw SoundException( "Sound::playForAtMostReturnChannel failed: "
00704             + string( ::Mix_GetError() ) ) ;
00705     else
00706         return static_cast<ChannelNumber>( channelNumber ) ;
00707             
00708 #else // OSDL_USES_SDL_MIXER
00709 
00710     throw SoundException( "Sound::playForAtMostReturnChannel failed: "
00711         "no SDL_mixer support available." ) ;
00712     
00713 #endif // OSDL_USES_SDL_MIXER
00714 
00715 }
00716 
00717 
00718 
00719 void Sound::playForAtMost( Ceylan::System::Millisecond maxDuration, 
00720     ChannelNumber mixingChannelNumber, PlaybackCount playCount ) 
00721 {
00722 
00723 #if OSDL_USES_SDL_MIXER
00724                 
00725     if ( ! hasContent() )
00726         throw AudibleException( "Sound::playForAtMost failed: "
00727             "no loaded sound available." ) ;
00728 
00729     if ( ::Mix_PlayChannelTimed( mixingChannelNumber, _content,
00730             GetLoopsForPlayCount( playCount ), maxDuration ) == -1 )        
00731         throw SoundException( "Sound::playForAtMost failed: "
00732             + string( ::Mix_GetError() ) ) ;
00733             
00734 #else // OSDL_USES_SDL_MIXER
00735 
00736     throw SoundException( "Sound::playForAtMost failed: "
00737         "no SDL_mixer support available." ) ;
00738     
00739 #endif // OSDL_USES_SDL_MIXER
00740 
00741 }
00742 
00743 
00744 
00745 
00746 
00747 
00748 
00749 
00750 void Sound::playWithFadeIn( Ceylan::System::Millisecond fadeInMaxDuration,
00751     PlaybackCount playCount )
00752 {
00753 
00754     
00755     playWithFadeInReturnChannel( fadeInMaxDuration, playCount ) ;
00756 
00757     
00758 }
00759 
00760 
00761 
00762 ChannelNumber Sound::playWithFadeInReturnChannel( 
00763     Ceylan::System::Millisecond fadeInMaxDuration, PlaybackCount playCount )
00764 {
00765 
00766 #if OSDL_USES_SDL_MIXER
00767         
00768     if ( ! hasContent() )
00769         throw AudibleException( "Sound::playWithFadeInReturnChannel failed: "
00770             "no loaded sound available." ) ;
00771 
00772     int channelNumber = ::Mix_FadeInChannel( 
00773          -1, _content, 
00774         GetLoopsForPlayCount( playCount ), fadeInMaxDuration ) ;
00775         
00776     if ( channelNumber == -1 )      
00777         throw SoundException( "Sound::playWithFadeInReturnChannel failed: "
00778             + string( ::Mix_GetError() ) ) ;
00779     else
00780         return static_cast<ChannelNumber>( channelNumber ) ;
00781             
00782 #else // OSDL_USES_SDL_MIXER
00783 
00784     throw SoundException( "Sound::playWithFadeInReturnChannel failed: "
00785         "no SDL_mixer support available." ) ;
00786     
00787 #endif // OSDL_USES_SDL_MIXER
00788 
00789 }
00790 
00791 
00792 
00793 void Sound::playWithFadeIn( Ceylan::System::Millisecond fadeInMaxDuration,
00794     ChannelNumber mixingChannelNumber, PlaybackCount playCount ) 
00795 {
00796 
00797 #if OSDL_USES_SDL_MIXER
00798         
00799     if ( ! hasContent() )
00800         throw AudibleException( "Sound::playWithFadeIn failed: "
00801             "no loaded sound available." ) ;
00802 
00803     if ( ::Mix_FadeInChannel( mixingChannelNumber, _content, 
00804             GetLoopsForPlayCount( playCount ), fadeInMaxDuration ) == -1 )      
00805         throw SoundException( "Sound::playWithFadeIn failed: "
00806             + string( ::Mix_GetError() ) ) ;
00807 
00808 #else // OSDL_USES_SDL_MIXER
00809 
00810     throw SoundException( "Sound::playWithFadeIn failed: "
00811         "no SDL_mixer support available." ) ;
00812     
00813 #endif // OSDL_USES_SDL_MIXER
00814 
00815     
00816 }
00817 
00818 
00819 
00820 
00821 
00822 
00823 
00824 void Sound::playWithFadeInForAtMost( 
00825     Ceylan::System::Millisecond playbackMaxDuration,
00826     Ceylan::System::Millisecond fadeInMaxDuration,
00827     PlaybackCount playCount ) 
00828 {
00829 
00830     
00831     playWithFadeInForAtMostReturnChannel( playbackMaxDuration,
00832         fadeInMaxDuration, playCount ) ;
00833 
00834 }
00835 
00836     
00837                     
00838 ChannelNumber Sound::playWithFadeInForAtMostReturnChannel( 
00839     Ceylan::System::Millisecond playbackMaxDuration,
00840     Ceylan::System::Millisecond fadeInMaxDuration,
00841     PlaybackCount playCount ) 
00842 {
00843 
00844 #if OSDL_USES_SDL_MIXER
00845     
00846     if ( ! hasContent() )
00847         throw AudibleException( 
00848             "Sound::playWithFadeInForAtMostReturnChannel failed: "
00849             "no loaded sound available." ) ;
00850 
00851     int channelNumber = ::Mix_FadeInChannelTimed( 
00852          -1, _content, 
00853         GetLoopsForPlayCount( playCount ), fadeInMaxDuration,
00854         playbackMaxDuration ) ;
00855         
00856     if ( channelNumber == -1 )      
00857         throw SoundException( 
00858             "Sound::playWithFadeInForAtMostReturnChannel failed: "
00859             + string( ::Mix_GetError() ) ) ;
00860     else
00861         return static_cast<ChannelNumber>( channelNumber ) ;
00862             
00863 #else // OSDL_USES_SDL_MIXER
00864 
00865     throw SoundException( "Sound::playWithFadeInForAtMostReturnChannel failed: "
00866         "no SDL_mixer support available." ) ;
00867     
00868 #endif // OSDL_USES_SDL_MIXER
00869 
00870 }
00871 
00872 
00873                     
00874 void Sound::playWithFadeInForAtMost( 
00875     Ceylan::System::Millisecond playbackMaxDuration,
00876     Ceylan::System::Millisecond fadeInMaxDuration,
00877     ChannelNumber mixingChannelNumber,
00878     PlaybackCount playCount ) 
00879 {
00880 
00881 #if OSDL_USES_SDL_MIXER
00882         
00883     if ( ! hasContent() )
00884         throw AudibleException( "Sound::playWithFadeInForAtMost failed: "
00885             "no loaded sound available." ) ;
00886             
00887     if ( ::Mix_FadeInChannelTimed( mixingChannelNumber, _content, 
00888             GetLoopsForPlayCount( playCount ), fadeInMaxDuration,
00889             playbackMaxDuration ) == -1 )       
00890         throw SoundException( "Sound::playWithFadeInForAtMost failed: "
00891             + string( ::Mix_GetError() ) ) ;
00892 
00893 #else // OSDL_USES_SDL_MIXER
00894 
00895     throw SoundException( "Sound::playWithFadeInForAtMost failed: "
00896         "no SDL_mixer support available." ) ;
00897     
00898 #endif // OSDL_USES_SDL_MIXER
00899 
00900 }
00901 
00902                                                                 
00903                     
00904 const string Sound::toString( Ceylan::VerbosityLevels level ) const
00905 {
00906     
00907     if ( level == Ceylan::low )
00908         return ( hasContent() ? string( "Loaded" ) : string( "Not loaded" ) )
00909             + " sound, whose content path is '" + _contentPath + "'" ;
00910 
00911 
00912     try
00913     {
00914     
00915         if ( hasContent() )
00916         {
00917         
00918             Volume v = getVolume() ;
00919     
00920             return "Loaded sound whose volume is " 
00921                 + Ceylan::toNumericalString( v )
00922                 + " (" + Ceylan::toString( 100 * v 
00923                     / ( AudioModule::MaxVolume - AudioModule::MinVolume ) )
00924                 + "%)" ;
00925             
00926         }
00927         else
00928         {
00929         
00930             return "Sound currently not loaded, whose content path is '" 
00931                 + _contentPath + "'" ;
00932             
00933         }       
00934     
00935     }
00936     catch(  const Ceylan::Exception & e )
00937     {
00938     
00939         return "Sound::toString failed (abnormal): " + e.toString() ;
00940          
00941     }
00942     
00943 }
00944