;
; player.inc: 24ppq player tick,
; called from hi-pri irq
;
; scale length of one step (48 ppqn)
; ----- ------------------
; 0 1/16 (12 ticks) shuffle 0...7
; 1 1/32 (6 ticks) shuffle 0...6
; 2 1/8 triplet (16 ticks) shuffle 0...7
; 3 1/16 triplet (8 ticks) shuffle 0...7
;
; author: Marko Kanala, raato ]a t[ mulletronic.com
;
; LICENSE
; Creative Commons Attribution-NonCommercial-ShareALike 2.5
;
; You are free:
;
; * to copy, distribute, display, and perform the work
; * to make derivative works
;
; Under the following conditions:
;
; 1. Attribution. You must attribute the work in the manner specified by the
; author or licensor.
; 2. Noncommercial. You may not use this work for commercial purposes.
; 3. Share Alike. If you alter, transform, or build upon this work, you may
; distribute the resulting work only under a license identical to this one.
;
; * For any reuse or distribution, you must make clear to others the license
; terms of this work.
; * Any of these conditions can be waived if you get permission from the
; copyright holder.
;
; Your fair use and other rights are in no way affected by the above.
;
; This is a human-readable summary of the Legal Code.
; See full license at http://creativecommons.org/licenses/by-nc-sa/2.5/legalcode
;
; Copyright: Marko Kanala (raato@mulletronic.com).
;
player_tick:
; are we running ?
IFRUNNING player_running
return
; starts the player
player_start:
IFNOTINMODE MODE_RUN, player_start_stopped
; we're running, send stop to sync to get
; synced machines to reset too
call player_stop
player_start_stopped:
; reset current step(s)
clrf currentstep
clrf currentstep_bdrum
clrf currentstep_sdrum
clrf currentstep_ltom
clrf currentstep_mtom
clrf currentstep_htom
clrf currentstep_rshot
clrf currentstep_hclap
clrf currentstep_chihat
clrf currentstep_ohihat
clrf currentstep_crash
clrf currentstep_ride
clrf currentstep_accent
clrf bpmtick
; set the running mode on
bsf mode, MODE_RUN
; send midi start
IFSETTINGONCALL SETTING_MIDIS_OUT, midi_out_start
;call midi_out_start
return
player_continue:
clrf bpmtick
; set the running mode on
bsf mode, MODE_RUN
; send midi continue
IFSETTINGONCALL SETTING_MIDIS_OUT, midi_out_continue
;call midi_out_continue
return
; stops the player, make's sure the sync stop gets sent
player_stop:
CLEARMODE MODE_RUN
clrf triggers_a
clrf triggers_b
call tr_set_trigger_latches
; send midi stop
IFSETTINGONCALL SETTING_MIDIS_OUT, midi_out_stop
; call midi_out_stop
; clear event bits to prevent stucking on syncs
CLEAREVENT EVENT_DINRUN
CLEAREVENT EVENT_MIDIRUN
return
player_running:
; resolve current scale:
; "bpmscaler" variable gets set
; with current tick count depending
; on the scale setting
SCALETOW 2
call get_scaleticks
movwf bpmscaler
incf bpmtick
movlw 1
cpfsgt bpmtick
call player_trig ; play triggers on first tick
decf flamcounter
bn player_flamneg
; flam positive or zero
bnz player_flamdone
; flam zero, play flams
call player_flams
player_flamneg:
; flamcounter was negative, flam must be 0
clrf flamcounter
player_flamdone:
; note: currentstep values from 1 - 16
btfsc currentstep, 0
bra currentstep_odd
; even step
; load shuffle to W
movf currentshuffle, W
subwf bpmscaler, W ; even steps take bpmscaler - shuffle ticks
bnn shufflescaleok
clrf WREG ; reset W if shuffle value too big
shufflescaleok:
cpfslt bpmtick ; should we reset bpmtick ?
clrf bpmtick
return
currentstep_odd:
; odd step, if this is the last step
; ignore shuffle
movf currentlength, W
cpfslt currentstep
bra player_laststep_odd
; odd steps take bpmscaler + shuffle ticks
; movf bpmscaler, W ; min 6
incf bpmscaler, W ; bpmscaler + 1, min of 7
; if bpmscaler is less than currentshuffle
; we need to correct the step duration by -1
cpfslt currentshuffle ; 0 ... 7
decf WREG
decf WREG
addwf currentshuffle, W ; bpmscaler + shuffle
cpfslt bpmtick
clrf bpmtick
return
; currentstep is the last step
; and the step is odd, ignore shuffle
player_laststep_odd:
movf bpmscaler, W
cpfslt bpmtick
clrf bpmtick
return
;
; triggers the current step
;
; note: we can do some processing before
; triggering the trigger circuit as the
; lcd bus needs to settle down anyway
;
player_trig:
; we should increment the step counters
incf currentstep
incf currentstep_bdrum
incf currentstep_sdrum
incf currentstep_ltom
incf currentstep_mtom
incf currentstep_htom
incf currentstep_rshot
incf currentstep_hclap
incf currentstep_chihat
incf currentstep_ohihat
incf currentstep_crash
incf currentstep_ride
incf currentstep_accent ; ... ~1.3us
movf currentlength, W
movwf player_temp ; store for INSTRCHECKPOS
cpfseq currentstep
bra player_not_last_step
; last step => mark as an event
SETEVENT EVENT_LASTSTEP
player_not_last_step:
cpfsgt currentstep
bra player_no_pat_reset
; currentstep > pat_length, reset to 1
movlw 1
movwf currentstep ; currenstep == 1
movlw (1<<MODE_TPLAY) | (1<<MODE_TWRITE)
andwf mode, W
bz player_not_trackmode
movf currentmeasuredata, W
DECODE_REPEAT_FROM_MEASURE ; W = repeat
cpfslt repeatcounter
bra player_advance_trackmode
; repeatcounter < current measure repeat
; just increment repeat counter and continue
incf repeatcounter
bra player_not_trackmode
player_advance_trackmode:
; roll track mode counters
movff nextmeasuredata, currentmeasuredata
movff nextmeasure, currentmeasure
movff nextmeasure + 1, currentmeasure + 1
clrf repeatcounter
player_not_trackmode:
; if we are in pattern write mode do not change the
; current pattern
IFMODE MODE_PWRITE, player_reset_done
; roll to the next pattern if needed,
; if next differs from current we are waiting for a flash event
; otherwise the event will never come
IFNOEVENT EVENT_FLASHREADOK, player_no_flash_done
; flash read done, roll over
CLEAREVENT EVENT_FLASHREADOK
movff nextbank, currentbank
movff nextpattern, currentpattern
LENGTHTOW 2
movwf currentlength
SHUFFLETOW 2
movwf currentshuffle
bra player_dochain
player_no_flash_done:
; no flash event, we should do the chain check anyway
; if next == current
movf currentbank, W
cpfseq nextbank
bra player_reset_done
movf currentpattern, W
cpfseq nextpattern
bra player_reset_done
player_dochain:
IFNOTINMODE MODE_CHAIN, player_reset_done
; if in chain mode get next pattern from chain
lfsr FSR2, chainbuffer
movf chainposition, W
addwf FSR2L
movf INDF2, W
bnn player_chain_ok
; chain ended
clrf chainposition
; try again from the start
movf chainbuffer, W
bn player_no_flash_done ; no chain, just skip
player_chain_ok:
; pattern was found in chain, decode pattern/bank
movwf nextpattern
movwf nextbank
movlw b'00001111'
andwf nextpattern ; b'0000pppp'
swapf nextbank ; b'pppp00bb'
andwf nextbank ; b'000000bb'
incf chainposition ; advance to next in chain
player_reset_done:
FORCEDISPLAYREFRESH ; display should be refreshed
IFMODE MODE_PWRITE, player_no_pat_reset
CLEARMODE MODE_FILL ; clear fill flag if in play mode
player_no_pat_reset:
; check and roll over the counters if needed
LOADPATTOFSR 2, PAT_LENGTHS ; ... ~3us
INSTRCHECKPOS currentstep_bdrum, currentstep_sdrum ; ~1.6us / check
INSTRCHECKPOS currentstep_ltom, currentstep_mtom
INSTRCHECKPOS currentstep_htom, currentstep_rshot
INSTRCHECKPOS currentstep_hclap, currentstep_chihat
INSTRCHECKPOS currentstep_ohihat, currentstep_crash
INSTRCHECKPOS currentstep_ride, currentstep_accent ; ... 12.6us
; blink blink_tempo with step advance
btg blink_tempo, 0
;
; step counters always 1 - 16 for triggering routines
;
; (this allows lcd to settle if
; triggers collide with lcd enable strobe)
;
; NOT NEEDED HERE
; ~13us delay already spent on length checks
; call player_lcd_delay
bcf PORT_LCD_EN, LCD_EN_PIN
; we should protect the lcd bus before
; messing up with the triggers
; RB0 - RB4 should be saved as they
; overlap with the trigger bus
movlw b'00011111'
andwf PORT_LCD, W
movwf player_temp
; see 9090.inc, triggers the p9090 circuit
call tr_do_triggers
; restore LCD bus
movlw b'11100000'
andwf PORT_LCD, W
iorwf player_temp, W
movwf PORT_LCD
; trigger midi outs set so
IFSETTINGONCALL SETTING_MIDIN_OUT, midi_do_triggers
; set flamcounter on trigger
FLAMTOW 2
addwf WREG ; flam * 2
movwf flamcounter
return
;
; checks if any flams should be played
; and triggers them accordingly
;
player_flams:
; protects the shared lcd bus
call player_lcd_delay
bcf PORT_LCD_EN, LCD_EN_PIN
movlw b'00011111'
andwf PORT_LCD, W
movwf player_temp
call tr_do_flams
; restore LCD bus
movlw b'11100000'
andwf PORT_LCD, W
iorwf player_temp, W
movwf PORT_LCD
return
;
; sets the triggers off, timed with timer 3
; for ~2ms trigger pulses
;
player_trig_off:
; protects the shared lcd bus
call player_lcd_delay
bcf PORT_LCD_EN, LCD_EN_PIN
movlw b'00011111'
andwf PORT_LCD, W
movwf player_temp
; see 9090.inc, sets the triggers off in p9090 circuit
call tr_clear_triggers
; restore LCD bus
movlw b'11100000'
andwf PORT_LCD, W
iorwf player_temp, W
movwf PORT_LCD
return
;
; 13us delay to avoid the lcd bus collision
;
player_lcd_delay:
movlw 32
movwf player_temp
player_lcd_delay_loop:
clrwdt
decfsz player_temp
bra player_lcd_delay_loop
return
External Labels :
player_stop
tr_set_trigger_latches
get_scaleticks
player_trig
player_flams
tr_do_triggers
player_lcd_delay
tr_do_flams
tr_clear_triggers