Plug-ins, Hosts, Apps,
Hardware, Soundware
Developers
(Brands)
Videos Groups
Whats's in?
Banks & Patches
Download & Upload
Music Search
KVR
   
KVR Forum » DSP and Plug-in Development
Thread Read
PPQ in Delphi
paoling
KVRist
- profile
- pm
- www
PostPosted: Mon Jul 16, 2012 2:19 pm reply with quote
Hi To all!
According to Leslie Sanford (http://www.kvraudio.com/forum/viewtopic.php?t=270213), to sync an LFO to the host I only need know the Tempo and the PPQN position.

I'm using the ASIO VST Project by Christian Budde, and if I understand correctly I have a record avaiable called TVstTimeInfo, that's probably obtained by using the procedure

GetTimeInfo(const Filter: TVstIntPtr): PVstTimeInfo;

Is this record provided by the host and I just need to get a pointer to it to read its attributes?

But.. What's that Filter parameter? Filter of what?

I don't have a clear idea...

Thank you in advance.

Paolo

EDIT: I add that: "filter should contain a mask indicating which fields are requested (see valid masks in aeffectx.h), as some items may require extensive conversions"
It don't helps me to understand...
^ Joined: 24 Jan 2012  Member: #273585  
mystran
KVRAF
- profile
- pm
- e-mail
- www
PostPosted: Mon Jul 16, 2012 4:00 pm reply with quote
Don't know about Delphi specifically but: the filter is a set of flags specifying what specific information you would like to be included in the time info. In this case you would want to do the equivalent of the C++

VstTimeInfo * vstTime = getTimeInfo(kVstTransportPlaying | kVstTempoValid | kVstPpqPosValid);

If you're not familiar with C++, that's just a bitwise OR of the flag contants.

You should probably request transport playing too (as done above). This way you can keep your own sample counter to run your LFOs at host tempo when the host playback is stopped (and then sync to PPQN position when host playback resumes).

Now, even if you ask for some fields, host isn't required to return those, so check afterwards (in timeinfo's flags field) that you actually got what you wanted before trying to use stuff (uninitialized fields might be anything).

Unfortunately no idea how this translates to Delphi but it's probably not too different. Hope this helped at least a bit.
----
<- my plugins | my music -> @Soundcloud
^ Joined: 11 Feb 2006  Member: #97939  Location: Helsinki, Finland
very angry mobster
KVRian
- profile
- pm
- e-mail
- www
PostPosted: Sat Jul 21, 2012 12:12 am reply with quote
Hi Paoling,

In case you haven't already found a solution, this is what I use.


procedure TMyPlugin.ProcessReplacing(inputs, outputs: PPSingle; sampleframes: Integer);
var
  TimeInfo : PVstTimeInfo;
  Tempo : single;
  PpqPos : double;
begin 
  //Get the TimeInfo pointer.
  TimeInfo := GetTimeInfo(32767);

  //Check if the tempo field is valid.
  if (TimeInfo^.flags and kVstTempoValid) >=1
    then Tempo := TimeInfo^.Tempo;

  //Check if the PPQ value is valid.
  if (TimeInfo^.Flags and kVstPpqPosValid) >= 1
    then PpqPos := TimeInfo^.ppqPos;
end;

The 32767 is a constant I saw used in an example plugin when I first started programming. If you need them, the flags mystran mentioned are defined in DAEffectX.pas.

Hope that helps.
^ Joined: 14 Dec 2003  Member: #11047  Location: Melbourne, Australia
paoling
KVRist
- profile
- pm
- www
PostPosted: Mon Jul 23, 2012 4:32 am reply with quote
Thank you so much Mystran and Very Angry Mobster; actually I found a solution like yours, Very Angry Mobster(VAM for simplyness).

I'm not very sure about the constant value... In DAEffectX.Pas (DAV_VSTEffect in the VST Framework), the constants range from 0 to 14 if I don't get wrong... But I noticed that changing the parameters doesn't give me different results. I'm trying it in Sonar and I see that I don't get PPQ, so I don't have a kind of way to understand the ticks used per quarter. I know that it is 960 ticks, but I don't have a way to find this info.

I think I could live without it...

Just for a future reference, let's describe the values and the format of the various entries. This is not very well documented to me in the main VST document from steinberg. I try to explain the things that I know and then if you can you add info for the things I don't know. And correct me if I'm wrong.

SamplePos : Double; // current location
Current Location in samples. If the Tempo is 120 bpm, a quarter is half a second, then a Bar in 4/4 is 2 seconds long. So the SamplePos of the 2nd bar is 2*SampleRate.
If there is a loop, SamplePos can jump backward, and if the sequencer is stopped the SamplePos simply continues to count.
Since the GetTimeInfo it is the same during the whole ProcessReplacing method, you can use an internal ISamplePos counter (<than SampleFrames) to keep track of the internal progress of the plugin.

SampleRate : Double;
The actual samplerate. It should be provided as a parameter in the ProcessReplacing method, so I don't see the point to use it here.
But I noticed the type of this parameter (like in SamplePos), why it isn't an integer value? Can fractional values of those parameters exists? It makes no meaning to me.
And it could save a Trunc function (i use the magic numbers trick in this case).


NanoSeconds : Double; // system time
According to the documentation it is: the system time in nanoseconds related to SamplePos (which is related to the first sample in the buffers passed to the process () methods).
I don't understand fully this value. What is that: is that just a conversion in time of the SamplePos value, or a measuring of the time passed from the first call to the Process() method?


PpqPos : Double; // 1 ppq
This seems not valid in Sonar to me; anyway I think that it should be a conversione
from SamplePos to the Thick value. If SamplePos is 44100 at a SampleRate of 44100, then the PpqPos should be 960 if the tick value is 960. Is it so?
Does exist a valid method to understand the Midi Tick value for the sequencer apart from doing a conversion like this?? This could be useful to set a Midi Resolution value in the plugin

Tempo : Double; // in bpm
Tempo is obviously the Time value. Very Happy
But what is the purpose of the TempoAt(Value) function? Is it to understand the Tempo
at SamplePos+ISamplePos values (The SamplePos + the internal offset < than SampleFrames?);

BarStartPos : Double; // last bar start, in 1 ppq
I suppose than this is pratically a conversion like:
BarStartPos:= PpqPos mod PPQN
PPQN is the number of ticks. In case of 960, then
it is PpqPos mod 960.
Right?

CycleStartPos : Double; // 1 ppq
CycleEndPos : Double; // 1 ppq
Those two values are the PPq position of the loop set in the sequencer? Right?



TimeSigNumerator : LongInt; // time signature
TimeSigDenominator : LongInt;
This is easy and those two values combined can give us the meter of the project.

SmpteOffset : LongInt;
SmpteFrameRate : LongInt; // 0:24, 1:25, 2:29.97, 3:30, 4:29.97 df,

We really care about those two values? They are video related and I can only imagine that they could be useful in a plugin for a video editing software. Am I wrong?

Please excuse me for the amount of errors I could have written..! I'm just looking to spread a bit of light in this topic Smile

Thank you,
Paolo
^ Joined: 24 Jan 2012  Member: #273585  
wiwatti
is BANNED
- profile
- pm
- e-mail
PostPosted: Mon Aug 06, 2012 5:49 pm reply with quote
Quote:
I'm not very sure about the constant value... In DAEffectX.Pas (DAV_VSTEffect in the VST Framework), the constants range from 0 to 14 if I don't get wrong... But I noticed that changing the parameters doesn't give me different results.

In DAV_VSTEffect, the values from TVstTimeInfoFlag go from 0 to 15 because they are in a Set. This is a Delphi trick. Their real values (in the memory or in the register, during the run-time) are not 0..15. 0 To 15 is actually the bit order in a TVstTimeInfoFlags.

For example in the example of VAM, the value 32767 is actually

1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 + 512 + 1024 + 2048 + 4096 + 8192 + 16384

which is:

2^0 or 2^1 or 2^2 or...or 2^14

(note that he forgets the last value)

So when you make your set, lets say

Var
  MyValidityFlags: TVstTimeInfoFlags;
Begin
  MyValidityFlags := [];
  Include(MyValidityFlags, vtiClockValid);
  Include(MyValidityFlags, vtiSmpteValid,);
  //
  GetTimeInfo(Integer(MyValidityFlags));
End;

Myflags won't be equal to 14 + 15 but rather to 2^14 + 2^15 which matches to the constants from the official SDK.
Then you can call GetTimeInfo by casting MyFlags as an integer.

Quote:
SampleRate : Double;
The actual samplerate. It should be provided as a parameter in the ProcessReplacing method, so I don't see the point to use it here.
But I noticed the type of this parameter (like in SamplePos), why it isn't an integer value? Can fractional values of those parameters exists? It makes no meaning to me.
And it could save a Trunc function (i use the magic numbers trick in this case).


The samplerate is not provided in the ProcessReplacing method...
You don't need any rounding operation. Just hold it as a single. You will rarely do some integer operations with the samplerate. But it's true that you don't really need to use this member of the structure as in DAV plugins you have an assignable SamplerateChange event.
So either the SR is valid from the start of the plugin life-time or you can use the event mentioned previously to update your SR-based audio classes and properties.

Quote:
PpqPos : Double; // 1 ppq
This seems not valid in Sonar to me; anyway I think that it should be a conversione
from SamplePos to the Thick value. If SamplePos is 44100 at a SampleRate of 44100, then the PpqPos should be 960 if the tick value is 960. Is it so?
Does exist a valid method to understand the Midi Tick value for the sequencer apart from doing a conversion like this?? This could be useful to set a Midi Resolution value in the plugin

No it is not so. ppqPos is independent from the sampling rate. It basically just increases by one every beat. You should use this to compute the midi tick. Usuallly to get a midi clock you just have to multiply this value with the resolution you require.
For example:

  // get the infos with tempovalid and ppqposvalid
  MyInfos := GetTimeInfos(512 + 1024);
  // clock with 192 ticks per beat
  Tick192 := Floor( MyInfos^.ppqPos * 192 );
  // clock with 96 ticks per beat
  Tick96 := Tick192 Shr 1;
  // clock with 48 ticks per beat
  Tick48 := Tick96 Shr1;
note that actually a clock is a bit more complex, Tick192 should be a property with a setter, as its value can be the same during 2 or more iterations of the audio loop

Quote:
Since the GetTimeInfo it is the same during the whole ProcessReplacing method

No, you can call GetTimeInfo for each sample in the loop (ppqpos will vary). But to use an internal counter can avoid some calls to the host.
^ Joined: 22 Oct 2011  Member: #267186  Location: France
All times are GMT - 8 Hours

Printable version
Page 1 of 1
Display posts from previous:   
ReplyNew TopicPrevious TopicNext Topic
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
Username: Password:  
KVR Developer Challenge 2012