;
; mode_pattplay.inc: handles pattern play mode
;
; 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).
;
; called when pattern play mode is entered
mode_pattplay_enter:
SETDISPLAY s_pp_main ; see lcd.inc
IFRUNNING mode_pattplay_enter_running
movff currentpattern, nextpattern
CLEARMODE MODE_FILL
mode_pattplay_enter_running:
; if we come from pattern write mode we probably
; don't want to handle the laststep events we've gotten
CLEAREVENT EVENT_LASTSTEP
return
; called in continuous loop when in pattern play mode
mode_pattplay:
; if the last step of the pattern has been
; reached read the next pattern from the
; flash memory if needed
IFEVENTCALL EVENT_LASTSTEP, pp_handleflash
; refresh lcd display if needed
call lcd_refresh
; do we have key events ?
IFNOEVENT EVENT_KEY, pp_no_keyevents
; shift is pressed, handle shifted keys at pp_shiftdown
; IFKEYDOWN DOWNKEY_SHIFTFUNC, pp_shiftdown
; starts the sequencer
KEYEVENT KEY_START, pp_start
; stops or continues the sequencer
KEYEVENT KEY_STOPCONT, pp_stopcont
; trigger a fill
KEYEVENT KEY_ENTER, pp_fill
; clears pattern chain
KEYEVENT KEY_SCALE, pp_clearchain
; KEYEVENT KEY_S1, pp_stepkey
; KEYEVENT KEY_S2, pp_stepkey
; KEYEVENT KEY_S3, pp_stepkey
; KEYEVENT KEY_S4, pp_stepkey
; KEYEVENT KEY_S5, pp_stepkey
; KEYEVENT KEY_S6, pp_stepkey
; KEYEVENT KEY_S7, pp_stepkey
; KEYEVENT KEY_S8, pp_stepkey
; KEYEVENT KEY_S9, pp_stepkey
; KEYEVENT KEY_S10, pp_stepkey
; KEYEVENT KEY_S11, pp_stepkey
; KEYEVENT KEY_S12, pp_stepkey
; KEYEVENT KEY_S13, pp_stepkey
; KEYEVENT KEY_S14, pp_stepkey
; KEYEVENT KEY_S15, pp_stepkey
; KEYEVENT KEY_S16, pp_stepkey
; optimized for space
; if stopped step keys change pattern
; if running step keys select the next pattern to be played
STEPKEYEVENT pp_stepkey
KEYEVENT KEY_BANKA, pp_banka
KEYEVENT KEY_BANKB, pp_bankb
KEYEVENT KEY_BANKC, pp_bankc
KEYEVENT KEY_BANKD, pp_bankd
KEYEVENT KEY_PATTPLAYWRITE, pp_pattplaywrite
KEYEVENT KEY_TRACKPLAYWRITE, pp_trackplaywrite
pp_no_keyevents:
; no specific keyevents, check for downkeys
IFKEYDOWN DOWNKEY_LASTSTEP, pp_setchaindown
pp_no_downkeys:
; no keyevents and no downkeys, all keys up
; set default display
SETDISPLAY s_pp_main
call pp_refreshleds
call lcd_refreshbpm
return
; all keyhandlers should call this afterwards
pp_keydone:
call pp_refreshleds
pp_keydone_keepleds:
CLEAREVENT EVENT_KEY
return
; downkeyhandlers should call this afterwards
pp_downkeydone:
call pp_refreshleds
pp_downkeydone_keepleds:
return
; ----------------------
; lights up the led of the selected pattern
; and xors the current step to the step leds if
; we're in the running mode
; additionally takes care of the bank selector leds
pp_refreshleds:
clrf leds_temp_1
clrf leds_temp_2
movlw -8
addwf currentpattern, W ; currentpattern = 0 - 15
bn pp_lower_ledbus
; over 8, upper ledbus, W ok (0 - 7)
call get_bit
iorwf leds_temp_2
bra pp_pat_ok
pp_lower_ledbus:
addlw 8
call get_bit
iorwf leds_temp_1
pp_pat_ok:
IFRUNNING pp_refreshleds_running
pp_writeleds:
; write leds to bus
movff leds_temp_1, leds_busa_1
movff leds_temp_2, leds_busa_2
; write bank leds (leds 7 - 4 in leds_busb_1)
movlw 15 ; %00001111
andwf leds_busb_1, W
movwf leds_temp_1
movf currentbank, W
call get_bit ; W = bit mask to busb_1
iorwf leds_temp_1
IFNOTRUNNING pp_bankled_done
; blink next bank only if running
movf nextbank, W
cpfseq currentbank
bra pp_bank_blinknext
pp_bankled_done:
movff leds_temp_1, leds_busb_1
return
pp_bank_blinknext:
tstfsz blink
bra pp_bankled_done
; blink next bank led if applicable (W=nextbank)
call get_bit ; W = bit mask to busb_1
iorwf leds_temp_1
bra pp_bankled_done
pp_refreshleds_running:
; we are running, xor currentstep
movf currentstep, W ; if currentstep is 0
bz pp_writeleds ; skip the xor
movlw -9
addwf currentstep, W ; W = currentstep - 9
bn pp_r_lower_ledbus
; over 8, upper ledbus, W ok (0 - 7)
call get_bit
xorwf leds_temp_2 ; leds XOR currentstep
bra pp_r_blinks
pp_r_lower_ledbus:
addlw 8 ; W = currentstep - 1
call get_bit
xorwf leds_temp_1
pp_r_blinks:
movf nextpattern, W
cpfseq currentpattern
bra pp_pattern_blinknext
bra pp_writeleds
pp_pattern_blinknext:
tstfsz blink
bra pp_writeleds
; blink next pattern led if applicable (W=nextpattern)
movlw -8
addwf nextpattern, W ; nextpattern = 0 - 15
bn pp_np_lower_ledbus
; over 8, upper ledbus, W ok (0 - 7)
call get_bit
iorwf leds_temp_2
bra pp_writeleds
pp_np_lower_ledbus:
addlw 8
call get_bit
iorwf leds_temp_1
bra pp_writeleds
pp_stepkey:
; laststep pressed, set pattern chain
IFKEYDOWN DOWNKEY_LASTSTEP, pp_setchain
; changes the active pattern in the current bank
; clear chain mode
CLEARMODE MODE_CHAIN
movlw 16
movwf temp
decf keypress, W
bn pp_keydone ; accept only keys 0 ...
cpfsgt temp
bra pp_keydone ; ... to 15
FORCEDISPLAYREFRESH
IFRUNNING pp_stepkey_running
movwf currentpattern
movwf nextpattern
call i2c_flash_read
bra pp_keydone
pp_stepkey_running:
movwf nextpattern
bra pp_keydone
; changes the active pattern bank
pp_banka:
movlw BANK_A
bra pp_set_bank
pp_bankb:
movlw BANK_B
bra pp_set_bank
pp_bankc:
movlw BANK_C
bra pp_set_bank
pp_bankd:
movlw BANK_D
pp_set_bank:
; if set chain down skip bank change
IFKEYDOWN DOWNKEY_LASTSTEP, pp_keydone
FORCEDISPLAYREFRESH
IFRUNNING pp_set_bank_running
; clear chain mode
CLEARMODE MODE_CHAIN
movwf currentbank
movwf nextbank
call i2c_flash_read
bra pp_keydone
pp_set_bank_running:
movwf nextbank
bra pp_keydone
; starts the sequencer
pp_start:
; make sure the sequencer is not running
; while messing with chainbuffer
CLEARMODE MODE_RUN
movf chainbuffer, W
bn pp_start_nochain
; something in chain buffer, let's play the chain
movlw b'00001111'
movwf temp
andwf chainbuffer, W
movwf currentpattern ; low nybble == pattern
swapf chainbuffer, W
andwf temp, W
movwf nextbank ; high nybble == bank
; set next pattern too
movf chainbuffer+1, W
bnn pp_start_chainnext
; chain with length of 1 ?? not a real chain
bra pp_start_nochain
pp_start_chainnext:
; read the first pattern from flash
movff currentpattern, nextpattern
movff currentbank, nextbank
call i2c_flash_read ; i2c_flash_read uses next-vars
movlw b'00001111'
andwf chainbuffer+1, W
movwf nextpattern
; set chain position to a correct value
movlw 2
movwf chainposition
SETMODE MODE_CHAIN
FORCEDISPLAYREFRESH
bra pp_start_ok
pp_start_nochain:
CLEARMODE MODE_CHAIN
movff currentbank, nextbank
movff currentpattern, nextpattern
pp_start_ok:
; set the running mode on
call player_start
bra pp_keydone
; stops or continues the sequencer
pp_stopcont:
FORCEDISPLAYREFRESH
IFRUNNING pp_stopcont_running
; sequencer is not running, we should continue
call player_continue
bra pp_keydone
pp_stopcont_running:
; sequencer is running, stop the player
call player_stop
bra pp_keydone
; changes the fill pattern as a active pattern
pp_fill:
SETMODE MODE_FILL
FORCEDISPLAYREFRESH
bra pp_keydone
; switches between pattern play and -write modes
pp_pattplaywrite:
SETMODE MODE_PWRITE
CLEARMODE MODE_PPLAY
call mode_pattwrite_enter
bra pp_keydone_keepleds
; switches to track play mode
pp_trackplaywrite:
SETMODE MODE_TPLAY
CLEARMODE MODE_PPLAY
call mode_trackplay_enter
bra pp_keydone_keepleds
; sets a pattern chain: when the last step key
; is pressed down the step keys can be used to
; program a chain of patterns played in sequence
;
; note: the chain play mode is activated when
; the key is lifted
pp_setchaindown:
SETDISPLAY s_pp_setchain
; show the chain with step leds
lfsr FSR1, chainbuffer
movf chainshowpos, W
addwf FSR1L
movf chainshowblink, W
cpfseq blink
bra pp_setchaindown_noadv
; advance only when blink changes
incf chainshowpos
btg chainshowblink, 0
pp_setchaindown_noadv:
movf INDF1, W ; show this pos
bn pp_setchaindown_neg
; not negative, blink this led
andlw 0x0f ; clear bank bits
btfsc WREG, 3
bra pp_setchaindown_upper
; < 8
call get_bit
movwf leds_busa_1
clrf leds_busa_2
bra pp_downkeydone_keepleds
pp_setchaindown_upper:
andlw 0x07
call get_bit
clrf leds_busa_1
movwf leds_busa_2
bra pp_downkeydone_keepleds
pp_setchaindown_neg:
; negative, reset to chainbuffer start
clrf chainshowpos
clrf leds_busa_1 ; and clear leds
clrf leds_busa_2
bra pp_downkeydone_keepleds
pp_setchain:
SETMODE MODE_CHAIN
movlw 16
mulwf currentbank
decf PRODL, W ; this substracts one
; from keypress
addwf keypress, W ; W = bank*4 + step key press
; W must be 0 - 63
movwf temp
movlw 64
cpfslt temp
bra pp_keydone ; 64 or more, ignore key press
; append temp to chainbuffer if possible
movlw 16
movwf temp2
lfsr FSR1, chainbuffer
pp_setchain_find:
movf POSTINC1, W
bn pp_setchain_endfound
decfsz temp2
bra pp_setchain_find
; chain buffer is full (16 positions used)
; => do nothing
pp_setchain_end:
; FORCEDISPLAYREFRESH
bra pp_keydone_keepleds
pp_setchain_endfound:
decf FSR1L
; FSR1 now the first empty position of chain buffer
movff temp, INDF1
; append done
bra pp_setchain_end
; scale key can be used to clear the programmed
; chain
pp_clearchain:
; chain is cleared by setting the buffer positions
; to -1
; if we've already exited chain mode don't mess with
; nextpattern
IFNOTINMODE MODE_CHAIN, pp_clearchain_patres
; set current pattern to be the next if chaining
movff currentpattern, nextpattern
movff currentbank, nextbank
CLEARMODE MODE_CHAIN ; clear chain mode
pp_clearchain_patres:
clrf chainposition ; chainposition = 0
movlw 16
movwf temp
lfsr FSR1, chainbuffer
movlw -1
pp_clearchainloop:
movwf POSTINC1 ; chainbuffer = -1
decfsz temp
bra pp_clearchainloop
SETDISPLAY s_pp_chaincleared
FORCEDISPLAYREFRESH
bra pp_keydone
; called always when last step of the pattern has been
; triggered
pp_handleflash:
CLEAREVENT EVENT_LASTSTEP ; ... or after readflash?
movf nextpattern, W
cpfseq currentpattern
bra pp_readflash
movf nextbank, W
cpfseq currentbank
bra pp_readflash
; flash read not needed
return
pp_readflash:
; read the pattern at nextbank/nextpattern
; from the flash memory
call i2c_flash_read
return
External Labels :
lcd_refresh
pp_refreshleds
lcd_refreshbpm
get_bit
i2c_flash_read
player_start
player_continue
player_stop
mode_pattwrite_enter
mode_trackplay_enter