; ; player.inc: 24ppq player tick, ; called from hi-pri irq ; ; scale length of one step (48 ppqn) ; ----- ------------------ ; 0 1/16 (12 ticks) shuffle 0...7 ; 1 1/32 (6 ticks) shuffle 0...6 ; 2 1/8 triplet (16 ticks) shuffle 0...7 ; 3 1/16 triplet (8 ticks) shuffle 0...7 ; ; 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). ; player_tick: ; are we running ? IFRUNNING player_running return ; starts the player player_start: IFNOTINMODE MODE_RUN, player_start_stopped ; we're running, send stop to sync to get ; synced machines to reset too call player_stop player_start_stopped: ; reset current step(s) clrf currentstep clrf currentstep_bdrum clrf currentstep_sdrum clrf currentstep_ltom clrf currentstep_mtom clrf currentstep_htom clrf currentstep_rshot clrf currentstep_hclap clrf currentstep_chihat clrf currentstep_ohihat clrf currentstep_crash clrf currentstep_ride clrf currentstep_accent clrf bpmtick ; set the running mode on bsf mode, MODE_RUN ; send midi start IFSETTINGONCALL SETTING_MIDIS_OUT, midi_out_start ;call midi_out_start return player_continue: clrf bpmtick ; set the running mode on bsf mode, MODE_RUN ; send midi continue IFSETTINGONCALL SETTING_MIDIS_OUT, midi_out_continue ;call midi_out_continue return ; stops the player, make's sure the sync stop gets sent player_stop: CLEARMODE MODE_RUN clrf triggers_a clrf triggers_b call tr_set_trigger_latches ; send midi stop IFSETTINGONCALL SETTING_MIDIS_OUT, midi_out_stop ; call midi_out_stop ; clear event bits to prevent stucking on syncs CLEAREVENT EVENT_DINRUN CLEAREVENT EVENT_MIDIRUN return player_running: ; resolve current scale: ; "bpmscaler" variable gets set ; with current tick count depending ; on the scale setting SCALETOW 2 call get_scaleticks movwf bpmscaler incf bpmtick movlw 1 cpfsgt bpmtick call player_trig ; play triggers on first tick decf flamcounter bn player_flamneg ; flam positive or zero bnz player_flamdone ; flam zero, play flams call player_flams player_flamneg: ; flamcounter was negative, flam must be 0 clrf flamcounter player_flamdone: ; note: currentstep values from 1 - 16 btfsc currentstep, 0 bra currentstep_odd ; even step ; load shuffle to W movf currentshuffle, W subwf bpmscaler, W ; even steps take bpmscaler - shuffle ticks bnn shufflescaleok clrf WREG ; reset W if shuffle value too big shufflescaleok: cpfslt bpmtick ; should we reset bpmtick ? clrf bpmtick return currentstep_odd: ; odd step, if this is the last step ; ignore shuffle movf currentlength, W cpfslt currentstep bra player_laststep_odd ; odd steps take bpmscaler + shuffle ticks ; movf bpmscaler, W ; min 6 incf bpmscaler, W ; bpmscaler + 1, min of 7 ; if bpmscaler is less than currentshuffle ; we need to correct the step duration by -1 cpfslt currentshuffle ; 0 ... 7 decf WREG decf WREG addwf currentshuffle, W ; bpmscaler + shuffle cpfslt bpmtick clrf bpmtick return ; currentstep is the last step ; and the step is odd, ignore shuffle player_laststep_odd: movf bpmscaler, W cpfslt bpmtick clrf bpmtick return ; ; triggers the current step ; ; note: we can do some processing before ; triggering the trigger circuit as the ; lcd bus needs to settle down anyway ; player_trig: ; we should increment the step counters incf currentstep incf currentstep_bdrum incf currentstep_sdrum incf currentstep_ltom incf currentstep_mtom incf currentstep_htom incf currentstep_rshot incf currentstep_hclap incf currentstep_chihat incf currentstep_ohihat incf currentstep_crash incf currentstep_ride incf currentstep_accent ; ... ~1.3us movf currentlength, W movwf player_temp ; store for INSTRCHECKPOS cpfseq currentstep bra player_not_last_step ; last step => mark as an event SETEVENT EVENT_LASTSTEP player_not_last_step: cpfsgt currentstep bra player_no_pat_reset ; currentstep > pat_length, reset to 1 movlw 1 movwf currentstep ; currenstep == 1 movlw (1<<MODE_TPLAY) | (1<<MODE_TWRITE) andwf mode, W bz player_not_trackmode movf currentmeasuredata, W DECODE_REPEAT_FROM_MEASURE ; W = repeat cpfslt repeatcounter bra player_advance_trackmode ; repeatcounter < current measure repeat ; just increment repeat counter and continue incf repeatcounter bra player_not_trackmode player_advance_trackmode: ; roll track mode counters movff nextmeasuredata, currentmeasuredata movff nextmeasure, currentmeasure movff nextmeasure + 1, currentmeasure + 1 clrf repeatcounter player_not_trackmode: ; if we are in pattern write mode do not change the ; current pattern IFMODE MODE_PWRITE, player_reset_done ; roll to the next pattern if needed, ; if next differs from current we are waiting for a flash event ; otherwise the event will never come IFNOEVENT EVENT_FLASHREADOK, player_no_flash_done ; flash read done, roll over CLEAREVENT EVENT_FLASHREADOK movff nextbank, currentbank movff nextpattern, currentpattern LENGTHTOW 2 movwf currentlength SHUFFLETOW 2 movwf currentshuffle bra player_dochain player_no_flash_done: ; no flash event, we should do the chain check anyway ; if next == current movf currentbank, W cpfseq nextbank bra player_reset_done movf currentpattern, W cpfseq nextpattern bra player_reset_done player_dochain: IFNOTINMODE MODE_CHAIN, player_reset_done ; if in chain mode get next pattern from chain lfsr FSR2, chainbuffer movf chainposition, W addwf FSR2L movf INDF2, W bnn player_chain_ok ; chain ended clrf chainposition ; try again from the start movf chainbuffer, W bn player_no_flash_done ; no chain, just skip player_chain_ok: ; pattern was found in chain, decode pattern/bank movwf nextpattern movwf nextbank movlw b'00001111' andwf nextpattern ; b'0000pppp' swapf nextbank ; b'pppp00bb' andwf nextbank ; b'000000bb' incf chainposition ; advance to next in chain player_reset_done: FORCEDISPLAYREFRESH ; display should be refreshed IFMODE MODE_PWRITE, player_no_pat_reset CLEARMODE MODE_FILL ; clear fill flag if in play mode player_no_pat_reset: ; check and roll over the counters if needed LOADPATTOFSR 2, PAT_LENGTHS ; ... ~3us INSTRCHECKPOS currentstep_bdrum, currentstep_sdrum ; ~1.6us / check INSTRCHECKPOS currentstep_ltom, currentstep_mtom INSTRCHECKPOS currentstep_htom, currentstep_rshot INSTRCHECKPOS currentstep_hclap, currentstep_chihat INSTRCHECKPOS currentstep_ohihat, currentstep_crash INSTRCHECKPOS currentstep_ride, currentstep_accent ; ... 12.6us ; blink blink_tempo with step advance btg blink_tempo, 0 ; ; step counters always 1 - 16 for triggering routines ; ; (this allows lcd to settle if ; triggers collide with lcd enable strobe) ; ; NOT NEEDED HERE ; ~13us delay already spent on length checks ; call player_lcd_delay bcf PORT_LCD_EN, LCD_EN_PIN ; we should protect the lcd bus before ; messing up with the triggers ; RB0 - RB4 should be saved as they ; overlap with the trigger bus movlw b'00011111' andwf PORT_LCD, W movwf player_temp ; see 9090.inc, triggers the p9090 circuit call tr_do_triggers ; restore LCD bus movlw b'11100000' andwf PORT_LCD, W iorwf player_temp, W movwf PORT_LCD ; trigger midi outs set so IFSETTINGONCALL SETTING_MIDIN_OUT, midi_do_triggers ; set flamcounter on trigger FLAMTOW 2 addwf WREG ; flam * 2 movwf flamcounter return ; ; checks if any flams should be played ; and triggers them accordingly ; player_flams: ; protects the shared lcd bus call player_lcd_delay bcf PORT_LCD_EN, LCD_EN_PIN movlw b'00011111' andwf PORT_LCD, W movwf player_temp call tr_do_flams ; restore LCD bus movlw b'11100000' andwf PORT_LCD, W iorwf player_temp, W movwf PORT_LCD return ; ; sets the triggers off, timed with timer 3 ; for ~2ms trigger pulses ; player_trig_off: ; protects the shared lcd bus call player_lcd_delay bcf PORT_LCD_EN, LCD_EN_PIN movlw b'00011111' andwf PORT_LCD, W movwf player_temp ; see 9090.inc, sets the triggers off in p9090 circuit call tr_clear_triggers ; restore LCD bus movlw b'11100000' andwf PORT_LCD, W iorwf player_temp, W movwf PORT_LCD return ; ; 13us delay to avoid the lcd bus collision ; player_lcd_delay: movlw 32 movwf player_temp player_lcd_delay_loop: clrwdt decfsz player_temp bra player_lcd_delay_loop return
player_stop tr_set_trigger_latches get_scaleticks player_trig player_flams tr_do_triggers player_lcd_delay tr_do_flams tr_clear_triggers