Engine.getPlayhead() functionality
-
Hey guys,
I was searching for a way to sync HISE to the host's playhead and came upon a post about modifying HISE source to un-comment some lines used for accomplishing this sort of thing in the hi-core main.cpp module. (originally from post: https://forum.hise.audio/topic/2307/the-things-we-all-want-to-see-in-hise-3-0/18).
void MainController::storePlayheadIntoDynamicObject(AudioPlayHead::CurrentPositionInfo &/*newPosition*/) { //static const Identifier bpmId("bpm"); //static const Identifier timeSigNumerator("timeSigNumerator"); //static const Identifier timeSigDenominator("timeSigDenominator"); //static const Identifier timeInSamples("timeInSamples"); //static const Identifier timeInSeconds("timeInSeconds"); //static const Identifier editOriginTime("editOriginTime"); //static const Identifier ppqPosition("ppqPosition"); //static const Identifier ppqPositionOfLastBarStart("ppqPositionOfLastBarStart"); //static const Identifier frameRate("frameRate"); //static const Identifier isPlaying("isPlaying"); //static const Identifier isRecording("isRecording"); //static const Identifier ppqLoopStart("ppqLoopStart"); //static const Identifier ppqLoopEnd("ppqLoopEnd"); //static const Identifier isLooping("isLooping"); //ScopedLock sl(getLock()); //hostInfo->setProperty(bpmId, newPosition.bpm); //hostInfo->setProperty(timeSigNumerator, newPosition.timeSigNumerator); //hostInfo->setProperty(timeSigDenominator, newPosition.timeSigDenominator); //hostInfo->setProperty(timeInSamples, newPosition.timeInSamples); //hostInfo->setProperty(timeInSeconds, newPosition.timeInSeconds); //hostInfo->setProperty(editOriginTime, newPosition.editOriginTime); //hostInfo->setProperty(ppqPosition, newPosition.ppqPosition); //hostInfo->setProperty(ppqPositionOfLastBarStart, newPosition.ppqPositionOfLastBarStart); //hostInfo->setProperty(frameRate, newPosition.frameRate); //hostInfo->setProperty(isPlaying, newPosition.isPlaying); //hostInfo->setProperty(isRecording, newPosition.isRecording); //hostInfo->setProperty(ppqLoopStart, newPosition.ppqLoopStart); //hostInfo->setProperty(ppqLoopEnd, newPosition.ppqLoopEnd); //hostInfo->setProperty(isLooping, newPosition.isLooping); }
I made these specific changes, recompiled HISE without issue, and tested things out, but I've been unable to get this to work. I always get "undefined" as a result of calling Engine.getPlayhead().isPlaying, for instance (I've tried all the available functions though, and have uncommented them all). I've made these experiments in the AU/VST versions of HISE running inside Live, Logic, and Bitwig.
I looked around for other variables in the HISE code that could be preventing these features from working, but couldn't find anything obvious. Am I missing something obvious?
Having MIDI playback functionality without any transport sync is fairly useless for my purposes. Has anyone gotten this particular change to work, or is there another way I should be going about this?
Thanks in advance :)
a
-
Nothing to add really except that this is sorely needed , for LFO and modulation purposes as well :)
-
For some reason, I couldn't get this to work before. I tried recompiling everything, and now it appears to be working for me. Go figure :/
I'll report back after I've had a while to do some testing and make sure it works correctly. Currently, all I've confirmed is that isPlaying() seems to report transport state correctly.
a
-
@lalalandsynth +1 On Synced Lfo's
Thanks, Lala For Mentioning This. -
@amounra Did this work for you eventually ? And if so , does it also work for modulators and lfos?
-
It did work for me....after many tries to get the right combination of version + modifications to give me the features I needed.
In what sense do you mean, "does it work for modulators and lfos"?
All I'm using it for at the moment is to get the playing state of the host software, so that I can play/sync or stop MidiPlayer sequences based on what the host is doing.
-
@amounra since the time that I was waiting for this .. it would finally allow us to make sidechains hoping to have the least possible latency. Let us know if you make your version of hise available. Thanks for that
-
Since I don't think it's been posted explicitly anywhere, it should be clarified that you should uncomment both the const and the setProperty lines corresponding to the properties you want to enable, as well as the &newPosition argument and the ScopedLock.
For example:
The object is a native script object, so you can just go
Console.print(trace(Engine.getPlayHead()));
to test it.Also the TransportHandler exists now which you should probably use instead, but it lacks some options like differentiating between playing and recording.
-
PSA:
Engine.getPlayHead().ppqPosition
gets all jittery on JACK audio with a buffer size 1024 or greater.With playback stopped, the playhead at 0 and a buffer size of 1024, ppqPosition alternates between
0.02133333333333333 0.0
very quickly. The values are different depending on the buffer size
2048
0.02133333333333333 0.04266666666666667 0.064 0.0 0.02133333333333333 0.04266666666666667 0.064 0.0 0.02133333333333333 0.042666666666666
At 512 and below everything is fine.
-
@Simon said in Engine.getPlayhead() functionality:
JACK audio
Are you using Pipewire > JACK or just JACK?
-
@d-healey Hard to tell since pipewire pretends to be everything else, but given that I have it installed, I'm going to assume it's Pipewire > Jack.
-
@Simon said in Engine.getPlayhead() functionality:
given that I have it installed, I'm going to assume it's Pipewire > Jack.
Yeah it will, just wanted to know because I'm using it so this probably affects me :)
-
It looks like the variation is a multiple of a fraction of the buffer size in samples.
At 1024, timeInSamples() goes between 0 and 512.
At 2048, it goes 0, 512, 1024, 1536, back to 0
At 4096 it goes, predictably
-
I hoped this was Linux only but the behavior is identical on Windows ASIO!
-
Alright, I have no idea why that happens, can't find any mention of it in JUCE forums so I have to assume it's something HISE specific.
I am only using the position to check if the user jumps somewhere else in the timeline. This means I can just use timeInSamples to ignore any movements smaller than 4096 samples.
I would base it on the current buffer size, but unfortunately
Engine.getBufferSize()
doesn't get updated if you change the ASIO buffer size without a restart, so it can't be relied on.If you're looking to use the current playback time for something more musical... godspeed, let us know how it goes.
-
@Simon said in Engine.getPlayhead() functionality:
I am only using the position to check if the user jumps somewhere else in the timeline.
Can't you use the transport handler for this?
-
I don't think so? Maybe I misunderstood one of the methods, but there doesn't seem to be one that fires when the playhead is moved.
-
@Simon I think
setOnGridChange
but the docs are sparse so not sure. -
@d-healey I have that commented in my script as the first thing I tried, and I can't get it to fire atm, so I'm gonna assume it's something else.
-
@Simon You might have to call this first
setEnableGrid
but I just looked at the example snippet from the docs and onBeatChanged might do the trick...