initial commit
[gbajam22] / libs / maxmod / mm_mixer_gba.S
1 /****************************************************************************
2  *                                                          __              *
3  *                ____ ___  ____ __  ______ ___  ____  ____/ /              *
4  *               / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __  /               *
5  *              / / / / / / /_/ />  </ / / / / / /_/ / /_/ /                *
6  *             /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/                 *
7  *                                                                          *
8  *                            GBA Audio System                              *
9  *                                                                          *
10  *         Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org)         *
11  *                                                                          *
12  * Permission to use, copy, modify, and/or distribute this software for any *
13  * purpose with or without fee is hereby granted, provided that the above   *
14  * copyright notice and this permission notice appear in all copies.        *
15  *                                                                          *
16  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
17  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         *
18  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  *
19  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   *
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    *
21  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  *
22  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           *
23  ****************************************************************************/
24
25 @ DEFINITIONS
26
27 #include "mp_macros.inc"
28 #include "mp_format_mas.inc"
29 #include "mp_defs.inc"
30
31 @ timer freq = 2^24 / mixfreq
32 @ mixlen ~= mixfreq * 0.01673
33 @ recommended mixing frequencies: 5734,7884,10512,13379,15768,18157,21024,26758,31536,36314,40137,42048
34 @ other mixing frequencies may cause clicks
35 @ mixlen must be divisible by 2
36
37 @==================================================================
38 @                          GLOBAL SYMBOLS
39 @==================================================================
40
41
42         .global mmVBlank
43         .type   mmVBlank STT_FUNC
44         .global mmMixerMix
45         .type   mmMixerMix STT_FUNC
46
47         .global mmMixerSetSource
48         .type   mmMixerSetSource STT_FUNC
49         .global mmMixerSetRead
50         .type   mmMixerSetRead STT_FUNC
51         .global mmMixerSetFreq
52         .type   mmMixerSetFreq STT_FUNC
53         .global mmMixerStopChannel
54         .type   mmMixerStopChannel STT_FUNC
55         .global mmMixerInit
56         .type   mmMixerInit STT_FUNC
57         .global mmMixerChannelActive
58         .type   mmMixerChannelActive STT_FUNC
59         .global mmMixerMulFreq
60         .type   mmMixerMulFreq STT_FUNC
61         .global mmMixerSetVolume
62         .type   mmMixerSetVolume STT_FUNC
63         .global mmMixerSetPan
64         .type   mmMixerSetPan STT_FUNC
65
66 //      .global mm_freqscalar
67         .global mm_mixlen
68         .global mm_bpmdv
69         .global mp_mix_seg
70         .global mp_writepos
71         .global mm_mixchannels
72
73 @===============================================
74 @ more definitions
75 @===============================================
76
77 .EQU    REG_SOUNDCNT_L, 0x4000080
78 .EQU    REG_SOUNDCNT_H, 0x4000082
79 .EQU    REG_SOUNDCNT_X, 0x4000084
80
81 .EQU    REG_TM0CNT,     0x4000100
82
83 .EQU    REG_DMA1SAD,    0x40000BC
84 .EQU    REG_DMA1DAD,    0x40000C0
85 .EQU    REG_DMA1CNT,    0x40000C4
86
87 .EQU    REG_DMA2SAD,    0x40000C8
88 .EQU    REG_DMA2DAD,    0x40000CC
89 .EQU    REG_DMA2CNT,    0x40000D0
90
91 .EQU    REG_DMA3SAD,    0x40000D4
92 .EQU    REG_DMA3DAD,    0x40000D8
93 .EQU    REG_DMA3CNT,    0x40000DC
94
95 .EQU    REG_SGFIFOA,    0x40000A0
96 .EQU    REG_SGFIFOB,    0x40000A4
97 .EQU    REG_VCOUNT,     0x4000006
98
99 @ MIXER CHANNEL FORMAT
100
101 .equ    CHN_SIZE, 24
102
103 .equ    CHN_SRC,0
104 .equ    CHN_READ,4
105 .equ    CHN_VOL,8
106 .equ    CHN_PAN,9
107 // 10
108 // 11
109 .equ    CHN_FREQ,12
110 .equ    CHN_SIZE,16
111
112 /////////////////////.equ       CHN_LOOP,8
113 /////////////////////.equ       CHN_LEN,16
114
115 @-------------------------------------
116
117 .equ    FETCH_SIZE, 384
118 .equ    FETCH_THRESHOLD, (6016)//7040           // frequency threshold (dont use fetch for high freqs!)
119
120 @======================================================================
121 @                               MEMORY
122 @======================================================================
123
124 .section .bss
125 .align 2
126
127 mp_writepos:    .space 4        @ wavebuffer write position
128
129 mm_mixbuffer:   .space 4        @ dont move (see init)
130 mm_mixchannels: .space 4        @ dont move
131 mm_wavebuffer:  .space 4        @ dont move
132 mm_mixlen:      .space 4        @ dont move
133 mm_mixch_count: .space 4        @ dont move
134 mm_mixch_end:   .space 4        @ dont move
135 mm_ratescale:   .space 4        @ dont move
136 mm_timerfreq:   .space 4        @ dont move
137
138 mm_bpmdv:       .space 4
139
140 mp_mix_seg:     .space 1        @ mixing segment select
141
142 .align 2
143
144 mm_fetch:       .space FETCH_SIZE+16
145
146 @ 11-bit mixed sample buffer
147 @ data is interleaved
148 @ left,left,right,right,left,left,etc...
149
150 @===========================================================================
151 @                                  PROGRAM
152 @===========================================================================
153
154 .section .iwram, "ax", %progbits
155
156 .ARM
157 .ALIGN 2
158
159 mpm_nullsample:
160 .byte   128
161
162 .align 2
163 @-----------------------------------------------------------------------------------------------------
164 mmVBlank:                               @ vblank wrapper, used to reset dma...HIGH PRIORITY PLEASE!
165 @-----------------------------------------------------------------------------------------------------
166         
167         b       .mpvb_disabled          @ disable until ready.. (overwrite this area with NOP)
168
169         ldr     r0,=mp_mix_seg          @ swap mixing segmentl
170         ldrsb   r1, [r0]
171         mvns    r1, r1
172         strb    r1, [r0]
173         beq     .mpvb_exit
174         
175         ldr     r1,=0x040000c6          @ dma control   RESTART DMA
176         ldr     r0,=0x0440              @ disable dma
177         strh    r0, [r1]
178         strh    r0, [r1,#12]
179         ldr     r0,=0xB600              @ restart dma
180         strh    r0, [r1]
181         strh    r0, [r1,#12]
182         
183         b       .mpvb_dontreset
184 .mpvb_exit:
185         ldr     r0,=mp_writepos         @ restart write position
186 @       ldr     r1,=mp_playbuffer_l     @ ...
187         ldr     r1,=mm_wavebuffer
188         ldr     r1, [r1]
189         str     r1, [r0]                @ ...
190 .mpvb_dontreset:
191
192 .mpvb_disabled:
193         ldr     r0,=0x3007FF8           @ acknowledge interrupt
194         ldrh    r2, [r0]
195         orr     r2, r2, #0x1
196         strh    r2, [r0]
197         
198         ldr     r0,=mm_vblank_function
199         ldr     r0, [r0]
200         cmp     r0, #0
201         bxeq    lr
202         bx      r0
203 .pool
204
205 .align 2
206 @-------------------------------------------------------------------------
207 mmMixerMix:                             @ params={ samples_count }
208 @-------------------------------------------------------------------------
209         
210 @ exit function if samples == 0
211 @ it will malfunction.
212         
213         cmp     r0, #0
214         bne     .mp_zerocheck
215         bx      lr
216
217 .mp_zerocheck:
218
219 @ preserve registers
220
221         stmfd   sp!, {r4-r11,lr}
222
223         stmfd   sp!, {r0}               @ preserve mixing count
224
225 @------------------------------------------------------------------------
226 @ SECTOR 0, INITIALIZATION
227 @------------------------------------------------------------------------
228
229 @ clear mixing buffers
230
231         and     r10, r0, #7
232         mov     r2, r0, lsr#3           @ clearing samps*2*2 bytes (hword*stereo) 32 bytes at a time
233         ldr     r0,=mm_mixbuffer
234         ldr     r0,[r0]
235         mov     r1, #0                  @ zero variable
236         mov     r3, r1
237         mov     r4, r1
238         mov     r5, r1
239         mov     r6, r1
240         mov     r7, r1
241         mov     r8, r1
242         mov     r9, r1
243
244         cmp     r2, #0
245         beq     2f
246
247 @ clear 32 bytes/write
248
249 1:      stmia   r0!, {r1,r3-r9}
250         subs    r2, r2, #1
251         bne     1b
252 2:
253         
254 @ clear remainder
255         cmp     r10, #0
256         beq     2f
257
258 1:      str     r1, [r0], #4
259         subs    r10, r10, #1
260         bne     1b
261 2:
262
263 @----------------------------------------------------------------------------------
264 @ BEGIN MIXING ROUTINE
265 @----------------------------------------------------------------------------------
266
267         ldr     r12,=mm_mixchannels
268         ldr     r12,[r12]
269         mov     r11, #0                 @ volume addition
270         
271 @--------------------
272 .mpm_cloop:
273 @--------------------
274
275 @----------------------------------------------------------------------
276 @ SECTOR 1, CALCULATIONS
277 @----------------------------------------------------------------------
278
279 @ aliases
280 #define rchan   r12
281 #define rvolA   r11
282 #define rsrc    r10
283 #define rfreq   r9
284 #define rmixb   r8
285 #define rread   r7
286 #define rvolL   r5
287 #define rvolR   r6
288 #define rmixc   r4
289 #define rmixcc  r3
290
291 @ read source address
292
293         ldr     rsrc, [rchan, #CHN_SRC]
294         cmp     rsrc, #0
295         bmi     .mpm_next               @ EXIT if MSB is set ------------>
296
297 @ read frequency value
298         
299         ldr     rfreq, [rchan, #CHN_FREQ]
300         cmp     rfreq, #0
301         beq     .mpm_next               @ EXIT if zero ----------------=->
302         
303         ldr     r0,=mm_ratescale
304         ldr     r0, [r0]
305         mul     rfreq, r0
306         lsr     rfreq, #14
307         
308 @ load mixing buffers
309
310         ldr     rmixb,=mm_mixbuffer
311         ldr     rmixb,[rmixb]
312
313 @ get read position
314         
315         ldr     rread, [rchan, #CHN_READ]
316
317 @ calculate volume
318
319         ldrb    rvolR,[rchan, #CHN_VOL] @ volume = 0-255
320         ldrb    r0, [rchan, #CHN_PAN]   @ pan = 0-255
321         
322         rsb     r0, r0, #256
323         mul     rvolL, r0, rvolR        @ (vol*pan) = right volume
324         mov     rvolL, rvolL, lsr#8
325         add     rvolA, rvolA, rvolL     @ add to volume counter
326         rsb     r0, r0, #256
327         mul     rvolR, r0, rvolR        @ calc left volume (256-pan)*vol
328         mov     rvolR, rvolR, lsr#8
329         add     rvolA, rvolA, rvolR, lsl#16
330         
331         ldr     rmixc, [sp]             @ get mix count
332         
333 @****************************************************************
334 .mpm_remix_test:
335 @****************************************************************
336         
337         mov     r2, #0
338         mul     r1, rmixc, rfreq        // get number of samples that will be read
339         
340         cmp     rfreq, #FETCH_THRESHOLD
341         bge     1f
342         
343         cmp     r1, #FETCH_SIZE<<12     // check if its > fetch size
344         movhi   r1, #FETCH_SIZE<<12     // if so: clamp to fetch size and set flag
345         movhi   r2, #1
346         
347 1:
348 //      ldr     r0, [rchan, #CHN_LEN]   // now subtract length - read to get # samples remaining
349         ldr     r0, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LEN]
350         rsb     r0, rread, r0, lsl#SAMPFRAC
351 //      sub     r0, r0, rread           // in the source
352         cmp     r1, r0                  // clamp mix count
353         movhi   r1, r0
354         bhi     .calc_mix
355         cmp     r2, #0
356         beq     .mpm_mix_full
357         
358 .calc_mix:
359         
360         
361         push    {r1}            // preserve sample count
362
363         
364 //--------------------------------
365 .macro DIV_ITER shift
366 //--------------------------------
367         cmp     r0, rfreq, lsl#\shift
368         subcs   r0, rfreq, lsl#\shift
369         addcs   r2, #1<<\shift
370 .endm
371 //--------------------------------
372 .macro DIVIDER shift
373 //--------------------------------
374         DIV_ITER \shift
375 .if \shift != 0
376         DIVIDER (\shift-1)
377 .endif
378 .endm
379 //--------------------------------
380         
381         mov     r0, r1                  // divide samples / frequency (24bit/16bit)
382         mov     r2, #0
383         
384 1:      subs    r0, rfreq, lsl#16       // divide top part
385         addcs   r2, #1<<16
386         bcs     1b
387         add     r0, rfreq, lsl#16
388         
389         DIVIDER 15                      // divide the rest...
390         
391         cmp     r0, #1                  // round up result
392         adc     r0, r2, #0
393         
394 //      mov     r0,r1
395 //      mov     r1,rfreq
396 //      swi     0x060000
397 //      cmp     r1, #0
398 //      addne   r0, #1
399         
400         pop     {r1}            // restore sample count
401         sub     rmixc, r0       // subtract from mixcount
402         mov     rmixcc, r0
403         b       .mpm_mix_short
404
405 @------------------------------------------------------------------------
406 @ SECTOR 2, MIXING
407 @------------------------------------------------------------------------
408         
409 @-----------------------------------------
410 .mpm_mix_full:
411 @-----------------------------------------
412
413 @ mix all samples
414         
415         mov     rmixcc, rmixc           @ <-- move mixing count
416         mov     rmixc, #0               @ clear mixing count
417 .mpm_mix_short:
418         
419 @------------------------------------------------------
420 .mpm_remix:
421 @------------------------------------------------------
422
423 @ mix samples...
424 @ preserve registers
425         stmfd   sp!, {rmixc,rvolA,rchan}
426
427 @ zero mixing count??
428         cmp     rmixcc, #0
429         beq     .mpm_mix_complete       @ exit -------->
430         
431         cmp     rfreq, #FETCH_THRESHOLD
432         bge     .dont_use_fetch
433         
434         /*
435         ldr     r0,=mm_fetch            // transfer samples from ROM to RAM
436         add     r1, #2<<14              // add threshold for safety
437         ldr     r2,=REG_DMA3SAD
438         str     r0, [r2, #4]
439         add     r0, r10, rread, lsr#12
440         bic     r0, #0b11
441         str     r0, [r2, #0]
442         mov     r0, #(1<<31)+(1<<26)
443         add     r0, r1, lsr#14
444         str     r0, [r2, #8]
445         b       fooo
446         */
447         
448         // [cycle timings assume 3,1 ROM waitstates]
449         
450         push    {r3-r12}
451         // r10 is SRC!
452         ldr     r0,=mm_fetch            // destination
453         add     r10, r10, rread, lsr#12 // add read offset to source
454         bic     r10, #0b11              // align to 32 bits
455         add     r1, #4<<12              // add safety threshold
456         subs    r1, #40<<12             // subtract 36
457         
458         bcc     .exit_fetch             // skip large fetch if negative
459 .fetch: ldmia   r10!, {r2-r9,r11,r14}   // read 40 samples      [44 cycles]
460         stmia   r0!, {r2-r9,r11,r14}    // write 40 samples     [11 cycles]
461         subs    r1, #40<<12             // count                [1  cycle ]
462         bcc     .exit_fetch             // exit if done         [1  cycle ]
463         ldmia   r10!, {r2-r9,r11,r14}   // read 40 samples      [44 cycles]
464         stmia   r0!, {r2-r9,r11,r14}    // write 40 samples     [11 cycles]
465         subs    r1, #40<<12             // count                [1  cycle ]
466         bcc     .exit_fetch             // exit if done         [1  cycle ]
467         ldmia   r10!, {r2-r9,r11,r14}   // read 40 samples      [44 cycles]
468         stmia   r0!, {r2-r9,r11,r14}    // write 40 samples     [11 cycles]
469         subs    r1, #40<<12             // count                [1  cycle ]
470         bcs     .fetch                  // loop if remaining    [3  cycles]
471                                         //                      [173 cycles/120 samples]
472 .exit_fetch:
473
474         adds    r1, #(40<<12)-(24<<12)
475         bmi     .end_medfetch
476 .medfetch:
477         ldmia   r10!, {r2-r7}           // read 24 samples      [26]
478         stmia   r0!, {r2-r7}            // write 24 samples     [7 ]
479         subs    r1, #24<<12             // count                [1 ]
480         bcc     .end_medfetch           // exit if done         [1 ]
481         ldmia   r10!, {r2-r7}           // read 24 samples      [26]
482         stmia   r0!, {r2-r7}            // write 24 samples     [7 ]
483         subs    r1, #24<<12             // count                [1 ]
484         bcc     .end_medfetch           // exit if done         [1 ]
485         ldmia   r10!, {r2-r7}           // read 24 samples      [26]
486         stmia   r0!, {r2-r7}            // write 24 samples     [7 ]
487         subs    r1, #24<<12             // count                [1 ]
488         bcs     .medfetch               // loop                 [3 ]
489 .end_medfetch:                          //                      [107]
490
491         adds    r1, #24<<12             // add 24 back
492         bmi     .end_fetch              // exit if <= 0
493 .fetchsmall:
494         ldr     r2, [r10], #4           // read 4 samples       [8]
495         str     r2, [r0], #4            // write 4 samples      [2]
496         subs    r1, #4<<12              // count                [1]
497         ble     .end_fetch              // exit maybe           [1]
498         ldr     r2, [r10], #4           // read 4 samples       [8]
499         str     r2, [r0], #4            // write 4 samples      [2]
500         subs    r1, #4<<12              // count                [1]
501         bgt     .fetchsmall             // exit maybe           [3]
502 .end_fetch:
503         
504         pop     {r3-r12}                // restore regs
505         
506 fooo:
507         
508         mov     r0, rread, lsr#12       // get read integer
509         push    {r0, rsrc}              // preserve regs
510         bic     rread, r0, lsl#12       // clear integer
511         and     r0, #0b11               // mask low bits
512         ldr     rsrc,=mm_fetch          //
513         add     rsrc, rsrc, r0          // offset source (fetch is word aligned!)
514         
515 .dont_use_fetch:
516         
517         tst     rmixb, #0b11            // test alignment of work output
518         beq     .mpm_aligned
519         
520 #define rsamp1  r1 
521 #define rsampa  r0
522 #define rsampb  r2
523                                                         @ routine to WORD align mixing sector
524         ldrb    rsampa, [rsrc, rread, lsr#SAMPFRAC]     @ load sample
525         add     rread, rread, rfreq                     @ add frequency
526         mul     rsampb, rsampa, rvolL                   @ multiply by left volume
527         ldrh    rsamp1, [rmixb]                         @ add to mixing buffer (left)
528         add     rsamp1, rsamp1, rsampb, lsr#5           
529         strh    rsamp1, [rmixb], #4
530         mul     rsampb, rsampa, rvolR                   @ multiply by right volume
531         ldrh    rsamp1, [rmixb]                         @ add to mixing buffer (right)
532         add     rsamp1, rsamp1, rsampb, lsr#5
533         strh    rsamp1, [rmixb], #2
534         sub     rmixcc, rmixcc, #1                      @ decrement mix count
535         
536 #undef rsamp1
537 #undef rsampa
538 #undef rsampb
539
540 .mpm_aligned:
541                                         // determine mixing mode
542         cmp     rvolL, rvolR            // if volume_left == volume_right then assume 'center' mixing
543         beq     .mpm_mix_ac             
544         cmp     rvolL, #0               // if left volume is zero, do 'right' mixing
545         beq     .mpm_mix_ar
546         cmp     rvolR, #0               // if right volume is zero, do 'left' mixing
547         beq     .mpm_mix_al
548         b       mmMix_ArbPanning        // otherwise do arb mixing
549 .mpm_mix_al:
550         b       mmMix_HardLeft
551 .mpm_mix_ar:
552         b       mmMix_HardRight
553
554 @ center mixing------------
555 .mpm_mix_ac:
556         cmp     rvolL, #0               // check if volume is zero
557         bne     mmMix_CenteredPanning   // mix samples if not zero
558         b       mmMix_Skip              // skip samples if zero
559 .mpm_mix_complete:
560
561         cmp     rfreq, #FETCH_THRESHOLD
562         poplt   {r0, rsrc}                      // restore regs
563         addlt   rread, rread, r0, lsl#12        // add old integer to read
564         ldmfd   sp!, {rmixc,rvolA,rchan}        // restore more regs
565         
566         ldr     r1, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LEN]
567         lsl     r1, #SAMPFRAC
568         //ldr   r1, [rchan, #CHN_LEN]           // check length against position
569         cmp     r1, rread
570         bgt     .mpm_channelfinished
571         
572 //      ldr     r1, [rchan, #CHN_LOOP]          // read channel loop
573         
574         ldr     r1, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LOOP]
575         cmp     r1, #0
576 //      movs    r1, r1, lsl#8                   // mask out high byte (that is VOLUME)
577         bmi     .mpm_channel_stop               // MSB = no loop, stop channel ->
578         
579
580         sub     rread,rread,r1,lsl#(SAMPFRAC)   // subtract loop length (<<SAMPFRAC) from position
581
582         cmp     rmixc, #0                       // mix more samples?    
583         ble     .mpm_channelfinished            // no ->
584         b       .mpm_remix_test                 // yes: loop
585
586 @----------------------------------------------------------------
587 .mpm_channel_stop:
588 @----------------------------------------------------------------
589
590 @ *** END OF SAMPLE
591         mov     r1, #1<<31                      // disable channel
592         str     r1, [rchan, #CHN_SRC]
593
594 @ mix zero into the rest of the buffer
595         ldr     rsrc,=mpm_nullsample            // mix zero into the rest of the buffer
596         mov     rfreq, #0                       // zero freq
597         mov     rread, #0                       // zero freq
598         movs    rmixcc, rmixc                   // mix remaining amount
599         ble     .mpm_channelfinished            // (exit if zero)
600         mov     rmixc, #0
601         mov     r1, #0
602         b       .mpm_remix                      // mix 'zero' into the rest of the data
603         
604 @---------------------------------------------------------------
605 .mpm_channelfinished:
606 @---------------------------------------------------------------
607         
608         cmp     rmixc, #0                       // mix more samples?
609         bne     .mpm_remix_test                 // yes: loop
610         
611 @  *** END OF MIXING ***
612
613         str     rread, [rchan, #CHN_READ]       // save read position
614         
615 @-----------------------
616 .mpm_next:
617 @-----------------------
618
619         add     rchan, rchan, #CHN_SIZE         // seek to next channel
620         ldr     r0,=mm_mixch_end                // compare with ending
621         ldr     r0,[r0]                         
622         cmp     rchan, r0                       
623         bne     .mpm_cloop                      // loop if !=
624
625 @----------------------------------------------------------------------------------
626 @ SECTOR 3, POST-PROCESSING
627 @----------------------------------------------------------------------------------
628
629 #define prmixl          r0
630 #define prwritel        r2
631 #define prwriter        r3
632 #define prcount         r4
633 #define prvolR          r12
634 #define prvolL          r11
635 #define prsamp1         r6
636 #define prsamp2         r5
637 #define prsamp3         r7
638         
639         ldr     prmixl,=mm_mixbuffer
640         ldr     prmixl,[prmixl]
641         
642         ldr     prwritel,=mp_writepos
643         ldr     prwritel, [prwritel]
644         ldr     prwriter,=mm_mixlen
645         ldr     prwriter, [prwriter]
646         add     prwriter, prwritel, prwriter, lsl#1 @#MP_MIXLEN*2
647         ldmfd   sp!, {prcount}
648
649 @ get volume accumulators
650         
651         mov     prvolR, rvolA, lsr#16+1
652         mov     prvolR, prvolR, lsl#3
653         
654         mov     prvolL, rvolA, lsl#16
655         mov     prvolL, prvolL, lsr#16+1
656         mov     prvolL, prvolL, lsl#3
657         
658         subs    prcount, prcount, #1
659         ble     .mpm_copy2_end
660
661 @--------------------------------------------------
662 .mpm_copy2:
663 @--------------------------------------------------
664
665 @ ***************** LEFT OUTPUT ******************
666
667         ldr     prsamp1, [prmixl], #4           @ get 2 mixed samples
668         sub     prsamp2, prsamp1, prvolL        @ convert to signed
669
670         mov     prsamp2, prsamp2, lsl#16        @ mask low hword with sign extension
671         movs    prsamp2, prsamp2, asr#16+3      @ and convert 11-bit to 8-bit
672
673         cmp     prsamp2, #-128                  @ clamp
674         movlt   prsamp2, #-128                  @
675         cmp     prsamp2, #127                   @
676         movgt   prsamp2, #127                   @
677         
678                                                 @ next sample...
679         rsbs    prsamp3, prvolL, prsamp1,lsr#16 @ convert to signed
680         movs    prsamp3, prsamp3, asr#3         @ convert 11-bit to 8-bit
681
682         cmp     prsamp3, #-128                  @ clamp
683         movlt   prsamp3, #-128                  @
684         cmp     prsamp3, #127                   @
685         movgt   prsamp3, #127                   @
686         
687         and     prsamp2, prsamp2, #255          @ write to output
688         orr     prsamp2, prsamp3, lsl#8         @
689         strh    prsamp2, [prwritel], #2         @
690
691 @ **************** RIGHT OUTPUT ******************
692         
693         ldr     prsamp1, [prmixl], #4           @ get 2 mixed samples
694         sub     prsamp2, prsamp1, prvolR        @ convert to signed
695         
696         mov     prsamp2, prsamp2, lsl#16        @ mask low hword and convert 11-bit to 8-bit
697         movs    prsamp2, prsamp2, asr#16+3      @
698         
699         cmp     prsamp2, #-128                  @ clamp value
700         movlt   prsamp2, #-128                  @
701         cmp     prsamp2, #127                   @
702         movgt   prsamp2, #127                   @
703         
704                                                 @ next sample...
705         rsbs    prsamp3, prvolR, prsamp1,lsr#16 @ convert to signed
706         movs    prsamp3, prsamp3, asr#3         @ convert 11-bit to 8-bit
707         
708         cmp     prsamp3, #-128                  @ clamp value
709         movlt   prsamp3, #-128                  @
710         cmp     prsamp3, #127                   @
711         movgt   prsamp3, #127                   @
712         
713         and     prsamp2, prsamp2, #255          @ write to output
714         orr     prsamp2, prsamp3, lsl#8         @
715         strh    prsamp2, [prwriter], #2         @
716
717         subs    prcount, prcount, #2            @ loop
718         bgt     .mpm_copy2                      @
719
720 @------------------------------------------------------------------
721
722 .mpm_copy2_end:
723         ldr     r0,=mp_writepos                 @ store new write position
724         str     prwritel, [r0]
725
726 @------------------------------------------------------------------
727
728         ldmfd   sp!, {r4-r11,lr}                // restore registers
729         bx      lr                              // phew!
730
731 .pool
732
733 @================================================================================
734 @                                 MIXING ROUTINES
735 @================================================================================
736
737 .macro READ_AND_INCREMENT reg
738         ldrb    \reg, [rsrc, rread, lsr#SAMPFRAC]
739         add     rread, rread, rfreq
740 .endm
741
742 .macro READ_D reg, tmp
743         READ_AND_INCREMENT \reg
744         READ_AND_INCREMENT \tmp
745         orr     \reg, \tmp, lsl#16
746 .endm
747
748 .macro MIX_D vol, tmp1, tmp2
749         READ_D  \tmp1, \tmp2                    // load&combine 2 samples
750         mul     \tmp2, \tmp1, \vol              // multiply by volume
751         bic     \tmp2, \tmp2, #0x1F0000         // prepare for shift
752 .endm
753
754 .macro MIX_DA vol, target, tmp1, tmp2
755         MIX_D   \vol, \tmp1, \tmp2
756         add     \target, \target, \tmp2, lsr#5  // add 11-bit values
757 .endm
758
759 .macro MIX_DC vol, target_a, target_b, tmp1, tmp2
760         MIX_D   \vol, \tmp1, \tmp2
761         add     \target_a, \target_a, \tmp2, lsr#5      // add 11-bit values
762         add     \target_b, \target_b, \tmp2, lsr#5
763 .endm
764
765 .macro  MIX_DB  vol_l, vol_r, target_a, target_b, tmp1, tmp2
766         READ_D  \tmp1, \tmp2
767         
768 .if \target_a != 0
769         mul     \tmp2, \tmp1, \vol_l                    // multiply by volume
770         bic     \tmp2, \tmp2, #0x1F0000                 // prepare for shift
771         add     \target_a, \target_a, \tmp2, lsr#5      // add 11-bit values
772 .endif
773 .if \target_b != 0
774         mul     \tmp2, \tmp1, \vol_r                    // multiply by volume
775         bic     \tmp2, \tmp2, #0x1F0000                 // prepare for shift
776         add     \target_b, \target_b, \tmp2, lsr#5      // add 11-bit values
777 .endif
778 .endm
779
780 @-----------------------------------------------------------------------------------
781 mmMix_Skip:
782 @-----------------------------------------------------------------------------------
783
784 @ mix nothing
785         mul     r0, rmixcc, rfreq       @ read += samples * frequency
786         add     rread, rread, r0
787         b       .mpm_mix_complete
788
789 @-----------------------------------------------------------------------------------
790 mmMix_HardLeft:
791 @-----------------------------------------------------------------------------------
792 @ mix hard panned left
793
794         bl      mmMix_SingleChannel     // mix left channel
795         bgt     mmMix_Remainder         // mix remaining amount
796         b       .mpm_mix_complete       // return
797
798 @-----------------------------------------------------------------------------------
799 mmMix_HardRight:
800 @-----------------------------------------------------------------------------------
801 @ hard panned right
802
803         mov     rvolL, rvolR            // move volume
804         add     rmixb, rmixb, #4        // offset to 'right' data
805         bl      mmMix_SingleChannel     // mix routine
806         mov     rvolL, #0               // clear left volume again
807         sub     rmixb, rmixb, #4        // remove offet
808         bgt     mmMix_Remainder         // mix remaining count
809         b       .mpm_mix_complete       // return
810
811 @----------------------------------------
812 mmMix_SingleChannel:
813 @----------------------------------------
814
815 #define rsamp1  r1 
816 #define rsamp2  r2
817 #define rsamp3  r11
818 #define rsamp4  r12
819 #define rsampa  r0
820 #define rsampb  r4
821
822 @ hard panned mixing (single channel mono)
823 @ interleaving really cuts this method's effectiveness :(
824
825 @ mix 8 samples/loop
826
827         subs    rmixcc, rmixcc, #8
828         bmi     .mpmah_8e
829 .mpmah_8:
830         ldmia   rmixb, {rsamp1, rsamp2, rsamp3}         // load data [2nd word not used]
831         MIX_DA  rvolL, rsamp1, rsampa, rsampb           // mix data
832         str     rsamp1, [rmixb], #8                     // store mixed word
833         MIX_DA  rvolL, rsamp3, rsampa, rsampb           // mix data
834         str     rsamp3, [rmixb], #8                     // store mixed word
835         ldmia   rmixb, {rsamp1, rsamp2, rsamp3}         // load data [2nd word not used]
836         MIX_DA  rvolL, rsamp1, rsampa, rsampb           // mix data
837         str     rsamp1, [rmixb], #8                     // store mixed word
838         MIX_DA  rvolL, rsamp3, rsampa, rsampb           // mix data
839         str     rsamp3, [rmixb], #8                     // store mixed word
840         subs    rmixcc, rmixcc, #8                      // decrement 8 samples
841         bpl     .mpmah_8                                // loop if >= 0
842 .mpmah_8e:
843
844 @ mix remainder samples
845
846         adds    rmixcc, rmixcc, #8                      // fix mixing count
847         bx      lr                                      // return
848
849 #undef rsamp1
850 #undef rsamp2
851 #undef rsamp3
852 #undef rsamp4
853 #undef rsampa
854 #undef rsampb
855
856 @----------------------------------------------------------
857 mmMix_CenteredPanning:
858 @----------------------------------------------------------
859         
860 #define rsamp1  r1 
861 #define rsamp2  r2
862 #define rsamp3  r4
863 #define rsamp4  r6
864 #define rsamp5  r11
865 #define rsamp6  r12
866 #define rsampa  r0
867 #define rsampb  lr
868
869 @ mix center panning (double channel mono)
870         
871         subs    rmixcc, rmixcc, #6
872         bmi     .mpmac_6e
873 .mpmac_6:
874         
875         ldmia   rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5,rsamp6}      // read words
876         MIX_DC  rvolL, rsamp1, rsamp2, rsampa, rsampb                   // mix data
877         MIX_DC  rvolL, rsamp3, rsamp4, rsampa, rsampb
878         MIX_DC  rvolL, rsamp5, rsamp6, rsampa, rsampb
879         stmia   rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5,rsamp6}     // write words
880         subs    rmixcc, rmixcc, #6                                      // count
881         bpl     .mpmac_6                                                // loop
882 .mpmac_6e:
883
884         mov     rvolR, rvolL                    // restore right volume (same as left)
885         adds    rmixcc, rmixcc, #6              // fix mix count
886         bgt     mmMix_Remainder                 // mix remaining amount
887         b       .mpm_mix_complete               // finished mixing segment
888         
889 #undef rsamp1
890 #undef rsamp2
891 #undef rsamp3
892 #undef rsamp4
893 #undef rsamp5
894 #undef rsamp6
895 #undef rsampa
896 #undef rsampb
897
898 @---------------------------------------------------
899 mmMix_ArbPanning:               // SLOWEST!
900 @---------------------------------------------------
901
902 #define rsamp1  r1 
903 #define rsamp2  r2
904 #define rsamp3  r4
905 #define rsamp4  r11
906 #define rsampa  r0
907 #define rsampb  r12
908 #define rsamp5  r14
909
910         subs    r3, r3, #10
911         bmi     .mpmaa_10e
912 .mpmaa_10:
913         
914         ldmia   rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5}     // load bufferdata
915         MIX_DB  rvolL, rvolR, rsamp1, rsamp2, rsampa, rsampb    // mix
916         MIX_DB  rvolL, rvolR, rsamp3, rsamp4, rsampa, rsampb    // mix
917         MIX_DB  rvolL, rvolR, rsamp5, 0, rsampa, rsampb         // mix half
918         stmia   rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5}    // store bufferdata
919         ldmia   rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5}     // load bufferdata
920         mul     rsampb, rsampa, rvolR                           // mix other half
921         bic     rsampb, rsampb, #0x1F0000                       // ..
922         add     rsamp1, rsamp1, rsampb, lsr#5                   // ..
923         MIX_DB  rvolL, rvolR, rsamp2, rsamp3, rsampa, rsampb    // mix
924         MIX_DB  rvolL, rvolR, rsamp4, rsamp5, rsampa, rsampb    // mix
925         stmia   rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5}    // store bufferdata
926         subs    rmixcc, rmixcc, #10                             // count
927         bpl     .mpmaa_10                                       // loop
928 .mpmaa_10e:
929         
930         adds    rmixcc, rmixcc, #10
931         bgt     mmMix_Remainder
932         b       .mpm_mix_complete
933
934 .pool
935
936 #undef rsamp1  
937 #undef rsamp2 
938 #undef rsamp3
939 #undef rsamp4
940 #undef rsampa
941 #undef rsampb
942
943 //---------------------------------------------------------------------------
944 mmMix_Remainder:
945 //---------------------------------------------------------------------------
946 // (slow function to mix remaining amount of samples)
947 // assumes mix count isn't zero!
948
949 #define rsamp1 r1
950 #define rsamp2 r2
951 #define rvol   r11
952 #define rsampa r0
953 #define rsampb r4
954
955         orr     rvol, rvolL, rvolR, lsl#16
956         
957 .mix_remaining:
958 /*      ldrb    rsampa, [rsrc, rread, lsr#SAMPFRAC]     @ 3 load sample
959         add     rread, rread, rfreq                     @ 1 add frequency
960         mul     rsampb, rsampa, rvolL                   @ 2 multiply by volume
961         ldrh    rsamp1, [rmixb]                         @ 3 load mix buffer entry
962         add     rsamp1, rsamp1, rsampb, lsr#5           @ 1 add
963         strh    rsamp1, [rmixb], #2                     @ 2 store
964         ldrh    rsamp1, [rmixb, #2]                     @ 3
965         mul     rsampb, rsampa, rvolR                   @ 2
966         add     rsamp1, rsamp1, rsampb, lsr#5           @ 1
967         strh    rsamp1, [rmixb, #2]                     @ 2
968 */
969         
970         ldrb    rsampa, [rsrc, rread, lsr#SAMPFRAC]     @ 3 load sample
971         add     rread, rread, rfreq                     @ 1 add frequency
972         mul     rsampb, rvol, rsampa                    @ 2 multiply by volume
973         ldrh    rsamp1, [rmixb]                         @ 3 load mix buffer entry (left)
974         bic     rsamp2, rsampb, #0xFF0000               @ 1 prep for shift
975         add     rsamp1, rsamp1, rsamp2, lsr#5           @ 1 add
976         strh    rsamp1, [rmixb], #2                     @ 2 store (left)
977         ldrh    rsamp1, [rmixb, #2]                     @ 3 load (right)
978         add     rsamp1, rsamp1, rsampb, lsr#16+5        @ 1 add values
979         strh    rsamp1, [rmixb, #2]                     @ 2 store (right)
980         
981         subs    rmixcc, rmixcc, #2                      @ 2
982         blt     .end_mix_remaining                      @ 1/exit
983
984 /*      ldrb    rsampa, [rsrc, rread, lsr#SAMPFRAC]     @ load sample
985         add     rread, rread, rfreq                     @ add frequency
986         mul     rsampb, rsampa, rvolL                   @ multiply by volume
987         ldrh    rsamp1, [rmixb]                         @ load mix buffer entry
988         add     rsamp1, rsamp1, rsampb, lsr#5           @ add
989         strh    rsamp1, [rmixb], #4                     @ store
990         ldrh    rsamp1, [rmixb]
991         mul     rsampb, rsampa, rvolR
992         add     rsamp1, rsamp1, rsampb, lsr#5
993         strh    rsamp1, [rmixb], #2
994 */
995
996         ldrb    rsampa, [rsrc, rread, lsr#SAMPFRAC]     @ 3 load sample
997         add     rread, rread, rfreq                     @ 1 add frequency
998         mul     rsampb, rvol, rsampa                    @ 2 multiply by volume
999         ldrh    rsamp1, [rmixb]                         @ 3 load mix buffer entry (left)
1000         bic     rsamp2, rsampb, #0xFF0000               @ 1 prep for shift
1001         add     rsamp1, rsamp1, rsamp2, lsr#5           @ 1 add
1002         strh    rsamp1, [rmixb], #4                     @ 2 store (left)
1003         ldrh    rsamp1, [rmixb]                         @ 3 load (right)
1004         add     rsamp1, rsamp1, rsampb, lsr#16+5        @ 1 add values
1005         strh    rsamp1, [rmixb], #2                     @ 2 store (right)
1006
1007         bgt     .mix_remaining
1008 .end_mix_remaining:
1009         
1010         b       .mpm_mix_complete
1011         
1012 #undef rsamp1
1013 #undef rsamp2
1014 #undef rvol
1015 #undef rsampa
1016 #undef rsampb
1017
1018 @============================================================================
1019 @                                 END OF MIXER
1020 @============================================================================
1021
1022         .TEXT
1023         .THUMB
1024         .ALIGN 2
1025
1026 /****************************************************************************
1027  * mmMixerSetSource( channel, p_sample )
1028  *
1029  * Set channel source
1030  ****************************************************************************/
1031                                         .thumb_func
1032 mmMixerSetSource: 
1033
1034         mov     r2, #CHN_SIZE           // get channel pointer from index
1035         mul     r0, r2                  //
1036         ldr     r2,=mm_mixchannels      //
1037         ldr     r2, [r2]                //
1038         add     r0, r2                  //
1039         
1040         add     r1, #C_SAMPLE_DATA      // set sample data address
1041         str     r1, [r0, #CHN_SRC]      //
1042         
1043         mov     r1, #0                  // reset read position
1044         str     r1, [r0, #CHN_READ]     //
1045         
1046         bx      lr
1047
1048 /****************************************************************************
1049  * mmMixerSetRead( channel, value )
1050  *
1051  * Set channel read position
1052  ****************************************************************************/
1053                                         .thumb_func
1054 mmMixerSetRead:
1055
1056         mov     r2, #CHN_SIZE           // get channel pointer from index
1057         mul     r0, r2                  //
1058         ldr     r2,=mm_mixchannels      //
1059         ldr     r2,[r2]                 //
1060         add     r0, r2                  //
1061         
1062         str     r1, [r0, #CHN_READ]     // store new offset
1063         bx      lr                      //
1064
1065 /****************************************************************************
1066  * mmMixerSetFreq
1067  *
1068  * Set channel mixing rate
1069  ****************************************************************************/
1070                                         .thumb_func
1071 mmMixerSetFreq:
1072
1073 //      push    {r3, r4}                // FIXME: why would you preserve r3?
1074         
1075         mov     r2, #CHN_SIZE           // get channel pointer from index
1076         mul     r0, r2, r0              // 
1077         ldr     r2,=mm_mixchannels      //
1078         ldr     r2,[r2]                 //
1079         add     r0, r0, r2              //
1080         
1081         lsl     r1, #2 // ...
1082         
1083         strh    r1, [r0, #CHN_FREQ]
1084         bx      lr
1085         
1086 /*
1087         ldr     r4,=mm_freqscalar       // r4=scale
1088         ldr     r4,[r4]                 //
1089
1090         add     r2, pc, #0              // switch to arm for a nice long multiply
1091         bx      r2
1092         
1093         .ARM
1094         
1095         //------------------------------------
1096         // fix frequency to match mixing rate
1097         // a = specified frequency
1098         // hz = a*2y13 / pr
1099         //------------------------------------
1100         
1101         umull   r3, r2, r1, r4          // long multiply
1102         add     r3, r3, #32768          // shift, etc..
1103         mov     r3, r3, lsr#16          //
1104         orr     r3, r3, r2, lsl#16      //
1105         
1106         str     r3, [r0, #CHN_FREQ]     // set chan frequency
1107         
1108         ldmfd   sp!, {r3,r4}            // pop registers
1109         bx      lr                      // return
1110         */
1111         .THUMB
1112
1113 /****************************************************************************
1114  * mmMixerMulFreq( channel, value )
1115  *
1116  * Scale mixing frequency
1117  ****************************************************************************/
1118                                         .thumb_func
1119 mmMixerMulFreq:
1120
1121         mov     r2, #CHN_SIZE           // get channel pointer from index
1122         mul     r0, r2                  //
1123         ldr     r2,=mm_mixchannels      //
1124         ldr     r2, [r2]                //
1125         add     r0, r2                  //
1126
1127         ldr     r3, [r0, #CHN_FREQ]     // scale
1128         mul     r3, r1                  //
1129         lsr     r3, #10                 //
1130         str     r3, [r0, #CHN_FREQ]     //
1131         bx      lr
1132
1133 /****************************************************************************
1134  * mmMixerStopChannel( channel )
1135  *
1136  * Stop mixing channel
1137  ****************************************************************************/
1138                                         .thumb_func
1139 mmMixerStopChannel:
1140
1141         mov     r1, #CHN_SIZE           // get channel pointer from index
1142         mul     r0, r1                  //
1143         ldr     r1,=mm_mixchannels      //
1144         ldr     r1,[r1]                 //
1145         add     r0, r1                  //
1146                 
1147         mov     r1, #1                  // set MSB (disable) of source
1148         lsl     r1, #31                 //
1149         str     r1, [r0]                //
1150         bx      lr
1151
1152 /****************************************************************************
1153  * mmMixerChannelActive( channel )
1154  *
1155  * Test if mixing channel is active
1156  ****************************************************************************/
1157                                         .thumb_func
1158 mmMixerChannelActive:
1159
1160         mov     r1, #CHN_SIZE           // get channel pointer from index
1161         mul     r0, r1                  //
1162         ldr     r1,=mm_mixchannels      //
1163         ldr     r1,[r1]                 //
1164         add     r0, r1                  //
1165         
1166 mp_Mixer_ChannelEnabledA:
1167         ldr     r0, [r0, #CHN_SRC]      // nonzero (-1) = enabled
1168         asr     r0, #31                 // zero         = disabled
1169         mvn     r0, r0                  //
1170         bx      lr
1171
1172 /****************************************************************************
1173  * mmMixerSetVolume( channel, volume )
1174  * 
1175  * Set channel volume
1176  ****************************************************************************/
1177                                         .thumb_func
1178 mmMixerSetVolume:
1179
1180         mov     r2, #CHN_SIZE           // get channel pointer from index
1181         mul     r0, r2                  //
1182         ldr     r2,=mm_mixchannels      //
1183         ldr     r2,[r2]                 //
1184         add     r0, r2                  //
1185         
1186         strb    r1, [r0, #CHN_VOL]      // set volume
1187         
1188         bx      lr
1189         
1190 /****************************************************************************
1191  * mmMixerSetPan( channel, panning )
1192  *
1193  * Set channel panning
1194  ****************************************************************************/
1195                                         .thumb_func
1196 mmMixerSetPan:
1197
1198         mov     r2, #CHN_SIZE           // get channel pointer from index
1199         mul     r0, r2                  //
1200         ldr     r2,=mm_mixchannels      //
1201         ldr     r2,[r2]                 //
1202         add     r0, r2                  //
1203         
1204         strb    r1, [r0, #CHN_PAN]      // set panning
1205         bx      lr
1206         
1207 /****************************************************************************
1208  * mmMixerInit( system )
1209  *
1210  * Initialize mixer
1211  ****************************************************************************/
1212                                         .thumb_func
1213 mmMixerInit:
1214
1215         ldr     r2,=mm_mixbuffer
1216         ldr     r1, [r0,#MM_GBA_SYSTEM_ACH_COUNT]
1217         str     r1, [r2,#16]
1218         
1219         mov     r3, #CHN_SIZE
1220         mul     r1, r3
1221         ldr     r3, [r0,#MM_GBA_SYSTEM_MIXCH]
1222         str     r3, [r2,#4]
1223         add     r3, r1
1224         str     r3, [r2,#20]
1225         ldr     r1, [r0,#MM_GBA_SYSTEM_MIXMEM]
1226         str     r1, [r2,#0]
1227         ldr     r1, [r0,#MM_GBA_SYSTEM_WAVEMEM]
1228         str     r1, [r2,#8]
1229         ldr     r1, [r0,#MM_GBA_SYSTEM_MODE]
1230         lsl     r1, #1
1231         adr     r3, mp_mixing_lengths
1232         ldrh    r3, [r3,r1]
1233         str     r3, [r2,#12]
1234         adr     r3, mp_rate_scales
1235         ldrh    r3, [r3, r1]
1236         str     r3, [r2, #24]
1237         adr     r3, mp_timing_sheet
1238         ldrh    r3, [r3, r1]
1239         str     r3, [r2, #28]
1240         adr     r3, mp_bpm_divisors
1241         lsl     r1, #1
1242         ldr     r3, [r3,r1]
1243
1244         ldr     r2,=mm_bpmdv
1245         str     r3, [r2,#0]
1246
1247         
1248         ldr     r0,=mm_wavebuffer               @ clear wave buffer
1249         ldr     r0,[r0]
1250         ldr     r1,=mm_mixlen
1251         ldr     r1, [r1]
1252         mov     r2, #0                          @ ..
1253 .mpi_loop1:                                     @ ..
1254         stmia   r0!, {r2}                       @ ..
1255         sub     r1, r1, #1                      @ ..
1256         bne     .mpi_loop1                      @ ..
1257         
1258         ldr     r0,=mp_mix_seg                  @ reset mixing segment
1259         strb    r2, [r0]                        @ ..
1260         
1261         ldr     r0,=mm_mixchannels              @ disable mixing channels
1262         ldr     r1,[r0,#12]@ nchannels
1263         ldr     r0,[r0]
1264         ldr     r3,=1<<31
1265 .mpi_loop2:
1266         str     r3, [r0, #CHN_SRC]
1267         add     r0, #CHN_SIZE
1268         sub     r1, #1
1269         bne     .mpi_loop2
1270
1271         ldr     r0,=mmVBlank                    @ enable vblank routine
1272         ldr     r1,=0xE1A00000                  @ ..
1273         str     r1, [r0]                        @ ..
1274         
1275         ldr     r0,=REG_SGFIFOA                 @ clear fifo data
1276         str     r2, [r0]                        @ ..
1277         str     r2, [r0, #4]                    @ ..
1278         ldr     r0,=REG_SOUNDCNT_H              @ reset direct sound
1279         strh    r2, [r0]                        @ ..
1280         ldr     r1,=0x9A0C                      @ setup sound [DIRECT SOUND A/B reset,timer0,A=left,B=right,volume=100%]
1281         strh    r1, [r0]                        @ ..
1282         ldr     r0,=REG_DMA1SAD                 @ setup DMA source addresses (playback buffers)
1283         ldr     r1,=mm_wavebuffer
1284         ldr     r2, [r1, #4]@mixlen
1285         ldr     r1, [r1]
1286         
1287         @ldr    r1,=mp_playbuffer_l             @ ..
1288         str     r1, [r0]                        @ ..
1289
1290         add     r1,r2
1291         add     r1,r2
1292
1293 @       ldr     r1,=mp_playbuffer_r             @ ..
1294         str     r1, [r0, #12]                   @ ..
1295         
1296         ldr     r1,=REG_SGFIFOA                 @ setup DMA destination (sound fifo)
1297         str     r1, [r0, #4]                    @ ..
1298         add     r1, #4                          @ ..
1299         str     r1, [r0, #16]                   @ ..
1300         
1301         ldr     r1,=0xB6000000                  @ enable DMA (enable,fifo request,32-bit,repeat)
1302         str     r1, [r0, #8]                    @ ..
1303         str     r1, [r0, #20]                   @ ..
1304         
1305         ldr     r0,=REG_SOUNDCNT_X              @ master sound enable
1306         mov     r1, #0x80                       @ ..
1307         strh    r1, [r0]                        @ ..
1308         
1309         ldr     r0,=REG_VCOUNT                  @ wait for new frame
1310 .mpi_vsync:                                     @ ..
1311         ldrh    r1, [r0]                        @ skip current vblank period
1312         cmp     r1, #160                        @ ..
1313         bge     .mpi_vsync                      @ ..
1314 .mpi_vsync2:
1315         ldrh    r1, [r0]                        @ wait for new one
1316         cmp     r1, #160                        @ ..
1317         blt     .mpi_vsync2                     @ ..
1318         
1319 .mpi_vsync_2:                                   @ pass#2
1320         ldrh    r1, [r0]                        @ skip current vblank period
1321         cmp     r1, #160                        @ ..
1322         bge     .mpi_vsync_2                    @ ..
1323 .mpi_vsync2_2:
1324         ldrh    r1, [r0]                        @ wait for new one
1325         cmp     r1, #160                        @ ..
1326         blt     .mpi_vsync2_2                   @ ..
1327         
1328         ldr     r0,=REG_TM0CNT                          @ enable sampling timer
1329         ldr     r1,=mm_timerfreq
1330         ldr     r1,[r1]
1331         mov     r2, #0x80
1332         lsl     r2, #16
1333         orr     r1, r2
1334         @ldr    r1,=(-MP_TIMERFREQ&0xFFFF) | (0x80<<16) @ ..
1335         str     r1, [r0]                                @ ..
1336         bx      lr                                      @ finished
1337         
1338
1339 // round(rate / 59.737)
1340 .align 2
1341 mp_mixing_lengths:
1342         .hword  136,  176,  224,  264,  304,  352,  448,  528
1343         @      8khz,10khz,13khz,16khz,18khz,21khz,27khz,32khz
1344
1345 .align 2
1346 //mp_freq_scales:               @ (16khz -> real)
1347 //      .hword 33056, 25536, 20064, 17024, 14784, 12768
1348
1349 // 15768*16384 / rate
1350 mp_rate_scales:
1351         .hword 31812, 24576, 19310, 16384, 14228, 12288,  9655,  8192
1352         @       8khz, 10khz, 13khz, 16khz, 18khz, 21khz, 27khz, 32khz
1353         @       8121, 10512, 13379, 15768, 18157, 21024, 26758, 31536,
1354
1355 .align 2
1356 // gbaclock / rate
1357 mp_timing_sheet:
1358         .hword -2066,-1596,-1254,-1064, -924, -798, -627, -532
1359         @       8khz,10khz,13khz,16khz,18khz,21khz,27khz,32khz
1360
1361 .align 2
1362 // rate * 2.5
1363 mp_bpm_divisors:
1364         .word 20302,26280,33447,39420,45393,52560,66895,78840
1365
1366         
1367 .end