initial commit
[gbajam22] / libs / maxmod / mm_mas_arm.S
1 /****************************************************************************
2  *                                                          __              *
3  *                ____ ___  ____ __  ______ ___  ____  ____/ /              *
4  *               / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __  /               *
5  *              / / / / / / /_/ />  </ / / / / / /_/ / /_/ /                *
6  *             /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/                 *
7  *                                                                          *
8  *                    Module Processing (ARM segment)                       *
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 @=============================================================
26 @                         DEFINITIONS
27 @=============================================================
28
29 #include "mp_format_mas.inc"
30 #include "mp_mas_structs.inc"
31 #include "mp_defs.inc"
32 #include "mp_macros.inc"
33
34 #ifdef SYS_GBA
35 #include "mp_mixer_gba.inc"
36 #include "swi_gba.inc"
37 #endif
38
39 #ifdef SYS_NDS
40 #include "mp_mixer_ds.inc"
41 #include "swi_nds.inc"
42 #endif
43
44 __SECTION_IWRAM
45
46 .arm
47 .align 2
48
49 .global mmAllocChannel
50 @********************************************************
51 mmAllocChannel:
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
57         ldr     r5, [r5]
58         ldr     r1,=mm_achannels                // pointer to active channels
59         ldr     r1, [r1]
60         add     r1, #MCA_FVOL
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
65         b       .mppac_start
66 .mppac_skip:
67         add     r1, #MCA_SIZE
68 .mppac_next_test:
69         cmp     r5, #0
70 .mppac_next_notest:
71         beq     .mppac_finished
72         add     r0, #1
73 .mppac_start:
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
80         
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
87                                                 // 17
88 .mppac_finished:
89         mov     r0, r3
90 //      cmp     r0, #255        //trap
91 //      5: bge 5b
92 .mppac_found:
93         pop     {r4,r5,r6}
94         bx      lr
95
96 .global mmReadPattern
97 @****************************************************
98 mmReadPattern:
99 @****************************************************
100         push    {r10-r12}
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
105         
106         ldr     r0,=mpp_channels
107         ldr     r9, [r0]
108         ldr     r7, [r8, #MPL_PATTREAD]
109         ldr     r0,=mpp_vars
110         str     r7, [r0, #MPV_PATTREAD_P]
111         
112         mov     r1, #0
113
114 @----------------------------------------------------------------
115 readpattern:
116 @----------------------------------------------------------------
117
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
123         orr     r1, r10, lsl r3
124         mov     r0, #MCH_SIZE
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
129         
130         tst     r2, #1                  // test note bit
131         beq     no_note
132         ldrb    r0, [r7], #1            // read note value
133         cmp     r0, #254                // test if < 254
134         strltb  r0, [r6, #MCH_PNOTE]    // [most common result]
135         blt     no_note
136         orreq   r5, #MF_NOTECUT         // 254 is note-cut
137         orrgt   r5, #MF_NOTEOFF         // 255 is note-off
138 no_note:
139         
140         tst     r2, #2                  // shift out instrument bit
141         beq     no_instrument
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
148         cmp     r0, r3
149         beq     same_instrument
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
153 same_instrument:
154         strb    r0, [r6, #MCH_INST]
155 no_instrument:
156         
157         tst     r10, r2, lsr#3          // test volume & effect bits
158         ldrcsb  r0, [r7], #1            // copy vcmd
159         strcsb  r0, [r6, #MCH_VOLCMD]
160 no_vcmd:
161         beq     no_effect
162         ldrb    r0, [r7], #1            // copy effect
163         ldrb    r3, [r7], #1            // copy param
164         orr     r0, r3, lsl#8
165         strh    r0, [r6, #MCH_EFFECT]   // write effect+param
166 no_effect:
167         orr     r5, r2, lsr#4           // orr in the new flags
168         strb    r5, [r6, #MCH_FLAGS]    // save flags
169         b       readpattern             // loop
170 end_of_row:
171         str     r7, [r8, #MPL_PATTREAD] // save read position
172         str     r1, [r8, #MPL_MCH_UPDATE] // save update bits
173         pop     {r10-r12}
174         bx      lr                      // return
175         
176 .macro get_channel branch
177         ldrb    r0, [r7, #MCH_ALLOC]    // get channel
178         cmp     r0, #255                //
179         bge     \branch         // no channel!
180         ldr     r6,=mm_achannels        //
181         ldr     r6, [r6]                //
182         mov     r1, #MCA_SIZE           //
183         mla     r6, r0, r1, r6          //
184 .endm
185
186 .global mmUpdateChannel_T0, mmUpdateChannel_TN
187 @***************************************************************************
188 mmUpdateChannel_T0:                     // for tick 0
189 @***************************************************************************
190         push    {lr}
191         
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
195         
196         tst     r5, #MF_HASFX           // test effect flag
197         beq     no_channel_effect
198         ldrh    r0, [r7, #MCH_EFFECT]   // read effect
199         and     r1, r0, #0xFF
200 //      cmp     r1, #19                 // test for 'SDx' (note delay)
201 //      lsreq   r2, r0, #12
202 //      cmpeq   r2, #0xD
203 //      beq     dont_start_channel      // dont start channel if delayed
204         
205                                         // test for glissando
206         tst     r5, #MF_NEWINSTR
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
210         
211 no_channel_effect:
212         tst     r5, #MF_NEWINSTR        // copeee
213         bne     start_channel           // always start channel if it's a new instrument
214         
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
223         blt     start_channel
224         cmp     r0, #202
225         bgt     start_channel
226         b       glissando_affected
227 xm_vcmd:                                // using XM effects:
228         cmp     r0, #0xF0               // glissando is Fx
229         bge     glissando_affected
230         b       start_channel
231 no_channel_vcmd:
232
233 glissando_affected:
234         
235         get_channel start_channel
236 /*      ldrb    r0, [r7, #MCH_ALLOC]    // if channel is invalid
237         cmp     r0, #255                // then skip this
238         bge     start_channel
239         
240         ldr     r6,=mm_achannels        // get channel
241         ldr     r6, [r6]                //
242         mov     r1, #MCA_SIZE           //
243         mla     r6, r0, r1, r6          //
244 */      
245         bl      mmChannelStartACHN      // start achn
246         bic     r5, #MF_START           // clear start flag
247         strb    r5, [r7, #MCH_FLAGS]
248         b       dont_start_channel
249         
250 start_channel:                          // ok start channel...
251         
252         ldr     r2,=mpp_Channel_NewNote
253         mov     lr, pc
254         bx      r2
255         get_channel     mmUpdateChannel_TN_
256         
257 //      cmp     r6, #0
258 //      beq     mmUpdateChannel_TN_
259         
260         bl      mmChannelStartACHN      // start achn
261 //----------------------------------------------
262         // r2 = note, calculate period
263         ldrb    r0, [r6, #MCA_SAMPLE]
264         subs    r0, #1
265         bcc     no_sample_to_make_period
266         
267         ldrb    r1, [r8, #MPL_FLAGS]
268         lsrs    r1, #C_FLAGS_SS
269         bcs     linear_periods
270         
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
275         
276         ldrh    r1, [r0, #C_MASS_FREQ]  // read tuning freq
277         lsl     r1, #2                  // shift ...
278 //      mov     r0, r2                  // move this.
279         bl      get_amiga_period
280         b       got_period
281 linear_periods:
282         LDR     R1,=IT_PitchTable
283         LDR     R0, [R1, R2, LSL#2]
284         //bl    get_linear_period
285 got_period:
286 //--------------------------------
287         
288 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
289         str     r0, [r7, #MCH_PERIOD]   // save period
290         ldrb    r0, [r6, #MCA_FLAGS]    // set start flag
291         orr     r0, #MCAF_START
292         strb    r0, [r6, #MCA_FLAGS]
293 no_sample_to_make_period:
294 //----------------------------------------------------
295         
296         b       channel_started
297         
298 dont_start_channel:
299         
300         get_channel     mmUpdateChannel_TN___
301         
302 channel_started:
303         tst     r5, #MF_DVOL
304         beq     dvol_skip
305         ldrb    r0, [r7, #MCH_INST]
306         subs    r0, #1
307         bcc     dvol_no_instrument
308         
309         ldr     r2, [r8, #MPL_SONGADR]  // get instrument pointer
310         ldr     r1, [r8, #MPL_INSTTABLE]
311         ldr     r0, [r1, r0, lsl#2]
312         add     r0, r2
313         
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]
319         
320         ldrb    r2, [r6, #MCA_FLAGS]    // read achn flags
321         bic     r2, #MCAF_VOLENV
322         tst     r1, #ENVFLAG_A<<8
323         orrne   r2, #MCAF_VOLENV
324         strb    r2, [r6, #MCA_FLAGS]
325         
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]
329 dvol_no_instrument:
330         
331         ldrb    r0, [r6, #MCA_SAMPLE]   // read sample#
332         subs    r0, #1
333         bcc     dvol_no_sample          // exit if invalid
334         
335         ldr     r2, [r8, #MPL_SONGADR]  // get sample address
336         ldr     r1, [r8, #MPL_SAMPTABLE]
337         ldr     r0, [r1, r0, lsl#2]
338         //add   r0, r2
339         
340         ldrh    r1, [r0, r2]
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
344         mov     r1, r1, lsr#24
345         strcsb  r1, [r7, #MCH_PANNING]
346 dvol_skip:
347 dvol_no_sample:
348
349         tst     r5, #MF_START|MF_DVOL
350         beq     dont_reset_volume
351         
352         ldrb    r0, [r8, #MPL_FLAGS]
353         tst     r0, #C_FLAGS_X
354         beq     1f
355         tst     r5, #MF_DVOL
356         beq     dont_reset_volume       // xm stuff
357 1:
358 reset_volume:
359         mov     r0, #(1<<10)            // [1]
360         mov     r1, #0                  // [1]
361         mov     r2, #0                  // [1]
362         add     r12, r6, #MCA_FADE      // [1]
363         stmia   r12, {r0-r2}            // [19]
364                                         // [23]
365         strh    r1, [r6, #MCA_ENVN_VOL]
366         strb    r1, [r6, #MCA_ENVN_PIC]
367         
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
372         
373         strb    r1, [r7, #MCH_FXMEM]    // clear fx memory
374         
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]
379         
380 dont_reset_volume:
381
382         tst     r5, #MF_NOTEOFF         // test noteoff bit
383         beq     skip_noteoff
384         
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]
391 skip_noteoff:
392
393         tst     r5, #MF_NOTECUT         // test notecut bit
394         movne   r0, #0                  // clear volume
395         strneb  r0, [r7, #MCH_VOLUME]   // on note-cut
396         
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 @************************************************************
403         push    {lr}
404         
405 mmUpdateChannel_TN_:
406         ldrb    r0, [r7, #MCH_ALLOC]    // get channel
407         cmp     r0, #255                //
408         bge     mmUpdateChannel_TN___   // no channel!
409         ldr     r6,=mm_achannels        //
410         ldr     r6, [r6]                //
411         mov     r1, #MCA_SIZE           //
412         mla     r6, r0, r1, r6          //
413         
414 mmUpdateChannel_TN___:
415         
416         movge   r6, #0
417
418         ldr     r5, [r7, #MCH_PERIOD]           // r5 will be used to hold the period
419         ldr     r1,=mpp_vars
420         mov     r0, #0
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]
425         
426 //---------------------------------------------
427 // Update Volume Commands
428 //---------------------------------------------
429
430         ldrb    r0, [r7, #MCH_FLAGS]
431         tst     r0, #MF_HASVCMD
432         ldrne   r1,=mpp_Process_VolumeCommand
433         movne   lr, pc
434         bxne    r1
435         //blne  mpp_Process_VolumeCommand
436         
437 //---------------------------------------------
438 // Update Effects
439 //--------------------------------------------- 
440         
441         ldrb    r0, [r7, #MCH_FLAGS]
442         tst     r0, #MF_HASFX
443         ldrne   r1,=mpp_Process_Effect
444         movne   lr, pc
445         bxne    r1
446         //blne  mpp_Process_Effect
447         
448 //---------------------------------------------
449
450         cmp     r6, #0
451         beq     no_achn
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
458         
459         ldr     r1,=mpp_vars            // 
460         ldrsb   r2, [r1, #MPV_VOLPLUS]  // read volume addition
461         adds    r0, r2, lsl#3           // add to volume
462         movmi   r0, #0
463         cmp     r0, #129
464         movcs   r0, #128
465         strb    r0, [r1, #MPV_AFVOL]    // store in immediate vol
466         
467         ldrb    r0, [r1, #MPV_NOTEDELAY]// read note delay
468         cmp     r0, #0                  // dont update if nonzero
469         beq     channel_update_achn
470         
471         ldrb    r0, [r6, #MCA_FLAGS]
472         orr     r0, #MCAF_UPDATED
473         strb    r0, [r6, #MCA_FLAGS]
474         b       no_achn
475         
476 channel_update_achn:
477
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]
482         mov     r0, #0
483         strh    r0, [r1, #MPV_PANPLUS]  // WHAT IS THIS??? "@ <---- RESERVED FOR LATER USE, CLEAR TO ZERO TEMPORARILY"
484         
485         ldrb    r0, [r6, #MCA_FLAGS]
486         orr     r0, #MCAF_UPDATED
487         strb    r0, [r6, #MCA_FLAGS]
488         
489         push    {r4}
490         ldrb    r4, [r7, #MCH_ALLOC]
491         ldr     r1,=mpp_Update_ACHN_notest
492         mov     lr, pc
493         bx      r1
494         
495         pop     {r4}
496 no_achn:
497         pop     {lr}
498         bx      lr
499
500 @***********************************************************
501 mmChannelStartACHN:             // returns r2=note
502 @***********************************************************
503         ldrb    r2, [r7, #MCH_BFLAGS+1]         // clear tremor/cutvol
504         bic     r2, #0b110
505         strb    r2, [r7, #MCH_BFLAGS+1]
506         
507         cmp     r6, #0                          // achn==0?
508         beq     1f                              // then skip this part
509         
510         mov     r0, #ACHN_FOREGROUND            // set foreground type
511         strb    r0, [r6, #MCA_TYPE]
512         
513         ldrb    r0, [r6, #MCA_FLAGS]            // read flags
514         bic     r0, #0b11000000                 // clear SUB, EFFECT
515         ldr     r1,=mpp_clayer                  // get layer
516         ldrb    r1, [r1]
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]
523         subs    r0, #1
524         bcc     invalid_instrument
525         
526         ldr     r2, [r8, #MPL_SONGADR]          // get instrument pointer
527         ldr     r1, [r8, #MPL_INSTTABLE]
528         ldr     r0, [r1, r0, lsl#2]
529         add     r0, r2
530         
531         ldrb    r2, [r7, #MCH_PNOTE]            // get pattern note
532         
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!
536                                                 // use single entry
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)
540         bx      lr                              // return
541         
542 full_notemap:
543         
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]           //   ..
550         and     r2, #255
551 invalid_instrument:
552         bx      lr                              // return
553         
554 /**********
555         
556         cmp     r6, #0                          // read notemap [sample]
557         ldrneb  r2, [r0, #C_MASI_MAP+1]
558         strneb  r2, [r6, #MCA_SAMPLE]
559         
560 //invalid_instrument:                           // BUG???
561         ldrb    r2, [r0, #C_MASI_MAP]           // read notemap [note]
562         strb    r2, [r7, #MCH_NOTE]
563 invalid_instrument:
564         
565         bx      lr
566 **************/
567         
568 .global mmGetPeriod
569 @***********************************************************
570 mmGetPeriod:
571 @***********************************************************
572
573         ldrb    r0, [r8, #MPL_FLAGS]
574         lsrs    r0, #C_FLAGS_SS
575         bcs     get_linear_period       // tuning not used here with linear periods
576         
577 get_amiga_period:
578         adr     r3, note_table_mod      // get octave/mod from note
579         ldrb    r0, [r3, r2]
580         sub     r3, #3*10
581         ldrb    r2, [r3, r2, lsr#2]
582         
583         // r0 = (note mod 12) << 1
584         // r1 = tuning
585         // r2 = (note / 12)
586         
587         ldr     r3,=ST3_FREQTABLE       // read st3 table entry
588         ldrh    r0, [r3, r0]
589         
590         mov     r3, #0x00AB0            // r3 = 133808
591         orr     r3, #0x20000
592         mul     r0, r3, r0              // multiply by magic number...
593         mov     r0, r0, lsr r2          // shift by octave
594         cmp     r1, #0
595         beq     1f
596         swi     SWI_DIVIDE<<16          // divide value / tuning
597 1:      bx      lr
598         
599 .global note_table_oct  // remove this, make this static
600 .global note_table_mod  // remove this, make this staic
601 note_table_oct:
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
603 note_table_mod:
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
605 .align 2
606
607 get_linear_period:
608         ldr     r1,=IT_PitchTable
609         ldr     r0, [r1, r2, lsl#2]
610         bx      lr
611
612 .pool