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 "OSDLMusic.h"
00028
00029 #include "OSDLAudio.h"
00030 #include "OSDLFileTags.h"
00031 #include "OSDLUtils.h"
00032
00033
00034 #ifdef OSDL_USES_CONFIG_H
00035 #include "OSDLConfig.h"
00036 #endif // OSDL_USES_CONFIG_H
00037
00038
00039 #if OSDL_ARCH_NINTENDO_DS
00040 #include "OSDLConfigForNintendoDS.h"
00041 #endif // OSDL_ARCH_NINTENDO_DS
00042
00043
00044
00045 #if OSDL_USES_SDL
00046 #include "SDL.h"
00047 #endif // OSDL_USES_SDL
00048
00049 #if OSDL_USES_SDL_MIXER
00050 #include "SDL_mixer.h"
00051 #endif // OSDL_USES_SDL_MIXER
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
00147 extern const BitrateType OSDL::Audio::CBR = 1 ;
00148 extern const BitrateType OSDL::Audio::VBR = 2 ;
00149
00150
00151
00152 MusicException::MusicException( const string & reason ) :
00153 AudibleException( reason )
00154 {
00155
00156 }
00157
00158
00159
00160 MusicException::~MusicException() throw()
00161 {
00162
00163 }
00164
00165
00166
00167
00169 Music * Music::_CurrentMusic = 0 ;
00170
00171
00172
00173
00174 #if OSDL_ARCH_NINTENDO_DS
00175
00176 const OSDL::CommandManagerSettings * Music::_CommandManagerSettings = 0 ;
00177
00178 #endif // OSDL_ARCH_NINTENDO_DS
00179
00180
00181
00182
00183 Music::Music( const std::string & musicFilename, bool preload ) :
00184 Audible( false ),
00185 Ceylan::LoadableWithContent<LowLevelMusic>( musicFilename ),
00186 _dataStream( 0 ),
00187 _isPlaying( false )
00188 {
00189
00190 if ( ! AudioModule::IsAudioInitialized() )
00191 throw MusicException( "Music constructor failed: "
00192 "audio module not already initialized" ) ;
00193
00194
00195
00196 #if ! OSDL_ARCH_NINTENDO_DS
00197
00198 if ( preload )
00199 {
00200
00201 try
00202 {
00203
00204 load() ;
00205
00206 }
00207 catch( const Ceylan::LoadableException & e )
00208 {
00209
00210 throw MusicException( "Music constructor failed while preloading: "
00211 + e.toString() ) ;
00212
00213 }
00214
00215 }
00216
00217 #endif // OSDL_ARCH_NINTENDO_DS
00218
00219 }
00220
00221
00222
00223 Music::~Music() throw()
00224 {
00225
00226 if ( _CurrentMusic == this )
00227 {
00228
00229 try
00230 {
00231 manageNoMoreCurrent() ;
00232
00233 }
00234 catch( const AudioException & e )
00235 {
00236
00237 LogPlug::error( "Music destructor failed "
00238 "while unsetting 'current music' status: " + e.toString() ) ;
00239
00240 }
00241
00242 }
00243
00244
00245 try
00246 {
00247
00248 if ( hasContent() )
00249 unload() ;
00250
00251 }
00252 catch( const Ceylan::LoadableException & e )
00253 {
00254
00255 LogPlug::error( "Music destructor failed while unloading: "
00256 + e.toString() ) ;
00257
00258 }
00259
00260
00261
00262
00263
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 bool Music::load()
00275 {
00276
00277 #if OSDL_ARCH_NINTENDO_DS
00278
00279 #ifdef OSDL_RUNS_ON_ARM7
00280
00281 throw Ceylan::LoadableException( "Music::load failed: "
00282 "not supported on the ARM7" ) ;
00283
00284 #elif defined(OSDL_RUNS_ON_ARM9)
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 _content = new LowLevelMusic() ;
00302
00303 LowLevelMusic & music = *_content ;
00304
00305
00306 try
00307 {
00308
00309
00310
00311
00312 music._musicFile = & File::Open( _contentPath ) ;
00313
00314
00315 FileTag readTag = music._musicFile->readUint16() ;
00316
00317 if ( readTag != MusicTag )
00318 throw Ceylan::LoadableException(
00319 "Music::load: expected music tag not found ("
00320 + Ceylan::toString( MusicTag ) + "), read instead "
00321 + Ceylan::toString( readTag ) + ", which corresponds to: "
00322 + DescribeFileTag( readTag ) ) ;
00323
00324 LOG_DEBUG_AUDIO( "Music::load: correct tag found." ) ;
00325
00326
00327 music._frequency = music._musicFile->readUint16() ;
00328
00329
00330 music._bitDepth = 16 ;
00331
00332
00333 music._mode = music._musicFile->readUint16() ;
00334
00335
00336 music._musicFile->readUint8() ;
00337
00338 music._size = music._musicFile->size() ;
00339
00340
00341 music._frameSizeUpperBound = music._musicFile->readUint16() ;
00342
00343
00344
00345 if ( _CommandManagerSettings->_bufferSize <=
00346 music._frameSizeUpperBound )
00347 throw Ceylan::LoadableException( "Music::load: "
00348 "buffer to small compared to frame size upper bound." ) ;
00349
00350
00351 music._startAfterDelta = _CommandManagerSettings->_doubleBuffer
00352 + music._frameSizeUpperBound ;
00353
00354 music._firstActualRefillSize =
00355 _CommandManagerSettings->_bufferSize - music._frameSizeUpperBound ;
00356
00357
00358
00359
00360
00361
00362 fillFirstBuffer() ;
00363
00364 music._requestFillOfSecondBuffer = true ;
00365
00366
00367 music._playbackCount = 1 ;
00368
00369 }
00370 catch( const Ceylan::System::SystemException & e )
00371 {
00372
00373 throw Ceylan::LoadableException( "Music::load failed: "
00374 + e.toString() ) ;
00375
00376 }
00377
00378 LOG_DEBUG_AUDIO( "Music::load: read first chunk of " + _contentPath +
00379 + " (" + Ceylan::toString( music._firstActualRefillSize)
00380 + " out of a total of " + Ceylan::toString( music._size )
00381 + " bytes)." ) ;
00382
00383
00384 _convertedToOutputFormat = true ;
00385
00386 return true ;
00387
00388 #endif // OSDL_RUNS_ON_ARM7
00389
00390 #else // OSDL_ARCH_NINTENDO_DS
00391
00392 #if OSDL_USES_SDL_MIXER
00393
00394
00395
00396
00397
00398
00399
00400
00401 if ( hasContent() )
00402 return false ;
00403
00404 try
00405 {
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 Ceylan::System::File & musicFile = File::Open( _contentPath ) ;
00420
00421
00422
00423
00424
00425
00426
00427
00428 _dataStream = & Utils::createDataStreamFrom( musicFile ) ;
00429
00430 _content = ::Mix_LoadMUS_RW( _dataStream ) ;
00431
00432
00433
00434 }
00435 catch( const Ceylan::Exception & e )
00436 {
00437
00438 throw Ceylan::LoadableException( "Music::load failed: "
00439 "unable to load from '" + _contentPath + "': " + e.toString() ) ;
00440
00441 }
00442
00443 if ( _content == 0 )
00444 throw Ceylan::LoadableException( "Music::load failed: "
00445 + string( ::Mix_GetError() ) ) ;
00446
00447 _convertedToOutputFormat = true ;
00448
00449 return true ;
00450
00451 #else // OSDL_USES_SDL_MIXER
00452
00453 throw Ceylan::LoadableException(
00454 "Music::load failed: no SDL_mixer support available." ) ;
00455
00456 #endif // OSDL_USES_SDL_MIXER
00457
00458 #endif // OSDL_ARCH_NINTENDO_DS
00459
00460 }
00461
00462
00463
00464 bool Music::unload()
00465 {
00466
00467 if ( ! hasContent() )
00468 return false ;
00469
00470
00471 #if OSDL_ARCH_NINTENDO_DS
00472
00473 #ifdef OSDL_RUNS_ON_ARM7
00474
00475 throw Ceylan::LoadableException( "Music::unload failed: "
00476 "not supported on the ARM7" ) ;
00477
00478 #elif defined(OSDL_RUNS_ON_ARM9)
00479
00480
00481 if ( _content->_musicFile != 0 )
00482 delete _content->_musicFile ;
00483
00484 delete _content ;
00485
00486 #endif // OSDL_RUNS_ON_ARM7
00487
00488 #else // OSDL_ARCH_NINTENDO_DS
00489
00490 #if OSDL_USES_SDL_MIXER
00491
00492
00493
00494
00495 ::Mix_FreeMusic( _content ) ;
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 _dataStream = 0 ;
00522
00523 #else // OSDL_USES_SDL_MIXER
00524
00525 throw Ceylan::LoadableException(
00526 "Music::unload failed: no SDL_mixer support available." ) ;
00527
00528 #endif // OSDL_USES_SDL_MIXER
00529
00530 #endif // OSDL_ARCH_NINTENDO_DS
00531
00532 _content = 0 ;
00533
00534 return true ;
00535
00536 }
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 Volume Music::getVolume() const
00547 {
00548
00549 #if OSDL_USES_SDL_MIXER
00550
00551 try
00552 {
00553
00554 if ( hasContent() )
00555 return::Mix_VolumeMusic( -1 ) ;
00556 else
00557 throw MusicException(
00558 "Music::getVolume failed: no loaded music available." ) ;
00559
00560 }
00561 catch( const Ceylan::LoadableException & e )
00562 {
00563
00564 throw MusicException( "Music::getVolume failed: " + e.toString() ) ;
00565
00566 }
00567
00568 #else // OSDL_USES_SDL_MIXER
00569
00570 throw MusicException(
00571 "Music::getVolume failed: no SDL_mixer support available." ) ;
00572
00573 #endif // OSDL_USES_SDL_MIXER
00574
00575 }
00576
00577
00578
00579 void Music::setVolume( Volume newVolume )
00580 {
00581
00582 #if OSDL_ARCH_NINTENDO_DS
00583
00584 #ifdef OSDL_RUNS_ON_ARM7
00585
00586 throw MusicException(
00587 "Music::setVolume failed: not supported on the ARM7" ) ;
00588
00589 #elif defined(OSDL_RUNS_ON_ARM9)
00590
00591
00592 _CommandManagerSettings->_commandManager->setMusicVolume( newVolume ) ;
00593
00594
00595 #endif // OSDL_RUNS_ON_ARM7
00596
00597
00598 #else // OSDL_ARCH_NINTENDO_DS
00599
00600
00601 #if OSDL_USES_SDL_MIXER
00602
00603 try
00604 {
00605
00606 if ( hasContent() )
00607 ::Mix_VolumeMusic( static_cast<int>( newVolume ) ) ;
00608 else
00609 throw MusicException(
00610 "Music::setVolume failed: no loaded music available." ) ;
00611
00612 }
00613 catch( const Ceylan::LoadableException & e )
00614 {
00615
00616
00617 throw MusicException( "Music::setVolume failed: " + e.toString() ) ;
00618
00619 }
00620
00621 #else // OSDL_USES_SDL_MIXER
00622
00623 throw MusicException(
00624 "Music::setVolume failed: no SDL_mixer support available." ) ;
00625
00626 #endif // OSDL_USES_SDL_MIXER
00627
00628 #endif // OSDL_ARCH_NINTENDO_DS
00629
00630 }
00631
00632
00633
00634 MusicType Music::getType() const
00635 {
00636
00637 #if OSDL_USES_SDL_MIXER
00638
00639 return GetTypeOf( this ) ;
00640
00641 #else // OSDL_USES_SDL_MIXER
00642
00643 throw MusicException(
00644 "Music::setVolume failed: no SDL_mixer support available." ) ;
00645
00646 #endif // OSDL_USES_SDL_MIXER
00647
00648 }
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 void Music::play( PlaybackCount playCount )
00662 {
00663
00664 if ( playCount == 0 )
00665 return ;
00666
00667 _isPlaying = true ;
00668
00669 #if OSDL_ARCH_NINTENDO_DS
00670
00671 #ifdef OSDL_RUNS_ON_ARM7
00672
00673 throw MusicException( "Music::play failed: not supported on the ARM7" ) ;
00674
00675 #elif defined(OSDL_RUNS_ON_ARM9)
00676
00677 if ( hasContent() )
00678 unload() ;
00679
00680 load() ;
00681
00682 _content->_playbackCount = playCount ;
00683
00684 try
00685 {
00686
00687 if ( _content->_playbackCount != Loop )
00688 _content->_playbackCount-- ;
00689
00690 _CommandManagerSettings->_commandManager->playMusic( *this ) ;
00691
00692 }
00693 catch( const CommandException & e )
00694 {
00695
00696 throw MusicException( "Music::play failed: " + e.toString() ) ;
00697
00698 }
00699
00700 return ;
00701
00702 #endif // OSDL_RUNS_ON_ARM7
00703
00704 #else // OSDL_ARCH_NINTENDO_DS
00705
00706 #if OSDL_USES_SDL_MIXER
00707
00708 if ( ! hasContent() )
00709 throw MusicException( "Music::play failed: "
00710 "no loaded music available" ) ;
00711
00712 if ( ::Mix_PlayMusic( _content, GetLoopsForPlayCount( playCount ) ) == -1 )
00713 throw MusicException( "Music::play failed: "
00714 + string( ::Mix_GetError() ) ) ;
00715
00716 #else // OSDL_USES_SDL_MIXER
00717
00718 throw MusicException(
00719 "Music::play failed: no SDL_mixer support available." ) ;
00720
00721 #endif // OSDL_USES_SDL_MIXER
00722
00723 #endif // OSDL_ARCH_NINTENDO_DS
00724
00725 }
00726
00727
00728
00729
00730
00731
00732
00733 void Music::playWithFadeIn( Ceylan::System::Millisecond fadeInMaxDuration,
00734 PlaybackCount playCount )
00735 {
00736
00737 _isPlaying = true ;
00738
00739 #if OSDL_ARCH_NINTENDO_DS
00740
00741 #ifdef OSDL_RUNS_ON_ARM7
00742
00743 throw MusicException(
00744 "Music::playWithFadeIn failed: not supported on the ARM7" ) ;
00745
00746 #elif defined(OSDL_RUNS_ON_ARM9)
00747
00748 if ( hasContent() )
00749 unload() ;
00750
00751 load() ;
00752
00753 _content->_playbackCount = playCount ;
00754
00755 try
00756 {
00757
00758 if ( _content->_playbackCount != Loop )
00759 _content->_playbackCount-- ;
00760
00761 _CommandManagerSettings->_commandManager->playMusicWithFadeIn( *this,
00762 fadeInMaxDuration ) ;
00763
00764 }
00765 catch( const CommandException & e )
00766 {
00767
00768 throw MusicException( "Music::playWithFadeIn failed: "
00769 + e.toString() ) ;
00770
00771 }
00772
00773 return ;
00774
00775 #endif // OSDL_RUNS_ON_ARM7
00776
00777 #else // OSDL_ARCH_NINTENDO_DS
00778
00779
00780 #if OSDL_USES_SDL_MIXER
00781
00782 if ( ! hasContent() )
00783 throw AudibleException( "Music::playWithFadeIn failed: "
00784 "no loaded music available" ) ;
00785
00786 if ( ::Mix_FadeInMusic( _content, GetLoopsForPlayCount( playCount ),
00787 fadeInMaxDuration ) == -1 )
00788 throw MusicException( "Music::playWithFadeIn failed: "
00789 + string( ::Mix_GetError() ) ) ;
00790
00791 #else // OSDL_USES_SDL_MIXER
00792
00793 throw MusicException(
00794 "Music::playWithFadeIn failed: no SDL_mixer support available." ) ;
00795
00796 #endif // OSDL_USES_SDL_MIXER
00797
00798 #endif // OSDL_ARCH_NINTENDO_DS
00799
00800 }
00801
00802
00803
00804 void Music::playWithFadeInFromPosition(
00805 Ceylan::System::Millisecond fadeInMaxDuration,
00806 MusicPosition position, PlaybackCount playCount )
00807 {
00808
00809 _isPlaying = true ;
00810
00811 #if OSDL_USES_SDL_MIXER
00812
00813 if ( ! hasContent() )
00814 throw AudibleException( "Music::playWithFadeInFromPosition failed: "
00815 "no loaded music available" ) ;
00816
00817 if ( ::Mix_FadeInMusicPos( _content, GetLoopsForPlayCount( playCount ),
00818 fadeInMaxDuration, static_cast<double>( position ) ) == -1 )
00819 throw MusicException( "Music::playWithFadeInFromPosition failed: "
00820 + string( ::Mix_GetError() ) ) ;
00821
00822 #else // OSDL_USES_SDL_MIXER
00823
00824 throw MusicException( "Music::playWithFadeInFromPosition failed: "
00825 "no SDL_mixer support available." ) ;
00826
00827 #endif // OSDL_USES_SDL_MIXER
00828
00829 }
00830
00831
00832
00833 bool Music::isPlaying()
00834 {
00835
00836 return _isPlaying ;
00837
00838 }
00839
00840
00841
00842 void Music::pause()
00843 {
00844
00845 #if OSDL_ARCH_NINTENDO_DS
00846
00847
00848 #ifdef OSDL_RUNS_ON_ARM7
00849
00850 throw MusicException( "Music::pause failed: "
00851 "not supported on the ARM7" ) ;
00852
00853 #elif defined(OSDL_RUNS_ON_ARM9)
00854
00855 try
00856 {
00857 if ( hasContent() )
00858 _CommandManagerSettings->_commandManager->pauseMusic() ;
00859
00860 }
00861 catch( const CommandException & e )
00862 {
00863
00864 throw MusicException( "Music::pause failed: " + e.toString() ) ;
00865
00866 }
00867
00868 return ;
00869
00870 #endif // OSDL_RUNS_ON_ARM7
00871
00872
00873 #else // OSDL_ARCH_NINTENDO_DS
00874
00875 #if OSDL_USES_SDL_MIXER
00876
00877
00878 ::Mix_PauseMusic() ;
00879
00880 #else // OSDL_USES_SDL_MIXER
00881
00882 throw MusicException( "Music::pause failed: "
00883 "no SDL_mixer support available." ) ;
00884
00885 #endif // OSDL_USES_SDL_MIXER
00886
00887 #endif // OSDL_ARCH_NINTENDO_DS
00888
00889 }
00890
00891
00892
00893 void Music::unpause()
00894 {
00895
00896 #if OSDL_ARCH_NINTENDO_DS
00897
00898
00899 #ifdef OSDL_RUNS_ON_ARM7
00900
00901 throw MusicException( "Music::unpause failed: "
00902 "not supported on the ARM7" ) ;
00903
00904 #elif defined(OSDL_RUNS_ON_ARM9)
00905
00906
00907 try
00908 {
00909
00910 if ( hasContent() )
00911 _CommandManagerSettings->_commandManager->unpauseMusic() ;
00912
00913 }
00914 catch( const CommandException & e )
00915 {
00916
00917 throw MusicException( "Music::unpause failed: " + e.toString() ) ;
00918
00919 }
00920
00921 return ;
00922
00923 #endif // OSDL_RUNS_ON_ARM7
00924
00925
00926 #else // OSDL_ARCH_NINTENDO_DS
00927
00928 #if OSDL_USES_SDL_MIXER
00929
00930
00931 ::Mix_ResumeMusic() ;
00932
00933 #else // OSDL_USES_SDL_MIXER
00934
00935 throw MusicException( "Music::unpause failed: "
00936 "no SDL_mixer support available." ) ;
00937
00938 #endif // OSDL_USES_SDL_MIXER
00939
00940 #endif // OSDL_ARCH_NINTENDO_DS
00941
00942 }
00943
00944
00945
00946 void Music::rewind()
00947 {
00948
00949 #if OSDL_USES_SDL_MIXER
00950
00951
00952 ::Mix_RewindMusic() ;
00953
00954 #else // OSDL_USES_SDL_MIXER
00955
00956 throw MusicException( "Music::rewind failed: "
00957 "no SDL_mixer support available." ) ;
00958
00959 #endif // OSDL_USES_SDL_MIXER
00960
00961 }
00962
00963
00964
00965 void Music::setPosition( MusicPosition newPosition )
00966 {
00967
00968 #if OSDL_USES_SDL_MIXER
00969
00970
00971 if ( ::Mix_SetMusicPosition( static_cast<double>( newPosition ) ) == -1 )
00972 throw MusicException( "Music::setPosition failed: "
00973 + string( ::Mix_GetError() ) ) ;
00974
00975 #else // OSDL_USES_SDL_MIXER
00976
00977 throw MusicException( "Music::setPosition failed: "
00978 "no SDL_mixer support available." ) ;
00979
00980 #endif // OSDL_USES_SDL_MIXER
00981
00982 }
00983
00984
00985
00986 void Music::stop()
00987 {
00988
00989 #if OSDL_ARCH_NINTENDO_DS
00990
00991
00992 #ifdef OSDL_RUNS_ON_ARM7
00993
00994 throw MusicException( "Music::stop failed: "
00995 "not supported on the ARM7" ) ;
00996
00997 #elif defined(OSDL_RUNS_ON_ARM9)
00998
00999
01000 try
01001 {
01002
01003 if ( hasContent() )
01004 {
01005
01006 _content->_playbackCount = 0 ;
01007 _CommandManagerSettings->_commandManager->stopMusic() ;
01008
01009 }
01010
01011 }
01012 catch( const CommandException & e )
01013 {
01014
01015 throw MusicException( "Music::stop failed: " + e.toString() ) ;
01016
01017 }
01018
01019 return ;
01020
01021 #endif // OSDL_RUNS_ON_ARM7
01022
01023
01024 #else // OSDL_ARCH_NINTENDO_DS
01025
01026 #if OSDL_USES_SDL_MIXER
01027
01028
01029
01030
01031 ::Mix_HaltMusic() ;
01032
01033 #else // OSDL_USES_SDL_MIXER
01034
01035 throw MusicException( "Music::stop failed: "
01036 "no SDL_mixer support available." ) ;
01037
01038 #endif // OSDL_USES_SDL_MIXER
01039
01040 #endif // OSDL_ARCH_NINTENDO_DS
01041
01042 }
01043
01044
01045
01046 void Music::fadeIn( Ceylan::System::Millisecond fadeInMaxDuration )
01047 {
01048
01049 #if OSDL_ARCH_NINTENDO_DS
01050
01051
01052 #ifdef OSDL_RUNS_ON_ARM7
01053
01054 throw MusicException( "Music::fadeIn failed: "
01055 "not supported on the ARM7" ) ;
01056
01057 #elif defined(OSDL_RUNS_ON_ARM9)
01058
01059 _CommandManagerSettings->_commandManager->fadeInMusic( fadeInMaxDuration ) ;
01060
01061 #endif // OSDL_RUNS_ON_ARM7
01062
01063
01064 #else // OSDL_ARCH_NINTENDO_DS
01065
01066
01067
01068 throw MusicException( "Music::fadeIn failed: "
01069 "not available on this platform." ) ;
01070
01071 #endif // OSDL_ARCH_NINTENDO_DS
01072
01073 }
01074
01075
01076
01077 void Music::fadeOut( Ceylan::System::Millisecond fadeOutMaxDuration )
01078 {
01079
01080 #if OSDL_ARCH_NINTENDO_DS
01081
01082
01083 #ifdef OSDL_RUNS_ON_ARM7
01084
01085 throw MusicException( "Music::fadeOut: "
01086 "not supported on the ARM7" ) ;
01087
01088 #elif defined(OSDL_RUNS_ON_ARM9)
01089
01090 _CommandManagerSettings->_commandManager->fadeOutMusic(
01091 fadeOutMaxDuration ) ;
01092
01093 #endif // OSDL_RUNS_ON_ARM7
01094
01095
01096 #else // OSDL_ARCH_NINTENDO_DS
01097
01098 #if OSDL_USES_SDL_MIXER
01099
01100
01101 if ( ::Mix_FadeOutMusic( fadeOutMaxDuration ) == 0 )
01102 throw MusicException( "Music::fadeOut failed: "
01103 + string( ::Mix_GetError() ) ) ;
01104
01105 #else // OSDL_USES_SDL_MIXER
01106
01107 throw MusicException( "Music::fadeOut failed: "
01108 "no SDL_mixer support available." ) ;
01109
01110 #endif // OSDL_USES_SDL_MIXER
01111
01112 #endif // OSDL_ARCH_NINTENDO_DS
01113
01114 }
01115
01116
01117
01118 void Music::setAsCurrent()
01119 {
01120
01121
01122 if ( _CurrentMusic != 0 && _CurrentMusic != this )
01123 _CurrentMusic->manageNoMoreCurrent() ;
01124
01125
01126
01127
01128
01129
01130 _CurrentMusic = this ;
01131
01132 LOG_DEBUG_AUDIO( "Music::setAsCurrent: " + toString( Ceylan::low ) +
01133 " set as current." ) ;
01134
01135 }
01136
01137
01138
01139 void Music::requestFillOfFirstBuffer()
01140 {
01141
01142 #if ! OSDL_USES_SDL_MIXER
01143
01144 _content->_requestFillOfFirstBuffer = true ;
01145
01146 #endif // OSDL_USES_SDL_MIXER
01147
01148 }
01149
01150
01151
01152 void Music::requestFillOfSecondBuffer()
01153 {
01154
01155 #if ! OSDL_USES_SDL_MIXER
01156
01157 _content->_requestFillOfSecondBuffer = true ;
01158
01159 #endif // OSDL_USES_SDL_MIXER
01160
01161 }
01162
01163
01164
01165 const string Music::toString( Ceylan::VerbosityLevels level ) const
01166 {
01167
01168 if ( level == Ceylan::low )
01169 return ( hasContent() ? string( "Loaded" ) : string( "Not loaded" ) )
01170 + " music, whose content path is '" + _contentPath + "'" ;
01171
01172
01173 try
01174 {
01175
01176 if ( hasContent() )
01177 {
01178
01179 Volume v = getVolume() ;
01180
01181 return "Loaded music from content path '" + _contentPath
01182 + "', whose volume is " + Ceylan::toNumericalString( v )
01183 + " (" + Ceylan::toNumericalString( 100 * v
01184 / ( AudioModule::MaxVolume - AudioModule::MinVolume ) )
01185 + "%) and whose type is " + DescribeMusicType( getType() )
01186 + string( ", currently " )
01187 + ( _isPlaying ? "playing": "not playing" ) ;
01188
01189 }
01190 else
01191 {
01192
01193 return "Music currently not loaded, whose content path is '"
01194 + _contentPath + "'" ;
01195
01196 }
01197
01198 }
01199 catch( const Ceylan::Exception & e )
01200 {
01201
01202 return "Music::toString failed (abnormal): " + e.toString() ;
01203
01204 }
01205
01206 }
01207
01208
01209
01210
01211 #if OSDL_ARCH_NINTENDO_DS
01212
01213 void Music::SetCommandManagerSettings( const CommandManagerSettings & settings )
01214 {
01215
01216 _CommandManagerSettings = & settings ;
01217
01218 }
01219
01220 #endif // OSDL_ARCH_NINTENDO_DS
01221
01222
01223
01224 void Music::ManageCurrentMusic()
01225 {
01226
01227 if ( _CurrentMusic != 0 )
01228 _CurrentMusic->manageBufferRefill() ;
01229
01230 }
01231
01232
01233
01234
01235
01236
01237
01238
01239 MusicType Music::GetTypeOf( const Music * music )
01240 {
01241
01242 #if OSDL_USES_SDL_MIXER
01243
01244 LowLevelMusic * actualMusic ;
01245
01246 if ( music == 0 )
01247 {
01248 actualMusic = 0 ;
01249 }
01250 else
01251 {
01252
01253 if ( music->hasContent() )
01254 actualMusic = const_cast<LowLevelMusic *>(
01255 & music->getExistingContentAsConst() ) ;
01256 else
01257 throw AudioException(
01258 "Music::GetTypeOf failed: no loaded music available" ) ;
01259
01260 }
01261
01262
01263 switch( ::Mix_GetMusicType( actualMusic ) )
01264 {
01265
01266 case MUS_WAV:
01267 return Wave ;
01268 break ;
01269
01270 case MUS_MOD:
01271 return MOD ;
01272 break ;
01273
01274 case MUS_MID:
01275 return MIDI ;
01276 break ;
01277
01278 case MUS_OGG:
01279 return OggVorbis ;
01280 break ;
01281
01282 case MUS_MP3:
01283 return MP3 ;
01284 break ;
01285
01286 case MUS_CMD:
01287 return CommandBased ;
01288 break ;
01289
01290 case MUS_NONE:
01291 return NoMusic ;
01292 break ;
01293
01294 default:
01295 return Unknown ;
01296 break ;
01297
01298 }
01299
01300
01301 #else // OSDL_USES_SDL_MIXER
01302
01303 throw AudioException( "Music::GetTypeOf failed: "
01304 "no SDL_mixer support available." ) ;
01305
01306 #endif // OSDL_USES_SDL_MIXER
01307
01308 }
01309
01310
01311
01312 string Music::DescribeMusicType( MusicType type )
01313 {
01314
01315 switch( type )
01316 {
01317
01318 case Wave:
01319 return "waveform audio format (WAVE/RIFF)" ;
01320 break ;
01321
01322 case MOD:
01323 return "soundtrack Module (MOD)" ;
01324 break ;
01325
01326 case MIDI:
01327 return "Musical Instrument Digital Interface (MIDI)" ;
01328 break ;
01329
01330 case OggVorbis:
01331 return "Vorbis encoding over Ogg container (OggVorbis)" ;
01332 break ;
01333
01334 case MP3:
01335 return "MPEG-1 Audio Layer 3 (MP3)" ;
01336 break ;
01337
01338 case CommandBased:
01339 return "music managed externally by a third-party player" ;
01340 break ;
01341
01342 case NoMusic:
01343 return "no music" ;
01344 break ;
01345
01346 default:
01347 return "unknown music type (abnormal)" ;
01348 break ;
01349
01350
01351 }
01352
01353
01354 }
01355
01356
01357
01358 string Music::DescribeBitrateType( BitrateType type )
01359 {
01360
01361 switch( type )
01362 {
01363
01364 case CBR:
01365 return "CBR (constant bitrate)" ;
01366 break ;
01367
01368 case VBR:
01369 return "VBR (variable bitrate)" ;
01370 break ;
01371
01372 default:
01373 return "unknown bitrate type (abnormal)" ;
01374 break ;
01375
01376 }
01377
01378
01379 }
01380
01381
01382
01383 void Music::onPlaybackEnded()
01384 {
01385
01386
01387 LOG_TRACE_AUDIO( "Music::onPlaybackEnded" ) ;
01388
01389 }
01390
01391
01392
01393 void Music::managePlaybackEnded()
01394 {
01395
01396 _isPlaying = false ;
01397
01398 #if OSDL_ARCH_NINTENDO_DS
01399
01400 #ifdef OSDL_RUNS_ON_ARM7
01401
01402 throw AudioException( "Music::managePlaybackEnded: "
01403 "not supported on the ARM7" ) ;
01404
01405 #elif defined(OSDL_RUNS_ON_ARM9)
01406
01407 PlaybackCount count = _content->_playbackCount ;
01408
01409 unload() ;
01410 onPlaybackEnded() ;
01411
01412 LOG_DEBUG_AUDIO( "Music::managePlaybackEnded: count = "
01413 + Ceylan::toString(count) ) ;
01414
01415
01416 if ( count != 0 )
01417 play( count ) ;
01418 else
01419 manageNoMoreCurrent() ;
01420
01421 #endif // OSDL_RUNS_ON_ARM7
01422
01423 #endif // OSDL_ARCH_NINTENDO_DS
01424
01425 }
01426
01427
01428
01429 void Music::onNoMoreCurrent()
01430 {
01431
01432 LOG_WARNING_AUDIO( "Music::onNoMoreCurrent: " + toString( Ceylan::low )
01433 + " not current anymore." ) ;
01434
01435 }
01436
01437
01438
01439 void Music::manageNoMoreCurrent()
01440 {
01441
01442 LOG_TRACE_AUDIO( "Music::manageNoMoreCurrent" ) ;
01443
01444 #if OSDL_ARCH_NINTENDO_DS
01445
01446 #ifdef OSDL_RUNS_ON_ARM7
01447
01448 throw AudioException( "Music::manageNoMoreCurrent: "
01449 "not supported on the ARM7" ) ;
01450
01451 #elif defined(OSDL_RUNS_ON_ARM9)
01452
01453 _isPlaying = false ;
01454
01455 if ( _CurrentMusic == this )
01456 {
01457
01458 _CurrentMusic = 0 ;
01459 _CommandManagerSettings->_commandManager->unsetCurrentMusic( *this ) ;
01460
01461 }
01462
01463 #endif // OSDL_RUNS_ON_ARM7
01464
01465 #else // OSDL_ARCH_NINTENDO_DS
01466
01467 _isPlaying = false ;
01468
01469 if ( _CurrentMusic == this )
01470 _CurrentMusic = 0 ;
01471
01472 #endif // OSDL_ARCH_NINTENDO_DS
01473
01474 onNoMoreCurrent() ;
01475
01476 }
01477
01478
01479
01480 void Music::manageBufferRefill()
01481 {
01482
01483 #if OSDL_ARCH_NINTENDO_DS
01484
01485 if ( _content->_requestFillOfFirstBuffer )
01486 fillFirstBuffer() ;
01487
01488 if ( _content->_requestFillOfSecondBuffer )
01489 fillSecondBuffer() ;
01490
01491 #endif // OSDL_ARCH_NINTENDO_DS
01492
01493 }
01494
01495
01496
01497 void Music::fillFirstBuffer()
01498 {
01499
01500 #if OSDL_ARCH_NINTENDO_DS
01501
01502 #ifdef OSDL_RUNS_ON_ARM7
01503
01504 throw AudioException( "Music::fillFirstBuffer: "
01505 "not supported on the ARM7" ) ;
01506
01507 #elif defined(OSDL_RUNS_ON_ARM9)
01508
01509
01510 LOG_TRACE_AUDIO( "Music::fillFirstBuffer." ) ;
01511
01512 LowLevelMusic & music = getContent() ;
01513
01514 music._requestFillOfFirstBuffer = false ;
01515
01516 try
01517 {
01518
01519
01520
01521
01522
01523 BufferSize readSize = music._musicFile->read(
01524 music._startAfterDelta,
01525 music._firstActualRefillSize ) ;
01526
01527 LOG_DEBUG_AUDIO( "Music::fillFirstBuffer: read "
01528 + Ceylan::toString( readSize ) + " bytes." ) ;
01529
01530
01531
01532
01533
01534
01535 if ( readSize < music._firstActualRefillSize )
01536 {
01537
01538 LOG_TRACE_AUDIO( "Padding first buffer." ) ;
01539
01540 ::memset(
01541 music._startAfterDelta + readSize,
01542 0,
01543 _CommandManagerSettings->_bufferSize
01544 - music._frameSizeUpperBound - readSize ) ;
01545
01546
01547 DC_FlushRange( (void*) music._startAfterDelta,
01548 music._firstActualRefillSize ) ;
01549
01550 try
01551 {
01552
01553 _CommandManagerSettings->_commandManager->notifyEndOfEncodedStreamReached()
01554 ;
01555
01556 }
01557 catch( const CommandException & e )
01558 {
01559
01560 throw AudioException( "Music::fillFirstBuffer failed: "
01561 + e.toString() ) ;
01562
01563 }
01564
01565 }
01566 else
01567 {
01568
01569
01570 DC_FlushRange( (void*) music._startAfterDelta,
01571 music._firstActualRefillSize ) ;
01572
01573 }
01574
01575
01576 }
01577 catch( const SystemException & e )
01578 {
01579
01580 throw AudioException( "Music::fillFirstBuffer failed: "
01581 + e.toString() ) ;
01582
01583 }
01584
01585 #endif // OSDL_RUNS_ON_ARM7
01586
01587 #endif // OSDL_ARCH_NINTENDO_DS
01588
01589 }
01590
01591
01592
01593 void Music::fillSecondBuffer()
01594 {
01595
01596 #if OSDL_ARCH_NINTENDO_DS
01597
01598 #ifdef OSDL_RUNS_ON_ARM7
01599
01600 throw AudioException( "Music::fillSecondBuffer: "
01601 "not supported on the ARM7" ) ;
01602
01603 #elif defined(OSDL_RUNS_ON_ARM9)
01604
01605 LOG_TRACE_AUDIO( "Music::fillSecondBuffer." ) ;
01606
01607 LowLevelMusic & music = getContent() ;
01608
01609 music._requestFillOfSecondBuffer = false ;
01610
01611 try
01612 {
01613
01614
01615
01616
01617 BufferSize readSize = music._musicFile->read(
01618 _CommandManagerSettings->_secondBuffer,
01619 _CommandManagerSettings->_bufferSize ) ;
01620
01621 LOG_DEBUG_AUDIO( "Music::fillSecondBuffer: read "
01622 + Ceylan::toString( readSize ) + " bytes." ) ;
01623
01624
01625
01626
01627
01628 if ( readSize < _CommandManagerSettings->_bufferSize )
01629 {
01630
01631 LOG_TRACE_AUDIO( "Padding second buffer." ) ;
01632
01633 ::memset(
01634 _CommandManagerSettings->_secondBuffer + readSize,
01635 0,
01636 _CommandManagerSettings->_bufferSize - readSize
01637 ) ;
01638
01639
01640
01641 DC_FlushRange( (void*) _CommandManagerSettings->_secondBuffer,
01642 _CommandManagerSettings->_bufferSize ) ;
01643
01644 try
01645 {
01646
01647 _CommandManagerSettings->_commandManager->notifyEndOfEncodedStreamReached() ;
01648
01649 }
01650 catch( const CommandException & e )
01651 {
01652
01653 throw AudioException( "Music::fillSecondBuffer failed: "
01654 + e.toString() ) ;
01655
01656 }
01657
01658 }
01659 else
01660 {
01661
01662
01663 DC_FlushRange( (void*) _CommandManagerSettings->_secondBuffer,
01664 _CommandManagerSettings->_bufferSize ) ;
01665
01666 }
01667
01668
01669 }
01670 catch( const SystemException & e )
01671 {
01672
01673 throw AudioException( "Music::fillSecondBuffer failed: "
01674 + e.toString() ) ;
01675
01676 }
01677
01678 #endif // OSDL_RUNS_ON_ARM7
01679
01680 #endif // OSDL_ARCH_NINTENDO_DS
01681
01682 }
01683