1 /****************************************************************************
3 * ____ ___ ____ __ ______ ___ ____ ____/ / *
4 * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
5 * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
6 * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
10 * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
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. *
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 ****************************************************************************/
27 #include "mp_macros.inc"
28 #include "mp_format_mas.inc"
29 #include "mp_defs.inc"
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
37 @==================================================================
39 @==================================================================
43 .type mmVBlank STT_FUNC
45 .type mmMixerMix STT_FUNC
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
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
64 .type mmMixerSetPan STT_FUNC
66 // .global mm_freqscalar
71 .global mm_mixchannels
73 @===============================================
75 @===============================================
77 .EQU REG_SOUNDCNT_L, 0x4000080
78 .EQU REG_SOUNDCNT_H, 0x4000082
79 .EQU REG_SOUNDCNT_X, 0x4000084
81 .EQU REG_TM0CNT, 0x4000100
83 .EQU REG_DMA1SAD, 0x40000BC
84 .EQU REG_DMA1DAD, 0x40000C0
85 .EQU REG_DMA1CNT, 0x40000C4
87 .EQU REG_DMA2SAD, 0x40000C8
88 .EQU REG_DMA2DAD, 0x40000CC
89 .EQU REG_DMA2CNT, 0x40000D0
91 .EQU REG_DMA3SAD, 0x40000D4
92 .EQU REG_DMA3DAD, 0x40000D8
93 .EQU REG_DMA3CNT, 0x40000DC
95 .EQU REG_SGFIFOA, 0x40000A0
96 .EQU REG_SGFIFOB, 0x40000A4
97 .EQU REG_VCOUNT, 0x4000006
99 @ MIXER CHANNEL FORMAT
112 /////////////////////.equ CHN_LOOP,8
113 /////////////////////.equ CHN_LEN,16
115 @-------------------------------------
118 .equ FETCH_THRESHOLD, (6016)//7040 // frequency threshold (dont use fetch for high freqs!)
120 @======================================================================
122 @======================================================================
127 mp_writepos: .space 4 @ wavebuffer write position
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
140 mp_mix_seg: .space 1 @ mixing segment select
144 mm_fetch: .space FETCH_SIZE+16
146 @ 11-bit mixed sample buffer
147 @ data is interleaved
148 @ left,left,right,right,left,left,etc...
150 @===========================================================================
152 @===========================================================================
154 .section .iwram, "ax", %progbits
163 @-----------------------------------------------------------------------------------------------------
164 mmVBlank: @ vblank wrapper, used to reset dma...HIGH PRIORITY PLEASE!
165 @-----------------------------------------------------------------------------------------------------
167 b .mpvb_disabled @ disable until ready.. (overwrite this area with NOP)
169 ldr r0,=mp_mix_seg @ swap mixing segmentl
175 ldr r1,=0x040000c6 @ dma control RESTART DMA
176 ldr r0,=0x0440 @ disable dma
179 ldr r0,=0xB600 @ restart dma
185 ldr r0,=mp_writepos @ restart write position
186 @ ldr r1,=mp_playbuffer_l @ ...
187 ldr r1,=mm_wavebuffer
193 ldr r0,=0x3007FF8 @ acknowledge interrupt
198 ldr r0,=mm_vblank_function
206 @-------------------------------------------------------------------------
207 mmMixerMix: @ params={ samples_count }
208 @-------------------------------------------------------------------------
210 @ exit function if samples == 0
211 @ it will malfunction.
221 stmfd sp!, {r4-r11,lr}
223 stmfd sp!, {r0} @ preserve mixing count
225 @------------------------------------------------------------------------
226 @ SECTOR 0, INITIALIZATION
227 @------------------------------------------------------------------------
229 @ clear mixing buffers
232 mov r2, r0, lsr#3 @ clearing samps*2*2 bytes (hword*stereo) 32 bytes at a time
235 mov r1, #0 @ zero variable
247 @ clear 32 bytes/write
249 1: stmia r0!, {r1,r3-r9}
263 @----------------------------------------------------------------------------------
264 @ BEGIN MIXING ROUTINE
265 @----------------------------------------------------------------------------------
267 ldr r12,=mm_mixchannels
269 mov r11, #0 @ volume addition
271 @--------------------
273 @--------------------
275 @----------------------------------------------------------------------
276 @ SECTOR 1, CALCULATIONS
277 @----------------------------------------------------------------------
291 @ read source address
293 ldr rsrc, [rchan, #CHN_SRC]
295 bmi .mpm_next @ EXIT if MSB is set ------------>
297 @ read frequency value
299 ldr rfreq, [rchan, #CHN_FREQ]
301 beq .mpm_next @ EXIT if zero ----------------=->
308 @ load mixing buffers
310 ldr rmixb,=mm_mixbuffer
315 ldr rread, [rchan, #CHN_READ]
319 ldrb rvolR,[rchan, #CHN_VOL] @ volume = 0-255
320 ldrb r0, [rchan, #CHN_PAN] @ pan = 0-255
323 mul rvolL, r0, rvolR @ (vol*pan) = right volume
324 mov rvolL, rvolL, lsr#8
325 add rvolA, rvolA, rvolL @ add to volume counter
327 mul rvolR, r0, rvolR @ calc left volume (256-pan)*vol
328 mov rvolR, rvolR, lsr#8
329 add rvolA, rvolA, rvolR, lsl#16
331 ldr rmixc, [sp] @ get mix count
333 @****************************************************************
335 @****************************************************************
338 mul r1, rmixc, rfreq // get number of samples that will be read
340 cmp rfreq, #FETCH_THRESHOLD
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
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
361 push {r1} // preserve sample count
364 //--------------------------------
365 .macro DIV_ITER shift
366 //--------------------------------
367 cmp r0, rfreq, lsl#\shift
368 subcs r0, rfreq, lsl#\shift
371 //--------------------------------
373 //--------------------------------
379 //--------------------------------
381 mov r0, r1 // divide samples / frequency (24bit/16bit)
384 1: subs r0, rfreq, lsl#16 // divide top part
387 add r0, rfreq, lsl#16
389 DIVIDER 15 // divide the rest...
391 cmp r0, #1 // round up result
400 pop {r1} // restore sample count
401 sub rmixc, r0 // subtract from mixcount
405 @------------------------------------------------------------------------
407 @------------------------------------------------------------------------
409 @-----------------------------------------
411 @-----------------------------------------
415 mov rmixcc, rmixc @ <-- move mixing count
416 mov rmixc, #0 @ clear mixing count
419 @------------------------------------------------------
421 @------------------------------------------------------
425 stmfd sp!, {rmixc,rvolA,rchan}
427 @ zero mixing count??
429 beq .mpm_mix_complete @ exit -------->
431 cmp rfreq, #FETCH_THRESHOLD
435 ldr r0,=mm_fetch // transfer samples from ROM to RAM
436 add r1, #2<<14 // add threshold for safety
439 add r0, r10, rread, lsr#12
442 mov r0, #(1<<31)+(1<<26)
448 // [cycle timings assume 3,1 ROM waitstates]
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
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]
474 adds r1, #(40<<12)-(24<<12)
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]
491 adds r1, #24<<12 // add 24 back
492 bmi .end_fetch // exit if <= 0
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]
504 pop {r3-r12} // restore regs
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!)
517 tst rmixb, #0b11 // test alignment of work output
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
541 // determine mixing mode
542 cmp rvolL, rvolR // if volume_left == volume_right then assume 'center' mixing
544 cmp rvolL, #0 // if left volume is zero, do 'right' mixing
546 cmp rvolR, #0 // if right volume is zero, do 'left' mixing
548 b mmMix_ArbPanning // otherwise do arb mixing
554 @ center mixing------------
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
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
566 ldr r1, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LEN]
568 //ldr r1, [rchan, #CHN_LEN] // check length against position
570 bgt .mpm_channelfinished
572 // ldr r1, [rchan, #CHN_LOOP] // read channel loop
574 ldr r1, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LOOP]
576 // movs r1, r1, lsl#8 // mask out high byte (that is VOLUME)
577 bmi .mpm_channel_stop // MSB = no loop, stop channel ->
580 sub rread,rread,r1,lsl#(SAMPFRAC) // subtract loop length (<<SAMPFRAC) from position
582 cmp rmixc, #0 // mix more samples?
583 ble .mpm_channelfinished // no ->
584 b .mpm_remix_test // yes: loop
586 @----------------------------------------------------------------
588 @----------------------------------------------------------------
591 mov r1, #1<<31 // disable channel
592 str r1, [rchan, #CHN_SRC]
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)
602 b .mpm_remix // mix 'zero' into the rest of the data
604 @---------------------------------------------------------------
605 .mpm_channelfinished:
606 @---------------------------------------------------------------
608 cmp rmixc, #0 // mix more samples?
609 bne .mpm_remix_test // yes: loop
611 @ *** END OF MIXING ***
613 str rread, [rchan, #CHN_READ] // save read position
615 @-----------------------
617 @-----------------------
619 add rchan, rchan, #CHN_SIZE // seek to next channel
620 ldr r0,=mm_mixch_end // compare with ending
623 bne .mpm_cloop // loop if !=
625 @----------------------------------------------------------------------------------
626 @ SECTOR 3, POST-PROCESSING
627 @----------------------------------------------------------------------------------
639 ldr prmixl,=mm_mixbuffer
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
649 @ get volume accumulators
651 mov prvolR, rvolA, lsr#16+1
652 mov prvolR, prvolR, lsl#3
654 mov prvolL, rvolA, lsl#16
655 mov prvolL, prvolL, lsr#16+1
656 mov prvolL, prvolL, lsl#3
658 subs prcount, prcount, #1
661 @--------------------------------------------------
663 @--------------------------------------------------
665 @ ***************** LEFT OUTPUT ******************
667 ldr prsamp1, [prmixl], #4 @ get 2 mixed samples
668 sub prsamp2, prsamp1, prvolL @ convert to signed
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
673 cmp prsamp2, #-128 @ clamp
674 movlt prsamp2, #-128 @
676 movgt prsamp2, #127 @
679 rsbs prsamp3, prvolL, prsamp1,lsr#16 @ convert to signed
680 movs prsamp3, prsamp3, asr#3 @ convert 11-bit to 8-bit
682 cmp prsamp3, #-128 @ clamp
683 movlt prsamp3, #-128 @
685 movgt prsamp3, #127 @
687 and prsamp2, prsamp2, #255 @ write to output
688 orr prsamp2, prsamp3, lsl#8 @
689 strh prsamp2, [prwritel], #2 @
691 @ **************** RIGHT OUTPUT ******************
693 ldr prsamp1, [prmixl], #4 @ get 2 mixed samples
694 sub prsamp2, prsamp1, prvolR @ convert to signed
696 mov prsamp2, prsamp2, lsl#16 @ mask low hword and convert 11-bit to 8-bit
697 movs prsamp2, prsamp2, asr#16+3 @
699 cmp prsamp2, #-128 @ clamp value
700 movlt prsamp2, #-128 @
702 movgt prsamp2, #127 @
705 rsbs prsamp3, prvolR, prsamp1,lsr#16 @ convert to signed
706 movs prsamp3, prsamp3, asr#3 @ convert 11-bit to 8-bit
708 cmp prsamp3, #-128 @ clamp value
709 movlt prsamp3, #-128 @
711 movgt prsamp3, #127 @
713 and prsamp2, prsamp2, #255 @ write to output
714 orr prsamp2, prsamp3, lsl#8 @
715 strh prsamp2, [prwriter], #2 @
717 subs prcount, prcount, #2 @ loop
720 @------------------------------------------------------------------
723 ldr r0,=mp_writepos @ store new write position
726 @------------------------------------------------------------------
728 ldmfd sp!, {r4-r11,lr} // restore registers
733 @================================================================================
735 @================================================================================
737 .macro READ_AND_INCREMENT reg
738 ldrb \reg, [rsrc, rread, lsr#SAMPFRAC]
739 add rread, rread, rfreq
742 .macro READ_D reg, tmp
743 READ_AND_INCREMENT \reg
744 READ_AND_INCREMENT \tmp
745 orr \reg, \tmp, lsl#16
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
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
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
765 .macro MIX_DB vol_l, vol_r, target_a, target_b, tmp1, tmp2
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
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
780 @-----------------------------------------------------------------------------------
782 @-----------------------------------------------------------------------------------
785 mul r0, rmixcc, rfreq @ read += samples * frequency
789 @-----------------------------------------------------------------------------------
791 @-----------------------------------------------------------------------------------
792 @ mix hard panned left
794 bl mmMix_SingleChannel // mix left channel
795 bgt mmMix_Remainder // mix remaining amount
796 b .mpm_mix_complete // return
798 @-----------------------------------------------------------------------------------
800 @-----------------------------------------------------------------------------------
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
811 @----------------------------------------
813 @----------------------------------------
822 @ hard panned mixing (single channel mono)
823 @ interleaving really cuts this method's effectiveness :(
827 subs rmixcc, rmixcc, #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
844 @ mix remainder samples
846 adds rmixcc, rmixcc, #8 // fix mixing count
856 @----------------------------------------------------------
857 mmMix_CenteredPanning:
858 @----------------------------------------------------------
869 @ mix center panning (double channel mono)
871 subs rmixcc, rmixcc, #6
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
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
898 @---------------------------------------------------
899 mmMix_ArbPanning: // SLOWEST!
900 @---------------------------------------------------
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
930 adds rmixcc, rmixcc, #10
943 //---------------------------------------------------------------------------
945 //---------------------------------------------------------------------------
946 // (slow function to mix remaining amount of samples)
947 // assumes mix count isn't zero!
955 orr rvol, rvolL, rvolR, lsl#16
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
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)
981 subs rmixcc, rmixcc, #2 @ 2
982 blt .end_mix_remaining @ 1/exit
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
991 mul rsampb, rsampa, rvolR
992 add rsamp1, rsamp1, rsampb, lsr#5
993 strh rsamp1, [rmixb], #2
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)
1018 @============================================================================
1020 @============================================================================
1026 /****************************************************************************
1027 * mmMixerSetSource( channel, p_sample )
1029 * Set channel source
1030 ****************************************************************************/
1034 mov r2, #CHN_SIZE // get channel pointer from index
1036 ldr r2,=mm_mixchannels //
1040 add r1, #C_SAMPLE_DATA // set sample data address
1041 str r1, [r0, #CHN_SRC] //
1043 mov r1, #0 // reset read position
1044 str r1, [r0, #CHN_READ] //
1048 /****************************************************************************
1049 * mmMixerSetRead( channel, value )
1051 * Set channel read position
1052 ****************************************************************************/
1056 mov r2, #CHN_SIZE // get channel pointer from index
1058 ldr r2,=mm_mixchannels //
1062 str r1, [r0, #CHN_READ] // store new offset
1065 /****************************************************************************
1068 * Set channel mixing rate
1069 ****************************************************************************/
1073 // push {r3, r4} // FIXME: why would you preserve r3?
1075 mov r2, #CHN_SIZE // get channel pointer from index
1077 ldr r2,=mm_mixchannels //
1083 strh r1, [r0, #CHN_FREQ]
1087 ldr r4,=mm_freqscalar // r4=scale
1090 add r2, pc, #0 // switch to arm for a nice long multiply
1095 //------------------------------------
1096 // fix frequency to match mixing rate
1097 // a = specified frequency
1099 //------------------------------------
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 //
1106 str r3, [r0, #CHN_FREQ] // set chan frequency
1108 ldmfd sp!, {r3,r4} // pop registers
1113 /****************************************************************************
1114 * mmMixerMulFreq( channel, value )
1116 * Scale mixing frequency
1117 ****************************************************************************/
1121 mov r2, #CHN_SIZE // get channel pointer from index
1123 ldr r2,=mm_mixchannels //
1127 ldr r3, [r0, #CHN_FREQ] // scale
1130 str r3, [r0, #CHN_FREQ] //
1133 /****************************************************************************
1134 * mmMixerStopChannel( channel )
1136 * Stop mixing channel
1137 ****************************************************************************/
1141 mov r1, #CHN_SIZE // get channel pointer from index
1143 ldr r1,=mm_mixchannels //
1147 mov r1, #1 // set MSB (disable) of source
1152 /****************************************************************************
1153 * mmMixerChannelActive( channel )
1155 * Test if mixing channel is active
1156 ****************************************************************************/
1158 mmMixerChannelActive:
1160 mov r1, #CHN_SIZE // get channel pointer from index
1162 ldr r1,=mm_mixchannels //
1166 mp_Mixer_ChannelEnabledA:
1167 ldr r0, [r0, #CHN_SRC] // nonzero (-1) = enabled
1168 asr r0, #31 // zero = disabled
1172 /****************************************************************************
1173 * mmMixerSetVolume( channel, volume )
1175 * Set channel volume
1176 ****************************************************************************/
1180 mov r2, #CHN_SIZE // get channel pointer from index
1182 ldr r2,=mm_mixchannels //
1186 strb r1, [r0, #CHN_VOL] // set volume
1190 /****************************************************************************
1191 * mmMixerSetPan( channel, panning )
1193 * Set channel panning
1194 ****************************************************************************/
1198 mov r2, #CHN_SIZE // get channel pointer from index
1200 ldr r2,=mm_mixchannels //
1204 strb r1, [r0, #CHN_PAN] // set panning
1207 /****************************************************************************
1208 * mmMixerInit( system )
1211 ****************************************************************************/
1215 ldr r2,=mm_mixbuffer
1216 ldr r1, [r0,#MM_GBA_SYSTEM_ACH_COUNT]
1221 ldr r3, [r0,#MM_GBA_SYSTEM_MIXCH]
1225 ldr r1, [r0,#MM_GBA_SYSTEM_MIXMEM]
1227 ldr r1, [r0,#MM_GBA_SYSTEM_WAVEMEM]
1229 ldr r1, [r0,#MM_GBA_SYSTEM_MODE]
1231 adr r3, mp_mixing_lengths
1234 adr r3, mp_rate_scales
1237 adr r3, mp_timing_sheet
1240 adr r3, mp_bpm_divisors
1248 ldr r0,=mm_wavebuffer @ clear wave buffer
1254 stmia r0!, {r2} @ ..
1258 ldr r0,=mp_mix_seg @ reset mixing segment
1261 ldr r0,=mm_mixchannels @ disable mixing channels
1262 ldr r1,[r0,#12]@ nchannels
1266 str r3, [r0, #CHN_SRC]
1271 ldr r0,=mmVBlank @ enable vblank routine
1272 ldr r1,=0xE1A00000 @ ..
1275 ldr r0,=REG_SGFIFOA @ clear fifo data
1277 str r2, [r0, #4] @ ..
1278 ldr r0,=REG_SOUNDCNT_H @ reset direct sound
1280 ldr r1,=0x9A0C @ setup sound [DIRECT SOUND A/B reset,timer0,A=left,B=right,volume=100%]
1282 ldr r0,=REG_DMA1SAD @ setup DMA source addresses (playback buffers)
1283 ldr r1,=mm_wavebuffer
1284 ldr r2, [r1, #4]@mixlen
1287 @ldr r1,=mp_playbuffer_l @ ..
1293 @ ldr r1,=mp_playbuffer_r @ ..
1294 str r1, [r0, #12] @ ..
1296 ldr r1,=REG_SGFIFOA @ setup DMA destination (sound fifo)
1297 str r1, [r0, #4] @ ..
1299 str r1, [r0, #16] @ ..
1301 ldr r1,=0xB6000000 @ enable DMA (enable,fifo request,32-bit,repeat)
1302 str r1, [r0, #8] @ ..
1303 str r1, [r0, #20] @ ..
1305 ldr r0,=REG_SOUNDCNT_X @ master sound enable
1309 ldr r0,=REG_VCOUNT @ wait for new frame
1311 ldrh r1, [r0] @ skip current vblank period
1315 ldrh r1, [r0] @ wait for new one
1317 blt .mpi_vsync2 @ ..
1319 .mpi_vsync_2: @ pass#2
1320 ldrh r1, [r0] @ skip current vblank period
1322 bge .mpi_vsync_2 @ ..
1324 ldrh r1, [r0] @ wait for new one
1326 blt .mpi_vsync2_2 @ ..
1328 ldr r0,=REG_TM0CNT @ enable sampling timer
1329 ldr r1,=mm_timerfreq
1334 @ldr r1,=(-MP_TIMERFREQ&0xFFFF) | (0x80<<16) @ ..
1339 // round(rate / 59.737)
1342 .hword 136, 176, 224, 264, 304, 352, 448, 528
1343 @ 8khz,10khz,13khz,16khz,18khz,21khz,27khz,32khz
1346 //mp_freq_scales: @ (16khz -> real)
1347 // .hword 33056, 25536, 20064, 17024, 14784, 12768
1349 // 15768*16384 / rate
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,
1358 .hword -2066,-1596,-1254,-1064, -924, -798, -627, -532
1359 @ 8khz,10khz,13khz,16khz,18khz,21khz,27khz,32khz
1364 .word 20302,26280,33447,39420,45393,52560,66895,78840