Pushing Messages onto an Array?
-
if I'm storing multiple members of the Message class, wouldn't it be more efficient to simply create an array of Messages?
You'd have to create message holders I think and there things might get interesting. I've not played with them for years so have fun :)
The MIDI list only seems to hold 128 elements; I'm not clear how this would be useful?
The MIDI list is useful if you want to store one value per note. A common scenario is storing the velocity for each note.
-
| The MIDI list is useful if you wan to store one value per note. A common scenario is storing the velocity for each note.
Isn't that only useful if I want to store less than 129 notes?
-
@clevername27 I follow Dave, in this case you need a message holder, which is in fact a midi sequence. But I haven't played with it for a while too :)
-
@clevername27 I'd say a midlist is useful when you want to hold a value during a time or until something happens so you reset the value until the next instance, or at the next instance of that note.
A message holder is more a sequence where you store the timestamp as well so it can be played back or batch modified, etc...So if you want to record all events and keep them in a sequence -> message holder
-
@clevername27 said in Pushing Messages onto an Array?:
| The MIDI list is useful if you wan to store one value per note. A common scenario is storing the velocity for each note.
Isn't that only useful if I want to store less than 129 notes?
Each real note (that comes from a keyboard press or DAW) can only have one velocity at a time. If you play MIDI note 60 its velocity would go in slot 59 of the MIDI list. If you play MIDI note 60 again it would overwrite the previous value. Unless you have a keyboard with two middle Cs there wouldn't be an issue.
-
@d-healey Thank you for answering my question; I'm still a little confused. Let's say I want to record 1,000 notes. But if the MIDIList can only be 128 elements long, wouldn't that mean I can only store 128 notes?
-
@clevername27 The MIDI list isn't for that purpose. It's not like an event list in a DAW.
Christoph explains it in this post - https://forum.hise.audio/topic/79/scripting-best-practices
-
@d-healey Thank you for the reference - I guess I'm still not seeing how this object would be useful here. Off the cuff, this object has a performance advantage because it allocates all 128 slots at once, allowing pointer mathematics to access individual slots (instead of pulling them individually off the heap or from the stack). In @Christoph-Hart 's example for an array of notes, he simply uses a regular array (i.e., traditional linked list).
https://docs.hise.audio/tutorials/recipes/event-processing/create-midi-sequence.html
-
There is another container class called unordered stack which can hold the full event data but I think it‘s also limited to 256 slots.
-
@Christoph-Hart Thank you - I'm also realizing you explicitly wrote in the documentation that the performance advantage of the MIDI List is not gained from pre-allocating the memory, so I'm not correct there.
-
With a bit more context of your use case I might help you out. Your initial approach is not recommended, the array will allocate in the audio thread (and the AudioThreadGuard should complain).
-
@Christoph-Hart Thank you, kindly. I'm looking to:
-
Capture all incoming MIDI notes in real-time.
-
Offline, I will adjust the Note-On and Note-Off timestamps.
-
Finally, pipe the resulting note list into a MIDI Player, and play it back in time with the host DAW.
Cheers, mate. I would post and comment my code for the community.
-
-
Before you reinvent the wheel, you are aware that the MIDI player has a record function that does exactly this? You can even supply it a post processing function that will give you an array of all new events that you then can process (eg. for quantization).
I'm using this in a current product I'm working on, so I would consider it stable but under documented - like everything in HISE that comes fresh out of the oven :)
These MIDIPlayer functions are useful in this case:
setUseTimestampInTicks()
- calling this in onInit is highly recommended as it will use ticks instead of samples as unit which makes sample rate agnostic operations much more simple (960 ticks = 1 quarter).record()
/stop()
: obvious...setRecordEventCallback()
- supply it with a function that modifies the array of MessageHolders before it gets written into the MIDI sequencesetSyncToMasterClock()
hooks the MIDI player to be controlled by the master clock (and then use the TransportHandler for DAW syncing).
-
@Christoph-Hart
Legend, Could you please Do an example for these?
setUseTimestampInTicks()
MidiPlayer.setSyncToMasterClock
-
@Natan EDIT: What I've written below is approximate, not actual code. You'll need to create MIDI player in your Module Tree.
const TH = Engine.createTransportHandler(); TH.setEnableGrid(true, 4); TH.setSyncMode(TH.PreferExternal); TH.setOnGridChange(true, GridChange); const var yourMidiPlayer = Synth.getMidiPlayer("myMidiPlayer"); yourMidiPlayer.setUseTimestampInTicks(); yourMidiPlayer.setSyncToMasterClock(true);
You'll need to either create a new sequence or load one.
-
@Christoph-Hart Thank you for the suggestion. I tried that first, actually, but the MIDI player, and particularly recording, seemed oriented to looping a couple bars (e.g., MidiPlayer.create(int nominator, int denominator, int barLength))?
-
@clevername27 Thank you so Much Mate <3 :folded_hands:
Is there any difference that I Can hear, I Mean the results of the above code are obvious or it's a daw and Midi Thing?IMPORTANT! And one Quick question, Let's say I have 3 MidiPlayers, is It safe to use the code three times? or Inside a Loop?
-
@Natan Can you explain your first question in more detail? If you have three MIDI players, then you'd need to do this for all three—you'd call this at init, not inside a loop.
-
@clevername27 except if they are stored in an array:
const var yourMidiPlayers = [Synth.getMidiPlayer("myMidiPlayer1"), Synth.getMidiPlayer("myMidiPlayer2"), Synth.getMidiPlayer("myMidiPlayer3")]; for (p in yourMidiPlayers) { p.setUseTimestampInTicks(); p.setSyncToMasterClock(); }
-