; ; 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
lcd_refresh pp_refreshleds lcd_refreshbpm get_bit i2c_flash_read player_start player_continue player_stop mode_pattwrite_enter mode_trackplay_enter