#include "na_macro.inc" .equ VOICE_COUNT, 32 .equ CHANNEL_COUNT, 48 .equ VS_FREE, 1 .equ VS_USED, 2 .equ VS_RELEASED, 3 .equ VS_LOCKED, 4 .equ DF_START, 1 .equ DF_VOLUME, 2 .equ DF_PANNING, 4 .equ DF_PITCH, 8 .equ DF_FILTER, 16 .equ DF_SOURCE, 32 STRUCT V16 TRACK_MVOL V8 TRACK_GVOL V8 TRACK_DFLAGS V32 TRACK_EXTENSIONS V8 TRACK_INDEX V8 TRACK_PITCHMODE V8 TRACK_TFLAGS V8 TRACK_ACTIVE V32 TRACK_PITCHADJUST V32 TRACK_GTIMER V32 TRACK_TIMER V32 TRACK_TEMPO V32 TRACK_FIRSTBLOCK V32 TRACK_LASTBLOCK V32 TRACK_FIRSTINST V32 TRACK_LASTINST V8 TRACK_CHSEL V8 TRACK_CHANNELSUSED VARR TRACK_CHANNELMAP, 30 ENDSTRUCT TRACK_SIZE STRUCT V32 EXT_PROGRAM V32 EXT_GMEM V32 EXT_CMEM V32 EXT_VMEM V8 EXT_GMSIZE V8 EXT_CMSIZE V8 EXT_VMSIZE V8 EXT_MODIFIERS V32 EXT_GMODS V32 EXT_CMODS V32 EXT_VMODS ENDSTRUCT EXT_SIZE STRUCT V8 CHANNEL_PARENT V8 CHANNEL_VOLUME V8 CHANNEL_INDEX V8 CHANNEL_DFLAGS V32 CHANNEL_VOICE ENDSTRUCT CHANNEL_SIZE STRUCT V8 VOICE_PANNING V8 VOICE_CUTOFF V8 VOICE_RESO V8 VOICE_DFLAGS V8 VOICE_HANDLE V8 VOICE_PARENTTRACK V8 VOICE_PARENTCHANNEL V8 VOICE_INDEX V8 VOICE_STATE V8 VOICE_SIG V8 VOICE_KEYOFF V8 VOICE_RES2 V16 VOICE_VOLUME V16 VOICE_PITCH V32 VOICE_SOURCE V32 VOICE_SOURCEOFS V32 VOICE_PREV V32 VOICE_NEXT ENDSTRUCT VOICE_SIZE STRUCT V16 MOD_VOLUME V16 MOD_PITCH V8 MOD_PANNING V8 MOD_CUTOFF V8 MOD_RESO V8 MOD_MODES ENDSTRUCT MOD_SIZE STRUCT V32 EXI_ELEMENT V32 EXI_MOD V32 EXI_LMEM V32 EXI_GMEM V32 EXI_PARAM1 ENDSTRUCT EXI_SIZE #define MODSIZE_L2 3 .bss pitch_table_copy: .space (768+1)*2 .TEXT ARM_CODE @=============================================================================== .macro test_run_extensions dat, treg, function @=============================================================================== ldrb \dat, [\treg, #TRACK_EXTENSIONS+3] @; test/run slot3 movs \dat, \dat, lsl#2 @; blne \function @; @------------------------------------------------------------------------------- ldrb \dat, [\treg, #TRACK_EXTENSIONS+2] @; test/run slot3 movs \dat, \dat, lsl#2 @; blne \function @; @------------------------------------------------------------------------------- ldrb \dat, [\treg, #TRACK_EXTENSIONS+1] @; test/run slot3 movs \dat, \dat, lsl#2 @; blne \function @; @------------------------------------------------------------------------------- ldrb \dat, [\treg, #TRACK_EXTENSIONS+0] @; test/run slot3 movs \dat, \dat, lsl#2 @; blne \function @; .endm @; @------------------------------------------------------------------------------- @=============================================================================== public function nasRunExtensionsG @=============================================================================== //; run sequencer extensions -- global/track //; //; r0 = track //; r1 = vector (0..7) //; r2 = param1 //; r3 = param2 @------------------------------------------------------------------------------- push {r4-r7,lr} //; preserve regs @------------------------------------------------------------------------------- push {r2, r3} //; init extensionInfo sub sp, #12 //; set element, param1/2 push {r0} //; reserve space for mod, lmem, gmem @------------------------------------------------------------------------------- mov r4, r0 //; r4 = track mov r5, r1, lsl#2 //; r5 = vector*4 ldr r6,=nasExtensionPtrs-4 //; r6 = extension pointers @------------------------------------------------------------------------------- test_run_extensions r0, r4, run_extension_g @------------------------------------------------------------------------------- add sp, #24 //; pop extensionInfo pop {r4-r7,lr} //; return ret // @------------------------------------------------------------------------------- run_extension_g: @------------------------------------------------------------------------------- ldr r3, [r6, r0] //; r3 = ext data ldr r0, [r3, #EXT_PROGRAM] //; r7 = vector ldr r7, [r0, r5] //; cmp r7, #0 //; quit if zero-vector bxeq lr //; @------------------------------------------------------------------------------- ldrb r0, [r4, #TRACK_INDEX] //; r0 = track# ldr r1, [r3, #EXT_GMODS] //; r1 = gmods ? gmods+track : null cmp r1, #0 //; ldrneb r2, [r4, #TRACK_INDEX] //; addne r1, r1, r0, lsl#MODSIZE_L2 //; str r1, [sp, #EXI_MOD] //; write to struct.mod ldr r2, [r3, #EXT_GMEM] //; r2 = gmem + track#*gmsize ldrb r3, [r3, #EXT_GMSIZE] //; mul r3, r0 //; add r2, r2, r3, lsl#2 //; str r2, [sp, #EXI_LMEM] //; write to struct.lmem str r2, [sp, #EXI_GMEM] //; write to struct.gmem mov r0, sp //; r0 = extensionInfo @------------------------------------------------------------------------------- bx r7 //; jump to vector @=============================================================================== public function nasRunExtensionsC @=============================================================================== //; run sequencer extensions -- channel //; //; r0 = track //; r1 = vector //; r2 = param1 //; r3 = param2 //; s1 = channel @------------------------------------------------------------------------------- push {r4-r7,lr} //; preserve regs ldr r6, [sp, #20] //; r6 = element (channel) @------------------------------------------------------------------------------- push {r2, r3} //; push param2,param1 sub sp, #12 //; reserve space for mod,lmem,gmem push {r6} //; push element @------------------------------------------------------------------------------- mov r4, r0 //; r4=track mov r5, r1, lsl#2 //; r5=channel vector (address) ldr r7,=nasExtensionPtrs-4 //; r7=extension ptrs add r5, #8*4 //; @------------------------------------------------------------------------------- test_run_extensions r0, r4, run_extension_c @------------------------------------------------------------------------------- add sp, #24 pop {r4-r7, lr} ret @------------------------------------------------------------------------------- run_extension_c: @------------------------------------------------------------------------------- ldr r3, [r7, r0] //; r3 = ext data ldr r0, [r3, #EXT_PROGRAM] //; r12 = vector ldr r12, [r0, r5] //; cmp r12, #0 //; bxeq lr //; quit on zerovector @------------------------------------------------------------------------------- ldr r0, [r3, #EXT_GMEM] //; set info.gmem ldrb r1, [r4, #TRACK_INDEX] //; ldrb r2, [r3, #EXT_GMSIZE] //; mul r2, r1 //; add r0, r2, lsl#2 //; str r0, [sp, #EXI_GMEM] //; @------------------------------------------------------------------------------- ldr r0, [r3, #EXT_CMEM] //; set info.lmem ldrb r1, [r6, #CHANNEL_INDEX] //; ldrb r2, [r3, #EXT_CMSIZE] //; mul r2, r1 //; add r0, r2, lsl#2 //; str r0, [sp, #EXI_LMEM] //; @------------------------------------------------------------------------------- ldr r0, [r3, #EXT_CMODS] //; set mod (cmod) cmp r0, #0 //; addne r0, r0, r1, lsl#MODSIZE_L2 //; str r0, [sp, #EXI_MOD] //; @------------------------------------------------------------------------------- mov r0, sp //; r0 = info @------------------------------------------------------------------------------- bx r12 @=============================================================================== public function nasRunExtensionsV @=============================================================================== //; run sequencer extensions -- voice //; //; r0 = track //; r1 = vector //; r2 = param1 //; r3 = param2 //; s1 = voice @------------------------------------------------------------------------------- push {r4-r7, lr} //; preserve regs ldr r6, [sp, #20] //; r6 = element (voice) @------------------------------------------------------------------------------- push {r2, r3} //; write param2,param1 sub sp, #12 //; reserve space push {r6} //; write element @------------------------------------------------------------------------------- mov r4, r0 //; r4=track mov r5, r1, lsl#2 //; r5 = voice routine address add r5, #16*4 //; r7 = extension ptrs ldr r7,=nasExtensionPtrs-4 //; @------------------------------------------------------------------------------- test_run_extensions r0, r4, run_extension_v @------------------------------------------------------------------------------- add sp, #24 pop {r4-r7, lr} ret @------------------------------------------------------------------------------- run_extension_v: @------------------------------------------------------------------------------- ldr r3, [r7, r0] //; r3 = ext data ldr r0, [r3, #EXT_PROGRAM] //; r12 = vector ldr r12, [r0, r5] //; cmp r12, #0 //; bxeq lr //; @------------------------------------------------------------------------------- ldr r0, [r3, #EXT_GMEM] //; write info.gmem ldrb r1, [r4, #TRACK_INDEX] //; ldrb r2, [r3, #EXT_GMSIZE] //; mul r2, r1 //; add r0, r2, lsl#2 //; str r0, [sp, #EXI_GMEM] //; @------------------------------------------------------------------------------- ldr r0, [r3, #EXT_VMEM] //; write info.lmem ldrb r1, [r6, #VOICE_INDEX] //; ldrb r2, [r3, #EXT_VMSIZE] //; mul r2, r1 //; add r0, r2, lsl#2 //; str r0, [sp, #EXI_LMEM] //; @------------------------------------------------------------------------------- ldr r0, [r3, #EXT_VMODS] //; write info.mod cmp r0, #0 //; addne r0, r1, lsl#MODSIZE_L2 //; str r0, [sp, #EXI_MOD] //; @------------------------------------------------------------------------------- mov r0, sp //; r0 = info @------------------------------------------------------------------------------- bx r12 //; jump to routine @=============================================================================== public function nasResetVoiceModifiers @=============================================================================== @ r0 = track @ r1 = voice @------------------------------------------------------------------------------- push {r4,lr} @ ldr r0, [r0, #TRACK_EXTENSIONS] @ r0 = extension list ldrb r1, [r1, #VOICE_INDEX] @ r1 = voice index mov r2, #0xFF @ r2 = 0FFh ldr r3,=nasExtensionPtrs-4 @ r3 = extension ptrs mov r12, #0 @ r12 = zero @------------------------------------------------------------------------------ ands r4, r2, r0 @ test extensions, r4=index blne .resetmod @ ands r4, r2, r0, lsr#8 @ blne .resetmod @ ands r4, r2, r0, lsr#16 @ blne .resetmod @ ands r4, r2, r0, lsr#24 @ blne .resetmod @ @------------------------------------------------------------------------------ pop {r4,lr} ret @------------------------------------------------------------------------------ .resetmod: @------------------------------------------------------------------------------ ldr r4, [r3, r4, lsl#2] @; r4 = vmods ldr r4, [r4, #EXT_VMODS] @; catch no modifiers cmp r4, #0 @; bxeq lr @; @------------------------------------------------------------------------------ str r12, [r4, r1, lsl#MODSIZE_L2]! @; reset modifier str r12, [r4, #4] @; bx lr @; #define voice r4 #define track r5 #define chan r6 #define vcount r7 #define df r8 #define ga r9 // general purpose #define gb r10 #define gc r11 #define gd r12 @=============================================================================== public function nasUpdateVoices @=============================================================================== push {r4-r11, lr} ldr voice,=nasVoices ldr track,=nasTracks - TRACK_SIZE ldr chan,=nasChannels - CHANNEL_SIZE mov vcount, #VOICE_COUNT @------------------------------------------------------------------------------- .nuv_loop: //; skip locked voices ldrb r0, [voice, #VOICE_STATE] // cmp r0, #VS_LOCKED // beq .next_voice // @------------------------------------------------------------------------------- cmp r0, #VS_FREE //; cut free voices bne .activevoice //; ldrb r0, [voice, #VOICE_INDEX] //; mov r1, #0 //; strb r1, [voice, #VOICE_DFLAGS] //; bl naxSetVolume //; b .next_voice //; @------------------------------------------------------------------------------- .activevoice: //; ldrb r0, [voice, #VOICE_PARENTTRACK] //; r0 = track ldrb r1, [voice, #VOICE_PARENTCHANNEL] //; r1 = channel cmp r0, #0 beq .next_voice cmp r1, #0 beq .next_voice @ adds r2, r0, r1 //; skip if no parent track or channel @ cmp r2, #2 //; @ blt .next_voice //; @------------------------------------------------------------------------------- push {track,chan} //; save track base, chan base mov r2, #TRACK_SIZE //; get local pointers mla track, r2, r0, track //; mov r2, #CHANNEL_SIZE //; mla chan, r2, r1, chan //; @------------------------------------------------------------------------------- ldrb df, [voice, #VOICE_DFLAGS] //; r8 = vdf|cdf|gdf ldrb r0, [track, #TRACK_DFLAGS] //; orr df, r0 //; ldrb r0, [chan, #CHANNEL_DFLAGS] //; orr df, r0 //; mov r0, #0 //; strb r0, [voice, #VOICE_DFLAGS] //; reset voice.df @------------------------------------------------------------------------------- tst df, #DF_SOURCE //; test source flag beq .source_test //; @------------------------------------------------------------------------------- ldr r1, [voice, #VOICE_SOURCE] //; set source ldrb r0, [voice, #VOICE_INDEX] //; +apply offset if nonzero bl naxSetSource //; ldr r1, [voice, #VOICE_SOURCEOFS] //; cmp r1, #0 //; beq 1f //; ldrb r0, [voice, #VOICE_INDEX] //; bl naxSetOffset //; ***todo: upgrade toolchain and test blne again 1: mov r0, #0 //; str r0, [voice, #VOICE_SOURCEOFS] //;-reset offset .source_test: //; @------------------------------------------------------------------------------- tst df, #DF_VOLUME //; test vol flag beq .volume_test //; @------------------------------------------------------------------------------- ldrh r0, [voice, #VOICE_VOLUME] //; compute volume ldrb r1, [track, #TRACK_GVOL] //; r0 = voice.vol (i.16) mul r0, r1 //; *= track.vol (i.7) ldrb r1, [chan, #CHANNEL_VOLUME] //; *= channel.vol (i.7) mul r0, r1 //; mov r0, r0, lsr#7+7 //; adjust to i.16 bl applyVolumeModifiers //; apply ext:vol ldrh r1, [track, #TRACK_MVOL] //; apply master volume mul r0, r1 //; add r0, #1<<11 //; mov r0, r0, lsr#12 //; cmp r0, #65536 //; saturate result ldrge r0,=65535 //; @------------------------------------------------------------------------------- mov r1, r0, lsr#8 //; set significance strb r1, [voice, #VOICE_SIG] //; mov r1, r0 //; @------------------------------------------------------------------------------- ldrb r0, [voice, #VOICE_INDEX] //; update nax bl naxSetVolume //; @------------------------------------------------------------------------------- .volume_test: @------------------------------------------------------------------------------- tst df, #DF_PANNING //; test pan flag beq .panning_test //; @------------------------------------------------------------------------------- ldrb r0, [voice, #VOICE_PANNING] //; r0 = panning (i.7) mov r0, r0, lsl#8 //; create i.15 bl applyPanningModifiers //; apply ext:pan add r0, #1<<6 //; create i.8 mov r1, r0, lsr#7 //; cmp r1, #256 //; saturate result movge r1, #255 //; ldrb r0, [voice, #VOICE_INDEX] //; bl naxSetPanning //; @------------------------------------------------------------------------------- .panning_test: @------------------------------------------------------------------------------- tst df, #DF_PITCH //; test pitch flag beq .pitch_test //; @------------------------------------------------------------------------------- ldrh r0, [voice, #VOICE_PITCH] //; r0 = pitch (16bit) bl applyPitchModifiers //; apply mods movs r1, r0 //; movmi r1, #0 //; cmp r1, #65536 //; ldrge r1,=65535 //; mov r0, track //; ldrb r2, [voice, #VOICE_INDEX] //; bl nasTranslatePitch //; translate pitch mov r1, r0 //; ldrb r0, [voice, #VOICE_INDEX] //; bl naxSetPitch //; update nax @------------------------------------------------------------------------------- .pitch_test: @------------------------------------------------------------------------------- tst df, #DF_FILTER //; test filter flag beq .filter_test //; @------------------------------------------------------------------------------- ldrb r0, [voice, #VOICE_CUTOFF] //; read cutoff cmp r0, #128 lsl r0, #8 //; bl applyCutoffModifiers //; apply mods add r0, #128 //; mov r0, r0, lsr#8 //; cmp r0, #128 //; disable filter if c >= 128 bge .filter_disabled //; @------------------------------------------------------------------------------- push {r0} //; save C ldrb r0, [voice, #VOICE_RESO] //; get resonance and apply mods lsl r0, #8 //; bl applyResoModifiers //; add r0, #128 //; mov r2, r0, lsr#8 //; cmp r2, #127 //; saturate resonance to 127 movge r2, #127 //; pop {r1} //; r1 = cutoff ldrb r0, [voice, #VOICE_INDEX] //; r0 = index bl naxSetFilter //; update nax b .filter_test //; @------------------------------------------------------------------------------- .filter_disabled: //; disable filtering ldrb r0, [voice, #VOICE_INDEX] //; bl naxDisableFilter //; .filter_test: //; @------------------------------------------------------------------------------- //; tst df, #DF_SOURCE //; test source flag //; beq .source_test //; @------------------------------------------------------------------------------- //; ldr r1, [voice, #VOICE_SOURCE] //; set new source //; ldrb r0, [voice, #VOICE_INDEX] //; //; bl naxSetSource //; //;.source_test: //; @------------------------------------------------------------------------------- //; restore tracks,chans pointers //; pop {track, chan} //; @------------------------------------------------------------------------------- .next_voice: //; adjust voice ptr add voice, #VOICE_SIZE //; subs vcount, vcount, #1 //; loop until vcount=0 bne .nuv_loop //; @------------------------------------------------------------------------------- ldr r0,=nasTracks+TRACK_DFLAGS //; reset track dflags mov r1, #0 //; strb r1, [r0], #TRACK_SIZE //; strb r1, [r0], #TRACK_SIZE //; strb r1, [r0], #TRACK_SIZE //; strb r1, [r0], #TRACK_SIZE //; @------------------------------------------------------------------------------- ldr r0,=nasChannels+CHANNEL_DFLAGS //; reset channel dflags mov r2, #CHANNEL_COUNT //; 1: strb r1, [r0, #CHANNEL_SIZE] //; subs r2, #1 //; bne 1b //; @------------------------------------------------------------------------------- pop {r4-r11,lr} bx lr @=============================================================================== applyVolumeModifiers: @=============================================================================== .macro runmods function push {lr} @ save LR ldr ga,=nasExtensionPtrs-4 @ ga = extension ptrs -4 ldr gb, [track, #TRACK_EXTENSIONS] @ gb = extension list movs r1, gb, lsr#24 @ test and run routine blne \function @ movs r1, gb, lsr#16 @ ands r1, #255 @ blne \function @ movs r1, gb, lsr#8 @ ands r1, #255 @ blne \function @ ands r1, gb, #255 @ blne \function @ pop {pc} @ .endm runmods .runmodv .runmodv: @ r1 = ext+1 push {lr} ldr r3, [ga, r1, lsl#2] @ r3 = ext .macro rm_routine mods, thing, index, routine @ load modifier ldr r1, [r3, #\mods] @ skip code if null cmp r1, #0 @ ldrneb r2, [\thing, #\index] @ blne \routine @ 1: .endm rm_routine EXT_VMODS, voice, VOICE_INDEX, .apply_volmod rm_routine EXT_CMODS, chan, CHANNEL_INDEX, .apply_volmod rm_routine EXT_GMODS, track, TRACK_INDEX, .apply_volmod pop {pc} @------------------------------------------------------------------------------- .apply_volmod: @------------------------------------------------------------------------------- @ r0 = value @ r1 = mods @ r2 = index @------------------------------------------------------------------------------- add r1, r1, r2, lsl#MODSIZE_L2 @ get mod ldrh r1, [r1, #MOD_VOLUME] @ get volume movs r2, r1, lsr#14 @ quit if 'disabled' bxeq lr @ @------------------------------------------------------------------------------- cmp r2, #2 @ test mode bgt .avm_over @ beq .avm_add @ @------------------------------------------------------------------------------- .avm_scale: @ v = v * a (1.13) bic r1, #0xC000 @ mul r0, r1 @ add r0, #1<<13 @ round result mov r0, r0, lsr#13 @ cmp r0, #65536 @ movge r0, #65536 @ ret @ @------------------------------------------------------------------------------- .avm_add: @ v = sat(v+a, 0, 65535) mov r1, r1, lsl#32-14 @ adds r0, r1, asr#32-17 @ movmi r0, #0 @ cmp r0, #65536 @ movge r0, #65536 @ ret @------------------------------------------------------------------------------- .avm_over: @ v = a mov r0, r1, lsl#32-14 @ mov r0, r0, lsr#16 @ ret @ @=============================================================================== applyPanningModifiers: @=============================================================================== runmods .runmodp .runmodp: push {lr} ldr r3, [ga, r1, lsl#2] @ r3 = ext rm_routine EXT_VMODS, voice, VOICE_INDEX, .apply_panmod rm_routine EXT_CMODS, chan, CHANNEL_INDEX, .apply_panmod rm_routine EXT_GMODS, track, TRACK_INDEX, .apply_panmod pop {pc} .apply_panmod: @ r0 = pan (i.15) add r1, r1, r2, lsl#MODSIZE_L2 @ get mod ldrb r2, [r1, #MOD_MODES] @ r2=modes ands r2, #3<<2 @ exit if 'disabled' bxeq lr @ ldrb r1, [r1, #MOD_PANNING] @ r1=panning @------------------------------------------------------------------------------- cmp r2, #2<<2 @ test mode bgt .apm_over @ beq .apm_add @ @------------------------------------------------------------------------------- .apm_scale: @ p = p + (a-0.5)*(0.5-|p-0.5|) sub r1, #0x80 @ r1 = a-0.5 (s.7) subs r2, r0, #16384 @ r2 = |p-0.5| rsbmi r2, r2, #0 @ rsb r2, r2, #16384 @ r2 = 0.5-r2 mul r1, r2 @ r1 = (a-0.5)*(0.5-|p-0.5|) : i.(15+7) adds r0, r1, asr#7 @ r0 = result movmi r0, #0 @ clamping needed ? cmp r0, #32768 @ movge r0, #32768 @ ret @ @------------------------------------------------------------------------------- .apm_add: @ p = sat(p+a) mov r1, r1, lsl#24 @ adds r0, r0, r1, asr#16 @ movmi r0, #0 @ cmp r0, #32768 @ movge r0, #32768 @ ret @ @------------------------------------------------------------------------------- .apm_over: @ p = a mov r0, r1, lsl#7 @ ret @ @=============================================================================== applyPitchModifiers: @=============================================================================== runmods .runmodpitch .runmodpitch: push {lr} ldr r3, [ga, r1, lsl#2] @ r3 = ext rm_routine EXT_VMODS, voice, VOICE_INDEX, .apply_pitchmod rm_routine EXT_CMODS, chan, CHANNEL_INDEX, .apply_pitchmod rm_routine EXT_GMODS, track, TRACK_INDEX, .apply_pitchmod pop {pc} @ r0 = pitch @ r1 = mod @------------------------------------------------------------------------------- .apply_pitchmod: @-------------------------------------------------------@----------------------- add r1, r1, r2, lsl#MODSIZE_L2 @ get mod ldrb r2, [r1, #MOD_MODES] @ get mode ands r2, #0x3 @ skip if disabled bxeq lr @ ldrsh r1, [r1, #MOD_PITCH] @ r1 = pitchmod (semitones*64, or direct value) @---------------------------------------@---------------@----------------------- cmp r2, #2 @ test mode bxlt lr @ 2=add bgt .aptm_over @ 3=overr @---------------------------------------@-------@------------------------------- .aptm_add: @ test pitchmode ldrb r2, [track, #TRACK_PITCHMODE] @ cmp r2, #1 @ bge .aptm_log @ @-------------------------------@---------------@------------------------------- .aptm_linear: @ p = sat(p+a) adds r0, r1 @ movmi r0, #0 @ cmp r0, #65536 @ movgt r0, #65536 @ ret @ @-------------------------------@----------------------------------------------- .aptm_log: @ "p = p * 2^(a/768)" rsbeq r1, r1, #0 @ negate amount in period mode adr r2, nas_table_div3 @ r2 = a / 768 (-16..16) ldrb r2, [r2, r1, asr#8] @ sub r1, r2, lsl#9 @ r1 = a % 768 (0..767) sub r1, r2, lsl#8 @ push {r0, r2, lr} @ (?dont need to preserve r2 for swi?) mov r0, r1 @ bl nasReadPitchTable @ get pitchtable entry pop {r1, r2, lr} @ mul r0, r1, r0 @ value *= pt rsb r2, r2, #16 @ value >>= (16-oct) mov r0, r0, lsr r2 @ ret @ @------------------------------------------------------------------------------- .aptm_over: mov r0, r1 ret @=============================================================================== applyCutoffModifiers: mov gc, #0 b 1f applyResoModifiers: mov gc, #1 @=============================================================================== 1: runmods .runmodco .runmodco: push {lr} ldr r3, [ga, r1, lsl#2] @ r3 = ext rm_routine EXT_VMODS, voice, VOICE_INDEX, .apply_filtermod rm_routine EXT_CMODS, chan, CHANNEL_INDEX, .apply_filtermod rm_routine EXT_GMODS, track, TRACK_INDEX, .apply_filtermod pop {pc} .apply_filtermod: add r1, r1, r2, lsl#MODSIZE_L2 @ get mod ldrb r2, [r1, #MOD_MODES] @ get mode cmp gc, #0 @ moveq r2, r2, lsr#4 @ movne r2, r2, lsr#6 @ ands r2, #0x3 @ skip if disabled bxeq lr @ cmp gc, #0 @ ldreqb r1, [r1, #MOD_CUTOFF] @ r1 = filter modifier (i.7) ldrneb r1, [r1, #MOD_RESO] @ @----------------------------------------------------------------------------------- cmp r2, #2 bgt .afm_over beq .afm_add .afm_scale: mul r0, r1 mov r0, r0, lsr#7 b .afm_sat .afm_add: adds r0, r0, r1, lsl#8 @ todo (sign extension with suitable range) movmi r0, #0 .afm_sat: cmp r0, #32768 movge r0, #32768 ret .afm_over: mov r0, r1, lsl#8 ret .global nas_table_div3 .byte -16, -16, -16, -15, -15, -15, -14, -14, -14, -13, -13, -13 .byte -12, -12, -12, -11, -11, -11, -10, -10, -10, -9, -9, -9 .byte -8, -8, -8, -7, -7, -7, -6, -6, -6, -5, -5, -5 .byte -4, -4, -4, -3, -3, -3, -2, -2, -2, -1, -1, -1 nas_table_div3: .byte 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3 .byte 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7 .byte 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11 .byte 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15 @=============================================================================== public function nasInitPitchTable @=============================================================================== @; internal pitch table swi takes too many cycles (80-90) @; buffer pitch table to local memory push {r4,r5} @------------------------------------------------------------------------------- ldr r4,=pitch_table_copy + 768*2 //; r4 = write mov r0, #0xFF //; set entry 768 (not incl in bios table) orr r0, #0xFF00 //; strh r0, [r4], #-2 //; @------------------------------------------------------------------------------- mov r5, #768 //; copy table values sub r5, #1 //; 1: mov r0, r5 //; swi 0x1B0000 //; strh r0, [r4], #-2 //; subs r5, #1 //; bpl 1b //; @------------------------------------------------------------------------------- pop {r4,r5} bx lr @=============================================================================== public function nasReadPitchTable @=============================================================================== @; input r0 = i = 0..768 @; output = 65536 * 2 ^ (i/768) @; slight error: input 768 = 65536*2-1 @------------------------------------------------------------------------------- ldr r1,=pitch_table_copy //; read pitch table mov r0, r0, lsl#1 //; ldrh r0, [r1, r0] //; add r0, #65536 //; bx lr //; @=============================================================================== public function nasReadCosine @=============================================================================== @; input r0 = angle 0..255 (will be masked) @; output = cos( angle * 2pi / 256 ) * 8000h @=============================================================================== rsb r0, r0, #64 //; cos(a) = sin(pi/2-a) @=============================================================================== public function nasReadSine @=============================================================================== @; input r0 = angle 0..255 (will be masked) @; output = sin( angle * 2pi / 256 )*8000h @=============================================================================== and r1, r0, #0xC0 and r0, #63 //; r0 = angle cmp r1, #2<<6 //; determine quadrant bgt .q3 //; beq .q2 //; cmp r1, #0<<6 //; bne .q1 //; @------------------------------------------------------------------------------- .q0: swi 0x1A0000 //; q0: return tab(y) bx lr //; @------------------------------------------------------------------------------- .q1: cmp r0, #0 //; q1: return tab(64-y) moveq r0, #0x8000 //; catch 0 (cannot give 64 to sin function) bxeq lr //; rsb r0, #64 //; swi 0x1A0000 //; bx lr //; @------------------------------------------------------------------------------- .q2: swi 0x1A0000 //; q2: return -tab(y) rsb r0, r0, #0 //; bx lr //; @------------------------------------------------------------------------------- .q3: cmp r0, #0 //; q3: return -tab(64-y) moveq r0, #0x8000 //; rsbeq r0, r0, #0 //; bxeq lr //; rsb r0, #64 //; swi 0x1A0000 //; rsb r0, r0, #0 //; bx lr //; @=============================================================================== public data nasFunctionTable @=============================================================================== .word nasReadSine .word nasReadCosine .word nasReadPitchTable