;
; mode_pattwrite.inc: handles the pattern write 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 write mode is entered
mode_pattwrite_enter:

	; not needed as player.inc ignores these if
	;  we're in pattern write mode	

	; no pattern advance in write mode!
	;movff	currentbank, nextbank
	;movff	currentpattern, nextpattern
	; no chain mode in write mode!
	;CLEARMODE	MODE_CHAIN

	SETDISPLAY	s_pw_main		; see lcd.inc
	return

; called in continuous loop when in pattern write mode
mode_pattwrite:
	; refresh lcd display if needed	
	call	lcd_refresh

	; do we have key events ?
	IFNOEVENT	EVENT_KEY, pw_no_keyevents

	; starts the sequencer
	KEYEVENT	KEY_START, pw_start
	; stops or continues the sequencer
	KEYEVENT	KEY_STOPCONT, pw_stopcont
	; select fill pattern or accent as instrument
	KEYEVENT	KEY_ENTER, pw_enter
	; changes scale
	KEYEVENT	KEY_SCALE, pw_scale

	; step keys enter the notes in write mode
	;  and change the pattern if not

;	KEYEVENT	KEY_S1, pw_stepkey		; bd / "enter name"
;	KEYEVENT	KEY_S2, pw_stepkey		; sd / "copy patt"
;	KEYEVENT	KEY_S3, pw_stepkey		; lt / "paste patt"
;	KEYEVENT	KEY_S4, pw_stepkey		; mt / "rol pattern"
;	KEYEVENT	KEY_S5, pw_stepkey		; ht / "ror pattern"
;	KEYEVENT	KEY_S6, pw_stepkey		; rs
;	KEYEVENT	KEY_S7, pw_stepkey		; hc / "dump pattern" 
;	KEYEVENT	KEY_S8, pw_stepkey		; chh
;	KEYEVENT	KEY_S9, pw_stepkey		; ohh / "copy instr"
;	KEYEVENT	KEY_S10, pw_stepkey		; cc / "paste instr"
;	KEYEVENT	KEY_S11, pw_stepkey		; rc / "rol instr"
;	KEYEVENT	KEY_S12, pw_stepkey		; "ror instr"
;	KEYEVENT	KEY_S13, pw_stepkey		; "randomize instr"
;	KEYEVENT	KEY_S14, pw_stepkey		;
;	KEYEVENT	KEY_S15, pw_stepkey		; "dump all"
;	KEYEVENT	KEY_S16, pw_stepkey		; "settings"
	STEPKEYEVENT	pw_stepkey

	KEYEVENT	KEY_PATTPLAYWRITE, pw_pattplaywrite
	KEYEVENT	KEY_TRACKPLAYWRITE, pw_trackplaywrite

	; bank a key toggles the flam write mode
	KEYEVENT	KEY_BANKA, pw_flamwritemode

	; bank d key acts as a tap write
	KEYEVENT	KEY_BANKD, pw_tapwrite


pw_no_keyevents:
; no specific keyevents, check for downkeys
	IFKEYDOWN	DOWNKEY_INSTRSEL, pw_instrseldown
	IFKEYDOWN	DOWNKEY_CLEAR, pw_cleardown
	IFKEYDOWN	DOWNKEY_LASTSTEP, pw_laststepdown
	IFKEYDOWN	DOWNKEY_SHUFFLEFLAM, pw_shuffleflamdown

pw_no_downkeys:
; no keyevents and no downkeys, all keys up
;  set default display
	SETDISPLAY	s_pw_main
	call	pw_refreshleds
	call	lcd_refreshbpm
	return

; all keyhandlers should call this afterwards
pw_keydone:
	call	pw_refreshleds
pw_keydone_keepleds:
	CLEAREVENT	EVENT_KEY
	return

; downkeyhandlers should call this afterwards
pw_downkeydone:
	call	pw_refreshleds
pw_downkeydone_keepleds:
	return

; sets the leds according to the selected instrument
;  and xors the current step to the step leds if
;  we're in the running mode
pw_refreshleds:
	LOADFSR1_CURRENTTRIGGERROW
	IFNOTINMODE	MODE_FLAMWRITE, pw_refreshleds_noflam
	; in flam write mode, show flams
	movlw	PAT_FLAMS - PAT_TRIGS
	addwf	FSR1L
	movff	POSTINC1, leds_temp_1	; steps 1 - 8
	movff	INDF1, leds_temp_2		; steps 9 - 16
	bra		pw_refreshleds_skipaccents
pw_refreshleds_noflam:
	movff	POSTINC1, leds_temp_1	; steps 1 - 8
	movff	INDF1, leds_temp_2		; steps 9 - 16
pw_refreshleds_accents:
	; blink accents ?
	; note: if total accent is selected this is skipped
	movlw	INSTR_ACCENT
	cpfslt	selectedinst
	bra 	pw_refreshleds_skipaccents
	; not total accent, instrument can be
	;  invidually accented - do blinks
	tstfsz	blink
	bra 	pw_refreshleds_skipaccents
	movlw	PAT_ACCENTS - PAT_TRIGS - 1		; skip to pattern instr specific accents
	addwf	FSR1L							
	comf	POSTINC1, W
	andwf	leds_temp_1
	comf	INDF1, W
	andwf	leds_temp_2
	decf	FSR1L						
pw_refreshleds_skipaccents:
	IFRUNNING	pw_refreshleds_running	
pw_refreshleds_skip:
	; write leds
	movff	leds_temp_1, leds_busa_1
	movff	leds_temp_2, leds_busa_2
	return
pw_refreshleds_running:
	; we are running, xor currentstep
	movf	currentstep, W			; if currentstep is 0
	bz		pw_refreshleds_skip		;  skip the xor					
	movlw	-9
	addwf	currentstep, W			; W = currentstep - 9
	bn		pw_lower_ledbus
	; over 8, upper ledbus, W ok (0 - 7)
	call	get_bit
	movwf	temp
	movlw	INSTR_ACCENT
	cpfslt	selectedinst
	bra 	pw_upper_accoff			; always toggle if total accent selected
									;  or flam write mode active
	IFMODE	MODE_FLAMWRITE, pw_upper_accoff
	; not total accent or flam write mode
	incf	FSR1L					; test accent
	movf	temp, W
	andwf	INDF1, W
	bz		pw_upper_accoff
	; accent is on => led always off
	comf	temp, W
	andwf	leds_temp_2
	bra 	pw_refreshleds_instrs	
pw_upper_accoff:
	; toggle bit
	movf	temp, W
	xorwf	leds_temp_2				; triggers XOR currentstep
	bra 	pw_refreshleds_instrs
pw_lower_ledbus:
	addlw	8						; W = currentstep - 1
	call	get_bit
	movwf	temp
	movlw	INSTR_ACCENT
	cpfslt	selectedinst
	bra 	pw_lower_accoff			; always toggle if total accent selected
									;  or flam write mode active
	IFMODE	MODE_FLAMWRITE, pw_lower_accoff
	movf	temp, W
	andwf	INDF1, W
	bz		pw_lower_accoff
	; accent is on => led always off
	comf	temp, W
	andwf	leds_temp_1
	bra 	pw_refreshleds_instrs
pw_lower_accoff:
	; toggle bit
	movf	temp, W
	xorwf	leds_temp_1
pw_refreshleds_instrs:
; show instrument specific length
;  with blinking led if currentstep != currentstep_<instr>
	tstfsz	blink
	bra 	pw_refreshleds_skip
	movf	selectedinst, W
	INSTRCURRENTSTEPTOW		1		; loads current step to W using FSR1
	bz		pw_refreshleds_skip		; skip if step == 0
	cpfseq	currentstep
	bra		pw_i_ok
	bra 	pw_refreshleds_skip		; do not blink if currentstep pointers overlap
pw_i_ok:
	movwf	temp
	movlw	-9
	addwf	temp, W					; W = step - 9
	bn		pw_i_lower_ledbus	
	; over 8, manipulate leds_busa_2, W = ok
	call	get_bit
	xorwf	leds_temp_2				; xor to upper half
	bra 	pw_refreshleds_skip
pw_i_lower_ledbus:
	; below 9, manipulate leds_busa_1
	addlw	8						; W = step - 1
	call	get_bit
	xorwf	leds_temp_1				; xor to lower half
	bra 	pw_refreshleds_skip

;; shifted keys handled here
;pw_shiftdown:
;	; TODO
;	bra 	pw_downkeydone

; instrument select pressed
pw_instrseldown:
	; instrsel + laststep selects instrument
	;  specific last step
	IFKEYDOWN	DOWNKEY_LASTSTEP, pw_laststepdown_instr
	SETDISPLAY	s_pw_instrsel
	call	lcd_refreshbpm
	bra 	pw_downkeydone

; clear pressed
pw_cleardown:
	; clear current step from selected
	;  instrument if running
	IFNOTRUNNING pw_cleardown_notrunning
	
	; set pattern as dirty
	SETEVENT	EVENT_DIRTY

	LOADFSR1_CURRENTTRIGGERROW	; load current memory row to FSR1
	movlw	9
	cpfslt	currentstep
	incf	FSR1L				; advance a byte for step keys 9 - 16
	call	get_currentbit		; W = pattern memory bit for 
								;  current step
	comf	WREG				; complement bit
	andwf	INDF1				; retain all other bits except
								;  the one cleared
	movwf	temp
	movlw	INSTR_ACCENT
	cpfslt	selectedinst
	bra 	pw_cleardown_notrunning	; if selectedinst != accent clear accents too
	; clear accent 
	movlw	(PAT_ACCENTS - PAT_TRIGS)
	addwf	FSR1L
	movf	temp, W
	andwf	INDF1
	; clear flam notes
	movlw	(PAT_FLAMS - PAT_ACCENTS)
	addwf	FSR1L
	movf	temp, W
	andwf	INDF1
pw_cleardown_notrunning:
	SETDISPLAY	s_pw_clear
	call	lcd_refreshbpm
	bra 	pw_downkeydone

; last step pressed
pw_laststepdown:
	; instrsel + laststep selects instrument
	;  specific last step
	IFKEYDOWN	DOWNKEY_INSTRSEL, pw_laststepdown_instr
	SETDISPLAY	s_pw_laststep
	call	lcd_refreshbpm
	bra 	pw_downkeydone
pw_laststepdown_instr:
	SETDISPLAY	s_pw_laststepinstr
	bra 	pw_downkeydone

; shuffle/flam pressed
pw_shuffleflamdown:
	SETDISPLAY	s_pw_shuffleflam
	call	pw_showshuffleflam
	bra 	pw_downkeydone_keepleds

; set led display to show shuffle / flam values
pw_showshuffleflam:
	SHUFFLETOW	1
	call	get_bit
	movwf	leds_busa_1
	FLAMTOW		1
	call	get_bit
	movwf	leds_busa_2
	return

; toggle flam write mode
pw_flamwritemode:
	TOGGLEMODE	MODE_FLAMWRITE		
	; if flam write mode is set, ensure that
	;  total accent is not selected
	IFNOTINMODE	MODE_FLAMWRITE, pw_flamwritemode_set
	movlw	INSTR_ACCENT
	subwf	selectedinst, W
	bnz		pw_flamwritemode_set
	; select bass drum
	movlw	INSTR_BASSDRUM
	movwf	selectedinst
pw_flamwritemode_set:
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; starts the sequencer
pw_start:
	call	player_start
	bra 	pw_keydone

; stops or continues the sequencer
pw_stopcont:
	IFRUNNING	pw_stopcont_running
	; sequencer is not running, we should continue
	call	player_continue
	bra 	pw_keydone
pw_stopcont_running:
	; sequencer is running, clear the running mode
	call	player_stop
	IFEVENTCALL	EVENT_DIRTY, pw_write_flash		; write current if needed
;	bcf		mode, MODE_RUN
	bra 	pw_keydone

; selects the accent as current instrument if appropriate
pw_enter:
	IFKEYDOWN	DOWNKEY_INSTRSEL, pw_selectinstrument
	IFKEYDOWN	DOWNKEY_CLEAR, pw_clear_accent
	; toggle fill mode if no downkeys
	btg		mode, MODE_FILL
	FORCEDISPLAYREFRESH
	bra 	pw_keydone
; clears accents if appropriate
pw_clear_accent:
	movlw	INSTR_ACCENT
	bra 	pw_clear

; toggles the steps according to a pressed
;  step key and selected instrument
pw_stepkey:
	; instrsel + laststep pressed, set instr. specific last step
	IFKEYSDOWN	DOWNKEY_INSTRSEL, DOWNKEY_LASTSTEP, pw_laststep_instr
	; instrsel pressed, change instrument
	IFKEYDOWN	DOWNKEY_INSTRSEL, pw_selectinstrument
	; laststep pressed, select pattern length
	IFKEYDOWN	DOWNKEY_LASTSTEP, pw_laststep
	; shuffle/flam pressed, select appropriate values
	IFKEYDOWN	DOWNKEY_SHUFFLEFLAM, pw_shuffleflam
	; shift pressed, commands
	IFKEYDOWN	DOWNKEY_SHIFTFUNC, pw_shiftcommand
	; if running set the steps
	IFRUNNING	pw_stepkey_skiprunning
	; we are not running
	; clear pressed, clear a row
	IFKEYDOWN	DOWNKEY_CLEAR, pw_clearinstrument
	; not running, nothing else pressed => set triggers

pw_stepkey_skiprunning:
	; set pattern as dirty
	SETEVENT	EVENT_DIRTY

	LOADFSR1_CURRENTTRIGGERROW		; load current memory row to FSR1
	movlw	KEY_S9
	cpfslt	keypress
	incf	FSR1L					; advance a byte for step keys 9 - 16
	call	get_stepbit				; W = pattern memory bit for 
									;  current step key

	movwf	temp					; temp = step bit
pw_stepkey_tapwrite:	; pw_tapwrite calls this after FSR1 & temp set
	IFNOTINMODE	MODE_FLAMWRITE, pw_stepkey_wr_notflam
	; flam write, adjust fsr1
	movlw	PAT_FLAMS - PAT_TRIGS
	addwf	FSR1L
pw_stepkey_wr_notflam:
	movlw	INSTR_ACCENT
	cpfslt	selectedinst
	bra 	pw_stepkey_accentselected
	; selectedinst < accent, handle normally
	movf	temp, W
	andwf	INDF1, W
	bz		pw_stepkey_wasnoton
	; if in flam write mode do not handle accents
	IFMODE	MODE_FLAMWRITE, pw_stepkey_flamon
	; bit was already on
	;  if step is on => set accent
	;  if step + accent is on => clear both
	movlw	PAT_ACCENTS - PAT_TRIGS
	addwf	FSR1L					; move FSR1 to accents
	movf	temp, W
	andwf	INDF1, W
	bz		pw_stepkey_accentoff	; is accent on ?
	; step + accent is on, clear both
	comf	temp, W
	andwf	INDF1					; clears accent
	movlw	-(PAT_ACCENTS - PAT_TRIGS)
	addwf	FSR1L					; move back to steps
pw_stepkey_flamon:
	comf	temp, W
	andwf	INDF1					; clears step
	bra 	pw_keydone
pw_stepkey_accentoff:
	; step is on but accent off, set accent
	movf	temp, W
	iorwf	INDF1
	bra 	pw_keydone
pw_stepkey_wasnoton:
	; no step and no accent => set step on
	movf	temp, W
	iorwf	INDF1
	bra 	pw_keydone
pw_stepkey_accentselected:
	; selectedinst == accent, skip instr specific accent handling
	IFMODE	MODE_FLAMWRITE, pw_keydone	; if in flam write mode, skip accent
	movf	temp, W
	xorwf	INDF1
	bra 	pw_keydone

; changes the current instrument
pw_selectinstrument:
	movlw	KEY_ENTER
	cpfseq	keypress
	bra 	pw_selectinstrument_notenter
	; enter pressed, select accent ?
	IFMODE	MODE_FLAMWRITE, pw_keydone
	movlw	INSTR_ACCENT
	bra 	pw_selectinstrument_done
pw_selectinstrument_notenter:
	movlw	KEY_S12
	cpfslt	keypress
	bra 	pw_keydone				; only keys < s12 accepted 
	decf	keypress, W
	bn		pw_selectinstrument_skip
pw_selectinstrument_done:
	movwf	selectedinst
	FORCEDISPLAYREFRESH
pw_selectinstrument_skip:
	bra 	pw_keydone

; clears an invidual instrument
pw_clearinstrument:
	movlw	KEY_ENTER
	cpfseq	keypress
	bra 	pw_clearinstrument_notenter
	; enter pressed, clear accent ?
	IFMODE	MODE_FLAMWRITE, pw_keydone
	movlw	INSTR_ACCENT
	bra 	pw_clear
pw_clearinstrument_notenter:
	movlw	KEY_S12
	cpfslt	keypress				; only keys < s12 accepted
	bra 	pw_keydone
	decf	keypress, W
	bn		pw_clearinstrument_done
	; now step key 1 == 0, accent 11
pw_clear:
	IFNOTINMODE	MODE_FILL, pw_clear_p
	lfsr	FSR1, fillpattern + PAT_TRIGS
	bra		pw_clear_fp
pw_clear_p:
	lfsr	FSR1, pattern + PAT_TRIGS
pw_clear_fp:
	; store cleared instrument index
	;  for lcd display routine
	movwf	display_arg

	addwf	WREG					; 2 bytes / instrument
	addwf	FSR1L					; advance to correct trigger
									;  row
	clrf	POSTINC1				; and .. clear
	clrf	INDF1

	; set pattern as dirty
	SETEVENT	EVENT_DIRTY

	; should we clear accents too ?
	movlw	INSTR_ACCENT
	cpfslt	selectedinst
	bra 	pw_clearinstrument_acc	; skip if selectedinst == accent
	movlw	(PAT_ACCENTS - PAT_TRIGS - 1)
	addwf	FSR1L
	clrf	POSTINC1				; clear accents too
	clrf	INDF1
	; clear flams too
	movlw	(PAT_FLAMS - PAT_ACCENTS - 1)
	addwf	FSR1L
	clrf	POSTINC1
	clrf	INDF1
pw_clearinstrument_acc:
	SETDISPLAY	s_pw_cleardone
pw_clearinstrument_done:
	bra 	pw_keydone

; sets the pattern length
pw_laststep:
	movf	keypress, W
	movwf	currentlength
	WTOLENGTH	temp, 1
	; set pattern as dirty
	SETEVENT	EVENT_DIRTY
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; sets the instrument specific last step
pw_laststep_instr:
	decf	keypress, W
	movwf	temp
	IFMODE	MODE_FILL, pw_laststep_instr_fill
	lfsr	FSR1, pattern + PAT_LENGTHS
	bra		pw_laststep_instr_pselected	
pw_laststep_instr_fill:
	lfsr	FSR1, fillpattern + PAT_LENGTHS
pw_laststep_instr_pselected:	
	btfss	selectedinst, 0
	bra		pw_laststep_instr_even
	; odd instrument => store to lsb nybble
	bcf		STATUS, C
	rrcf	selectedinst, W			; instrument / 2
	addwf	FSR1L					; select correct patt reg
	movlw	0xf0
	andwf	INDF1, W				; XXXX0000
	iorwf	temp, W					; XXXXLLLL
	movwf	INDF1					; store
	bra 	pw_laststep_instr_done	
pw_laststep_instr_even:
	; even instrument => store to msb nybble
	bcf		STATUS, C
	rrcf	selectedinst, W			; instrument / 2
	addwf	FSR1L					; select correct patt reg
	swapf	temp					; LLLL0000
	movlw	0x0f
	andwf	INDF1, W				; 0000XXXX
	iorwf	temp, W					; LLLLXXXX
	movwf	INDF1					; store
pw_laststep_instr_done:
	; set pattern as dirty
	SETEVENT	EVENT_DIRTY
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; sets the shuffle and flam values
;  step keys 1 - 8 select shuffle
;  step keys 9 - 13 select flam
pw_shuffleflam:
	movlw	KEY_S9
	cpfslt	keypress	
	bra 	pw_shuffleflam_flam		; > key 8, flam?
	; step key < 9, setting shuffle
	movf	keypress, W
	bz		pw_shuffleflam_done		; keypress = none, skip
	; shuffle value in (0 ... 7)
	decf	WREG
	movwf	currentshuffle
	; store shuffle value
	WTOSHUFFLE	temp, 1
	bra 	pw_shuffleflam_done
pw_shuffleflam_flam:
	movlw	KEY_S14
	cpfslt	keypress
	bra 	pw_shuffleflam_done		; > key 13, skip
	movlw	KEY_S8
	cpfsgt	keypress
	bra 	pw_shuffleflam_done		; < key 9, skip
	movf	keypress, W
	bz		pw_shuffleflam_done		; keypress = none, skip
	; flam values in (0, 1, 2, 3, 4)
	addlw	-KEY_S9
	; store flam value
	WTOFLAM		temp, 1
pw_shuffleflam_done:
	; set pattern as dirty
	SETEVENT	EVENT_DIRTY
	FORCEDISPLAYREFRESH
	bra 	pw_keydone_keepleds

; changes and shows scale
pw_scale:
	SETDISPLAY	s_pw_scale
	FORCEDISPLAYREFRESH
	SCALETOW	1
	movwf	temp
	movlw	SCALE_16TR
	cpfseq	temp
	bra 	pw_scale_inc
	; reloop scale to 0
	movlw	SCALE_16
	bra 	pw_scale_store
pw_scale_inc:
	; increment scale to next value
	incf	temp, W
pw_scale_store:
	WTOSCALE	temp, 1
	; set pattern as dirty
	SETEVENT	EVENT_DIRTY
	bra 	pw_keydone

; switches between pattern play and -write modes
pw_pattplaywrite:
	IFEVENTCALL	EVENT_DIRTY, pw_write_flash		; write current if needed
	SETMODE		MODE_PPLAY
	CLEARMODE	MODE_PWRITE
	CLEARMODE	MODE_FLAMWRITE
	call	mode_pattplay_enter
	bra 	pw_keydone_keepleds

; switches to track play mode
pw_trackplaywrite:
	IFEVENTCALL	EVENT_DIRTY, pw_write_flash		; write current if needed
	SETMODE		MODE_TPLAY
	CLEARMODE	MODE_PWRITE
	CLEARMODE	MODE_FLAMWRITE
	call	mode_trackplay_enter
	bra 	pw_keydone_keepleds

; writes the currentbank/currentpattern pattern to the
;  flash memory
pw_write_flash:
	call	i2c_flash_save
	CLEAREVENT	EVENT_DIRTY
	return

; enters a trigger (or accent) to the current step
pw_tapwrite:
	; tap only when running
	IFNOTRUNNING	pw_keydone
	; set pattern as dirty
	SETEVENT	EVENT_DIRTY
	movf	selectedinst, W
	INSTRCURRENTSTEPTOW	1			; calculate tap pos from instrument pos
	incf	WREG					; tap sets on the _next_ step
	movwf	temp					; 2 - 17 (!)
	movf	selectedinst, W
	INSTRLENGTHTOW	1, temp2		; 1 - 16
	cpfsgt	temp
	bra		pw_tapwrite_noroll
	; currentstep + 1 > instr len => roll to first step
	movlw	1
	movwf	temp
pw_tapwrite_noroll:
	LOADFSR1_CURRENTTRIGGERROW		; load current memory row to FSR1
	movlw	8
	cpfsgt	temp
	bra		pw_tapwrite_lower
	incf	FSR1L
	subwf	temp, F
pw_tapwrite_lower:
	decf	temp, W
	call	get_bit
	movwf	temp					; temp = step bit
	bra 	pw_stepkey_tapwrite		; FSR1 = step byte, do the write



; -- Commands -->

; handles shifted edit commands
;
;  s1 == enter name
;  s2 == copy pattern
;  s3 == paste pattern
;  s4 == rol pattern
;  s5 == ror pattern
;  ...
;  s7 == dump pattern
;  ...
;  s9 == copy instrument
;  s10 == paste instrument
;  s11 == rol instrument
;  s12 == ror instrument
;  s13 == random instrument
;  ...
;  s15 == dump all
;  s16 == settings
pw_shiftcommand:
	; decode command
	KEYEVENT	KEY_S1, pw_cmd_entername
	KEYEVENT	KEY_S2, pw_cmd_copy_patt
	KEYEVENT	KEY_S3, pw_cmd_paste_patt
	KEYEVENT	KEY_S4, pw_cmd_rol_patt
	KEYEVENT	KEY_S5, pw_cmd_ror_patt

	KEYEVENT	KEY_S7, pw_cmd_dump_patt

	KEYEVENT	KEY_S9, pw_cmd_copy_instr
	KEYEVENT	KEY_S10, pw_cmd_paste_instr
	KEYEVENT	KEY_S11, pw_cmd_rol_instr
	KEYEVENT	KEY_S12, pw_cmd_ror_instr
	KEYEVENT	KEY_S13, pw_cmd_random_instr

	KEYEVENT	KEY_S15, pw_cmd_dump_all
	KEYEVENT	KEY_S16, pw_cmd_settings
	bra 	pw_keydone

; enters the naming mode - step keys are used in the
;  same way as the sms writing in cell phones ie.
;  step key 1 == abc
;  step key 2 == def
;  ...
;  step key 9 == number
;  step key 14 == delete char
;  step key 15 == previous char
;  step key 16 == next char
;  enter == done
pw_cmd_entername:
	SETDISPLAY	s_pw_entername
	; text destination
	lfsr	FSR1, pat_name		; FSR1 == pattern name (0x0100!)
	; read keyboard
	call	keyboard
	; enter pressed
	SETEVENT	EVENT_DIRTY
	IFRUNNING	pw_cmd_entername_done_running
	; if not running force flash write
	call	pw_write_flash
pw_cmd_entername_done_running:
	bra		pw_keydone

; copies the current pattern (either non-fill OR fill pattern)
;  to the copy buffer
pw_cmd_copy_patt:
	call	copy_patt_to_buf
	SETDISPLAY	s_pw_pattbuffered
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; pastes the pattern from copy buffer to the current pattern
pw_cmd_paste_patt:
	call	copy_buf_to_patt
	SETEVENT	EVENT_DIRTY
	SETDISPLAY	s_pw_pattpasted
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; rotates the current pattern to the left
pw_cmd_rol_patt:
	call	rotate_pattern_left
	SETEVENT	EVENT_DIRTY
	SETDISPLAY	s_pw_pattrold
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; rotates the current pattern to the right
pw_cmd_ror_patt:
	call	rotate_pattern_right
	SETEVENT	EVENT_DIRTY
	SETDISPLAY	s_pw_pattrord
	FORCEDISPLAYREFRESH
	bra 	pw_keydone




; copies the current instrument (either from non-fill OR fill pattern)
;  to the copy buffer
pw_cmd_copy_instr:
	call	copy_instr_to_buf
	SETDISPLAY	s_pw_instrbuffered
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; pastes the instrument from copy buffer to the current instrument
pw_cmd_paste_instr:
	call	copy_buf_to_instr
	SETEVENT	EVENT_DIRTY
	SETDISPLAY	s_pw_instrpasted
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; rotates the current instrument to the left
pw_cmd_rol_instr:
	call	rotate_instr_trigs_left
	SETEVENT	EVENT_DIRTY
	SETDISPLAY	s_pw_instrrold
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; rotates the current instrument to the right
pw_cmd_ror_instr:
	call	rotate_instr_trigs_right
	SETEVENT	EVENT_DIRTY
	SETDISPLAY	s_pw_instrrord
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; randomizes the current instrument
pw_cmd_random_instr:
	call	randomize_instr
	SETEVENT	EVENT_DIRTY
	SETDISPLAY	s_pw_instrrandomized
	FORCEDISPLAYREFRESH
	bra 	pw_keydone



; dumps the whole sequencer memory to midi sysex
pw_cmd_dump_all:
	; clear the running mode
	call	player_stop
	IFEVENTCALL	EVENT_DIRTY, pw_write_flash		; write current if needed

	; set lcd display
	call	px_lcd_smemdump

	call	midi_out_dump_all
	SETDISPLAY	s_memdump
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; dumps the current pattern to midi sysex
pw_cmd_dump_patt:
	; clear the running mode
	call	player_stop
	IFEVENTCALL	EVENT_DIRTY, pw_write_flash		; write current if needed

	; set lcd display
	call	px_lcd_spattdump

	call	midi_out_dump_patt
	SETDISPLAY	s_pattdump
	FORCEDISPLAYREFRESH
	bra 	pw_keydone

; stops sequencer, goes to settings mode
pw_cmd_settings:
	call	player_stop
	SETSETTINGSMODE
;	CLEARMODE	MODE_PWRITE						; not necessary as settings mode == clrf mode
	call	mode_settings_enter
	bra		pw_keydone

External Labels :

lcd_refresh
pw_refreshleds
lcd_refreshbpm
get_bit
get_currentbit
pw_showshuffleflam
player_start
player_continue
player_stop
get_stepbit
mode_pattplay_enter
mode_trackplay_enter
i2c_flash_save
keyboard
pw_write_flash
copy_patt_to_buf
copy_buf_to_patt
rotate_pattern_left
rotate_pattern_right
copy_instr_to_buf
copy_buf_to_instr
rotate_instr_trigs_left
rotate_instr_trigs_right
randomize_instr
px_lcd_smemdump
midi_out_dump_all
px_lcd_spattdump
midi_out_dump_patt
mode_settings_enter