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 #pragma GCC diagnostic ignored "-Wsign-compare"
00028
00029
00030
00031 #include "OSDLConfigForNintendoDS.h"
00032
00033
00034
00035 #include "OSDLARM7Base.h"
00036
00037
00038
00039
00040 #include "OSDLARM7Codes.h"
00041
00042
00043
00044 #include "OSDLIPCCommands.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #include "stdlib.h"
00055 #include "string.h"
00056
00057
00058
00059
00060 #include "helix/pub/mp3dec.h"
00061
00062
00063
00064
00065
00066
00067
00069 volatile bool startMP3PlaybackRequested = false ;
00070
00071
00073 volatile bool pauseMP3PlaybackRequested = false ;
00074
00075
00076
00081 volatile HMP3Decoder currentDecoder ;
00082
00083
00084
00086 volatile MP3FrameInfo frameInfo ;
00087
00088
00089 typedef uint16 SampleRate ;
00090
00091
00093 volatile SampleRate outputSampleRate ;
00094
00095
00096 const SampleRate DefaultSampleRate = 22050 ;
00097
00098
00099
00100
00101
00102
00104 volatile BufferSize bufferSize ;
00105
00106
00108 volatile BufferSize frameSizeUpperBound ;
00109
00110
00111
00117 volatile Byte * doubleBuffer ;
00118
00119
00120
00125 volatile Byte * secondBuffer ;
00126
00127
00128
00130 volatile Byte * readPointer ;
00131
00132
00137 volatile bool readingFirstBuffer ;
00138
00139
00140
00146 volatile Byte * endOfSafeRead ;
00147
00148
00149
00151 volatile Byte * destinationOffset ;
00152
00153
00155 volatile Byte * sizeOffset ;
00156
00157
00158
00160 volatile bool endOfStreamDetected ;
00161
00162
00164 volatile bool readingLastBuffer ;
00165
00166
00167
00169 volatile uint8 musicFadeInIncrement ;
00170
00171
00173 volatile uint8 musicFadeOutDecrement ;
00174
00175
00176
00183 volatile bool endOfProcessingReached ;
00184
00185
00186
00188 volatile bool decodingInError ;
00189
00190
00191
00192
00193
00194
00195
00196
00205 volatile Byte * decodedBuffer ;
00206
00207
00208
00219 const uint32 DecodedBufferSize = 2 * MAX_NGRAN * MAX_NSAMP ;
00220
00221
00222
00226 volatile Byte * decodePointer ;
00227
00228
00229
00230
00231 typedef uint8 ChannelVolume ;
00232
00233
00234
00235
00236
00237
00238
00239 volatile ChannelVolume currentMusicVolume = 0x7f ;
00240
00241
00242
00243
00244
00245
00246
00247
00248 const volatile ChannelVolume defaultSoundVolume = 0x7f ;
00249
00250
00251
00252
00253
00254 typedef uint8 ChannelPanning ;
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 volatile ChannelPanning currentMusicPanning = 0 ;
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 volatile ChannelPanning defaultSoundPanning = 0 ;
00275
00276
00277
00285 const uint16 DecodedFrameLength = 576 * sizeof(uint16) ;
00286
00287
00288
00297 const uint8 MusicChannel = 0 ;
00298
00299
00300
00307 s32 getFreeSoundChannel()
00308 {
00309
00310 int i ;
00311
00312
00313 for ( i=1; i<16; i++ )
00314 {
00315
00316 if ( ( SCHANNEL_CR(i) & SCHANNEL_ENABLE ) == 0 )
00317 return i ;
00318
00319 }
00320
00321 return -1 ;
00322
00323 }
00324
00325
00326
00327
00332 void triggerFirstBufferRefill()
00333 {
00334
00335 InterruptMask previous = setEnabledInterrupts( AllInterruptsDisabled ) ;
00336
00337 writeBlocking( prepareFIFOCommand( FirstBufferFillRequest ) ) ;
00338
00339 setEnabledInterrupts( previous ) ;
00340
00341 notifyCommandToARM9() ;
00342
00343 }
00344
00345
00346
00351 void triggerSecondBufferRefill()
00352 {
00353
00354 InterruptMask previous = setEnabledInterrupts( AllInterruptsDisabled ) ;
00355
00356 writeBlocking( prepareFIFOCommand( SecondBufferFillRequest ) ) ;
00357
00358 setEnabledInterrupts( previous ) ;
00359
00360 notifyCommandToARM9() ;
00361
00362 }
00363
00364
00365
00366
00367 int counter = 0 ;
00368
00369
00376 bool decodeNextMP3Frame()
00377 {
00378
00379
00380 if ( readPointer > endOfSafeRead )
00381 {
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 memmove(
00409 (Byte*) (readPointer - destinationOffset),
00410 ((Byte *) readPointer),
00411 (size_t) ( sizeOffset - (int) readPointer ) ) ;
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 if ( ! endOfStreamDetected )
00422 {
00423
00424 triggerSecondBufferRefill() ;
00425
00426 }
00427 else
00428 {
00429
00430 if ( readingLastBuffer )
00431 endOfProcessingReached = true ;
00432 else
00433 readingLastBuffer = true ;
00434
00435 }
00436
00437
00438 readPointer = (Byte *) (readPointer - ((Byte *) destinationOffset)) ;
00439
00440 readingFirstBuffer = true ;
00441
00442 }
00443
00444 if ( endOfProcessingReached )
00445 return true ;
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 int syncOffset = MP3FindSyncWord(
00456 (unsigned char *) readPointer,
00457
00458 sizeOffset - readPointer ) ;
00459
00460 if ( syncOffset < 0 )
00461 {
00462
00463
00464
00465
00466
00467
00468 setError( HelixSyncWordNotFound ) ;
00469
00470 decodingInError = true ;
00471 return false ;
00472
00473 }
00474
00475 readPointer += syncOffset ;
00476
00477
00478
00479
00480
00481
00482 int bytesLeft = sizeOffset - readPointer ;
00483
00484 #warning Next two warnings (MP3Decode/MP3GetLastFrameInfo), due to volatile type, cannot be removed.
00485
00486
00487 int errorCode = MP3Decode(
00488 currentDecoder,
00489 &readPointer,
00490 &bytesLeft,
00491 (short*) decodePointer,
00492 0 ) ;
00493
00494
00495 if ( errorCode != 0 )
00496 {
00497
00498 decodingInError = true ;
00499
00500
00501
00502
00503
00504
00505
00506 switch ( errorCode )
00507 {
00508
00509 case ERR_MP3_INDATA_UNDERFLOW:
00510 setError( HelixFoundTruncatedFrame ) ;
00511 return false ;
00512 break ;
00513
00514 case ERR_MP3_MAINDATA_UNDERFLOW:
00515 setError( HelixLacksDataInBitReservoir ) ;
00516 return false ;
00517 break ;
00518
00519 case ERR_MP3_FREE_BITRATE_SYNC:
00520 setError( HelixLacksFreeBitrateSlot ) ;
00521 return false ;
00522 break ;
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 default:
00536 setError( HelixDecodingError ) ;
00537 return false ;
00538 break ;
00539
00540 }
00541
00542
00543 }
00544
00545
00546
00547 if ( decodePointer == decodedBuffer )
00548 decodePointer += DecodedFrameLength ;
00549 else
00550 decodePointer = decodedBuffer ;
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 if ( readingFirstBuffer && ( readPointer > secondBuffer ) )
00567 {
00568
00569 if ( endOfStreamDetected )
00570 {
00571
00572 if ( readingLastBuffer )
00573 endOfProcessingReached = true ;
00574 else
00575 readingLastBuffer = true ;
00576
00577 }
00578 else
00579 {
00580
00581 triggerFirstBufferRefill() ;
00582
00583 }
00584
00585 readingFirstBuffer = false ;
00586
00587 }
00588
00589
00590 MP3GetLastFrameInfo( currentDecoder, &frameInfo ) ;
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 return true ;
00602
00603 }
00604
00605
00606
00607
00608
00609
00610
00611
00613 void handlePlaySoundRequest( FIFOElement firstElement )
00614 {
00615
00616 s32 channel = getFreeSoundChannel() ;
00617
00618 if ( channel == -1 )
00619 {
00620
00621
00622
00623
00624
00625 writeBlocking( prepareFIFOCommand( NoAvailableChannelNotification ) ) ;
00626
00627 notifyCommandToARM9() ;
00628
00629 return ;
00630
00631 }
00632
00633
00634 SCHANNEL_TIMER(channel) =
00635 SOUND_FREQ( (uint16) (firstElement & 0x0000fffff) ) ;
00636
00637
00638 SCHANNEL_SOURCE(channel) = (uint32) readBlocking() ;
00639
00640
00641 SCHANNEL_LENGTH(channel) = ( (uint32) readBlocking() ) >> 2 ;
00642
00643
00644
00645
00646 uint32 sampleFormat ;
00647
00648 switch( (firstElement & 0x00f00000) >> 5 * 4 )
00649 {
00650
00651 case 0x0:
00652 sampleFormat = SOUND_FORMAT_ADPCM ;
00653 break ;
00654
00655 case 0x1:
00656 sampleFormat = SOUND_FORMAT_8BIT ;
00657 break ;
00658
00659 case 0x2:
00660 sampleFormat = SOUND_FORMAT_16BIT ;
00661 break ;
00662
00663 default:
00664 setError( UnexpectedSampleFormat ) ;
00665 return ;
00666
00667 }
00668
00669 SCHANNEL_CR(channel) = SCHANNEL_ENABLE | SOUND_ONE_SHOT | sampleFormat
00670 | SOUND_VOL( defaultSoundVolume ) | SOUND_PAN( defaultSoundPanning ) ;
00671
00672 }
00673
00674
00675
00692 void handlePlayMusicRequest( FIFOElement firstElement )
00693 {
00694
00695 readingFirstBuffer = (bool) (firstElement & 0x00000001) ;
00696
00697
00698 doubleBuffer = (Byte *) readBlocking() ;
00699
00700 uint32 secondElement = (uint32) readBlocking() ;
00701
00702 bufferSize = ( secondElement >> 16 ) ;
00703
00704 secondBuffer = doubleBuffer + bufferSize ;
00705
00706 frameSizeUpperBound = secondElement & 0x0000fffff ;
00707
00708
00709
00710 if ( readingFirstBuffer )
00711 readPointer = doubleBuffer + frameSizeUpperBound ;
00712 else
00713 readPointer = secondBuffer ;
00714
00715
00716 destinationOffset = (Byte *) ( 2*bufferSize - frameSizeUpperBound ) ;
00717 sizeOffset = doubleBuffer + 2*bufferSize ;
00718
00719
00720 endOfSafeRead = doubleBuffer + (int) destinationOffset ;
00721
00722
00723 pauseMP3PlaybackRequested = false ;
00724 endOfStreamDetected = false ;
00725 readingLastBuffer = false ;
00726 endOfProcessingReached = false ;
00727 decodingInError = false ;
00728
00729 outputSampleRate = 0 ;
00730
00731 musicFadeInIncrement = 0 ;
00732 musicFadeOutDecrement = 0 ;
00733
00734
00735
00736
00737 decodePointer = decodedBuffer ;
00738
00739
00740 startMP3PlaybackRequested = true ;
00741
00742 }
00743
00744
00745
00752 void handleFadeInMusicRequest( FIFOElement firstElement )
00753 {
00754
00755
00756 currentMusicVolume = 0 ;
00757
00758 uint16 requestedDuration = (firstElement & 0x0000ffff) ;
00759
00760 SampleRate usedRate ;
00761
00762
00763 if ( outputSampleRate == 0 )
00764 {
00765
00766
00767 usedRate = DefaultSampleRate ;
00768
00769 }
00770 else
00771 {
00772
00773 usedRate = outputSampleRate ;
00774
00775 }
00776
00777
00778
00779
00780
00781
00782
00783
00784 uint16 frameCount =
00785 2 * requestedDuration * usedRate / ( 1000 * DecodedFrameLength ) ;
00786
00787
00788 musicFadeInIncrement = 127 / frameCount ;
00789
00790 if ( musicFadeInIncrement == 0 )
00791 musicFadeInIncrement = 1 ;
00792
00793 }
00794
00795
00796
00803 void handleFadeOutMusicRequest( FIFOElement firstElement )
00804 {
00805
00806 uint16 requestedDuration = (firstElement & 0x0000ffff) ;
00807
00808 SampleRate usedRate ;
00809
00810
00811 if ( outputSampleRate == 0 )
00812 {
00813
00814
00815 usedRate = DefaultSampleRate ;
00816
00817 }
00818 else
00819 {
00820
00821 usedRate = outputSampleRate ;
00822
00823 }
00824
00825
00826
00827
00828
00829
00830
00831
00832 uint16 frameCount = 2 * requestedDuration * usedRate
00833 / ( 1000 * DecodedFrameLength ) ;
00834
00835
00836 if ( frameCount == 0 )
00837 frameCount = 1 ;
00838
00839
00840 musicFadeOutDecrement = currentMusicVolume / frameCount ;
00841
00842 if ( musicFadeOutDecrement == 0 )
00843 musicFadeOutDecrement = 1 ;
00844
00845 }
00846
00847
00848
00857 void handleStopMusicRequest()
00858 {
00859
00860 endOfProcessingReached = true ;
00861
00862 }
00863
00864
00865
00866 void handlePauseMusicRequest()
00867 {
00868
00869 pauseMP3PlaybackRequested = true ;
00870
00871 }
00872
00873
00874
00875 void handleSetMusicVolumeRequest( FIFOElement firstElement )
00876 {
00877
00878 currentMusicVolume = firstElement & 0x000000ff ;
00879
00880 }
00881
00882
00883
00884 void handleUnpauseMusicRequest()
00885 {
00886
00887 pauseMP3PlaybackRequested = false ;
00888
00889 }
00890
00891
00892
00898 void handleEndOfEncodedStreamReached()
00899 {
00900
00901 endOfStreamDetected = true ;
00902
00903 }
00904
00905
00906
00908 void handleReceivedIntegratingLibrarySpecificCommand( FIFOCommandID commandID,
00909 FIFOElement firstElement )
00910 {
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967 if ( commandID == PlaySoundRequest )
00968 handlePlaySoundRequest( firstElement ) ;
00969 else if ( commandID == PlayMusicRequest )
00970 handlePlayMusicRequest( firstElement ) ;
00971 else if ( commandID == FadeInMusicRequest )
00972 handleFadeInMusicRequest( firstElement ) ;
00973 else if ( commandID == FadeOutMusicRequest )
00974 handleFadeOutMusicRequest( firstElement ) ;
00975 else if ( commandID == StopMusicRequest )
00976 handleStopMusicRequest() ;
00977 else if ( commandID == PauseMusicRequest )
00978 handlePauseMusicRequest() ;
00979 else if ( commandID == SetMusicVolumeRequest )
00980 handleSetMusicVolumeRequest( firstElement ) ;
00981 else if ( commandID == UnpauseMusicRequest )
00982 handleUnpauseMusicRequest() ;
00983 else if ( commandID == EndOfEncodedStreamReached )
00984 handleEndOfEncodedStreamReached() ;
00985 else
00986 setError( UnexpectedOSDLCommand ) ;
00987
00988 }
00989
00990
00991
00996 void shutdownOSDLSound()
00997 {
00998
00999 if ( currentDecoder != 0 )
01000 {
01001
01002 MP3FreeDecoder( currentDecoder ) ;
01003 currentDecoder = 0 ;
01004
01005 }
01006
01007 }
01008
01009
01010
01011 void setMusicBasicSettings()
01012 {
01013
01014
01015 SCHANNEL_CR( MusicChannel ) = SCHANNEL_ENABLE | SOUND_REPEAT | SOUND_16BIT
01016 | SOUND_VOL( currentMusicVolume ) | SOUND_PAN( currentMusicPanning ) ;
01017
01018 TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1 ;
01019
01020 }
01021
01022
01023
01024 void unsetMusicBasicSettings()
01025 {
01026
01027 SCHANNEL_CR( MusicChannel ) = 0 ;
01028
01029 TIMER0_CR = 0 ;
01030
01031
01032 outputSampleRate = 0 ;
01033
01034 }
01035
01036
01037
01038 void blankDecodedBuffer()
01039 {
01040
01041 memset( (Byte*) decodedBuffer, 0,
01042 DecodedBufferSize ) ;
01043
01044 }
01045
01046
01047
01048
01049 void enableMusicPlayback()
01050 {
01051
01052
01053 blankDecodedBuffer() ;
01054
01055 SCHANNEL_REPEAT_POINT( MusicChannel ) = 0 ;
01056
01057
01058 SCHANNEL_SOURCE( MusicChannel ) = ( u32 ) decodedBuffer ;
01059
01060
01061
01062
01063
01064
01065 SCHANNEL_LENGTH( MusicChannel ) = ( DecodedFrameLength * 2 ) >> 2 ;
01066
01067 outputSampleRate = frameInfo.samprate ;
01068
01069
01070 SCHANNEL_TIMER( MusicChannel ) = SOUND_FREQ( outputSampleRate ) ;
01071
01072 setMusicBasicSettings() ;
01073
01074
01075 TIMER0_DATA = SOUND_FREQ( outputSampleRate ) ;
01076
01077
01078
01079
01080
01081 TIMER1_DATA = 65536 - DecodedFrameLength ;
01082 TIMER1_CR = TIMER_ENABLE | TIMER_DIV_1 | TIMER_CASCADE ;
01083
01084
01085 TIMER2_DATA = 0 ;
01086 TIMER2_CR = TIMER_ENABLE | TIMER_DIV_1 | TIMER_CASCADE ;
01087
01088 }
01089
01090
01091
01092
01093 void manageMusicFadeEffect()
01094 {
01095
01096 if ( musicFadeInIncrement != 0 )
01097 {
01098
01099 if ( currentMusicVolume + musicFadeInIncrement >= 127 )
01100 {
01101 currentMusicVolume = 127 ;
01102 musicFadeInIncrement = 0 ;
01103 }
01104 else
01105 {
01106 currentMusicVolume += musicFadeInIncrement ;
01107 }
01108
01109 SCHANNEL_CR( MusicChannel ) = SCHANNEL_ENABLE | SOUND_REPEAT
01110 | SOUND_16BIT | SOUND_VOL( currentMusicVolume )
01111 | SOUND_PAN( currentMusicPanning ) ;
01112
01113 }
01114 else if ( musicFadeOutDecrement != 0 )
01115 {
01116
01117
01118 if ( musicFadeOutDecrement >= currentMusicVolume )
01119 {
01120 currentMusicVolume = 0 ;
01121 musicFadeOutDecrement = 0 ;
01122
01123
01124 endOfProcessingReached = true ;
01125 }
01126 else
01127 {
01128 currentMusicVolume -= musicFadeOutDecrement ;
01129 }
01130
01131
01132 SCHANNEL_CR( MusicChannel ) = SCHANNEL_ENABLE | SOUND_REPEAT
01133 | SOUND_16BIT | SOUND_VOL( currentMusicVolume )
01134 | SOUND_PAN( currentMusicPanning ) ;
01135
01136 }
01137
01138 }
01139
01140
01141
01142
01143 void disableMusicPlayback()
01144 {
01145
01146 unsetMusicBasicSettings() ;
01147
01148
01149 TIMER1_CR = 0 ;
01150 TIMER2_CR = 0 ;
01151
01152 TIMER0_DATA = 0 ;
01153 TIMER1_DATA = 0 ;
01154 TIMER2_DATA = 0 ;
01155
01156 }
01157
01158
01159
01164 void manageMP3Playback()
01165 {
01166
01167
01168
01169
01170
01171
01172 startMP3PlaybackRequested = false ;
01173
01174
01175
01176
01177
01178
01179
01180 if ( ! decodeNextMP3Frame() )
01181 return ;
01182
01183
01184 decodeNextMP3Frame() ;
01185
01186 int CurrentFrameCounter ;
01187 int LastFrameCounter = 0 ;
01188
01189 enableMusicPlayback() ;
01190
01191 do
01192 {
01193
01194 CurrentFrameCounter = TIMER2_DATA ;
01195
01196
01197
01198
01199
01200
01201
01202 while ( CurrentFrameCounter > LastFrameCounter )
01203 {
01204
01205 decodeNextMP3Frame() ;
01206 manageMusicFadeEffect() ;
01207 LastFrameCounter++ ;
01208
01209 }
01210
01211
01212 if ( pauseMP3PlaybackRequested )
01213 {
01214
01215 unsetMusicBasicSettings() ;
01216
01217 while ( pauseMP3PlaybackRequested )
01218 atomicSleep() ;
01219
01220 setMusicBasicSettings() ;
01221
01222 }
01223
01224
01225 } while ( ! endOfProcessingReached && ! decodingInError ) ;
01226
01227
01228 if ( ! decodingInError )
01229 {
01230
01231
01232 CurrentFrameCounter = ( TIMER2_DATA + 1 ) ;
01233
01234 while ( TIMER2_DATA == CurrentFrameCounter )
01235 atomicSleep() ;
01236
01237 }
01238
01239 disableMusicPlayback() ;
01240
01241
01242
01243 InterruptMask previous = setEnabledInterrupts( AllInterruptsDisabled ) ;
01244
01245 writeBlocking( prepareFIFOCommand( MusicEndedNotification ) ) ;
01246
01247 setEnabledInterrupts( previous ) ;
01248
01249 notifyCommandToARM9() ;
01250
01251 }
01252
01253
01254
01259 void initOSDLSound()
01260 {
01261
01262
01263 currentDecoder = MP3InitDecoder() ;
01264
01265 if ( currentDecoder == 0 )
01266 {
01267
01268 setError( HelixInitializationFailed ) ;
01269 return ;
01270
01271 }
01272
01273
01274 decodedBuffer = (Byte *) malloc( DecodedBufferSize ) ;
01275
01276
01277 atomicSleep() ;
01278
01279 }
01280
01281
01282
01287 void initOSDL()
01288 {
01289
01290 initCeylan() ;
01291
01292 initOSDLSound() ;
01293
01294 }
01295