Post by ki on Feb 9, 2019 23:59:30 GMT
I was asked on the Audiobus Forum to write a script to hold sustained notes using the sustain pedal - which should be usefull for instruments not supporting the CC40 message.
The idea is to suppress the note-off when the sustain switch is on and release the held notes with their given note-off velocity when the sustain pedal goes off.
The initial version worked fine with the internal keyboard of AUM or my external keyboard - but i soon realized that some more handling is needed for MPE support. With MPE its possible to press the same key/note on different midi channels, so i had to refactor the script to its current version.
There are no user variables to be set up, just run the script an pipe the keyboard and sustain pedal to it and feed the ouput to a synth or instrument.
The idea is to suppress the note-off when the sustain switch is on and release the held notes with their given note-off velocity when the sustain pedal goes off.
The initial version worked fine with the internal keyboard of AUM or my external keyboard - but i soon realized that some more handling is needed for MPE support. With MPE its possible to press the same key/note on different midi channels, so i had to refactor the script to its current version.
There are no user variables to be set up, just run the script an pipe the keyboard and sustain pedal to it and feed the ouput to a synth or instrument.
# SustainNotes - Delay note-off‘s depending on sustain pedal
# Version: 3 / 09.02.2019
# Author: -ki https://forum.audiob.us/profile/_ki
#
# Displays NOR or SUS state on left label
# Displays number of playing/hold notes on right label
#
# - Support for MPE (even same note on different channels)
# - Allows to retrigger already hold notes when sustaining
# - Uses note-off velocity when releasing hold notes
#
# The CC40 sustain pedal cmd itself is blocked, all other
# midi events are forwarded
#
#
#
# Variables
# ——————————-
# K00-7F cnArray[] Channel|Note
# L00-7F hvArray[] Hold |Velocity
#
# J00 sustainNotes
# J01 noteCount / number of notes in K/L array
IF MT == B0 # if (inputCmd == ControllerChange) {
IF M1 == 40 7F # if (sustain pedal on) {
ASS J0 = 1 # sustainNotes = 1
SET LB0 SSUS # show(left, „SUS“)
END # }
IF M1 == 40 00 # if (sustain pedal off) {
ASS J0 = 0 # sustainNotes = 0
# // Stop all hold note
ASS I0 = 0 # i = 0
IF I0 < J1 +L # while(i < noteCount) {
MAT I1 = LI0 & FF00 # flags = hvArray[i]
IF I1 == 8000 # if (flags == HOLD) {
MAT I2 = KI0 / 100 # channel = cnArray[i] >> 8
MAT I3 = 80 + I2 # offCmd = $80 + channel
MAT I4 = KI0 & 00FF # note = cnArray[i] & $00FF
MAT I5 = LI0 & 00FF # vel = hvArray[i] & $00FF
SND I3 I4 I5 # snd(offCmd, note, vel)
# // Remove note by swapping last
MAT J1 = J1 - 1 # noteCount -= 1
ASS KI0 = KJ1 # cnArray[i] = cnArray[noteCount]
ASS LI0 = LJ1 # hvArray[i] = hvArray[noteCount]
END # }
IF I1 != 8000 # if (flags != HOLD) {
MAT I0 = I0 + 1 # i += 1
END # }
END #
SET LB0 SNOR # show(left, „NOR„)
IF J1 > 0 # if (noteCnt > 0) {
SET LB1 J1 # show(right, noteCnt)
END # }
IF J1 == 0 # if (noteCnt == 0) {
SET LB1 S— # show(right, „-„)
END # }
END # }
BX 40 = XX +B # // Block sustain pedal cmd
END # }
9X XX 00 = 8X # // Convert note-ons with vel 0 to note-off
IF MT == 90 # if (noteOn) {
ASS I0 = 0 # i = 0
MAT I1 = MC * 100 # channelHigh = inputChannel << 8
MAT I1 = I1 + M1 # channelAndNote = channelHigh + inputNote
ASS I2 = 0 # found = FALSE
IF I0 < J1 +L # while(i < noteCount) {
IF KI0 == I1 # if (cnArray[i] == channelAndNote) {
ASS I2 = 1 # found = TRUE
IF J0 != 0 # if (sustainNotes) {
# // Retrigger already hold notes
MAT I3 = 80 + MC # offCmd = $80 + inputChannel
MAT I4 = LI0 & 00FF # offVel = pvArray[i] & $00FF
ASS LI0 = M2 # hvArray[i] = inputVel // no HOLD flag
SND I3 M1 I4 # snd(offCmd, inputNote, offVel)
SND M0 M1 M2 # snd(inputCmd, inputNote, inputVel)
9X = XX +B # block(incomming note-on)
ASS I0 = J1 # i = noteCount // break
END # }
END # }
MAT I0 = I0 + 1 # i += 1
END # }
IF I2 == 0 # if (!found) {
ASS KI0 = I1 # cnArray[i] = channelAndNote
ASS LI0 = M2 # hvArray[i] = inputVel // no HOLD flag
MAT J1 = J1 + 1 # noteCount += 1
END # }
SET LB1 J1 # show(right, noteCnt)
END # }
IF MT == 80 # if (noteOff) {
ASS I0 = 0 # i = 0
MAT I1 = MC * 100 # channelHigh = inputChannel << 8
MAT I1 = I1 + M1 # channelAndNote = channelHigh + inputNote
IF I0 < J1 +L # while(i < noteCount) {
IF KI0 == I1 # if (cnArray[i] == channelAndNote) {
IF J0 != 0 # if (sustainNotes) {
# // Hold note, update vel and flag
MAT LI0 = 8000 + M2 # hvArray[i] = HOLD + inputVel
8X = XX +B # block note-off
END # }
IF J0 == 0 # if (!sustainNotes) {
# // Remove note
MAT J1 = J1 - 1 # noteCount -= 1
ASS KI0 = KJ1 # cnArray[i] = cnArray[noteCount]
ASS LI0 = LJ1 # hvArray[i] = hvArray[noteCount]
END # }
ASS I0 = J1 # i = noteCount // break
END # }
MAT I0 = I0 + 1 # i += 1
END # }
IF J1 > 0 # if (noteCnt > 0) {
SET LB1 J1 # show(right, noteCnt)
END # }
IF J1 == 0 # if (noteCnt == 0) {
SET LB1 S— # show(right, „-„)
END # }
END # }
IF LOAD # if (initialLoad) {
ASS J0 = 0 # sutainNotes = 0
ASS J1 = 0 # noteCount = 0
SET LB0 SNOR # show(left, „NOR„)
END # }