How to time shift incoming midi notes?

Hello I try to Timeshift incoming midi notes in a 32 step grid by percent relative to DAW’s current BPM. Can some one point me to some sample code? I found arpeggio example but what I try does not work.
In general I understand how to create midi events and swap buffer but what ever I try to change midi note timing does not work.

basically the same as with audio. you’d make a ringbuffer (but with midi events rather than floats). have you tried that yet?

I use processbuffer as described in examples. never heard about ring buffer. What does this mean?

it is a concept that describes a code structure where you have a buffer, like an array of midi events, and for each sample you write something to it and read something from it. the so-called writehead defines where to write on the buffer. it moves forward one sample for each sample and wraps around to 0 when it reaches the end. the readhead is another index value that defines where to read from that buffer. in this case it would be following the writehead with the same speed and their distance is the delay in samples. pretty easy thing to implement for audio, so you should try that first. midi is a bit more complicated because it could be that multiple events happen on the same sample (chords etc)

when I add midievents to buffer is it a matter of midi event property or timing in eventloop to shift midi notes forward or backward? I mean it has to be some midi event property. Settimestamp changes nothing so far.

just changing the timestamp can not be enough. imagine you’re at sample 240 of 250 and you wanna delay the event by 12 samples. that would have to be at sample 2 of the incoming block

ok so its event loop related. means i need to know forthcomin notes if I want to pull them back in time,:persevere:

not quite. looking at “forthcoming” notes would be possible too by sending latency with the setLatencySamples() method in the pluginProcessor. but you don’t need that here. i’d rather think about it like this: when you are at a certain point in time you want to push something onto a buffer, an audio sample, or a midi note, doesn’t matter. but before you go on to the next point in time (the next sample of this block) you pop something from your buffer that has been written to it earlier in time. that way you get a delayed thing. imagine a buffer of 44100 samples on a sampleRate of 44100. used as a ringbuffer it resembles a length of maximally 1sec. imagine writing something to the 0th entry, but reading something from the 1st one. the 1st one has not been visited by your write head for 1sec so it contains the delay of 1sec. that’s how it works. you are storing things now to get them back later

1 Like

setLatencySamples sounds most promising for me. will try this evening. seems i had a slightly wrong understanding on how prog ress buffer event loop works. quite difficult with current api docs seems written by devs already expert in vst development not specificly for newbies.

if i didn’t completely misunderstand you setLatencySamples is not what you want. that method is used for lookahead features. it tells your daw that your plugin produces n samples of latency. let’s say 44100. that would mean the daw will now send audio and midi data to the plugin that would only come 1sec later normally. but if i understood you correctly you don’t wanna get data earlier, but rather delay incoming data

I want both. move notes slightly back and/or forward. In my mind in percentage of 32 or 64 steped grid based on special groove setting. I want to realize a groove vst . Because my DAW does not support it and did not found a VST. So I try to make my own since a few days. I ve a librariy of mpc and so on midi grooves transpiled to json where I feel it could be possible to realize this as VST with some Math. with some work I hope get something close to Reason Studio’s Groove mixer. If you are expierenced and have some code snippes that might fit would be helpfull :slight_smile: Here is an example of one setting I am experimenting with. appreciate your help bro! Thanks for your time helping me out.

MPC60 16 Swing 64
[
  {
    "i": 0,
    "percent": 0,
    "perc": 0,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 0,
    "time": 0,
    "velocity": 1
  },
  {
    "i": 1,
    "percent": 0.6041666666666666,
    "perc": 0.6,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 29,
    "time": 0.15104166666666666,
    "velocity": 1
  },
  {
    "i": 2,
    "percent": 0.6666666666666666,
    "perc": 0.67,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 48,
    "time": 0.25,
    "velocity": 1
  },
  {
    "i": 3,
    "percent": 0.8125,
    "perc": 0.81,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 78,
    "time": 0.40625,
    "velocity": 1
  },
  {
    "i": 4,
    "percent": 0.7916666666666667,
    "perc": 0.79,
    "duration": 0.031249999999999944,
    "durationTicks": 6,
    "ticks": 95,
    "time": 0.4947916666666667,
    "velocity": 1
  },
  {
    "i": 5,
    "percent": 0.875,
    "perc": 0.88,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 126,
    "time": 0.65625,
    "velocity": 1
  },
  {
    "i": 6,
    "percent": 0.8571428571428571,
    "perc": 0.86,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 144,
    "time": 0.75,
    "velocity": 1
  },
  {
    "i": 7,
    "percent": 0.90625,
    "perc": 0.91,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 174,
    "time": 0.90625,
    "velocity": 1
  },
  {
    "i": 8,
    "percent": 0.8842592592592592,
    "perc": 0.88,
    "duration": 0.03125000000000011,
    "durationTicks": 6,
    "ticks": 191,
    "time": 0.9947916666666666,
    "velocity": 1
  },
  {
    "i": 9,
    "percent": 0.9249999999999999,
    "perc": 0.93,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 222,
    "time": 1.15625,
    "velocity": 1
  },
  {
    "i": 10,
    "percent": 0.9090909090909091,
    "perc": 0.91,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 240,
    "time": 1.25,
    "velocity": 1
  },
  {
    "i": 11,
    "percent": 0.9375,
    "perc": 0.94,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 270,
    "time": 1.40625,
    "velocity": 1
  },
  {
    "i": 12,
    "percent": 0.9198717948717949,
    "perc": 0.92,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 287,
    "time": 1.4947916666666667,
    "velocity": 1
  },
  {
    "i": 13,
    "percent": 0.9464285714285714,
    "perc": 0.95,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 318,
    "time": 1.65625,
    "velocity": 1
  },
  {
    "i": 14,
    "percent": 0.9333333333333333,
    "perc": 0.93,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 336,
    "time": 1.75,
    "velocity": 1
  },
  {
    "i": 15,
    "percent": 0.953125,
    "perc": 0.95,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 366,
    "time": 1.90625,
    "velocity": 1
  },
  {
    "i": 16,
    "percent": 0.9387254901960784,
    "perc": 0.94,
    "duration": 0.031249999999999778,
    "durationTicks": 6,
    "ticks": 383,
    "time": 1.9947916666666667,
    "velocity": 1
  },
  {
    "i": 17,
    "percent": 0.9583333333333334,
    "perc": 0.96,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 414,
    "time": 2.15625,
    "velocity": 1
  },
  {
    "i": 18,
    "percent": 0.9473684210526315,
    "perc": 0.95,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 432,
    "time": 2.25,
    "velocity": 1
  },
  {
    "i": 19,
    "percent": 0.9625000000000001,
    "perc": 0.96,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 462,
    "time": 2.40625,
    "velocity": 1
  },
  {
    "i": 20,
    "percent": 0.9503968253968254,
    "perc": 0.95,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 479,
    "time": 2.4947916666666665,
    "velocity": 1
  },
  {
    "i": 21,
    "percent": 0.9659090909090908,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 510,
    "time": 2.65625,
    "velocity": 1
  },
  {
    "i": 22,
    "percent": 0.9565217391304348,
    "perc": 0.96,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 528,
    "time": 2.75,
    "velocity": 1
  },
  {
    "i": 23,
    "percent": 0.96875,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 558,
    "time": 2.90625,
    "velocity": 1
  },
  {
    "i": 24,
    "percent": 0.9583333333333334,
    "perc": 0.96,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 575,
    "time": 2.9947916666666665,
    "velocity": 1
  },
  {
    "i": 25,
    "percent": 0.9711538461538461,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 606,
    "time": 3.15625,
    "velocity": 1
  },
  {
    "i": 26,
    "percent": 0.9629629629629629,
    "perc": 0.96,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 624,
    "time": 3.25,
    "velocity": 1
  },
  {
    "i": 27,
    "percent": 0.9732142857142857,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 654,
    "time": 3.40625,
    "velocity": 1
  },
  {
    "i": 28,
    "percent": 0.9640804597701149,
    "perc": 0.96,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 671,
    "time": 3.4947916666666665,
    "velocity": 1
  },
  {
    "i": 29,
    "percent": 0.9750000000000001,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 702,
    "time": 3.65625,
    "velocity": 1
  },
  {
    "i": 30,
    "percent": 0.9677419354838709,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 720,
    "time": 3.75,
    "velocity": 1
  },
  {
    "i": 31,
    "percent": 0.9765625,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 750,
    "time": 3.90625,
    "velocity": 1
  },
  {
    "i": 32,
    "percent": 0.9684343434343434,
    "perc": 0.97,
    "duration": 0.031250000000000444,
    "durationTicks": 6,
    "ticks": 767,
    "time": 3.9947916666666665,
    "velocity": 1
  },
  {
    "i": 33,
    "percent": 0.9779411764705883,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 798,
    "time": 4.15625,
    "velocity": 1
  },
  {
    "i": 34,
    "percent": 0.9714285714285715,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 816,
    "time": 4.25,
    "velocity": 1
  },
  {
    "i": 35,
    "percent": 0.9791666666666667,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 846,
    "time": 4.40625,
    "velocity": 1
  },
  {
    "i": 36,
    "percent": 0.9718468468468469,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 863,
    "time": 4.494791666666667,
    "velocity": 1
  },
  {
    "i": 37,
    "percent": 0.9802631578947367,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 894,
    "time": 4.65625,
    "velocity": 1
  },
  {
    "i": 38,
    "percent": 0.9743589743589742,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 912,
    "time": 4.75,
    "velocity": 1
  },
  {
    "i": 39,
    "percent": 0.98125,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 942,
    "time": 4.90625,
    "velocity": 1
  },
  {
    "i": 40,
    "percent": 0.9745934959349593,
    "perc": 0.97,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 959,
    "time": 4.994791666666667,
    "velocity": 1
  },
  {
    "i": 41,
    "percent": 0.9821428571428572,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 990,
    "time": 5.15625,
    "velocity": 1
  },
  {
    "i": 42,
    "percent": 0.9767441860465117,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1008,
    "time": 5.25,
    "velocity": 1
  },
  {
    "i": 43,
    "percent": 0.9829545454545455,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1038,
    "time": 5.40625,
    "velocity": 1
  },
  {
    "i": 44,
    "percent": 0.976851851851852,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1055,
    "time": 5.494791666666667,
    "velocity": 1
  },
  {
    "i": 45,
    "percent": 0.983695652173913,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1086,
    "time": 5.65625,
    "velocity": 1
  },
  {
    "i": 46,
    "percent": 0.978723404255319,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1104,
    "time": 5.75,
    "velocity": 1
  },
  {
    "i": 47,
    "percent": 0.984375,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1134,
    "time": 5.90625,
    "velocity": 1
  },
  {
    "i": 48,
    "percent": 0.9787414965986395,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1151,
    "time": 5.994791666666667,
    "velocity": 1
  },
  {
    "i": 49,
    "percent": 0.9850000000000001,
    "perc": 0.99,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1182,
    "time": 6.15625,
    "velocity": 1
  },
  {
    "i": 50,
    "percent": 0.9803921568627451,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1200,
    "time": 6.25,
    "velocity": 1
  },
  {
    "i": 51,
    "percent": 0.985576923076923,
    "perc": 0.99,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1230,
    "time": 6.40625,
    "velocity": 1
  },
  {
    "i": 52,
    "percent": 0.9803459119496855,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1247,
    "time": 6.494791666666667,
    "velocity": 1
  },
  {
    "i": 53,
    "percent": 0.9861111111111112,
    "perc": 0.99,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1278,
    "time": 6.65625,
    "velocity": 1
  },
  {
    "i": 54,
    "percent": 0.9818181818181817,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1296,
    "time": 6.75,
    "velocity": 1
  },
  {
    "i": 55,
    "percent": 0.9866071428571429,
    "perc": 0.99,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1326,
    "time": 6.90625,
    "velocity": 1
  },
  {
    "i": 56,
    "percent": 0.9817251461988304,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1343,
    "time": 6.994791666666667,
    "velocity": 1
  },
  {
    "i": 57,
    "percent": 0.9870689655172414,
    "perc": 0.99,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1374,
    "time": 7.15625,
    "velocity": 1
  },
  {
    "i": 58,
    "percent": 0.9830508474576272,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1392,
    "time": 7.25,
    "velocity": 1
  },
  {
    "i": 59,
    "percent": 0.9874999999999999,
    "perc": 0.99,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1422,
    "time": 7.40625,
    "velocity": 1
  },
  {
    "i": 60,
    "percent": 0.9829234972677596,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1439,
    "time": 7.494791666666667,
    "velocity": 1
  },
  {
    "i": 61,
    "percent": 0.9879032258064517,
    "perc": 0.99,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1470,
    "time": 7.65625,
    "velocity": 1
  },
  {
    "i": 62,
    "percent": 0.9834656084656085,
    "perc": 0.98,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1487,
    "time": 7.744791666666667,
    "velocity": 1
  },
  {
    "i": 63,
    "percent": 0.9882812500000001,
    "perc": 0.99,
    "duration": 0.03125,
    "durationTicks": 6,
    "ticks": 1518,
    "time": 7.90625,
    "velocity": 1
  }
]
64
{
  "keySignatures": [],
  "meta": [],
  "name": "MPC60 16 Swing 64\u0000",
  "ppq": 96,
  "tempos": [],
  "timeSignatures": [
    {
      "ticks": 0,
      "timeSignature": [
        4,
        4
      ],
      "measures": 0
    },
    {
      "ticks": 0,
      "timeSignature": [
        4,
        4
      ],
      "measures": 0
    }
  ]
}

I think the ticks property could be the sample in transport timeline. So maybe I just need to quantize midi notes to these time steps. Over the toop iam also a complete c++ noob ^^

to state the obvious, moving something “forward” in time is not possible.

Hmm some how i just achived exact that. But I do not claim to know exactly what I am doing here ^^. Just experimenting with setLatencySamples. Orange = Input Green = output

You’re respacing the orange notes backward in time - the green notes are played later on the timeline than the orange ones (to the right).

I recorded the green bar in my daw. Its the out from VST feeded with orange bar. I just put a piano below with 4 on the floor. Seems to work. :thinking:

  • the orange bar inputs some midi to your plugin

  • the output, the green bar, shows that midi delayed by a little bit

this is moving the notes backward in time, not forward

fuck me. god bless you pointed this out. Some how it might be possible as @Mrugalla suggested to call addmidievent later in time to achive delayed notes. So with combination of both it might be possible.

god mode would be to read entire midi track and pre render midi event sequence to just ouput them on computed sequence timestamp But I guess this is far away from possible.

That’s what you’ve already done, is delay some input notes and output them later.

You can check out ARA: Audio Random Access - Wikipedia

1 Like

huh? ofc you can move something forward in time. that is literally what setLatencySamples() is for. ofc if you are recording or monitoring some input right now it can’t be lookahead, since that is physically impossible, even to current knowledge about quantum physics. but once an audio- or midi-section is recorded into your daw already ofc you can just lookahead on those things. for example i’m doing that in the vibrato plugin that i am programming, where i use a delay to vibrate the input signal. the delay has a certain size and i let an lfo modulate across it. then i setLatencySamples(delaySize / 2) to let the signal always be on average where it would normally be. that is classic lookahead. totally valid thing to do in a plugin