;
; mode_trawrite.inc: handles track write mode
;
; author: Marko Kanala, raato ]a t[ mulletronic.com
;
; Note: current bank, pattern and repeat is kept
; encoded in currentmeasuredata and editedmeasuredata
; variables.
;
; 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 the track write mode is entered
mode_trackwrite_enter:
SETDISPLAY s_tw_main ; see lcd.inc
return
; called in continuous loop when in track write mode
mode_trackwrite:
; if the last step of the pattern has been
; reached read the next pattern from the
; flash memory if needed
IFEVENTCALL EVENT_LASTSTEP, tw_handleflash
; refresh lcd display if needed
call lcd_refresh
; do we have key events ?
IFNOEVENT EVENT_KEY, tw_no_keyevents
; note: step/bank keys ignored when running
; KEYEVENT KEY_S1, tw_stepkey
; KEYEVENT KEY_S2, tw_stepkey
; KEYEVENT KEY_S3, tw_stepkey
; KEYEVENT KEY_S4, tw_stepkey
; KEYEVENT KEY_S5, tw_stepkey
; KEYEVENT KEY_S6, tw_stepkey
; KEYEVENT KEY_S7, tw_stepkey
; KEYEVENT KEY_S8, tw_stepkey
; KEYEVENT KEY_S9, tw_stepkey
; KEYEVENT KEY_S10, tw_stepkey
; KEYEVENT KEY_S11, tw_stepkey
; KEYEVENT KEY_S12, tw_stepkey
; KEYEVENT KEY_S13, tw_stepkey
; KEYEVENT KEY_S14, tw_stepkey
; KEYEVENT KEY_S15, tw_stepkey
; KEYEVENT KEY_S16, tw_stepkey
STEPKEYEVENT tw_stepkey
KEYEVENT KEY_BANKA, tw_banka
KEYEVENT KEY_BANKB, tw_bankb
KEYEVENT KEY_BANKC, tw_bankc
KEYEVENT KEY_BANKD, tw_bankd
KEYEVENT KEY_START, tw_start
KEYEVENT KEY_STOPCONT, tw_stopcont
IFRUNNING tw_running_enter
; set/insert measure if not running
KEYEVENT KEY_ENTER, tw_setinsct
bra tw_enter_cont
tw_running_enter:
; trigger a fill if running
KEYEVENT KEY_ENTER, tw_fill
tw_enter_cont:
; note: ignored when running
KEYEVENT KEY_SCALE, tw_nextmeasure
KEYEVENT KEY_CLEAR, tw_cleartrack
KEYEVENT KEY_PATTPLAYWRITE, tw_pattplaywrite
KEYEVENT KEY_TRACKPLAYWRITE, tw_trackplaywrite
tw_no_keyevents:
; no specific keyevents, check for downkeys
; hoax to generate a key events from downkeys
IFKEYNOTDOWN DOWNKEY_LASTSTEP, tw_laststeplifted
IFKEYDOWN DOWNKEY_LASTSTEP, tw_laststeppressed
tw_laststepchecked:
IFKEYNOTDOWN DOWNKEY_CLEAR, tw_clearlifted
IFKEYDOWN DOWNKEY_CLEAR, tw_clearpressed
tw_clearchecked:
tw_no_downkeys:
; no keyevents and no downkeys, all keys up
; set default display
SETDISPLAY s_tw_main
call tw_refreshleds
return
; all keyhandlers should call this afterwards
tw_keydone:
call tw_refreshleds
tw_keydone_keepleds:
CLEAREVENT EVENT_KEY
return
; called when laststep downkey is pressed
tw_laststeppressed:
; call tw_prevmeasure only, if the laststep downkey
; was lifted before
btfsc downkeypresses, DOWNKEY_LASTSTEP
bra tw_laststepchecked
bsf downkeypresses, DOWNKEY_LASTSTEP
bra tw_prevmeasure
; called when laststep downkey is not pressed
tw_laststeplifted:
bcf downkeypresses, DOWNKEY_LASTSTEP
bra tw_laststepchecked
; called when clear downkey is pressed
tw_clearpressed:
; call tw_deletemeasure only, if the clear downkey
; was lifted before
; OR if FUNC is pressed ask for clear track confirmation
IFKEYDOWN DOWNKEY_SHIFTFUNC, tw_cleartrackconfirm
btfsc downkeypresses, DOWNKEY_CLEAR
bra tw_clearchecked
bsf downkeypresses, DOWNKEY_CLEAR
bra tw_deletemeasure
; called when clear downkey is not pressed
tw_clearlifted:
bcf downkeypresses, DOWNKEY_CLEAR
bra tw_clearchecked
; lights up the led for the measure pattern
tw_refreshleds:
movf editedmeasuredata, W
cpfseq currentmeasuredata
bra tw_refreshleds_blink
; not edited, no blink
bra tw_refreshleds_nob
tw_refreshleds_blink:
tstfsz blink
bra tw_refreshleds_boff
tw_refreshleds_nob:
DECODE_BANK_FROM_MEASURE ; w = bank
call get_bit
btfsc leds_busb_1, LED_START ; preserve start led
bsf WREG, LED_START
movwf leds_busb_1 ; write bank leds
movf editedmeasuredata, W
DECODE_PATTERN_FROM_MEASURE ; w = pattern
movwf temp
movlw 8
cpfslt temp
bra tw_refreshleds_edited_upper
; lower 8
movf temp, W
call get_bit
movwf leds_temp_1
clrf leds_temp_2
IFRUNNING tw_refreshleds_running
bra tw_refreshleds_write
tw_refreshleds_edited_upper:
subwf temp, W
call get_bit
clrf leds_temp_1
movwf leds_temp_2
IFRUNNING tw_refreshleds_running
bra tw_refreshleds_write
tw_refreshleds_boff:
clrf leds_temp_1
clrf leds_temp_2
andlw b'00001111'
andwf leds_busb_1
IFRUNNING tw_refreshleds_running
bra tw_refreshleds_write
tw_refreshleds_running:
movf currentstep, W ; if currentstep is 0
bz tw_refreshleds_write ; skip the xor
movlw -9
addwf currentstep, W ; W = currentstep - 9
bn tw_r_lower_ledbus
; over 8, upper ledbus, W ok (0 - 7)
call get_bit
xorwf leds_temp_2 ; leds XOR currentstep
bra tw_refreshleds_write
tw_r_lower_ledbus:
addlw 8 ; W = currentstep - 1
call get_bit
xorwf leds_temp_1
tw_refreshleds_write:
movff leds_temp_1, leds_busa_1
movff leds_temp_2, leds_busa_2
return
; changes the fill pattern as a active pattern
tw_fill:
SETMODE MODE_FILL
FORCEDISPLAYREFRESH
bra tw_keydone
; switches between track play and -write modes
tw_trackplaywrite:
; IFEVENTCALL EVENT_DIRTY, pw_write_flash ; write current if needed
SETMODE MODE_TPLAY
CLEARMODE MODE_TWRITE
call mode_trackplay_enter
bra tw_keydone_keepleds
; switches between pattern play and -write modes
tw_pattplaywrite:
; IFEVENTCALL EVENT_DIRTY, pw_write_flash ; write current if needed
SETMODE MODE_PPLAY
CLEARMODE MODE_TWRITE
call mode_pattplay_enter
bra tw_keydone_keepleds
; encodes the current pattern / repeat to
; editedmeasuredata
tw_stepkey:
IFRUNNING tw_stepkey_skip
; shift pressed, commands
IFKEYDOWN DOWNKEY_SHIFTFUNC, tw_shiftcommand
; encode data to editedmeasuredata
movlw 16
movwf temp
decf keypress, W
bn tw_keydone ; accept only keys 0 ...
cpfsgt temp
bra tw_keydone ; to 15
rlncf WREG
rlncf WREG ; 00PPPP00
movwf temp
FORCEDISPLAYREFRESH
movlw b'00111100'
andwf editedmeasuredata, W ; current 00PPPP00
cpfseq temp
bra tw_stepkey_differentpatt
; same pattern pressed, increment repeat
movlw b'00000011'
andwf editedmeasuredata, W ; current repeat
incf WREG ; increment
movwf temp
movlw 3 ; 0 - 3
cpfsgt temp
bra tw_stepkey_setrepeat
clrf temp ; rollover if necessary
tw_stepkey_setrepeat:
movlw b'11111100'
andwf editedmeasuredata, W
iorwf temp, W
movwf editedmeasuredata
bra tw_keydone
tw_stepkey_differentpatt:
; different pattern, change pattern and clear repeat
movlw b'11000000'
andwf editedmeasuredata, W
iorwf temp, W ; bbPPPP00
movwf editedmeasuredata
; refresh pattern name
call i2c_flash_read_trackpattern_name
tw_stepkey_skip:
bra tw_keydone
; moves to previous measure on track if possible
tw_prevmeasure:
IFRUNNING tw_prevmeasure_skip
; check if we can go back one step
tstfsz nextmeasure ; xx__ == 0
bra tw_prevmeasure_dec
tstfsz nextmeasure + 1 ; __xx == 0
bra tw_prevmeasure_dec
; position == 0, rollover to the last position
movff currenttracklen, nextmeasure
movff currenttracklen + 1, nextmeasure + 1
tw_prevmeasure_dec:
DECF16 nextmeasure
; note: this discards current edit which is fine
call i2c_flash_read_measure
movff nextmeasure, currentmeasure
movff nextmeasure + 1, currentmeasure + 1
; refresh pattern name
call i2c_flash_read_trackpattern_name
FORCEDISPLAYREFRESH
tw_prevmeasure_skip:
bra tw_keydone
; moves to next measure on track if possible
tw_nextmeasure:
IFRUNNING tw_nextmeasure_skip
INCF16 nextmeasure
FORCEDISPLAYREFRESH
; if currentmeasure == currenttracklen
; rollover to position 1
movf nextmeasure, W
cpfseq currenttracklen
bra tw_nextmeasure_ok
movf nextmeasure + 1, W
cpfseq currenttracklen + 1
bra tw_nextmeasure_ok
clrf nextmeasure
clrf nextmeasure + 1
tw_nextmeasure_ok:
call i2c_flash_read_measure
; update currentmeasure
movff nextmeasure, currentmeasure
movff nextmeasure + 1, currentmeasure + 1
; refresh pattern name
call i2c_flash_read_trackpattern_name
tw_nextmeasure_skip:
bra tw_keydone
; deletes a measure
tw_deletemeasure:
IFRUNNING tw_deletemeasure_skip
; allowed only if currenttracklen != 0x0001
clrf WREG
cpfseq currenttracklen
bra tw_deletemeasure_ok
movlw 1
cpfseq currenttracklen + 1
bra tw_deletemeasure_ok
bra tw_keydone ; len == 1, abort
tw_deletemeasure_ok:
; backup current position
movff currentmeasure, temp
movff currentmeasure + 1, temp2
movff currentmeasure, nextmeasure
movff currentmeasure + 1, nextmeasure + 1
tw_deletemeasure_loop:
; read at currentmeasure + 1
INCF16 nextmeasure
; done when nextmeasure reaches currenttracklen
movf nextmeasure, W
cpfseq currenttracklen
bra tw_deletemeasure_loopcont
movf nextmeasure + 1, W
cpfseq currenttracklen + 1
bra tw_deletemeasure_loopcont
bra tw_deletemeasure_cont
tw_deletemeasure_loopcont:
call i2c_flash_read_measure
; store to currentmeasure
call i2c_flash_save_measure
INCF16 currentmeasure
bra tw_deletemeasure_loop
tw_deletemeasure_cont:
; restore position
movff temp, currentmeasure
movff temp2, currentmeasure + 1
DECF16 currenttracklen
; if currentmeasure == currenttracklen go back one step
movf currenttracklen, W
cpfseq currentmeasure
bra tw_deletemeasure_notlast
movf currenttracklen + 1, W
cpfseq currentmeasure + 1
bra tw_deletemeasure_notlast
; was last measure, go back one step
DECF16 currentmeasure
tw_deletemeasure_notlast:
movff currentmeasure, nextmeasure
movff currentmeasure + 1, nextmeasure + 1
; save track len
call i2c_flash_save_tracklength
call i2c_flash_read_measure
; refresh pattern name
call i2c_flash_read_trackpattern_name
FORCEDISPLAYREFRESH
SETDISPLAY s_tw_measuredeleted
tw_deletemeasure_skip:
bra tw_keydone
; asks for track clear confirmation
tw_cleartrackconfirm:
IFRUNNING tw_cleartrackconfirm_skip
SETDISPLAY s_tw_clearconfirm
tw_cleartrackconfirm_skip:
bra tw_keydone
;
; Enter key (Set / Ins) pressed
;
; if FUNC is pressed a measure is inserted to the
; current position
;
; if CLEAR and FUNC are pressed clear the track
; (track clear confirmed)
tw_setinsct:
IFKEYSDOWN DOWNKEY_CLEAR, DOWNKEY_SHIFTFUNC, tw_cleartrack
IFKEYDOWN DOWNKEY_SHIFTFUNC, tw_insertmeasure
; move editedmeasuredata to currentmeasuredata
; and save to flash
movff editedmeasuredata, currentmeasuredata
; store current measure data to flash
call i2c_flash_save_measure
; if we're in the last measure and current track len <= 354
; 1. add a new measure to the track (incr track len)
; 2. copy current measure data to new measure
; 3. advance to new measure
; 354 = 0x162
movlw 0x01
cpfslt currenttracklen
bra tw_keydone
movlw 0x63
cpfslt currenttracklen + 1
bra tw_keydone
; current measure <= 354
; hack a bit because currentmeasure is always
; < track length
movff currentmeasure, temp
movff currentmeasure + 1, temp2
INCF16 temp
movf temp, W
cpfseq currenttracklen
bra tw_keydone
movf temp2, W
cpfseq currenttracklen + 1
bra tw_keydone
; we're in the last measure, let's do the "add"
; hoax to set the edit mode :/
; this fucks up if we've just added D16x4,
; el�m� on laiffii
movlw -1
movwf currentmeasuredata
INCF16 currenttracklen
INCF16 nextmeasure
INCF16 currentmeasure
; save track len
call i2c_flash_save_tracklength
FORCEDISPLAYREFRESH
bra tw_keydone
; inserts a measure at the current position
tw_insertmeasure:
; if current track len <= 354
movlw 0x01
cpfslt currenttracklen
bra tw_keydone
movlw 0x63
cpfslt currenttracklen + 1
bra tw_keydone
; current measure <= 354
; backup editedmeasuredata as it is thrashed
; on insertion
movff editedmeasuredata, tw_temp
; backup current position
movff currentmeasure, temp
movff currentmeasure + 1, temp2
; go to last measure
movff currenttracklen, nextmeasure
movff currenttracklen + 1, nextmeasure + 1
movff currenttracklen, currentmeasure
movff currenttracklen + 1, currentmeasure + 1
; add a new measure and insert the
; data to the new measure at the end
call i2c_flash_read_measure ; *data now last measure
INCF16 currenttracklen ; add a new measure
INCF16 currentmeasure ; advance to new measure
call i2c_flash_save_measure ; last measure moved
; nextmeasure = currentmeasure - 1
tw_insertmeasure_loop:
DECF16 nextmeasure
call i2c_flash_read_measure
DECF16 currentmeasure
call i2c_flash_save_measure
; loop until nextmeasure == measure we started in
movf nextmeasure, W
cpfseq temp
bra tw_insertmeasure_loop
movf nextmeasure + 1, W
cpfseq temp2
bra tw_insertmeasure_loop
; insertion done, store the data we were inserting
DECF16 currentmeasure ; nextmeasure == currentmeasure
movff tw_temp, editedmeasuredata
call i2c_flash_save_measure
; save track len
call i2c_flash_save_tracklength
SETDISPLAY s_tw_measureinserted
bra tw_keydone
; actually clears the current track
tw_cleartrack:
IFRUNNING tw_cleartrack_skip
; 1. sets the track length to 1
; 2. sets the measure at position 0 to A01x1
; 3. moves the currentmeasure to 0
clrf currentmeasure
clrf currentmeasure + 1
clrf nextmeasure
clrf nextmeasure + 1
clrf editedmeasuredata
clrf currenttracklen
movlw 1
movwf currenttracklen + 1
call i2c_flash_save_measure
call i2c_flash_save_tracklength
; refresh pattern name
call i2c_flash_read_trackpattern_name
SETDISPLAY s_tw_trackcleared
tw_cleartrack_skip:
bra tw_keydone
; alter bank to editedmeasuredata
tw_banka:
movlw BANK_A<<6
bra tw_setbank
tw_bankb:
movlw BANK_B<<6
bra tw_setbank
tw_bankc:
movlw BANK_C<<6
bra tw_setbank
tw_bankd:
movlw BANK_D<<6
tw_setbank:
FORCEDISPLAYREFRESH
movwf temp
movlw b'00111111'
andwf editedmeasuredata, W
iorwf temp, W
movwf editedmeasuredata
; refresh pattern name
call i2c_flash_read_trackpattern_name
bra tw_keydone
; starts the sequencer
tw_start:
; trash edited data on start
movff currentmeasuredata, editedmeasuredata
movf currentmeasuredata, W
DECODE_BANK_FROM_MEASURE
movwf currentbank
movf currentmeasuredata, W
DECODE_PATTERN_FROM_MEASURE
movwf currentpattern
movff currentpattern, nextpattern
movff currentbank, nextbank
; load first pattern from flash
call i2c_flash_read
; reset repeat counter
clrf repeatcounter
; and start
call player_start
FORCEDISPLAYREFRESH
bra tw_keydone
; stops / continues
tw_stopcont:
FORCEDISPLAYREFRESH
IFNOTRUNNING tw_stopcont_cont
call player_stop
bra tw_keydone
tw_stopcont_cont:
call player_continue
bra tw_keydone
;; if stopped go to measure 001
;tw_stopcont_reset:
; ; go to measure 001
; clrf currentmeasure
; clrf currentmeasure + 1
; clrf nextmeasure
; clrf nextmeasure + 1
; call i2c_flash_read_measure
; ; refresh pattern name
; call i2c_flash_read_trackpattern_name
; bra tw_keydone
; called always when last step of the pattern has been
; triggered
; If incremented nextmeasure points to a different pattern than
; the current the pattern is loaded to the current
tw_handleflash:
CLEAREVENT EVENT_LASTSTEP
; check if repeats are played
movf currentmeasuredata, W
DECODE_REPEAT_FROM_MEASURE ; W = repeat
cpfseq repeatcounter
; repeat counter != current repeat
;
; advance only if all repeats are played
; otherwise just return
return
INCF16 nextmeasure
; if currentmeasure == currenttracklen
; rollover to position 1
movf nextmeasure, W
cpfseq currenttracklen
bra tw_handleflash_nm_ok
movf nextmeasure + 1, W
cpfseq currenttracklen + 1
bra tw_handleflash_nm_ok
clrf nextmeasure
clrf nextmeasure + 1
tw_handleflash_nm_ok:
lfsr FSR1, nextmeasuredata
; read measure from "nextmeasure"
call i2c_flash_read_measure_fsr1
movf INDF1, W ; nextmeasuredata
cpfseq currentmeasuredata ; do we need a new pattern ?
bra tw_handleflash_loadpat
return
tw_handleflash_loadpat:
; pattern is changed in next measure,
; decode nextmeasuredata to nextbank/nextpattern
; and load
movf INDF1, W
DECODE_BANK_FROM_MEASURE
movwf nextbank
movf INDF1, W
DECODE_PATTERN_FROM_MEASURE
movwf nextpattern
call i2c_flash_read
return
; -- Commands
; track write FUNCs
;
; s1 == enter name
tw_shiftcommand:
KEYEVENT KEY_S1, tw_cmd_entername
bra tw_keydone
tw_cmd_entername:
; text destination
SETDISPLAY s_tw_entername
lfsr FSR1, track_name
; read keyboard
call keyboard
call i2c_flash_save_trackname
bra tw_keydone
External Labels :
lcd_refresh
tw_refreshleds
get_bit
mode_trackplay_enter
mode_pattplay_enter
i2c_flash_read_trackpattern_name
i2c_flash_read_measure
i2c_flash_save_measure
i2c_flash_save_tracklength
i2c_flash_read
player_start
player_stop
player_continue
i2c_flash_read_measure_fsr1
keyboard
i2c_flash_save_trackname