Rev 897 | Blame | Compare with Previous | Last modification | View Log | RSS feed
; $Id: sid_midi_b.inc 1122 2013-04-20 12:37:28Z tk $
;
; MIDIbox SID
; MIDI Interface part for Bassline Engine
;
; ==========================================================================
;
; Copyright 1998-2007 Thorsten Klose (tk@midibox.org)
; Licensed for personal non-commercial use only.
; All other rights reserved.
;
; ==========================================================================
;; --------------------------------------------------------------------------
;; This function is called to forward a Note On event to the synthesizer
;; Input:
;; o MIDI Voice in SID_CURRENT_MIDI_VOICE
;; o MIDI channel in SID_CURRENT_CHANNEL
;; o note number in SID_MIDI_PARAMETER1
;; o velocity in SID_MIDI_PARAMETER2
;; --------------------------------------------------------------------------
SID_MIDI_B_NoteOn
;; go through four midi voices
;; 1 and 2 used to play the bassline/select the sequence
;; 3 and 4 used to transpose a sequence
clrf SID_CURRENT_MIDIVOICE, BANKED ; loop counter
lfsr FSR0, SID_MV1_BASE
SID_MIDI_B_NoteOn_Loop
;; check if MIDI channel and split zone matches
call SID_MIDI_Hlp_ChkChnAndSplit
bnz SID_MIDI_B_NoteOn_Loop_Next
;; branch depending on voice
BRA_IFCLR SID_CURRENT_MIDIVOICE, 1, BANKED, SID_MIDI_B_NoteOn_Loop_Voice
SID_MIDI_B_NoteOn_Loop_Trans
;; determine pointer to note stack -> FSR2
call SID_MIDI_Hlp_GetNoteStackFSR2
;; check the active note
call SID_MIDI_Hlp_CheckActiveNote
bz SID_MIDI_B_NoteOn_Loop_TransNClr
SID_MIDI_B_NoteOn_Loop_TransClr
call SID_MIDI_Hlp_ClrStack ; clear note stack (for the case that some notes are marked with bit #7 (key released)
SID_MIDI_B_NoteOn_Loop_TransNClr
;; push note into stack
#if 0
call SID_MIDI_Hlp_PushArpHold ; push at the end of stack
#else
call SID_MIDI_Hlp_PushNote ; push at the beginning of stack
#endif
rgoto SID_MIDI_B_NoteOn_Loop_Next
SID_MIDI_B_NoteOn_Loop_Voice
;; set velocity value
;; L/R selection depending on MIDI voice number
movff CS_MENU_SELECTED_SID_LR, TMP1 ; taken from CS_MENU_SELECTED_SID_LR... dirty :-/
movf SID_CURRENT_MIDIVOICE, W, BANKED
call MIOS_HLP_GetBitORMask
movwf CS_MENU_SELECTED_SID_LR
clrc
rlf SID_MIDI_PARAMETER2, W, BANKED
movwf MIOS_PARAMETER1
movlw SID_KNOB_VEL
call SID_KNOB_SetValue
movff TMP1, CS_MENU_SELECTED_SID_LR
;; get pointer to instrument -> FSR2
rcall SID_MIDI_B_Hlp_FSR2_Ins
;; SID_Ix_Vx_ARP_MODE of instrument -> TMP1
movlw SID_Ix_Vx_ARP_MODE
movff PLUSW2, TMP1
;; SID_Ix_Vx_ARP_SPEED_DIV of instrument -> TMP2
movlw SID_Ix_Vx_ARP_SPEED_DIV
movff PLUSW2, TMP2
;; copy SID_Ix_B_Vx_FLAGS2 to temporary register SID_MIDI_FLAGS
movlw SID_Ix_B_Vx_FLAGS2
movff PLUSW2, SID_MIDI_FLAGS
;; calculate pointer to voice (SIDL/SIDR Voice 1)
rcall SID_MIDI_B_Hlp_FSR1_Voice
;; branch depending on Normal/Arp/Sequencer mode
BRA_IFSET SID_MIDI_FLAGS, SID_I_B_V_FLAGS2_WT_ONLY, BANKED, SID_MIDI_B_NoteOn_Loop_Seq
BRA_IFSET TMP1, SID_I_V_ARP_MODE_ENABLE, ACCESS, SID_MIDI_B_NoteOn_Loop_Arp
SID_MIDI_B_NoteOn_Loop_Norm
;; push note into WT stack
call SID_MIDI_Hlp_GetNoteStackFSR2
lfsr FSR2, SID_MV1_BASE + SID_MVx_WT_STACK_0
movf SID_CURRENT_MIDIVOICE, W, BANKED
mullw SID_MVx_RECORD_LEN
movf PRODL, W
addwf FSR2L, F
call SID_MIDI_Hlp_PushWT
;; determine pointer to note stack -> FSR2
movlw SID_MVx_NOTE_STACK_0 - SID_MVx_WT_STACK_0
addwf FSR2L, F
;; push note into stack
rcall SID_MIDI_Hlp_PushNote
;; switch off gate if not in legato mode
RCALL_IFCLR SID_MIDI_FLAGS, SID_I_B_V_FLAGS2_LEGATO, BANKED, SID_MIDI_B_Hlp_GateOff
;; call note-on handler
rcall SID_MIDI_B_Hlp_NoteOn
rgoto SID_MIDI_B_NoteOn_Loop_Next
SID_MIDI_B_NoteOn_Loop_Arp
;; save voice number in midivoice (instrument) record
movlw SID_MVx_LAST_VOICE
movff SID_CURRENT_VOICE, PLUSW0
;; save midivoice (instrument) number in voice record
movlw SID_Vx_ASSIGNED_MV
movff SID_CURRENT_MIDIVOICE, PLUSW1
;; determine pointer to note stack -> FSR2
call SID_MIDI_Hlp_GetNoteStackFSR2
;; call Arp handler
call SID_MIDI_Hlp_ArpNoteOn
rgoto SID_MIDI_B_NoteOn_Loop_Next
SID_MIDI_B_NoteOn_Loop_Seq
;; push note into WT stack
lfsr FSR2, SID_MV1_BASE + SID_MVx_WT_STACK_0
movf SID_CURRENT_MIDIVOICE, W, BANKED
mullw SID_MVx_RECORD_LEN
movf PRODL, W
addwf FSR2L, F
call SID_MIDI_Hlp_PushWT
;; determine pointer to note stack -> FSR2
movlw SID_MVx_NOTE_STACK_0 - SID_MVx_WT_STACK_0
addwf FSR2L, F
;; push note into stack
rcall SID_MIDI_Hlp_PushNote
;; save midivoice (instrument) number in voice record
movlw SID_Vx_ASSIGNED_MV
movff SID_CURRENT_MIDIVOICE, PLUSW1
;; reset sequencer if voice was not active before
;; do this with both voices for proper synchronisation!
;; only done in master mode
BRA_IFSET SID_STAT, SID_STAT_CLK_SLAVE, ACCESS, SID_MIDI_B_NoteOn_Loop_Seq_NoR01
movff SIDL_V1_BASE + SID_Vx_STATE, WREG
BRA_IFSET WREG, SID_V_STATE_VOICE_ACTIVE, ACCESS, SID_MIDI_B_NoteOn_Loop_Seq_NoR0
SID_MIDI_B_NoteOn_Loop_Seq_R0
movlw 0x01
iorwf SID_SE_TRG_EVNT_U, F, BANKED
SID_MIDI_B_NoteOn_Loop_Seq_NoR0
movff SIDR_V1_BASE + SID_Vx_STATE, WREG
BRA_IFSET WREG, SID_V_STATE_VOICE_ACTIVE, ACCESS, SID_MIDI_B_NoteOn_Loop_Seq_NoR1
SID_MIDI_B_NoteOn_Loop_Seq_R1
movlw 0x02
iorwf SID_SE_TRG_EVNT_U, F, BANKED
SID_MIDI_B_NoteOn_Loop_Seq_NoR1
SID_MIDI_B_NoteOn_Loop_Seq_NoR01
;; select new sequence
rcall SID_MIDI_B_Hlp_SetSeq
;; always set voice active flag of both voices to ensure that they are in sync
;; ensure that this is only done for instruments where WTO (sequencer enabled) is selected
SET_BSR SIDL_V1_BASE
movff SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S1V1_BASE + SID_Ix_B_Vx_FLAGS2, WREG
btfsc WREG, SID_I_B_V_FLAGS2_WT_ONLY
bsf SIDL_V1_BASE + SID_Vx_STATE, SID_V_STATE_VOICE_ACTIVE
movff SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S2V1_BASE + SID_Ix_B_Vx_FLAGS2, WREG
btfsc WREG, SID_I_B_V_FLAGS2_WT_ONLY
bsf SIDR_V1_BASE + SID_Vx_STATE, SID_V_STATE_VOICE_ACTIVE
SET_BSR SID_BASE
;; rgoto SID_MIDI_B_NoteOn_Loop_Next
SID_MIDI_B_NoteOn_Loop_Next
movlw SID_MVx_RECORD_LEN
addwf FSR0L, F
incf SID_CURRENT_MIDIVOICE, F, BANKED
movlw 4 - 1
cpfsgt SID_CURRENT_MIDIVOICE, BANKED
rgoto SID_MIDI_B_NoteOn_Loop
SID_MIDI_B_NoteOn_End
return
;; --------------------------------------------------------------------------
;; This function is called to forward a Note Off event to the synthesizer
;; Input:
;; o MIDI channel in SID_CURRENT_CHANNEL
;; o note number in SID_MIDI_PARAMETER1
;; o velocity in SID_MIDI_PARAMETER2
;; --------------------------------------------------------------------------
SID_MIDI_B_NoteOff
SET_BSR SID_BASE
;; go through four midi voices
;; 1 and 2 used to play the bassline/select the sequence
;; 3 and 4 used to transpose a sequence
clrf SID_CURRENT_MIDIVOICE, BANKED ; loop counter
clrf SID_CURRENT_VOICE, BANKED ; corresponding voice number (0 or 3)
lfsr FSR0, SID_MV1_BASE
SID_MIDI_B_NoteOff_Loop
;; check if MIDI channel and split zone matches
call SID_MIDI_Hlp_ChkChnAndSplit
bnz SID_MIDI_B_NoteOff_Loop_Next
;; branch depending on voice
BRA_IFCLR SID_CURRENT_MIDIVOICE, 1, BANKED, SID_MIDI_B_NoteOff_Loop_Voice
SID_MIDI_B_NoteOff_Loop_Trans
;; determine pointer to note stack -> FSR2
call SID_MIDI_Hlp_GetNoteStackFSR2
;; pop note from stack
call SID_MIDI_Hlp_PopArpHold
;; TODO: add new algorithm which shifts the de-activated note to the end of the stack
;; this would allow following handling (example):
;; Press C-3: plays sequence with base note
;; Press E-3 in addition: transposes sequence by +4
;; Depress E-3: currently holds the transpose - desired behaviour: play C-3 (base note) again, since the key is still pressed
rgoto SID_MIDI_B_NoteOff_Loop_Next
SID_MIDI_B_NoteOff_Loop_Voice
;; SID_Ix_Vx_ARP_MODE of instrument -> TMP1
rcall SID_MIDI_B_Hlp_FSR2_Ins
movlw SID_Ix_Vx_ARP_MODE
movff PLUSW2, TMP1
;; SID_Ix_Vx_ARP_SPEED_DIV of instrument -> TMP2
movlw SID_Ix_Vx_ARP_SPEED_DIV
movff PLUSW2, TMP2
;; copy SID_Ix_B_Vx_FLAGS2 to temporary register SID_MIDI_FLAGS
movlw SID_Ix_B_Vx_FLAGS2
movff PLUSW2, SID_MIDI_FLAGS
;; pop note from WT stack
lfsr FSR2, SID_MV1_BASE + SID_MVx_WT_STACK_0
movf SID_CURRENT_MIDIVOICE, W, BANKED
mullw SID_MVx_RECORD_LEN
movf PRODL, W
addwf FSR2L, F
call SID_MIDI_Hlp_PopWT
;; calculate pointer to voice (SIDL/SIDR Voice 1)
rcall SID_MIDI_B_Hlp_FSR1_Voice
;; determine pointer to note stack -> FSR2
movlw SID_MVx_NOTE_STACK_0 - SID_MVx_WT_STACK_0
addwf FSR2L, F
movff INDF2, TMP3 ; save current #0 entry in TMP3 for later use
;; branch depending on Normal/Arp/Sequencer mode
BRA_IFSET SID_MIDI_FLAGS, SID_I_B_V_FLAGS2_WT_ONLY, BANKED, SID_MIDI_B_NoteOff_Loop_Seq
BRA_IFSET TMP1, SID_I_V_ARP_MODE_ENABLE, ACCESS, SID_MIDI_B_NoteOff_Loop_Arp
SID_MIDI_B_NoteOff_Loop_Norm
;; pop note from stack (pointer to stack in FSR2)
rcall SID_MIDI_Hlp_PopNote
bnz SID_MIDI_B_NoteOff_Loop_Next ; ZERO flag cleared: note not found!
movf TMP3, W ; restore note
rcall SID_MIDI_B_Hlp_NoteOff
RCALL_IFSET WREG, 0, ACCESS, SID_MIDI_B_Hlp_NoteOn
rgoto SID_MIDI_B_NoteOff_Loop_Next
SID_MIDI_B_NoteOff_Loop_Arp
;; call Arp handler
call SID_MIDI_Hlp_ArpNoteOff
rgoto SID_MIDI_B_NoteOff_Loop_Next
SID_MIDI_B_NoteOff_Loop_Seq
;; pop note from stack (pointer to stack in FSR2)
rcall SID_MIDI_Hlp_PopNote
bnz SID_MIDI_B_NoteOff_Loop_Next ; ZERO flag cleared: note not found!
;; FSR2 -> pointer to instrument patch
rcall SID_MIDI_B_Hlp_FSR2_Ins
;; select sequence if there is still a note in stack
movlw SID_MVx_NOTE_STACK_PTR
movf PLUSW0, W
skpz
rcall SID_MIDI_B_Hlp_SetSeq
;; disabled --- hold mode always activated, sequence can be disabled with key G#/A/A#/B
#if 0
;; clear "voice active" flag if no note played and no sequence active
rcall SID_MIDI_B_Hlp_FSR2_Ins
movlw SID_Ix_B_Vx_SEQ_SPEED
BRA_IFSET PLUSW2, SID_I_V_SEQ_HOLD, ACCESS, SID_MIDI_B_NoteOff_Loop_Seq_NoS
movlw SID_MVx_NOTE_STACK_PTR
movf PLUSW0, W
bnz SID_MIDI_B_NoteOff_Loop_Seq_NoS
SID_MIDI_B_NoteOff_Loop_Seq_S
movlw SID_Vx_STATE
bcf PLUSW1, SID_V_STATE_VOICE_ACTIVE
SID_MIDI_B_NoteOff_Loop_Seq_NoS
#endif
;; disable voice active flag of both voices if both are playing invalid sequences (seq off)
;; only used in master mode
BRA_IFSET SID_STAT, SID_STAT_CLK_SLAVE, ACCESS, SID_MIDI_B_NoteOff_Loop_Seq_NoDs
;; always set voice active flag of both voices to ensure that they are in sync
movff SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S1V1_BASE + SID_Ix_B_Vx_SEQ_NUM, WREG
andlw 0xf8
bz SID_MIDI_B_NoteOff_Loop_Seq_NoDs
movff SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S2V1_BASE + SID_Ix_B_Vx_SEQ_NUM, WREG
andlw 0xf8
bz SID_MIDI_B_NoteOff_Loop_Seq_NoDs
SID_MIDI_B_NoteOff_Loop_Seq_Dis
;; ensure that this is only done for instruments where WTO (sequence) is selected
SET_BSR SIDL_V1_BASE
movff SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S1V1_BASE + SID_Ix_B_Vx_FLAGS2, WREG
btfsc WREG, SID_I_B_V_FLAGS2_WT_ONLY
bcf SIDL_V1_BASE + SID_Vx_STATE, SID_V_STATE_VOICE_ACTIVE, BANKED
movff SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S2V1_BASE + SID_Ix_B_Vx_FLAGS2, WREG
btfsc WREG, SID_I_B_V_FLAGS2_WT_ONLY
bcf SIDR_V1_BASE + SID_Vx_STATE, SID_V_STATE_VOICE_ACTIVE, BANKED
SET_BSR SID_BASE
SID_MIDI_B_NoteOff_Loop_Seq_NoDs
;; rgoto SID_MIDI_B_NoteOff_Loop_Next
SID_MIDI_B_NoteOff_Loop_Next
movlw SID_MVx_RECORD_LEN
addwf FSR0L, F
incf SID_CURRENT_MIDIVOICE, F, BANKED
movlw 4 - 1
cpfsgt SID_CURRENT_MIDIVOICE, BANKED
rgoto SID_MIDI_B_NoteOff_Loop
SID_MIDI_B_NoteOff_End
return
;; --------------------------------------------------------------------------
;; This function is called to forward a PitchBender event to the synthesizer
;; Input:
;; o MIDI channel in SID_CURRENT_CHANNEL
;; o 8bit PitchBender value in SID_MIDI_PARAMETER1
;; --------------------------------------------------------------------------
SID_MIDI_B_PitchBender
;; first MIDI voice has already been handled in sid_midi.inc
;; now check for MIDI channel of second voice
;; forward to knob handler (only checks for MIDI channel of first MIDI voice)
lfsr FSR0, SID_MV2_BASE
;; check for MIDI channel
movlw SID_MVx_MIDI_CHANNEL
movf PLUSW0, W
cpfseq SID_CURRENT_CHANNEL, BANKED
rgoto SID_MIDI_B_PitchBender_NoKnob
SID_MIDI_B_PitchBender_Knob
;; select second instrument
movff CS_MENU_SELECTED_SID_LR, TMP1 ; taken from CS_MENU_SELECTED_SID_LR... dirty :-/
movlw 0x02
movwf CS_MENU_SELECTED_SID_LR
;; copy converted pitch bender into mod matrix source
movff SID_MIDI_PARAMETER1, MIOS_PARAMETER1
movlw SID_KNOB_PB
call SID_KNOB_SetValue
movff TMP1, CS_MENU_SELECTED_SID_LR
SID_MIDI_B_PitchBender_NoKnob
return
;; --------------------------------------------------------------------------
;; This function is called to forward a CC event to the synthesizer
;; Input:
;; o MIDI channel in SID_CURRENT_CHANNEL
;; o CC number in SID_MIDI_PARAMETER1
;; o CC value in SID_MIDI_PARAMETER2
;; --------------------------------------------------------------------------
SID_MIDI_B_CC
SET_BSR SID_BASE
;; go through all midi voices
clrf SID_CURRENT_MIDIVOICE, BANKED ; loop counter
lfsr FSR0, SID_MV1_BASE
SID_MIDI_B_CC_Loop
;; check for MIDI channel
movlw SID_MVx_MIDI_CHANNEL
movf PLUSW0, W
cpfseq SID_CURRENT_CHANNEL, BANKED
rgoto SID_MIDI_B_CC_Loop_Next
;; if CC#06 (NRPN data MSB) received, forward to parameter handler
movlw 0x06
cpfseq SID_MIDI_PARAMETER1, BANKED
rgoto SID_MIDI_B_CC_NoNRPNDataH
SID_MIDI_B_CC_NRPNDataH
;; prepare MIOS_PARAMETER3 (selection options)
swapf SID_CURRENT_MIDIVOICE, W, BANKED ; expecting instrument in MIOS_PARAMETER3[6:4]
movwf MIOS_PARAMETER3 ; (L/R selection done in NRPN function)
call SID_PARIN_SetNRPN
rgoto SID_MIDI_B_CC_Loop_Next
SID_MIDI_B_CC_NoNRPNDataH
;; if CC#64 (Sustain) received, set/clear sustain flags and release notes if required
movlw 0x40
cpfseq SID_MIDI_PARAMETER1, BANKED
rgoto SID_MIDI_B_CC_Not64
SID_MIDI_B_CC_64
;; TODO: not supported yet
SID_MIDI_B_CC_Not64
;; handle remaining CCs
movf SID_CURRENT_MIDIVOICE, W, BANKED ; expecting instrument in MIOS_PARAMETER3[5:4]
call MIOS_HLP_GetBitORMask
andlw 0x03
swapf WREG, W
movwf MIOS_PARAMETER3
call SID_CC_TABLE_Set
SID_MIDI_B_CC_Loop_Next
movlw SID_MVx_RECORD_LEN
addwf FSR0L, F
incf SID_CURRENT_MIDIVOICE, F, BANKED
movlw 2-1
cpfsgt SID_CURRENT_MIDIVOICE, BANKED
rgoto SID_MIDI_B_CC_Loop
SID_MIDI_B_CC_Loop_End
return
;; --------------------------------------------------------------------------
;; help routines for Bassline Engine
;; --------------------------------------------------------------------------
;; --------------------------------------------------------------------------
;; Note On help function
;; IN: pointer to voice in FSR1, pointer to MIDI voice in FSR0
;; MIDI voice number in SID_CURRENT_MIDIVOICE
;; Voice number in SID_CURRENT_VOICE
;; ALSO USED BY SID_PATCH_Init !
;; --------------------------------------------------------------------------
SID_MIDI_B_Hlp_NoteOn
;; save note into SID_Vx_NOTE and SID_Vx_PLAYED_NOTE (last one is relevant for MIDI handler)
movlw SID_MVx_NOTE_STACK_0
movff PLUSW0, PRODL
movlw SID_Vx_NOTE
movff PRODL, PLUSW1
movlw SID_Vx_PLAYED_NOTE
movff PRODL, PLUSW1
;; sus-key activated?
BRA_IFCLR SID_MIDI_FLAGS, SID_I_B_V_FLAGS2_SUS_KEY, BANKED, SID_MIDI_B_Hlp_NoteOn_NoSusKey
SID_MIDI_B_Hlp_NoteOn_SusKey
;; in suy-key mode, we activate portamento only if at least one key is played
movlw SID_MVx_NOTE_STACK_PTR
decf PLUSW0, W
bz SID_MIDI_B_Hlp_NoteOn_NoSusKeyPr
SID_MIDI_B_Hlp_NoteOn_NoSusKey
;; omit portamento if first key played after patch initialisation
movlw SID_Vx_STATE2
BRA_IFCLR PLUSW1, SID_V_STATE2_PORTA_INITIALIZED, ACCESS, SID_MIDI_B_Hlp_NoteOn_NoSusKeyPr
movlw SID_Vx_STATE
bsf PLUSW1, SID_V_STATE_PORTA_ACTIVE
SID_MIDI_B_Hlp_NoteOn_NoSusKeyPr
;; next key will allow portamento
movlw SID_Vx_STATE2
bsf PLUSW1, SID_V_STATE2_PORTA_INITIALIZED
;; skip the rest if legato and voice already active
BRA_IFCLR SID_MIDI_FLAGS, SID_I_B_V_FLAGS2_LEGATO, BANKED, SID_MIDI_B_Hlp_NoteOn_NoLegato
SID_MIDI_B_Hlp_NoteOn_Legato
movlw SID_Vx_STATE
BRA_IFSET PLUSW1, SID_V_STATE_VOICE_ACTIVE, ACCESS, SID_MIDI_B_Hlp_NoteOn_NoGate
SID_MIDI_B_Hlp_NoteOn_NoLegato
;; request gate bit
rcall SID_MIDI_B_Hlp_GateOn
SID_MIDI_B_Hlp_NoteOn_NoGate
;; don't sync if WTO mode or legato mode and current note is first note
RCALL_IFCLR SID_MIDI_FLAGS, SID_I_B_V_FLAGS2_LEGATO, BANKED, SID_MIDI_B_Hlp_NoteOn_NOnTrg
movlw SID_MVx_NOTE_STACK_0
movff PLUSW0, PRODL
movf SID_MIDI_PARAMETER1, W, BANKED
cpfseq PRODL, ACCESS
rgoto SID_MIDI_B_Hlp_NoteOn_NoNOnTrg
movlw SID_MVx_NOTE_STACK_1
movf PLUSW0, W
bnz SID_MIDI_B_Hlp_NoteOn_NoNOnTrg
SID_MIDI_B_Hlp_NoteOn_NOnTrg
;; TODO: ??? removed code???
SID_MIDI_B_Hlp_NoteOn_NoNOnTrg
;; save voice number in midivoice (instrument) record
movlw SID_MVx_LAST_VOICE
movff SID_CURRENT_VOICE, PLUSW0
;; save midivoice (instrument) number in voice record
movlw SID_Vx_ASSIGNED_MV
movff SID_CURRENT_MIDIVOICE, PLUSW1
return
;; --------------------------------------------------------------------------
;; Note Off help function
;; IN: pointer to voice in FSR1, pointer to MIDI voice in FSR0
;; OUT: returns 0x01 if gate should be retriggered (mono mode, more than one note was played)
;; --------------------------------------------------------------------------
SID_MIDI_B_Hlp_NoteOff
;; last note number of #0 (before pop) in WREG!
movwf TABLAT
;; if not in legato mode and current note-off number equal to last entry #0: gate off
movf TABLAT, W
cpfseq SID_MIDI_PARAMETER1, BANKED
rgoto SID_MIDI_B_Hlp_NoteOff_End
BRA_IFSET SID_MIDI_FLAGS, SID_I_B_V_FLAGS2_LEGATO, BANKED, SID_MIDI_B_Hlp_NoteOff_NoGOff
rcall SID_MIDI_B_Hlp_GateOff
SID_MIDI_B_Hlp_NoteOff_NoGOff
;; ------------------------------------------------------------------
;; if there is still a note in the stack, play new note with NoteOn function (checked by caller)
movlw SID_MVx_NOTE_STACK_PTR
movf PLUSW0, W
bz SID_MIDI_B_Hlp_NoteOff_GOff
;; activate portamento (will be ignored by Pitch handler if no portamento active - important for SusKey function to have it here!)
movlw SID_Vx_STATE
bsf PLUSW1, SID_V_STATE_PORTA_ACTIVE
retlw 0x01 ; return, request Note On!
SID_MIDI_B_Hlp_NoteOff_GOff
;; else request gate clear bit
rcall SID_MIDI_B_Hlp_GateOff
SID_MIDI_B_Hlp_NoteOff_End
retlw 0x00 ; return, request NO Note On!
;; --------------------------------------------------------------------------
;; Gate On help function
;; IN: pointer to voice in FSR1, pointer to MIDI voice in FSR0
;; voice number in SID_CURRENT_VOICE
;; --------------------------------------------------------------------------
SID_MIDI_B_Hlp_GateOn
;; set "voice active" flag
movlw SID_Vx_STATE
bsf PLUSW1, SID_V_STATE_VOICE_ACTIVE
;; request gate via trigger matrix
movf SID_CURRENT_VOICE, W, BANKED
call MIOS_HLP_GetBitORMask
iorwf SID_SE_TRG_EVNT_L, F, BANKED
;; request LFO re-sync
movf SID_CURRENT_VOICE, W, BANKED
addlw 2
call MIOS_HLP_GetBitORMask
iorwf SID_SE_TRG_EVNT_H, F, BANKED
movf SID_CURRENT_VOICE, W, BANKED
movlw 0x01
skpz
movlw 0x02
iorwf SID_SE_TRG_EVNT_U, F, BANKED
;; ENV attack phase via trigger matrix
movf SID_CURRENT_VOICE, W, BANKED
call MIOS_HLP_GetBitORMask
iorwf SID_SE_TRG_EVNT_ENVA, F, BANKED
;; set accent flag depending on velocity (set when velocity >= 0x40)
movlw SID_Vx_STATE
bcf PLUSW1, SID_V_STATE_ACCENT
btfsc SID_MIDI_PARAMETER2, 6, BANKED
bsf PLUSW1, SID_V_STATE_ACCENT
SID_MIDI_B_Hlp_GateOn_End
return
;; --------------------------------------------------------------------------
;; Gate Off help function
;; IN: pointer to voice in FSR1, pointer to MIDI voice in FSR0
;; note in SID_MIDI_PARAMETER1, velocity in SID_MIDI_PARAMETER2
;; --------------------------------------------------------------------------
SID_MIDI_B_Hlp_GateOff
movlw SID_Vx_STATE
BRA_IFCLR PLUSW1, SID_V_STATE_VOICE_ACTIVE, ACCESS, SID_MIDI_B_Hlp_GateOff_End
movlw SID_Vx_PLAYED_NOTE
movf PLUSW1, W
cpfseq SID_MIDI_PARAMETER1, BANKED
rgoto SID_MIDI_B_Hlp_GateOff_End
;; request gate off
movlw SID_Vx_STATE
bcf PLUSW1, SID_V_STATE_VOICE_ACTIVE
bcf PLUSW1, SID_V_STATE_GATE_SET_REQ
;; request gate clear
movf SID_CURRENT_VOICE, W, BANKED
call MIOS_HLP_GetBitORMask
movlw SID_Vx_STATE
bsf PLUSW1, SID_V_STATE_GATE_CLR_REQ
;; ENV release phase via trigger matrix
movf SID_CURRENT_VOICE, W, BANKED
call MIOS_HLP_GetBitORMask
iorwf SID_SE_TRG_EVNT_ENVR, F, BANKED
SID_MIDI_B_Hlp_GateOff_End
return
;; --------------------------------------------------------------------------
;; Help function which returns a pointer to the SID voice of a MIDI voice in FSR1
;; IN: SID_CURRENT_MIDIVOICE
;; OUT: pointer to voice in FSR1, voice number in SID_CURRENT_VOICE
;; --------------------------------------------------------------------------
SID_MIDI_B_Hlp_FSR1_Voice
;; MIDI instrument 0 -> SIDL_V1_VOICE (voice #0)
;; MIDI instrument 1 -> SIDR_V1_VOICE (voice #3)
movf SID_CURRENT_MIDIVOICE, W, BANKED
skpz
movlw 3
movwf SID_CURRENT_VOICE, BANKED
lfsr FSR1, SIDL_V1_BASE
skpz
lfsr FSR1, SIDR_V1_BASE
return
;; --------------------------------------------------------------------------
;; Help function which returns a pointer to the assigned instrument
;; of a MIDI voice in FSR2
;; IN: SID_CURRENT_MIDIVOICE
;; OUT: pointer to instrument in FSR2
;; --------------------------------------------------------------------------
SID_MIDI_B_Hlp_FSR2_Ins
lfsr FSR2, SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S1V1_BASE
movf SID_CURRENT_MIDIVOICE, W, BANKED
mullw SID_Ix_B_S2V1_BASE-SID_Ix_B_S1V1_BASE
movf PRODL, W
addwf FSR2L, F
movf PRODH, W
addwfc FSR2H, F
return
;; --------------------------------------------------------------------------
;; Help function which selects the sequence based on played note
;; IN: SID_CURRENT_MIDIVOICE (0 or 1), voice base in FSR1, midi voice base in FSR0
;; --------------------------------------------------------------------------
SID_MIDI_B_Hlp_SetSeq
;; get first note
movlw SID_MVx_NOTE_STACK_0
movff PLUSW0, PRODL
;; add MIDI voice based transpose value (ensure that within range 0x00..0x7f)
movlw SID_MVx_TRANSPOSE
movf PLUSW0, W
addlw -0x40
BRA_IFSET WREG, 7, ACCESS, SID_MIDI_B_Hlp_SetSeq_TrnN
SID_MIDI_B_Hlp_SetSeq_TrnP
addwf PRODL, F
BRA_IFCLR PRODL, 7, ACCESS, SID_MIDI_B_Hlp_SetSeq_Trn_Cont
addlw -12
rgoto SID_MIDI_B_Hlp_SetSeq_TrnP
SID_MIDI_B_Hlp_SetSeq_TrnN
addwf PRODL, F
BRA_IFCLR PRODL, 7, ACCESS, SID_MIDI_B_Hlp_SetSeq_Trn_Cont
movlw 12
rgoto SID_MIDI_B_Hlp_SetSeq_TrnN
SID_MIDI_B_Hlp_SetSeq_Trn_Cont
;; store note in voice record
movlw SID_Vx_PLAYED_NOTE
movff PRODL, PLUSW1
;; determine sequence based on note number
;; remove octave from note
SID_MIDI_B_Hlp_SetSeq_RemoveOct
movlw 12 - 1
cpfsgt PRODL, ACCESS
rgoto SID_MIDI_B_Hlp_SetSeq_OctOk
movlw -12
addwf PRODL, F
rgoto SID_MIDI_B_Hlp_SetSeq_RemoveOct
SID_MIDI_B_Hlp_SetSeq_OctOk
;; if note number >= 8: set to 8 (sequence off)
movlw 8
cpfslt PRODL, ACCESS
movwf PRODL
;; set new sequence
BRA_IFSET SID_CURRENT_MIDIVOICE, 0, BANKED, SID_MIDI_B_Hlp_SetSeq_1
SID_MIDI_B_Hlp_SetSeq_0
;; patch/shadow buffer
movff PRODL, SID_PATCH_BUFFER + SID_Ix_B_S1V1_BASE + SID_Ix_B_Vx_SEQ_NUM
movff PRODL, SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S1V1_BASE + SID_Ix_B_Vx_SEQ_NUM
;; forward to edit buffer if SID selected
call CS_MENU_MS_GetSIDNumber
xorwf CS_MENU_EDIT_BUFFER_SID, W
skpnz
movff PRODL, SID_EDIT_BUFFER + SID_Ix_B_S1V1_BASE + SID_Ix_B_Vx_SEQ_NUM
return
SID_MIDI_B_Hlp_SetSeq_1
;; patch/shadow buffer
movff PRODL, SID_PATCH_BUFFER + SID_Ix_B_S2V1_BASE + SID_Ix_B_Vx_SEQ_NUM
movff PRODL, SID_PATCH_BUFFER_SHADOW + SID_Ix_B_S2V1_BASE + SID_Ix_B_Vx_SEQ_NUM
;; forward to edit buffer if SID selected
call CS_MENU_MS_GetSIDNumber
xorwf CS_MENU_EDIT_BUFFER_SID, W
skpnz
movff PRODL, SID_EDIT_BUFFER + SID_Ix_B_S2V1_BASE + SID_Ix_B_Vx_SEQ_NUM
return
Generated by GNU enscript 1.6.4.