;
; mode_traplay.inc: handles track play mode
;
; author: Marko Kanala, raato ]a t[ mulletronic.com
;
; Play mode:
;
; T01:my demo song
; 001/003:A02   x2
;
; Edit mode:
;
; Edit T01 001/002
; A02: pattern  x2
;
;
; 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 play mode is entered
mode_trackplay_enter:
	SETDISPLAY	s_tp_main		; see lcd.inc
	; load first measure
	call	i2c_flash_read_measure
	CLEARMODE	MODE_FILL
	CLEARMODE	MODE_CHAIN
	return

; called in continuous loop when in track play mode
mode_trackplay:
	; if the last step of the pattern has been
	;  reached read the next pattern from the
	;  flash memory if needed
	IFEVENTCALL	EVENT_LASTSTEP, tp_handleflash

	; refresh lcd display if needed	
	call	lcd_refresh

	; do we have key events ?
	IFNOEVENT	EVENT_KEY, tp_no_keyevents

	; starts the sequencer
	KEYEVENT	KEY_START, tp_start
	; stops or continues the sequencer
	KEYEVENT	KEY_STOPCONT, tp_stopcont
	; trigger a fill
	KEYEVENT	KEY_ENTER, tp_fill

;	KEYEVENT	KEY_S1, tp_stepkey
;	KEYEVENT	KEY_S2, tp_stepkey
;	KEYEVENT	KEY_S3, tp_stepkey
;	KEYEVENT	KEY_S4, tp_stepkey
;	KEYEVENT	KEY_S5, tp_stepkey
;	KEYEVENT	KEY_S6, tp_stepkey
;	KEYEVENT	KEY_S7, tp_stepkey
;	KEYEVENT	KEY_S8, tp_stepkey
;	KEYEVENT	KEY_S9, tp_stepkey
;	KEYEVENT	KEY_S10, tp_stepkey
;	KEYEVENT	KEY_S11, tp_stepkey
;	KEYEVENT	KEY_S12, tp_stepkey
;	KEYEVENT	KEY_S13, tp_stepkey
;	KEYEVENT	KEY_S14, tp_stepkey
;	KEYEVENT	KEY_S15, tp_stepkey
;	KEYEVENT	KEY_S16, tp_stepkey
	STEPKEYEVENT	tp_stepkey

	KEYEVENT	KEY_SCALE, tp_nextmeasure

	KEYEVENT	KEY_PATTPLAYWRITE, tp_pattplaywrite
	KEYEVENT	KEY_TRACKPLAYWRITE, tp_trackplaywrite

tp_no_keyevents:
; no specific keyevents, check for downkeys

	; hoax to generate a key events from downkeys
	IFKEYNOTDOWN DOWNKEY_LASTSTEP, tp_laststeplifted
	IFKEYDOWN	DOWNKEY_LASTSTEP, tp_laststeppressed
tp_laststepchecked:

tp_no_downkeys:
; no keyevents and no downkeys, all keys up
;  set default display
	SETDISPLAY	s_tp_main
	call	tp_refreshleds
;	call	lcd_refreshbpm
	return

; all keyhandlers should call this afterwards
tp_keydone:
	call	tp_refreshleds
tp_keydone_keepleds:
	CLEAREVENT	EVENT_KEY
	return

; called when laststep downkey is pressed
tp_laststeppressed:
	; call tp_prevmeasure only, if the laststep downkey
	;  was lifted before
	btfsc	downkeypresses, DOWNKEY_LASTSTEP
	bra		tp_laststepchecked
	bsf		downkeypresses, DOWNKEY_LASTSTEP
	bra		tp_prevmeasure

; called when laststep downkey is not pressed
tp_laststeplifted:
	bcf		downkeypresses, DOWNKEY_LASTSTEP
	bra		tp_laststepchecked

; lights up the led for selected track
tp_refreshleds:
	movlw	1<<LED_START		; preserve start-led
	andwf	LEDREG_START		;  and clear bus b
	clrf	leds_busb_2
	movlw	8
	cpfslt	currenttrack
	bra		tp_refreshleds_upper
	movf	currenttrack, W
	call	get_bit
	movwf	leds_temp_1
	clrf	leds_temp_2
	IFRUNNING	tp_refreshleds_running
	bra		tp_refreshleds_write
tp_refreshleds_upper:
	subwf	currenttrack, W
	call	get_bit
	clrf	leds_temp_1
	movwf	leds_temp_2
	IFRUNNING	tp_refreshleds_running
	bra		tp_refreshleds_write
tp_refreshleds_running:
	movf	currentstep, W			; if currentstep is 0
	bz		tp_refreshleds_write	;  skip the xor					
	movlw	-9
	addwf	currentstep, W			; W = currentstep - 9
	bn		tp_r_lower_ledbus
	; over 8, upper ledbus, W ok (0 - 7)
	call	get_bit
	xorwf	leds_temp_2				; leds XOR currentstep
	bra 	tp_refreshleds_write
tp_r_lower_ledbus:
	addlw	8						; W = currentstep - 1
	call	get_bit
	xorwf	leds_temp_1
tp_refreshleds_write:
	movff	leds_temp_1, leds_busa_1
	movff	leds_temp_2, leds_busa_2
	return

; switches between track play and -write modes
tp_trackplaywrite:
	SETMODE		MODE_TWRITE
	CLEARMODE	MODE_TPLAY
	call	mode_trackwrite_enter
	bra 	tp_keydone_keepleds

; switches between pattern play and -write modes
tp_pattplaywrite:
	SETMODE		MODE_PPLAY
	CLEARMODE	MODE_TPLAY
	call	mode_pattplay_enter
	bra 	tp_keydone_keepleds

; changes the current track
tp_stepkey:
	IFRUNNING	tp_keydone	; only allow the change when stopped
	movlw	16
	movwf	temp
	decf	keypress, W
	bn		tp_keydone		; accept only keys 0 ...
	cpfsgt	temp			
	bra		tp_keydone		;					     to 15
	FORCEDISPLAYREFRESH
	movwf	currenttrack
	CLRF16	currentmeasure
	CLRF16	nextmeasure
	clrf	currentrepeat
	; fetch track name and length
	call	i2c_flash_read_trackmeta
	; fetch first measure
	call	i2c_flash_read_measure
	bra		tp_keydone

; moves to prev measure if stopped
tp_prevmeasure:
	IFRUNNING	tp_keydone
	; check if we can go back one step
	tstfsz	nextmeasure				; xx__ == 0
	bra		tp_prevmeasure_dec
	tstfsz	nextmeasure + 1			; __xx == 0
	bra		tp_prevmeasure_dec
	; position == 0, rollover to the last position
	movff	currenttracklen, nextmeasure
	movff	currenttracklen + 1, nextmeasure + 1
tp_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
	FORCEDISPLAYREFRESH
	bra		tp_keydone

; moves to next measure if stopped
tp_nextmeasure:
	IFRUNNING	tp_keydone
	INCF16	nextmeasure
	; if currentmeasure == currenttracklen 
	;  rollover to position 1
	movf	nextmeasure, W
	cpfseq	currenttracklen
	bra		tw_nextmeasure_ok
	movf	nextmeasure + 1, W
	cpfseq	currenttracklen + 1
	bra		tp_nextmeasure_ok
	clrf	nextmeasure
	clrf	nextmeasure + 1
tp_nextmeasure_ok:
	call	i2c_flash_read_measure
	; update currentmeasure
	movff	nextmeasure, currentmeasure
	movff	nextmeasure + 1, currentmeasure + 1
	FORCEDISPLAYREFRESH
	bra		tp_keydone

; starts the sequencer
tp_start:
	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
	bra		tp_keydone

; stops / continues
tp_stopcont:
	FORCEDISPLAYREFRESH
	IFRUNNING	pp_stopcont_running
	; sequencer is not running, we should continue
	call	player_continue
	bra 	tp_keydone
tp_stopcont_running:
	; sequencer is running, stop the player
	call	player_stop
	bra 	tp_keydone

; changes the fill pattern as a active pattern
tp_fill:
	SETMODE	MODE_FILL
	FORCEDISPLAYREFRESH
	bra 	tp_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
tp_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		tp_handleflash_nm_ok
	movf	nextmeasure + 1, W
	cpfseq	currenttracklen + 1
	bra		tp_handleflash_nm_ok
	clrf	nextmeasure
	clrf	nextmeasure + 1
tp_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		tp_handleflash_loadpat
	return
tp_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

External Labels :

i2c_flash_read_measure
lcd_refresh
tp_refreshleds
get_bit
mode_trackwrite_enter
mode_pattplay_enter
i2c_flash_read_trackmeta
i2c_flash_read
player_start
player_continue
player_stop
i2c_flash_read_measure_fsr1