initial commit
[gbajam22] / libs / maxmod / mm_main.S
1 /****************************************************************************
2  *                                                          __              *
3  *                ____ ___  ____ __  ______ ___  ____  ____/ /              *
4  *               / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __  /               *
5  *              / / / / / / /_/ />  </ / / / / / /_/ / /_/ /                *
6  *             /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/                 *
7  *                                                                          *
8  *         Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org)         *
9  *                                                                          *
10  * Permission to use, copy, modify, and/or distribute this software for any *
11  * purpose with or without fee is hereby granted, provided that the above   *
12  * copyright notice and this permission notice appear in all copies.        *
13  *                                                                          *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         *
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  *
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   *
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    *
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  *
20  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           *
21  ****************************************************************************/
22
23 /******************************************************************************
24  *
25  * Definitions
26  *
27  ******************************************************************************/
28
29 #include "mp_defs.inc"
30 #include "mp_mas.inc"
31 #include "mp_mas_structs.inc"
32 #include "mp_macros.inc"
33
34 #ifdef SYS_GBA
35 #include "mp_mixer_gba.inc"
36 #endif
37
38 #ifdef SYS_NDS
39 #include "mp_mixer_ds.inc"
40 #endif
41
42 /******************************************************************************
43  *
44  * Memory
45  *
46  ******************************************************************************/
47
48         .BSS
49         .ALIGN 2
50
51 /******************************************************************************
52  * mmCallback
53  *
54  * Function pointer to user event handler
55  ******************************************************************************/
56                                         .global mmCallback
57 mmCallback:     .space 4
58
59 /******************************************************************************
60  * mmModuleCount
61  *
62  * Number of modules in soundbank
63  ******************************************************************************/
64                                         .global mmModuleCount
65 mmModuleCount:  .space 4
66
67 /******************************************************************************
68  * mmModuleBank
69  *
70  * Address of module bank
71  ******************************************************************************/
72                                         .global mmModuleBank
73 mmModuleBank:   .space 4
74
75 /******************************************************************************
76  * mmSampleBank
77  *
78  * Address of sample bank
79  ******************************************************************************/
80                                         .global mmSampleBank
81 mmSampleBank:   .space 4
82
83 /******************************************************************************
84  * mm_ch_mask
85  *
86  * Bitmask to select which hardware/software channels can be used
87  ******************************************************************************/
88                                         .global mm_ch_mask
89 mm_ch_mask:     .space 4
90
91 /******************************************************************************
92  * mm_vblank_function
93  *
94  * Pointer to a user function to be called during the vblank irq
95  ******************************************************************************/
96                                         .global mm_vblank_function
97 mm_vblank_function:     .space 4
98
99 /******************************************************************************
100  * mm_rds_pchannels, mm_rds_achannels
101  *
102  * Memory for module/active channels for NDS system
103  ******************************************************************************/
104 #ifdef SYS_NDS
105 mm_rds_pchannels:       .space MCH_SIZE*32
106 mm_rds_achannels:       .space MCA_SIZE*32
107 #endif
108
109 /******************************************************************************
110  * mmInitialized
111  *
112  * Variable that will be 'true' if we are ready for playback
113  ******************************************************************************/
114                                         .global mmInitialized
115 mmInitialized:          .space 1
116
117
118
119
120 /******************************************************************************
121  *
122  * Program
123  *
124  ******************************************************************************/
125
126
127
128
129 /******************************************************************************
130  * mpp_call_*
131  *
132  * Functions to branch to a register
133  ******************************************************************************/
134
135 #ifdef SYS_GBA
136 .section ".iwram", "ax", %progbits
137 .thumb
138 .align 2
139
140 .global mpp_call_r7i, mpp_call_r2i, mpp_call_r1i
141
142         .thumb_func
143 //-----------------------------------------------------------------------------
144 mpp_call_r7i: bx r7
145 //-----------------------------------------------------------------------------
146
147         .thumb_func
148 //-----------------------------------------------------------------------------
149 mpp_call_r2i: bx r2
150 //-----------------------------------------------------------------------------
151
152         .thumb_func
153 //-----------------------------------------------------------------------------
154 mpp_call_r1i: bx r1
155 //-----------------------------------------------------------------------------
156
157 #endif
158
159 //-----------------------------------------------------------------------------
160         .TEXT
161         .THUMB
162         .ALIGN 2
163 //-----------------------------------------------------------------------------
164
165 .global mpp_call_r7, mpp_call_r1, mpp_call_r2, mpp_call_r3
166
167         .thumb_func
168 @------------------------------------------------------------------------------
169 mpp_call_r7: bx r7
170 @------------------------------------------------------------------------------
171
172         .thumb_func
173 @------------------------------------------------------------------------------
174 mpp_call_r1: bx r1
175 @------------------------------------------------------------------------------
176
177         .thumb_func
178 @------------------------------------------------------------------------------
179 mpp_call_r2: bx r2
180 @------------------------------------------------------------------------------
181         
182         .thumb_func
183 @------------------------------------------------------------------------------
184 mpp_call_r3: bx r3
185 @------------------------------------------------------------------------------
186
187 /******************************************************************************
188  * mmSetEventHandler
189  *
190  * Set function for handling playback events
191  ******************************************************************************/
192                                                 .global mmSetEventHandler
193                                                 .thumb_func
194 mmSetEventHandler:
195
196         ldr     r1,=mmCallback
197         str     r0, [r1]
198         bx      lr
199
200 #ifdef SYS_NDS
201 /******************************************************************************
202  * mmLockChannels( mask )
203  *
204  * Lock audio channels to prevent the sequencer from using them.
205  ******************************************************************************/
206                                                 .global mmLockChannels
207                                                 .thumb_func
208 mmLockChannels:
209         push    {r4, r5, lr}
210         ldr     r1,=mm_ch_mask                  // clear bits
211         ldr     r2, [r1]                        //
212         bic     r2, r0                          //
213         str     r2, [r1]                        //
214         
215         mov     r4, r0
216         mov     r5, #0
217         
218 2:      lsr     r4, #1
219         bcc     1f
220         mov     r0, r5
221         bl      StopActiveChannel
222 1:      add     r5, #1
223         cmp     r4, #0
224         bne     2b
225         
226         pop     {r4,r5}
227         pop     {r3}
228         bx      r3
229         
230 /******************************************************************************
231  * StopActiveChannel( index )
232  *
233  * Stop active channel
234  ******************************************************************************/
235                                                 .thumb_func
236 StopActiveChannel:
237         push    {r4}
238         
239         GET_MIXCH r1                            // stop mixing channel
240         mov     r2, #MIXER_CHN_SIZE             //
241         mul     r2, r0                          //
242         add     r1, r2                          //
243                                                 //
244                                                 //
245         #ifdef SYS_GBA                          //
246                                                 //
247         mov     r2, #0                          //
248         sub     r2, #1                          //
249         str     r2, [r1, #MIXER_CHN_SRC]        //
250                                                 //
251         #endif                                  //
252                                                 //
253         #ifdef SYS_NDS                          //
254                                                 //
255         mov     r2, #0                          //
256         str     r2, [r1, #MIXER_CHN_SAMP]       //
257         strh    r2, [r1, #MIXER_CHN_CVOL]       //
258         strh    r2, [r1, #MIXER_CHN_VOL]        //
259                                                 //
260         #endif                                  //
261         
262         ldr     r1,=0x4000400                   // stop hardware channel
263         lsl     r2, r0, #4                      //
264         mov     r3, #0                          //
265         str     r3, [r1, r2]                    //
266         
267         ldr     r1,=mm_achannels                // disable achn
268         ldr     r1, [r1]                        //
269         mov     r2, #MCA_SIZE                   //
270         mul     r2, r0                          //
271         add     r1, r2                          //
272         mov     r2, #0                          //
273         ldrb    r4, [r1, #MCA_FLAGS]            //
274         strb    r2, [r1, #MCA_FLAGS]            //
275         strb    r2, [r1, #MCA_TYPE]             //
276         
277         lsr     r1, r4, #8
278         bcs     .iseffect
279         
280         lsr     r4, #7
281         bcs     .issub
282         
283         ldr     r1,=mm_pchannels                // stop hooked pchannel
284         ldr     r1, [r1]                        //
285         ldr     r2,=mm_num_mch                  //
286         ldr     r2, [r2]                        //
287                                                 //
288 2:      ldrb    r3, [r1, #MCH_ALLOC]            //
289         cmp     r3, r0                          //
290         bne     1f                              //
291         mov     r3, #255                        //
292         strb    r3, [r1, #MCH_ALLOC]            //
293         b       .iseffect                       //
294 1:      sub     r2, #1                          //
295         bne     2b                              //
296         
297         b       .iseffect                       //
298         
299 .issub:
300         // stop sub pchannel
301         ldr     r1,=mm_schannels
302         mov     r2, #4
303         
304 2:      ldrb    r3, [r1, #MCH_ALLOC]            //
305         cmp     r3, r0                          //
306         bne     1f                              //
307         mov     r3, #255                        //
308         strb    r3, [r1, #MCH_ALLOC]            //
309         b       .iseffect                       //
310 1:      sub     r2, #1                          //
311         bne     2b                              //
312         
313 .iseffect:
314
315         // hope it works out for effects...
316         
317         pop     {r4}
318         bx      lr
319         
320
321 /******************************************************************************
322  * mmUnlockChannels( mask )
323  *
324  * Unlock audio channels so they can be used by the sequencer.
325  ******************************************************************************/
326                                                 .global mmUnlockChannels
327                                                 .thumb_func
328 mmUnlockChannels:
329
330 #ifdef SYS_NDS
331         ldr     r1,=mm_mixing_mode              // can NOT unlock channels in mode b
332         ldrb    r1, [r1]                        //
333         cmp     r1, #1                          //
334         beq     1f                              //
335 #endif
336         
337         ldr     r1,=mm_ch_mask
338         ldr     r2, [r1]
339         orr     r2, r0
340         str     r2, [r1]
341 1:      bx      lr
342 #endif
343
344
345
346 /******************************************************************************
347  *
348  * GBA
349  *
350  ******************************************************************************/
351
352
353
354
355 //-----------------------------------------------------------------------------
356 #ifdef SYS_GBA
357 //-----------------------------------------------------------------------------
358
359         .BSS
360         .ALIGN 2
361
362 /******************************************************************************
363  * mp_solution
364  *
365  * Address of soundbank in memory/rom
366  ******************************************************************************/
367                                                 .global mp_solution
368 mp_solution:    .space 4
369
370         .TEXT
371         .THUMB
372         .ALIGN 2
373         
374 /******************************************************************************
375  * mmInit(system)
376  *
377  * Initialize maxmod
378  ******************************************************************************/
379                                                 .global mmInit
380                                                 .thumb_func
381 mmInit:
382         push    {lr}
383         
384         ldr     r2,=mp_solution
385         mov     r1, #MM_GBA_SYSTEM_SOUNDBANK
386         ldr     r1, [r0,r1]
387         str     r1, [r2]
388
389         ldr     r2,=mm_achannels
390         ldr     r1, [r0,#MM_GBA_SYSTEM_ACTCH]
391         str     r1, [r2]
392         ldr     r1, [r0,#MM_GBA_SYSTEM_MODCH]
393         str     r1, [r2,#4]
394         ldr     r1, [r0,#MM_GBA_SYSTEM_MCH_COUNT]
395         str     r1, [r2,#8]
396         ldr     r1, [r0,#MM_GBA_SYSTEM_ACH_COUNT]
397         str     r1, [r2,#12]
398         
399         bl      mmMixerInit     @ initialize software/hardware mixer
400
401         ldr     r1,=mm_num_ach
402         ldr     r1,[r1]
403         mov     r0,#1
404         lsl     r0, r1
405         sub     r0,#1
406         
407         ldr     r1,=mm_ch_mask
408         str     r0, [r1]
409         
410         ldr     r0,=0x400                       //
411         bl      mmSetModuleVolume
412         ldr     r0,=0x400                       //
413         bl      mmSetJingleVolume       
414         ldr     r0,=0x400                       //
415         bl      mmSetEffectsVolume              //
416         
417         
418         ldr     r0,=0x400
419         bl      mmSetModuleTempo
420         
421         ldr     r0,=0x400
422         bl      mmSetModulePitch
423         
424         bl      mmResetEffects
425         
426         ret0
427
428 /******************************************************************************
429  * mmSetVBlankHandler
430  *
431  * Set function to be called during the vblank IRQ
432  ******************************************************************************/
433                                                 .global mmSetVBlankHandler
434                                                 .thumb_func
435 mmSetVBlankHandler:
436
437         ldr     r1,=mm_vblank_function
438         str     r0, [r1]
439         bx      lr
440
441 /******************************************************************************
442  * mmFrame()
443  *
444  * Work routine, user _must_ call this every frame.
445  ******************************************************************************/
446                                                 .global mmFrame
447                                                 .thumb_func
448 mmFrame:
449         
450         push    {lr}
451         push    {r4-r7}
452
453 @ update effects
454         
455         ldr     r7,=mmUpdateEffects
456         bl      _call_via_r7
457         
458 @ update sub layer
459 @ sub layer has 60hz accuracy
460         
461         ldr     r7,=mppUpdateSub
462         bl      _call_via_r7
463         
464 @ update main layer and mix samples.
465 @ main layer is sample-accurate.
466
467         ldr     r0,=mpp_channels        @ copy channels
468         ldr     r1,=mm_pchannels
469         ldr     r1,[r1]
470         str     r1, [r0]
471         ldr     r0,=mpp_nchannels       @ copy #channels
472         ldr     r1,=mm_num_mch
473         ldr     r1,[r1]
474         strb    r1, [r0] 
475         ldr     r0,=mpp_clayer          @ layer=0 (main)
476         mov     r1, #0
477         strb    r1, [r0]
478
479         ldr     r0,=mmLayerMain @mpp_layerA             @ copy layer pointer
480         ldr     r1,=mpp_layerp
481         str     r0, [r1]
482         
483         ldr     r4,=mm_mixlen
484         ldr     r4,[r4]
485                                         @ mixlen is divisible by 2
486
487         ldrb    r1, [r0, #MPL_ISPLAYING]        @ check if main layer is active
488         cmp     r1, #0
489         beq     .mpf_no_mainlayer       @ skip processing if disabled (and just mix samples)
490         
491 .mpf_mix_advr:
492         
493         ldr     r0,=mpp_layerp          @ get layer
494         ldr     r0, [r0]
495         
496         mov     r1, #MPL_TICKRATE       @ get samples/tick
497         ldrh    r5, [r0, r1]
498         
499         mov     r1, #MPL_SAMPCOUNT      @ get sample count
500         ldrh    r6, [r0,r1]
501         
502         sub     r5, r6                  @ calc tickrate-counter
503         cmp     r5, #0
504         bge     1f
505         mov     r5, #0
506 1:      cmp     r5, r4                  @ > mixlen?
507         blt     .mpf_mix_adv            @ no, mix and process tick
508         b       .mpf_mix                @ yes, mix the rest of samples
509         
510 .mpf_mix_adv:
511         
512         mov     r1, #MPL_SAMPCOUNT      @ reset sample counter
513         mov     r7, #0                  @
514         strh    r7, [r0,r1]             @
515         sub     r4, r5                  @ subtract from #samples to mix
516         
517         PROF_START
518         
519         mov     r0, r5
520         ldr     r7,=mmMixerMix  @ mix samples
521         bl      _call_via_r7
522         
523         PROF_END 0
524                 
525         ldr     r7,=mppProcessTick
526         bl      _call_via_r7
527
528         b       .mpf_mix_advr   @ process more samples
529 .mpf_mix:
530
531 @ add samples remaining to SAMPCOUNT
532 @ and mix more samples
533         
534         mov     r1, #MPL_SAMPCOUNT
535         add     r6, r4
536         strh    r6, [r0, r1]
537         mov     r0, r4
538         PROF_START
539         ldr     r1,=mmMixerMix
540         bl      _call_via_r1
541         PROF_END 0
542
543         pop     {r4-r7}
544         ret1                    @ return to user
545
546 .mpf_no_mainlayer:
547
548 @ main layer isn't active,
549 @ mix full amount
550
551         mov     r0, r4
552         
553         PROF_START
554         ldr     r1,=mmMixerMix
555         bl      _call_via_r1
556         PROF_END 0
557
558         pop     {r4-r7}
559         ret1
560
561 .pool
562
563 //-----------------------------------------------------------------------------
564 #endif
565 //-----------------------------------------------------------------------------
566
567
568
569 /******************************************************************************
570  *
571  * NDS
572  *
573  ******************************************************************************/
574
575
576
577 //-----------------------------------------------------------------------------
578 #ifdef SYS_NDS
579 //-----------------------------------------------------------------------------
580
581         .TEXT
582         .THUMB
583         .ALIGN 2
584
585 /******************************************************************************
586  * mmSuspendIRQ_t
587  *
588  * Function to disable interrupts via the status register
589  ******************************************************************************/
590                                                 .global mmSuspendIRQ_t
591                                                 .thumb_func
592 mmSuspendIRQ_t:
593         ldr     r0,=1f
594         bx      r0
595
596 .arm
597 .align 2
598 1:      mrs     r0, cpsr
599         and     r1, r0, #0x80
600         orr     r0, #0x80
601         msr     cpsr, r0
602         str     r1, previous_irq_state
603         bx      lr
604 .thumb
605
606 /******************************************************************************
607  * mmRestoreIRQ_t
608  *
609  * Function to enable interrupts via the status register
610  ******************************************************************************/        
611                                                 .global mmRestoreIRQ_t
612                                                 .thumb_func
613 mmRestoreIRQ_t:
614         ldr     r0,=1f
615         bx      r0
616
617 .arm
618 .align 2
619 1:      mrs     r0, cpsr
620         ldr     r1, previous_irq_state
621         bic     r0, #0x80
622         orr     r0, r1
623         msr     cpsr, r0
624         bx      lr
625         
626 .thumb
627
628 previous_irq_state:
629         .space  4
630
631         .thumb_func
632 /******************************************************************************
633  * mmIsInitialized()
634  *
635  * Returns true if the system is ready for playback
636  ******************************************************************************/
637                                                 .global mmIsInitialized
638                                                 .thumb_func
639 mmIsInitialized:
640         ldr     r0,=mmInitialized
641         ldrb    r0, [r0]
642         bx      lr
643         
644 /******************************************************************************
645  * mmInit7()
646  *
647  * Initialize system
648  ******************************************************************************/
649                                                 .global mmInit7
650                                                 .thumb_func
651 mmInit7:
652         push    {lr}
653         mov     r0, #0x08
654         ldr     r1,=mmFrame
655         bl      irqSet
656         
657         mov     r0, #0x08
658         bl      irqEnable
659         
660         ldr     r0,=0x400                       // set volumes
661         bl      mmSetModuleVolume               //
662         ldr     r0,=0x400                       //
663         bl      mmSetJingleVolume               //
664         ldr     r0,=0x400                       //
665         bl      mmSetEffectsVolume              //
666         
667         ldr     r0,=mmInitialized               // set initialized flag
668         mov     r1, #42                         //
669         strb    r1, [r0]                        //
670         
671         ldr     r0,=0xFFFF                      // select all hardware channels
672         bl      mmUnlockChannels                //
673         
674         ldr     r0,=mm_achannels                // setup channel addresses 
675         ldr     r1,=mm_rds_achannels            //
676         str     r1, [r0]                        //
677         ldr     r1,=mm_rds_pchannels            //
678         str     r1, [r0,#4]                     //
679         mov     r1, #32                         // 32 channels
680         str     r1, [r0,#8]                     //
681         str     r1, [r0,#12]                    //
682         
683         ldr     r0,=0x400
684         bl      mmSetModuleTempo
685         
686         ldr     r0,=0x400
687         bl      mmSetModulePitch
688         
689         bl      mmResetEffects
690         
691         bl      mmMixerInit                     // setup mixer
692         
693         ldr     r0,=mmEventForwarder            // forward events
694         bl      mmSetEventHandler
695         
696         ldr     r0,=mmInitialized               // set initialized flag
697         mov     r1, #42                         //
698         strb    r1, [r0]                        //
699         
700 .exit_r3:
701         pop     {r3}
702         bx      r3
703
704 /******************************************************************************
705  * mmInstall( channel )
706  *
707  * Install ARM7 system
708  ******************************************************************************/
709                                                 .global mmInstall
710                                                 .thumb_func
711 mmInstall:
712         push    {lr}
713         
714         ldr     r1,=mmInitialized               // not initialized until we get soundbank data
715         mov     r2, #0                          //
716         strb    r2, [r1]                        //
717         
718         bl      mmSetupComms                    // setup communication
719         
720         b       .exit_r3
721
722 /******************************************************************************
723  * mmEventForwarder( msg, param )
724  *
725  * Forward event to arm9
726  ******************************************************************************/
727                                                 .thumb_func
728 mmEventForwarder:
729         
730         push    {lr}
731         lsl     r1, #8
732         orr     r0, r1
733         mov     r1, #1
734         lsl     r1, #20
735         orr     r0, r1
736         bl      mmARM9msg
737         pop     {pc}
738         
739 /******************************************************************************
740  * mmGetSoundBank( n_songs, bank )
741  *
742  * Load sound bank address
743  ******************************************************************************/
744                                                 .global mmGetSoundBank
745                                                 .thumb_func
746 mmGetSoundBank:
747         ldr     r2,=mmModuleCount               // save data
748         stmia   r2!, {r0,r1}                    //
749         
750         lsl     r0, #2                          // also sample bank address
751         add     r1, r0                          //      
752         stmia   r2!, {r1}                       //
753         
754 //------------------------------------------------
755 // initialize system
756 //------------------------------------------------
757
758         b       mmInit7
759
760 /******************************************************************************
761  * mmFrame()
762  *
763  * Routine function
764  ******************************************************************************/
765                                                 .global mmFrame
766                                                 .thumb_func
767 mmFrame:
768         
769         push    {lr}
770         
771         ldr     r0,=mmInitialized       // catch not-initialized
772         ldrb    r0, [r0]                //
773         cmp     r0, #42                 //
774         bne     1f                      //
775
776         bl      mmMixerPre              // <-- critical timing
777         
778         ldr     r0,=0x4000208           // enable irq
779         mov     r1, #1                  //
780         strh    r1, [r0]                //
781         
782         bl      mmUpdateEffects         // update sound effects
783         bl      mmPulse                 // update module playback
784         bl      mmMixerMix              // update audio
785         
786         
787         bl      mmSendUpdateToARM9
788         
789 1:      bl      mmProcessComms          // process communications
790         
791         ret1
792         
793 .pool
794
795 //-----------------------------------------------------------------------------
796 #endif
797 //-----------------------------------------------------------------------------
798
799 //-----------------------------------------------------------------------------
800 .end
801 //-----------------------------------------------------------------------------
802