This project has moved and is read-only. For the latest updates, please go here.

Transport Events

Nov 20, 2015 at 7:52 AM
How can I detect when my host's Transport Stop/Start events have been fired, and how can I pass that down to VSTs I host?
Nov 20, 2015 at 8:07 AM
Edited Nov 20, 2015 at 8:17 AM
I have found that in Ableton, when the stop button is pushed, a midi event is sent.

The data is:

But, it doesn't send data when the start button is pushed. Is there a midi event for this?

Is there an enumeration available somewhere for midi events?

According to the midi standards Start = 0xFA. How do I send that to a VST? I'm sure I'd call process events, but how do I structure the Data array for that?
Nov 20, 2015 at 8:24 AM
Edited Nov 20, 2015 at 8:24 AM
There are no dedicated events on the VST interface for that. As you have discovered the events do exist as MIDI messages but it's up to the host to send them.

As a work around you could try to look at "GetTimeInfo" repeatedly and infer from the result if the transport is running (not sure)?
Nov 20, 2015 at 8:26 AM
OK. My confusion with events is that they are 7bit? Is that right? So 0xFA is actually 127?

Anyway, to be more specific, my issue is that I'm trying to host and start a step sequencer. It starts in Ableton when the play button is pressed, but I'm not sure what message to send it when I want to start it. It's like Ableton is starting it with ozmosis.
Nov 20, 2015 at 8:27 AM
At this point I don't really care if Ableton has started or stopped. I just want the step sequencer I'm hosting to start...
Nov 20, 2015 at 8:34 AM
Edited Nov 20, 2015 at 8:37 AM
I think you've put me on the right track. I've discovered that the VST keeps calling GetTimeInfo on me, so i guess I just need to feed it the right thing...

What flags do you reckon it wants?

This is my code so far:

            return new Jacobi.Vst.Core.VstTimeInfo
                Tempo = 120,
                Flags = Jacobi.Vst.Core.VstTimeInfoFlags.TransportPlaying |
                Jacobi.Vst.Core.VstTimeInfoFlags.TransportCycleActive |
                Jacobi.Vst.Core.VstTimeInfoFlags.TimeSignatureValid |
                Jacobi.Vst.Core.VstTimeInfoFlags.ClockValid |
Nov 20, 2015 at 9:16 AM
I'm really struggling here. I'm trying to constantly poll ableton for the time info, but something is going wrong.

This is my horrible code on my synth's constructor:
            var bgWorker = new BackgroundWorker();
            bgWorker.DoWork += (s2, e2) =>
                var timer = new Timer();
                timer.Interval = 500;
                timer.Elapsed += (s, e) =>
                    if (_HostStubAdapter != null && _HostStubAdapter.IsInitialized())
                        _TimeInfo = _HostStubAdapter.GetTimeInfo(VstTimeInfoFlags.TempoValid);
                while (true)

It keeps erroring on the line "if (_HostStubAdapter != null && _HostStubAdapter.IsInitialized())" with an "Object reference not set to an instance of an object" exception. But the object _HostStubAdapter is not null at runtime! I can see that it's not null in the debugger.
Nov 20, 2015 at 9:47 AM
MIDI messages are 8-bits - but the MSB indicates a status-byte, the start of a MIDI message (command). There are MIDI messages that consist of 1 to 3 bytes (not counting sysex).

Start with passing the GetTimeInfo call back to the host - just pass it through.
See how that goes.
Nov 20, 2015 at 9:24 PM
Edited Nov 20, 2015 at 9:46 PM

OK. I've done that.

The sequencer plugin still doesn't startup. It's still not firing midi.

The plugin keeps calling "GetProcessLevel". Ableton keeps returning "Realtime" so that's what I am passing through.

Lost again....

This is the TimeInfo that Ableton is passing through to the plugin:
    BarStartPosition    88  double
    CycleEndPosition    24  double
    CycleStartPosition  8   double
    Flags   TransportPlaying | PpqPositionValid | TempoValid | BarStartPositionValid | CyclePositionValid | TimeSignatureValid  Jacobi.Vst.Core.VstTimeInfoFlags
    NanoSeconds 0   double
    PpqPosition 91.672380952380948  double
    SamplePosition  2021376 double
    SampleRate  44100   double
    SamplesToNearestClock   0   int
    SmpteFrameRate  Smpte24fps  Jacobi.Vst.Core.VstSmpteFrameRate
    SmpteOffset 0   int
    Tempo   120 double
    TimeSignatureDenominator    4   int
    TimeSignatureNumerator  4   int
Nov 20, 2015 at 10:02 PM
When I load these plugins up in Ableton, they flash with lights when I hit play on the transport. When I host them, they don't flash. What is it that Ableton is magically doing that I'm not doing? I've confirmed that I'm passing through everything that the plugin is asking for. It was asking for the version, and I pass that.
Nov 20, 2015 at 11:57 PM
I tried loading both of the plugins that I'm trying to work with in the Plugin Wrapper. They both lock Ableton up. One of them opens the plugin successfully, and the other throws an error. But, with both of them, when I hit the play button on the transport, it freezes up all controls in Ableton. I can't remove the plugin, I can't exit the app. Here's the error I see when I load the plugin. This doesn't happen when I load the plugin in Ableton directly.

Nov 21, 2015 at 8:04 AM
Pfjew that sounds messy. One thing you could try is to turn on VST.NET tracing while using the wrapper plugin - and/or your own plugin.
Here is a template app.config you need to put next to the host (Ableton) and rename it to the exact name of the host (for instance Ableton.exe) and append '.config' (Ableton.exe.config)
Fill in the plugin name (the name of the renamed interop .dll) and set the levels of tracing and the output (TraceListeners) you want. Perhaps you can see if there is something more to this...?

The assertion has something to dp with sampleFrames - it expects them to be 0. Perhaps you can attach a debugger and break when this dialog is shown to see what the callstack is?
Nov 21, 2015 at 9:21 PM
That midi VST sequencer I remember that b***** of a plugin. It was tough to make it work as it tends to not check it's parameter leading to segfaults but it is possible to host it accurately in Vt.Net. It will call GetVstInfo quite often, make sure everything in VstTimeInfo is implemented and at valid values. Don't leave important fields like tempo at 0. You can search in the Discussion tab of CodePlex to find examples of VstTimeInfo I posted previously.
Nov 21, 2015 at 9:24 PM
You also need to set TransportPlaying. This is working for me:
        public Jacobi.Vst.Core.VstTimeInfo GetTimeInfo(Jacobi.Vst.Core.VstTimeInfoFlags filterFlags)
            vstTimeInfo.SamplePosition = ConstAudio.SamplePlayed;
            vstTimeInfo.SampleRate = ConstAudio.SampleRate;
            vstTimeInfo.Tempo = tempo;
            vstTimeInfo.PpqPosition = (vstTimeInfo.SamplePosition / vstTimeInfo.SampleRate) * (vstTimeInfo.Tempo / 60.0);
            vstTimeInfo.NanoSeconds = 0.0;
            vstTimeInfo.BarStartPosition = 0.0;
            vstTimeInfo.CycleStartPosition = 0.0;
            vstTimeInfo.CycleEndPosition = 0.0;
            vstTimeInfo.TimeSignatureNumerator = 4;
            vstTimeInfo.TimeSignatureDenominator = 4;
            vstTimeInfo.SmpteOffset = 0;
            vstTimeInfo.SmpteFrameRate = new Jacobi.Vst.Core.VstSmpteFrameRate();
            vstTimeInfo.SamplesToNearestClock = 0;
            vstTimeInfo.Flags = VstTimeInfoFlags.TempoValid & 

            if (RunActions.IsPlaying())
                vstTimeInfo.Flags |= VstTimeInfoFlags.TransportPlaying;

            return vstTimeInfo;
Nov 21, 2015 at 11:50 PM
Thanks Yury. I tried this and it has't worked:
        public VstTimeInfo GetTimeInfo(VstTimeInfoFlags filterFlags)
            var hostTimeInfo = _DAWCommandStub.GetTimeInfo(filterFlags);

            var vstTimeInfo = new VstTimeInfo();

            vstTimeInfo.SamplePosition = hostTimeInfo.SamplePosition;
            vstTimeInfo.SampleRate = hostTimeInfo.SampleRate;
            vstTimeInfo.Tempo = hostTimeInfo.Tempo;
            vstTimeInfo.PpqPosition = (vstTimeInfo.SamplePosition / vstTimeInfo.SampleRate) * (vstTimeInfo.Tempo / 60.0);
            vstTimeInfo.NanoSeconds = 0.0;
            vstTimeInfo.BarStartPosition = 0.0;
            vstTimeInfo.CycleStartPosition = 0.0;
            vstTimeInfo.CycleEndPosition = 0.0;
            vstTimeInfo.TimeSignatureNumerator = 4;
            vstTimeInfo.TimeSignatureDenominator = 4;
            vstTimeInfo.SmpteOffset = 0;
            vstTimeInfo.SmpteFrameRate = new VstSmpteFrameRate();
            vstTimeInfo.SamplesToNearestClock = 0;
            vstTimeInfo.Flags = VstTimeInfoFlags.TempoValid &

            vstTimeInfo.Flags |= VstTimeInfoFlags.TransportPlaying;

            return vstTimeInfo;
Is there any chance you could try this plugin for me? Basically, if a light flashes, you will know it is working:
Nov 21, 2015 at 11:52 PM
Obiwan, when I get time, I'll try to set this up.
Nov 22, 2015 at 7:29 AM
Looks like that plugin is made with SyndEdit. Perhaps there are some clue's in their documentation...?

Nov 27, 2015 at 11:58 PM
Well, I believe my original question is answered. I guess this is a weird midi thing. My original question was how to pass the start transport message to a VST. The answer to that is that while some VSTs might expect that, at least some VSTs don't. Actually, in my case, theses VSTs are simply waiting for TimeInfo. They constantly poll for Time Info. This makes sense because a step sequencer will constantly need updated Time Info.

So, in my case, rather than implement my own Time Info system, I'm simply passing the time info from the DAW Host. I never got the original Apollo sequencer to work inside my modular, so that is still an outstanding issue, but I got another one called B-Step to work without an issue:

When I create the vst context, I pass in an interface with this. The _DAWCommandStub variable is just what I get from my host Ableton on GetPluginInfo:
 public plugin.VstPluginInfo GetPluginInfo(plugin.IVstHostCommandStub hostCmdStub)
        public Jacobi.Vst.Core.VstTimeInfo GetTimeInfo(Jacobi.Vst.Core.VstTimeInfoFlags filterFlags)
                return _DAWCommandStub.GetTimeInfo(filterFlags);
                return null;
Dec 4, 2015 at 6:40 PM
@Mark yep this looks like a SynthEdit abomination.
@Kruddler I've checked again maybe checking this can help:
public VstCanDoResult CanDo(string cando)
    cando = cando.ToLowerInvariant().Trim();

    if (cando == "sendvstevents" || 
        cando == "sendvstmidievent" ||
        cando == "sendvsttimeinfo" ||
        cando == "receivevstevents" ||
        cando == "receivevstmidievent" ||
        cando == "sizewindow" ||
        cando == "asyncprocessing" ||
        cando == "offline" ||
        cando == "supplyidle" ||
        cando == "editfile" ||
        cando == "closefileselector" ||
        cando == "startstopprocess" ||
        cando == "sendvstmidieventflagisrealtime")
        return VstCanDoResult.Yes;
    else if (cando == "shellcategory" ||
                cando == "supportshell" ||
                cando == "acceptiochanges" ||
                cando == "openfileselector" ||
                cando == "reportconnectionchanges")
        return VstCanDoResult.No;

    return Jacobi.Vst.Core.VstCanDoResult.Unknown;
Dec 5, 2015 at 3:46 AM
Sorry Yury. It seems to make no difference.

At the end of the day, I'm not too worried about this one. I just wanted to get a step sequencer to output midi to another VST plugin, and I achieved that with B-Step which works perfectly. Basically, it looks like this plugin does something weird. I would like to fix this, but I can't get too caught up on this one.