1 /****************************************************************************
3 * ____ ___ ____ __ ______ ___ ____ ____/ / *
4 * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
5 * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
6 * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
8 * Module Processing (ARM segment) *
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 ****************************************************************************/
25 @=============================================================
27 @=============================================================
29 #include "mp_format_mas.inc"
30 #include "mp_mas_structs.inc"
31 #include "mp_defs.inc"
32 #include "mp_macros.inc"
35 #include "mp_mixer_gba.inc"
36 #include "swi_gba.inc"
40 #include "mp_mixer_ds.inc"
41 #include "swi_nds.inc"
49 .global mmAllocChannel
50 @********************************************************
52 @********************************************************
53 // finds a channel to use
54 // returns invalid channel [255] if none available
55 push {r4,r5,r6} // preserve regs
56 ldr r5,=mm_ch_mask // read channel mask
58 ldr r1,=mm_achannels // pointer to active channels
61 mov r0, #0 // r0 = counter
62 mov r2, #0x80000000 // r2 = min vol
63 mov r3, #255 // r3 = best channel [255=none]
64 mov r6, #ACHN_BACKGROUND
74 movs r5, r5, lsr#1 // 1 shift out channel bit
75 bcc .mppac_skip // 1/3 skip if cleared
76 ldrh r4, [r1], #MCA_SIZE // 5 read type setting & increment pointer
77 cmp r6, r4, lsr #8 // 1 compare background/disabled
78 blt .mppac_next_test // 1/3 if > background then its important, dont use this channel
79 bgt .mppac_found // 1/3 if < background then its disabled, use this channel
81 cmp r2, r4, lsl#23 // 1 compare volume with our record
82 bls .mppac_next_test // 1/3 goto next if not less
83 mov r3, r0 // 1 otherwise save this channel
84 movs r2, r4, lsl#23 // 1 and volume level
85 // beq .mppac_finished // 1/3 exit immediately if volume is zero
86 b .mppac_next_test // 3 loop
90 // cmp r0, #255 //trap
97 @****************************************************
99 @****************************************************
101 ldr r11, [r8, #MPL_SONGADR]
102 ldrb r12, [r11, #C_MAS_INSTN] // read instr count
103 ldrb r11, [r8, #MPL_FLAGS] // read flags
104 mov r10, #1 // for various things
108 ldr r7, [r8, #MPL_PATTREAD]
110 str r7, [r0, #MPV_PATTREAD_P]
114 @----------------------------------------------------------------
116 @----------------------------------------------------------------
118 mov r5, #0 // clear flags
119 ldrb r3, [r7], #1 // read pattern byte
120 movs r3, r3, lsl#32-7 // mask channel#
121 beq end_of_row // 0 = end of row
122 rsb r3, r10, r3, lsr#32-7 // get channel number
125 mla r6, r3, r0, r9 // get channel pointer
126 ldrcsb r2, [r7], #1 // read new maskvariable if bit was set
127 strcsb r2, [r6, #MCH_CFLAGS] // and save it
128 ldrccb r2, [r6, #MCH_CFLAGS] // otherwise read previous flags
130 tst r2, #1 // test note bit
132 ldrb r0, [r7], #1 // read note value
133 cmp r0, #254 // test if < 254
134 strltb r0, [r6, #MCH_PNOTE] // [most common result]
136 orreq r5, #MF_NOTECUT // 254 is note-cut
137 orrgt r5, #MF_NOTEOFF // 255 is note-off
140 tst r2, #2 // shift out instrument bit
142 ldrb r0, [r7], #1 // read instrument value
143 tst r5, #MF_NOTEOFF|MF_NOTECUT
144 bne no_instrument // skip if note-off or cut is set
145 cmp r0, r12 // check if value > max instruments
146 movgt r0, #0 // zero if so
147 ldrb r3, [r6, #MCH_INST] // test if instrument is the same
150 movs r3, r11, lsr#C_FLAGS_LS // shift out 'mod/s3m' flag
151 orrcs r5, #MF_START // set start flag if old
152 orr r5, #MF_NEWINSTR // set new instrument flag
154 strb r0, [r6, #MCH_INST]
157 tst r10, r2, lsr#3 // test volume & effect bits
158 ldrcsb r0, [r7], #1 // copy vcmd
159 strcsb r0, [r6, #MCH_VOLCMD]
162 ldrb r0, [r7], #1 // copy effect
163 ldrb r3, [r7], #1 // copy param
165 strh r0, [r6, #MCH_EFFECT] // write effect+param
167 orr r5, r2, lsr#4 // orr in the new flags
168 strb r5, [r6, #MCH_FLAGS] // save flags
169 b readpattern // loop
171 str r7, [r8, #MPL_PATTREAD] // save read position
172 str r1, [r8, #MPL_MCH_UPDATE] // save update bits
176 .macro get_channel branch
177 ldrb r0, [r7, #MCH_ALLOC] // get channel
179 bge \branch // no channel!
180 ldr r6,=mm_achannels //
183 mla r6, r0, r1, r6 //
186 .global mmUpdateChannel_T0, mmUpdateChannel_TN
187 @***************************************************************************
188 mmUpdateChannel_T0: // for tick 0
189 @***************************************************************************
192 ldrb r5, [r7, #MCH_FLAGS] // read channel flags
193 tst r5, #MF_START // test start flag
194 beq dont_start_channel // skip section if cleared
196 tst r5, #MF_HASFX // test effect flag
197 beq no_channel_effect
198 ldrh r0, [r7, #MCH_EFFECT] // read effect
200 // cmp r1, #19 // test for 'SDx' (note delay)
203 // beq dont_start_channel // dont start channel if delayed
205 // test for glissando
207 bne start_channel // always start channel if it's a new instrument
208 cmp r1, #0x7 // test if effect is Gxx
209 beq glissando_affected
212 tst r5, #MF_NEWINSTR // copeee
213 bne start_channel // always start channel if it's a new instrument
215 tst r5, #MF_HASVCMD // test for volume commmand
216 beq start_channel // none = start channel
217 ldrb r0, [r8, #MPL_FLAGS] // read mod flags
218 movs r0, r0, lsr#C_FLAGS_XS // test for XM mode
219 ldrb r0, [r7, #MCH_VOLCMD] // read volume command
220 bcs xm_vcmd // branch
221 it_vcmd: // using IT effects:
222 cmp r0, #193 // glissando is 193..202
227 xm_vcmd: // using XM effects:
228 cmp r0, #0xF0 // glissando is Fx
229 bge glissando_affected
235 get_channel start_channel
236 /* ldrb r0, [r7, #MCH_ALLOC] // if channel is invalid
237 cmp r0, #255 // then skip this
240 ldr r6,=mm_achannels // get channel
243 mla r6, r0, r1, r6 //
245 bl mmChannelStartACHN // start achn
246 bic r5, #MF_START // clear start flag
247 strb r5, [r7, #MCH_FLAGS]
250 start_channel: // ok start channel...
252 ldr r2,=mpp_Channel_NewNote
255 get_channel mmUpdateChannel_TN_
258 // beq mmUpdateChannel_TN_
260 bl mmChannelStartACHN // start achn
261 //----------------------------------------------
262 // r2 = note, calculate period
263 ldrb r0, [r6, #MCA_SAMPLE]
265 bcc no_sample_to_make_period
267 ldrb r1, [r8, #MPL_FLAGS]
271 ldr r3, [r8, #MPL_SONGADR] // read song addr
272 ldr r1, [r8, #MPL_SAMPTABLE]// get sample table
273 ldr r0, [r1, r0, lsl#2] // get sample address
274 add r0, r3 // add module base
276 ldrh r1, [r0, #C_MASS_FREQ] // read tuning freq
277 lsl r1, #2 // shift ...
278 // mov r0, r2 // move this.
282 LDR R1,=IT_PitchTable
283 LDR R0, [R1, R2, LSL#2]
284 //bl get_linear_period
286 //--------------------------------
288 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
289 str r0, [r7, #MCH_PERIOD] // save period
290 ldrb r0, [r6, #MCA_FLAGS] // set start flag
292 strb r0, [r6, #MCA_FLAGS]
293 no_sample_to_make_period:
294 //----------------------------------------------------
300 get_channel mmUpdateChannel_TN___
305 ldrb r0, [r7, #MCH_INST]
307 bcc dvol_no_instrument
309 ldr r2, [r8, #MPL_SONGADR] // get instrument pointer
310 ldr r1, [r8, #MPL_INSTTABLE]
311 ldr r0, [r1, r0, lsl#2]
314 ldr r1, [r0, #C_MASI_NNA] // read nna,envflags,pan
315 ldrb r2, [r7, #MCH_BFLAGS] // read bflags
316 bic r2, #0b11000000 // clear old nna
317 orr r2, r1, lsl#6 // set new nna
318 strb r2, [r7, #MCH_BFLAGS]
320 ldrb r2, [r6, #MCA_FLAGS] // read achn flags
322 tst r1, #ENVFLAG_A<<8
323 orrne r2, #MCAF_VOLENV
324 strb r2, [r6, #MCA_FLAGS]
326 movs r1, r1, lsl#8+1 // shift out panning MSB
327 movcs r1, r1, lsr#24 // if set, use new panning value
328 strcsb r1, [r7, #MCH_PANNING]
331 ldrb r0, [r6, #MCA_SAMPLE] // read sample#
333 bcc dvol_no_sample // exit if invalid
335 ldr r2, [r8, #MPL_SONGADR] // get sample address
336 ldr r1, [r8, #MPL_SAMPTABLE]
337 ldr r0, [r1, r0, lsl#2]
341 //ldrh r1, [r0, #C_MASS_DV] // read dvol & pan
342 strb r1, [r7, #MCH_VOLUME] // copy volume
343 movs r1, r1, lsl#24-7
345 strcsb r1, [r7, #MCH_PANNING]
349 tst r5, #MF_START|MF_DVOL
350 beq dont_reset_volume
352 ldrb r0, [r8, #MPL_FLAGS]
356 beq dont_reset_volume // xm stuff
359 mov r0, #(1<<10) // [1]
362 add r12, r6, #MCA_FADE // [1]
363 stmia r12, {r0-r2} // [19]
365 strh r1, [r6, #MCA_ENVN_VOL]
366 strb r1, [r6, #MCA_ENVN_PIC]
368 // the last bit of code sets fade to (1<<10)
369 // and clears ENVC_VOL,ENVC_PAN,ENVC_PIC,
370 // AVIB_DEP, and AVIB_POS
371 // second bit clears ENVN vars
373 strb r1, [r7, #MCH_FXMEM] // clear fx memory
375 ldrb r1, [r6, #MCA_FLAGS] // set keyon
376 orr r1, #MCAF_KEYON // and clear envend+fade
377 bic r1, #MCAF_ENVEND | MCAF_FADE
378 strb r1, [r6, #MCA_FLAGS]
382 tst r5, #MF_NOTEOFF // test noteoff bit
385 ldrb r1, [r6, #MCA_FLAGS] // read flags
386 bic r1, #MCAF_KEYON // clear key-on
387 ldrb r0, [r8, #MPL_FLAGS] // read mod flags
388 tst r0, #C_FLAGS_X // test xm mode
389 orrne r1, #MCAF_FADE // XM starts fade immediately on note-off
390 strb r1, [r6, #MCA_FLAGS]
393 tst r5, #MF_NOTECUT // test notecut bit
394 movne r0, #0 // clear volume
395 strneb r0, [r7, #MCH_VOLUME] // on note-cut
397 bic r5, #MF_START // clear start flag
398 strb r5, [r7, #MCH_FLAGS] // save flags
399 b mmUpdateChannel_TN_
400 @************************************************************
401 mmUpdateChannel_TN: // for other ticks
402 @************************************************************
406 ldrb r0, [r7, #MCH_ALLOC] // get channel
408 bge mmUpdateChannel_TN___ // no channel!
409 ldr r6,=mm_achannels //
412 mla r6, r0, r1, r6 //
414 mmUpdateChannel_TN___:
418 ldr r5, [r7, #MCH_PERIOD] // r5 will be used to hold the period
421 strb r0, [r1, #MPV_SAMPOFF] // clear variables
422 strb r0, [r1, #MPV_VOLPLUS]
423 strb r0, [r1, #MPV_PANPLUS]
424 strb r0, [r1, #MPV_NOTEDELAY]
426 //---------------------------------------------
427 // Update Volume Commands
428 //---------------------------------------------
430 ldrb r0, [r7, #MCH_FLAGS]
432 ldrne r1,=mpp_Process_VolumeCommand
435 //blne mpp_Process_VolumeCommand
437 //---------------------------------------------
439 //---------------------------------------------
441 ldrb r0, [r7, #MCH_FLAGS]
443 ldrne r1,=mpp_Process_Effect
446 //blne mpp_Process_Effect
448 //---------------------------------------------
452 ldrh r0, [r7, #MCH_VOLUME] // read volume & cvolume
453 and r1, r0, #255 // mask volume
454 mov r0, r0, lsr#8 // mask cvolume
455 mul r0, r1, r0 // multiply together
456 mov r0, r0, lsr#5 // shift
457 strb r0, [r6, #MCA_VOLUME] // save in achn volume
460 ldrsb r2, [r1, #MPV_VOLPLUS] // read volume addition
461 adds r0, r2, lsl#3 // add to volume
465 strb r0, [r1, #MPV_AFVOL] // store in immediate vol
467 ldrb r0, [r1, #MPV_NOTEDELAY]// read note delay
468 cmp r0, #0 // dont update if nonzero
469 beq channel_update_achn
471 ldrb r0, [r6, #MCA_FLAGS]
472 orr r0, #MCAF_UPDATED
473 strb r0, [r6, #MCA_FLAGS]
478 ldrb r0, [r7, #MCH_PANNING] // copy panning
479 strb r0, [r6, #MCA_PANNING]
480 ldr r0, [r7, #MCH_PERIOD] // copy period
481 str r0, [r6, #MCA_PERIOD]
483 strh r0, [r1, #MPV_PANPLUS] // WHAT IS THIS??? "@ <---- RESERVED FOR LATER USE, CLEAR TO ZERO TEMPORARILY"
485 ldrb r0, [r6, #MCA_FLAGS]
486 orr r0, #MCAF_UPDATED
487 strb r0, [r6, #MCA_FLAGS]
490 ldrb r4, [r7, #MCH_ALLOC]
491 ldr r1,=mpp_Update_ACHN_notest
500 @***********************************************************
501 mmChannelStartACHN: // returns r2=note
502 @***********************************************************
503 ldrb r2, [r7, #MCH_BFLAGS+1] // clear tremor/cutvol
505 strb r2, [r7, #MCH_BFLAGS+1]
507 cmp r6, #0 // achn==0?
508 beq 1f // then skip this part
510 mov r0, #ACHN_FOREGROUND // set foreground type
511 strb r0, [r6, #MCA_TYPE]
513 ldrb r0, [r6, #MCA_FLAGS] // read flags
514 bic r0, #0b11000000 // clear SUB, EFFECT
515 ldr r1,=mpp_clayer // get layer
517 orr r0, r1, lsl#6 // orr into flags
518 orr r0, r10, r0, lsl#8 // orr PARENT
519 strh r0, [r6, #MCA_PARENT] // store parent/flags
520 ldrb r0, [r7, #MCH_INST] // copy instrument
521 strb r0, [r6, #MCA_INST]
522 1: ldreqb r0, [r7, #MCH_INST]
524 bcc invalid_instrument
526 ldr r2, [r8, #MPL_SONGADR] // get instrument pointer
527 ldr r1, [r8, #MPL_INSTTABLE]
528 ldr r0, [r1, r0, lsl#2]
531 ldrb r2, [r7, #MCH_PNOTE] // get pattern note
533 ldrh r1, [r0, #C_MASI_MAP] // read notemap offset
534 tst r1, #0x8000 // test MSB
535 beq full_notemap // if set: notemap doesnt exist!
537 cmp r6, #0 // if channel is valid
538 strneb r1, [r6, #MCA_SAMPLE] // write sample value
539 strb r2, [r7, #MCH_NOTE] // write note value (without notemap, all entries == PNOTE)
544 add r0, r2, lsl#1 // add note offset
545 ldrh r2, [r0, r1] // read notemap entry [instr+note*2+notemap_offset]
546 strb r2, [r7, #MCH_NOTE] // write note value
547 cmp r6, #0 // if channel is valid
548 mov r0, r2, lsr#8 // write sample value
549 strneb r0, [r6, #MCA_SAMPLE] // ..
556 cmp r6, #0 // read notemap [sample]
557 ldrneb r2, [r0, #C_MASI_MAP+1]
558 strneb r2, [r6, #MCA_SAMPLE]
560 //invalid_instrument: // BUG???
561 ldrb r2, [r0, #C_MASI_MAP] // read notemap [note]
562 strb r2, [r7, #MCH_NOTE]
569 @***********************************************************
571 @***********************************************************
573 ldrb r0, [r8, #MPL_FLAGS]
575 bcs get_linear_period // tuning not used here with linear periods
578 adr r3, note_table_mod // get octave/mod from note
581 ldrb r2, [r3, r2, lsr#2]
583 // r0 = (note mod 12) << 1
587 ldr r3,=ST3_FREQTABLE // read st3 table entry
590 mov r3, #0x00AB0 // r3 = 133808
592 mul r0, r3, r0 // multiply by magic number...
593 mov r0, r0, lsr r2 // shift by octave
596 swi SWI_DIVIDE<<16 // divide value / tuning
599 .global note_table_oct // remove this, make this static
600 .global note_table_mod // remove this, make this staic
602 .byte 0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5, 6,6,6 ,7,7,7,8,8,8,9,9,9
604 .byte 0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0
608 ldr r1,=IT_PitchTable
609 ldr r0, [r1, r2, lsl#2]