* * * FLANGE.ASM - flanging effect for TI DSK module. * * * * Knobs - adjust these values within suggested range for * variations on the effect. * * Patch Name Dry Wet FB Step Range Delay * Very slow flange 07fffh 07fffh 00000h 0008h 060h 0000h * Flange w/ FB 07fffh 07fffh 06800h 0020h 050h 0000h * Invert flange 07fffh 08000h 00000h 000eh 060h 0000h * Invert w/ invert FB 07fffh 08000h 0a000h 0012h 060h 0000h * Fast flange 07fffh 07fffh 01000h 0180h 038h 0008h * Chorus 07fffh 07fffh 0000h 0040h 070h 0350h * DRY_LEVEL .set 07fffh ; (0 - 07fffh dry signal level) WET_LEVEL .set 07fffh ; (08000h - 07fffh wet signal level) FB_LEVEL .set 01000h ; (08000h - 07fffh regeneration amount) SWEEP_STEP .set 00080h ; (01h - 07fffh sweep rate) SWEEP_RANGE .set 00050h ; (010h - 03e0h sweep width) SWEEP_DELAY .set 00000h ; (0 - 3e0h delay) * * Misc. defines * BUF .set 0410h ; main circular buffer start and end BUFEND .set 0800h SWEEPUP .set 0 ; flag value for AR5 SWEEPDOWN .set 1 ; ditto * * Data storage * SWEEPCNT .set 00h ; primary interp factor SWEEPCOMP .set 01h ; complement of interp factor STEP .set 02h ; inc/dec value for sweepcnt TMP .set 03h ; temporary storage reg INPVAL .set 04h ; input value OUTVAL .set 05h ; output value FEEDBACK .set 06h ; mix params... WET .set 07h DRY .set 08h .include "setup.asm" * * main * main: ssxm ; set sign extension mode spm 1 ; set P shift for Q15 (1 bit left shift ; from P => accum) ldpk 8 ; data at 0400h lrlk AR0,BUFEND ; permanently point to end of mem buf lrlk AR1,BUF ; write ptr, point to start of mem buf lrlk AR4,SWEEP_RANGE ; breadth of sweep sar AR4,TMP lalk SWEEP_DELAY ; add in delay factor for chorus effects add TMP sacl TMP lalk BUFEND ; calc starting point for read ptrs sub TMP ; end of buf minus sweep range subk 1 ; keep 'em from getting too close to write ptr sacl TMP lar AR2,TMP ; load 1st read ptr lar AR3,TMP ; 2nd read ptr, initial value for first access lrlk AR5,SWEEPUP ; set initial sweep direction lack 0 sacl SWEEPCNT ; set initial fractional sweep lalk SWEEP_STEP ; install sweep rate sacl STEP lalk FB_LEVEL sacl FEEDBACK ; delayed signal feedback mix lalk WET_LEVEL sacl WET ; delayed signal output mix lalk DRY_LEVEL sacl DRY ; straight signal output mix lack 014h ; enable AIC recv interrupts ldpk 0 sacl IMR ; loop here forever processing interrupts loop: idle b loop * * rint * * Recv interrupt handler performs all the work. Since there is * no main thread, there is no need to save or restore regs. * We can assume: * * AR0 - points to end of buffer * AR1 - current write ptr * AR2 - 1st read ptr * AR3 - 2nd read ptr * AR4 - sweep range counter * AR5 - sweep direction flag * rint: ; note: no need to save/restore processor state since ; main thread does absolutely nothing sovm ; set clipping overflow mode for the ; "analog" processing ldpk 0 lac DRR ; read in new input value ldpk 8 sfr ; dump low 2 junk bits sfr sacl INPVAL ; temporary storage ; interpolate ouput value from the two read ptrs lalk 32767 ; develop complement of fractional sub SWEEPCNT ; sweep position sacl SWEEPCOMP larp AR2 ; use 1st read ptr lt SWEEPCNT ; get fractional sweep position mpy *,AR3 ; scale 1st read value ltp SWEEPCOMP mpy *,AR1 ; scale 2nd read value apac ; glob 'em together sach OUTVAL ; this will be our "wet" output value ; do feedback lt OUTVAL mpy FEEDBACK ; scale feedback to taste pac addh INPVAL sach *+ ; store finished input value thru AR1 cmpr 0 ; check for wrap on store ptr bbz nowrap1,*,AR5 ; (arp to directon flag) lrlk AR1,BUF nowrap1: ; do level scaling on direct and wet lt OUTVAL mpy WET ; scale wet signal pac lt INPVAL ; get original input value mpy DRY ; scale dry signal apac ; generate composite final output sach OUTVAL lac OUTVAL ; prepare final output for AIC andk 0fffch ; clear lowest 2 bits ldpk 0 sacl DXR ; do output ldpk 8 ; ; now update our sweep stuff, 1st see which direction we're going ; rovm ; normal overflow operation for arithmetic banz down,*,AR2 ; ; UPWARD SWEEP (delay decreasing sweep) ; ; always move forward at least one notch sar AR2,TMP ; copy AR2 to AR3 lar AR3,TMP mar *+ ; inc AR2 cmpr 0 bbz nowrap2,*,AR3 lrlk AR2,BUF nowrap2: ; now update fractional delay zac ; clear accum addh SWEEPCNT ; use high accum for calc addh STEP sach SWEEPCNT bnv done,*,AR2 ; fractional part didn't overflow, ; no need to advance sweep further ; fractional portion overflowed, adjust main sweep forward sar AR2,TMP ; move AR2 to AR3 lar AR3,TMP mar *+ ; inc AR2 cmpr 0 bbz nowrap3,*,AR4 ; (arp to sweep cnt AR4) lrlk AR2,BUF nowrap3: lac SWEEPCNT andk 07fffh ; mask sign bit sacl SWEEPCNT ; adjust main sweep counter mar *- banz done ; main sweep expired, reload, swap step sign lrlk AR4,SWEEP_RANGE lac STEP ; invert sign of step value neg sacl STEP lark AR5,SWEEPDOWN ; show new direction b done ; DOWNWARD SWEEP (delay increasing) down: lac SWEEPCNT add STEP ; step is negative here so we're actually sacl SWEEPCNT ; subtracting blz underflow,*,AR2 ; cnt went less than zero, skip ptr advance ; no underflow, advance ptrs but skip rest of sweep updates sar AR2,TMP ; copy AR3 to AR2 lar AR3,TMP mar *+ ; inc AR2 cmpr 0 bbz done lrlk AR2,BUF b done ; fractional portion underflowed, update major sweep underflow: lac SWEEPCNT ; mask off sign stuff from underflow andk 07fffh sacl SWEEPCNT larp AR4 mar *- banz done ; main sweep expired, reload, swap step sign lrlk AR4,SWEEP_RANGE lac STEP ; invert sign of step value neg sacl STEP lark AR5,SWEEPUP ; show new direction ; ; DONE ; done: eint ret * * tint * * Timer interrupt - not used. * tint: eint ret * * xint * * AIC xmit interrupt - not used. * xint: eint ret