How to delay note on?
-
@d-healey I have a script where I needed to have the controller send a message before a noteOn.
I used onNote:Message.delayEvent(8); // Delays a note by 8 samples
It works.
-
Synth.addNoteOn(int channel, int noteNumber, int velocity, int timeStampSamples)
timeStampSamples - is the delay in samples
-
@d-healey
Message.delayEvent();
Works for all events, not only note ons.
It will delay the event that's triggering the callback. So if you want to do processing on the delayed event, you need to hierarchically step down and do it in the following processor as it catches the event (either right after or in a child sound generator).
This is extremely important for artificial events (well, note ons, artificial controller events don't flag up as artificial events, these you have to mark yourself), i.e. generated notes by your timer; you need to delay these after they are already created, in a downstream MIDI processor.
-
@aaronventure said in How to delay note on?:
Message.delayEvent();
I'm creating my own events in a timer, there is no Message object there.
@Lindon said in How to delay note on?:
Synth.addNoteOn(int channel, int noteNumber, int velocity, int timeStampSamples)
This looks like what I need, but... I also need to be able to set a note offset.
-
@d-healey said in How to delay note on?:
@Lindon said in How to delay note on?:
Synth.addNoteOn(int channel, int noteNumber, int velocity, int timeStampSamples)
This looks like what I need, but... I also need to be able to set a note offset.
A note offset? You mean transpose? or something else?
heres some code(mildy edited) from my arp theat does "stutter effects...
for (i = 0; i<= stutter-1; i++) { //Console.print("playing stutter:" + i); playingNoteIDs[i] = Synth.addNoteOn(thisArpChannel, playNote, steps[currentStep].Velocity, i * playLength); // set the note off time //Console.print("note off length:" + ((i+1) * playLength)); Synth.noteOffDelayedByEventId(playingNoteIDs[i], (i+1) * playLength); }
-
@Lindon said in How to delay note on?:
A note offset? You mean transpose? or something else?
I mean sample start offset.
Currently I'm using
Synth.playNoteWithStartOffset()
I also need to be able to change the pitch of the event and the active group... maybe I'm asking too much :p
-
@d-healey said in How to delay note on?:
@Lindon said in How to delay note on?:
A note offset? You mean transpose? or something else?
I mean sample start offset.
Currently I'm using
Synth.playNoteWithStartOffset()
I also need to be able to change the pitch of the event and the active group... maybe I'm asking too much :p
Ok so theres no way to do exactly this (i.e. pitch change) what you have to do is a variant of what @aaronventure says - have a "noteProcessor" script that follows the "note generator" script....
This is because the pitch fade only happens for notes that are currently playing - not to notes that are delayed... look for @ulrik s recent post about this problem and the work around we came up with - for pitch "bends" what i do to de-couple the generator from the processor is have the generator issue a CC message (say something unused like cc110) and the processor "listens" for CC110 and thus knows what the current "bend " amount is...
-
@Lindon I think rather than using a CC you could just set the event's pitch bend amount and pick that up in the processor?
-
@d-healey said in How to delay note on?:
@Lindon I think rather than using a CC you could just set the event's pitch bend amount and pick that up in the processor?
I think you will find that the event data doesnt get set for delayed events...but as we all know I've been wrong before.... this guy I know called Dave says "try it and see..."
-
@Lindon Oh yeah :)
That's a bummer, I don't like this hacky workaround, but I guess it's the best we have for now.
-
@d-healey I don't see it as that hacky - the "generator" is now a completely decoupled process, any downstream note owners either honour its messaging or not as they see fit...
-
@d-healey said in How to delay note on?:
I'm creating my own events in a timer, there is no Message object there.
Yeah the events are generated after that MIDI Processor. You can catch them in the next MIDI processor, filter them with
Message.isArtificial()
or in any other way you might flag a MIDI event (remember the MessageCustom class we discussed and Chris posted two months ago or so) and if they match, delay them. -
@aaronventure said in How to delay note on?:
remember the MessageCustom class we discussed and Chris posted two months ago
I don't remember, my brain is like a sieve. Tell me more.
-
@d-healey https://forum.hise.audio/topic/9190/synth-addnotepan-eventid/10
Allows you to have event ID related storage.
You can also just have a global (oh no!) event storage and check whether it contains the id of your timer generated event, and if it does, delay it.
-
@d-healey Here's a silly demo for you. Check the onNoteOn callbacks for each MIDI processor in this snippet
HiseSnippet 1572.3oc6Y0saaTDEdWmrUMgBhJg3Bt.MJ2DagaRb+CTKRsoINPDMoQ0oUvUUi2cr2QY1YVsyrIcEhq40hWEdC3MnbNyr1qSrcpioUzBNWT44myb9+b9NaOJSExzZUlm+JGWjx77uQPmBoIdmXJW5s+td9eVvATsgkQba8jhTpVyh778W5GvM7WYYO6e+0idBUPkgrps77dohGxdJOgap18nG+SbgXOZD6XdxH29tOd+PkbGkPkCxyRAa4kRCOg1mcHEuVs.O+q0NhaTYcLTCSC24IpnhNwpyjt6+Rtl2UvvEs75.Ojaauch4hniFnqZOO+fipz7kbZ9WDb.OhOb+JKvmaOfTQwn1.+ZWlH05JHRKMhHsrSjtYPmvLdpo5DTd9jf8kfCoGEL0iJJt654+GA6nfKHMajPOgsWFrXHA0u+Va0j.+SiG1KWFZ3JIQIOTYXOSVuwp+5pqr5usJ4hG0q2DOCYSlRHXYS7Xz6lcYDVWlmzkk0jbJUjyFdQP8OuM8ZylMMzo0ibQkbeI27rTV458ThHzVg+dbOfWoYC90K1eWpgBNE+x8f6kxxLbTb72kcJDU6bQqDrKSehQkBw0yn+6KgLJtj7bFUX.SDozuMAWYserV.YJ9oCfGDxM1f2WpxXsOEDx5lLvL9PxlaRLwbMIMigaqgULRZbglGREDI7HvaoI8UbYeBvTyfqWJkfaXEaUfMREzBjo0Gvs9LCt9PqiqdiljQN3kLgJjaJp2vICBlYcMAiAITIgBVud7PdoDf7.rsZkfsQZFGD901mDlw.OtUbG45Vk.dhHhSWsmC2Tr4PcxdkMHGOpd5HKRwJkANXHNiVLIEtIg5LRcnQVF8TkjIJpR4If5oQ4NFLYarViGNlviA6OXMx2PZK6ykV6wKRQ2KZM9.LmJ3cUN0+d4QeUvzbWSLW5M9SMWBBVOFCHNSIW2PrdTRWVHMW6B1vDItJejHFBj.imngVSDzHAYzPORW.pKVxF+U91SHdlaimJC4iH4RCWPnBQICGvGHRVzEZCpcbDnRqxAUtOC3GEbnjX5oLPZYRB60rvb3wFOyZ8DhNOMUAlDhQQngFvBLnRPSR2bCrPBJaFueePORJFx3yYHvrtJ4uKjueB7hk1hgVIs0hWoD1DlEo.+iRA.PHpnbA5wGEYBBAq7.vFbt3drmuTC0iGEh1U.txVWJbkYUDuYvQbSX7jkwZSPFAK06CYrDj2mFztWOVnoR.WNXueddQzM6r+5SAc8MrX0rEOZ8t.ac5Lis1eoOlwRe4Vd+ZyZOjuNvV3Gq8GyJgV.UTfhdPWb8D6i7m9ucLY5sGVtudCxiHiizgl2OFA0PptIwBhqYItoHFf8B.srVCxClN8VTjSivqDJEXy0He+stkqSnNVkKh.fSPtq0nXQpp5Y+8jfu5.EUYBrRgCUZEu5PSRErmCd25M1rENDBhSzIvcKHvNjD8hNEuO.KsUvurNhtnOf4Pq.2VBhj15PATAiAOYxg9+9zC8uPf11EplPJEECHGF9fYXOhbEB+nBspLFb.JDN9hcY3jKkfU..HPryDmYnWlJYpQrVji3gt3uDFXIhrvd.HUNvYVTUkvX.1TvLKfxr.JyBnLuMnL29iUnLK+gGTF+YsB+pA2IhwRuWxD+pf0hqMq0t2IlAi80Fv+Xf5rP41PbNuGbIEtw51aCPnfQgADMZFq4XjiPrf96IZBMlQivuUC0UJuZ5RWQarCksjraxR7y1fZCVwOBre1aFyggeyBiKFT5eBvNZ3pkOX3TZF93WX3Y2nubbZXQgkyUU6o8vu5M9DCGEt7PTTNCZQDgiL2CFA2.5BxACODJM.iO6jFrCHOLtIg1GBZZBuCz7w1SxoTYVTanzk39D6WbzdrCksOsNkEhs1.Aon4kiAaQyoEMm9eVyomqxMPN4AT.Q3qg3sCyS5.MGBY.2kRl.iA8qgQKt0agqQKPGlLxt3MvekG1BW6WdXqAG9eFdjPCyTuJzkAi8WttcGv1Js+ursRvA3ZRKOaV8nwKIP6tWEFd9mZLBu87R3clWBu67R38lWBu+7R32NuD9cucBQzHamaTItzeOuCNpssjnueaIExjrYcd+Mv0rudC
Key takeaways:
- Succeeding processors within the same sound generator won't catch the delayed event, but will be deprived of any event that entered the preceding processor and got ignored
- In order to be able to process the delayed event, you need to step down in hierarchy by creating a child sound processor, because the delaying of the event will only take place once all the callbacks within that sound processor have been executed and HISE knows for sure what the queue looks like before handing it down to the child sound generator(s)
-
@aaronventure Thanks!
In order to be able to process the delayed event, you need to step down in hierarchy by creating a child sound processor, because the delaying of the event will only take place once all the callbacks within that sound processor have been executed and HISE knows for sure what the queue looks like before handing it down to the child sound generator(s)
This is definitely a hacky solution :p But it's better than nothing.
In my world view each midi processor is responsible for the life cycle of its own events.
-
@d-healey Instead think of them like serial security gates in an airport. Each event needs to be checked as it comes down from upstream. You need to check the luggage of one before you delay them, and then whenever they arrive at the next security gate (processor) in series (child), they get processed.
I wouldn't quite call it hacky, that just seems to be how HISE works. Compared to Kontakt which can delay an execution of a callback and so create an infinitely complex mess of asynchronously synchronous executions which can become hard to keep track of, HISE is like an airport with tools that let you keep a close watch on the event traffic and carefully filter each and every one at whichever point you want.
The hierarchy paradigm is the key part of it.
I think the limited GUI column width might be what's tripping up your anxiety, the titles do get a bit crampy once you get 4 levels deep :grinning_face_with_sweat:
-
@aaronventure What I don't like about it is I'm going to have to write all this info down somewhere so when I come back to it in a year, or when I want to move it to another project, I can figure out what's going on.