How to get event ids for artificial events?
-
Use a MIDI list for storing polyphonic data
-
Would a MidiList work for when you have the pedal down, and have multiple voices happening on the same key?
-
@benosterhouse A MIDI list is just an array that is dedicated to tracking 128 integer values (designed for polyphonic MIDI data).
-
What I'm thinking is: say on a piano library you put the pedal down and played several repeated notes. When you lift the pedal, you'd want to noteoff all the repeated notes, not just the most recent one. How do you keep track of all those previous repeated notes?
-
@benosterhouse Why not just use
Engine.allNotesOff();
? -
When you lift the pedal, you don't want to note off notes that you're still playing.
-
@benosterhouse Good point, so why script it at all since this is the default behaviour?
-
A couple reasons, but one of them would be so I can keep track of the play position of notes in the onTimer callback.
The next question would be why I'm wanting to keep track of the play position of every event. -
The next question would be why I'm wanting to keep track of the play position of every event.
Go on :)
On a piano wouldn't a repeated note cancel out the previous note, since it's striking the same string?
-
Basically, I'm seeing if I can port a library to vst using hise.
It has string swells in it, which are tempo synced. I see that hise doesn't really have timestretching yet, but I was realizing there's another way around it:
If you play the beginning of the swell, then crossfade into the middle of the swell, you can adjust the length of the swell, so it'd fit into any project tempo (the phasing isn't too bad. I have some ideas to get around that).If you're fading together different parts of the swell, the tail end of it needs to be started with an artificial event.
If you have multiple stiched-together swells (which use artificial events), and they're happening on the same key at the same time, you need a way to note-off all the artificial events when you lift the pedal. -
@benosterhouse I get it, I'll play around with it a little tomorrow and see if I can come up with a way of managing the sustain/note off thing manually.
-
Ok cool!
On a sampled piano, if you play a repeated note with the pedal down you want to keep the previous sample going. -
Ok, that way I was trying to iterate through things before was too complicated and didn't actually work.
I just added another dimension to the array so I could record more than one event id per key!
Waaay simpler. -
How many events do you want to record per key? I'm still thinking that with acoustic instruments in general each repeated note will kill old notes, causing them to decay.
-
That's not completely true. For example if you press down the sustain pedal, play a loud note on the piano, then play a soft note on the same key shortly after it, you would hear that the new note is fading down the old note which sounds really bad.
That's why in the sampler options you have the "Kill second note" retrigger behaviour which allows you to have at least two notes of the same key ringing at once. This weakens that effect a little bit, but it's still noticeable.
-
@Christoph-Hart Very good point!
-
This should record as many event ids per key as needed --I didn't set a max number.
Here's what I got!
function onNoteOn() { Message.ignoreEvent(true); note = Message.getNoteNumber(); if (keyDown.getValue(note) == 1) keyVoiceCount[note]++; g_group_allows[G_START] = 1; eventIds[note][keyVoiceCount[note]] = Synth.playNote(note, 64); eventTimeStamp[note][keyVoiceCount[note]] = Engine.getUptime(); keyDown.setValue(note, 1); } function onNoteOff() { if (pedal == 0) { keyDown.setValue(Message.getNoteNumber(), 0); note = Message.getNoteNumber(); for (v = 0; v <= keyVoiceCount[note]; v++) { Synth.noteOffByEventId(eventIds[note][v]); if (delayedEventIds[note][v]) { Synth.noteOffByEventId(delayedEventIds[note][v]); delayedEventIds[note][v] = 0; }; eventTimeStamp[note][v] = 0; }; keyVoiceCount[note] = 0; }; } function onTimer() { for (n = 0; n < 128; n++) { for (v = 0; v <= keyVoiceCount[n]; v++) { if (eventTimeStamp[n][v]) { playPos = (Engine.getUptime() - eventTimeStamp[n][v]) * 1000; playPos = Engine.getQuarterBeatsForMilliSeconds(playPos); if (playPos > 4 && !delayedEventIds[n][v]) { g_group_allows[G_START] = 1; delayedEventIds[n][v] = Synth.playNote(n, 64); }; }; }; }; } function onController() { if (Message.getControllerNumber() == 64) { if (Message.getControllerValue() > 5) { pedal = 1; //Console.print("pedal down"); } else { pedal = 0; for (n = 0; n < 128; n++) { if (Synth.isKeyDown(n) == 0 && keyDown.getValue(n) == 1) { keyDown.setValue(n, 0); for (v = 0; v <= keyVoiceCount[n]; v++) { Synth.noteOffByEventId(eventIds[n][v]); eventIds[n][v] = 0; Synth.noteOffByEventId(delayedEventIds[n][v]); delayedEventIds[n][v] = 0; eventTimeStamp[n][v] = 0; }; keyVoiceCount[n] = 0; }; }; }; }; }
So basically now you can have multiple parallel sequences of artificial events on the same key, which are note off'd correctly by the pedal.
Before, I did this by using
Synth.addNote()
to schedule the sequence of artificial events, but I was running into some problems there.This is with Retrigger set to "Do nothing"
Man, this was a lot of work! Maybe I should have just done the "Kill Duplicate" option and just NOT allowed overlapping swells on the same key haha :face_with_tongue:
-
Maybe I should have just done the "Kill Duplicate" option and just NOT allowed overlapping swells on the same key haha
Looks like you're having fun though :)
-
Yep, I'm learning a lot :)
-
Yep, I'm learning a lot
Make sure you use the
reserve
function for all those arrays to avoid allocating items in the MIDI callbacks:https://docs.hise.audio/scripting/scripting-api/array/index.html#reserve