; ; 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
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