Get Current BarsBeatsPosition

SDK for VST 3 audio plug-in and host development.
Post Reply
ErezEitan007
Posts: 4
Joined: Tue Jun 27, 2017 7:30 am

Get Current BarsBeatsPosition

Post by ErezEitan007 » Wed Jul 05, 2017 9:42 am

Dear Steinberg Team,

Is there a way to extract the current position of the project cursor in terms of Bars and Beats (as presented to the user).
Currently I can only get in terms of quarter notes, but when changing time signature along the track, I cannot extract from the quarter notes alone the current bar.

(Or something similar to AAX’s GetBarBeatPosition().)

Kind Regards,
Erez

Arne Scheffler
Posts: 282
Joined: Mon Jun 20, 2016 7:53 am

Re: Get Current BarsBeatsPosition

Post by Arne Scheffler » Wed Jul 05, 2017 2:10 pm

Hi,
what's your use case for this ?

Cheers,
Arne

ErezEitan007
Posts: 4
Joined: Tue Jun 27, 2017 7:30 am

Re: Get Current BarsBeatsPosition

Post by ErezEitan007 » Wed Jul 05, 2017 2:38 pm

I need to know the current bar when a user changes the playback cursor to a specific time.
My plugin needs to be synced with the bars and if the time signature changes along the session, I cannot extract the bar from the given info(current quarter note + current time signature).

Any help would be appreciated.

Thanks,
Erez

howardantares
Posts: 126
Joined: Tue Jun 21, 2016 1:46 pm

Re: Get Current BarsBeatsPosition

Post by howardantares » Wed Jul 05, 2017 4:40 pm

We've always wanted this, too. Our graph can show the bar/beat, but if they don't start "recording" into our graph at time 0, then any time sig/tempo changes prior to that start are lost.

For sample accuracy, it would be *most* helpful if we could get the sample position of the next bar/beat event with each buffer we process. As it is (even leaving aside time sig/tempo changes), we'd have to check the q-note for every sample position in the buffer in order to find out when exactly it changes.

ygrabit
Posts: 121
Joined: Fri Jun 17, 2016 7:52 am
Location: Hamburg

Re: Get Current BarsBeatsPosition

Post by ygrabit » Fri Jul 07, 2017 10:08 am

Hi
Did you check this member of ProcessContext:

TQuarterNotes barPositionMusic; ///< last bar start position, in quarter notes

from it you can compute where are the bar positions around the current position.
is it what you mean?
YVan Grabit

howardantares
Posts: 126
Joined: Tue Jun 21, 2016 1:46 pm

Re: Get Current BarsBeatsPosition

Post by howardantares » Fri Jul 07, 2017 2:28 pm

Yeah, I forgot we do use that now, when hosts make it available (which some don't). Still a little complex, having to compute backwards into our graph from the current buffer start to when the most recent bar/beat occurred. And the code assumes that there hasn't been a time sig or tempo change since the last bar. If it helps, here's the code we use:

Code: Select all

if (data.processContext != NULL)
	{
		//
		Steinberg::uint32	state	= data.processContext->state;
		if (	isSamplePosKnown &&
				((state & ProcessContext::kPlaying) != 0) &&
				((state & ProcessContext::kProjectTimeMusicValid) != 0) &&
				((state & ProcessContext::kBarPositionValid) != 0) &&
				((state & ProcessContext::kTempoValid) != 0) &&
				((state & ProcessContext::kTimeSigValid) != 0) )
		{
			// Compute last bar#, and fraction of a bar since then
			float		beatsPerQNote			= (float)(data.processContext->timeSigDenominator) / 4.0;
			float		barsPerQNote			= beatsPerQNote / data.processContext->timeSigNumerator;
			float		lastBarNumberFloat	= data.processContext->barPositionMusic * barsPerQNote; //barPositionMusic is in qNotes!
			float		barNumberIntPart		= floor( lastBarNumberFloat ); // -2.3 becomes -3.0, as we want!
			int32		lastBarNumber			= (int32)barNumberIntPart;

			/* TODO: what if this is not zero?
			float		barNumberFraction		= (lastBarNumberFloat >= 0) ? 
														lastBarNumberFloat - barNumberIntPart :	// if >= 0
														barNumberIntPart - lastBarNumberFloat;		// if < 0
			*/

			// Compute last beat# in current bar, and fraction of a beat since then
			float		qNotesBackToLastBar	= data.processContext->projectTimeMusic - data.processContext->barPositionMusic;
			float		currentBeatFloat		= qNotesBackToLastBar * beatsPerQNote;
			float		currentBeatIntPart	= floor( currentBeatFloat ); // always >= 0
			float		currentBeatFraction	= currentBeatFloat - currentBeatIntPart;
			
			Steinberg::uint16	lastBeatNumber			= (Steinberg::uint16)currentBeatIntPart;
			
			// Increment bar and beat, since calculations is 0-based, but numbers are 1-based!
			lastBarNumber++;
			lastBeatNumber++;
			// Are we at a new bar or beat?
			if ((lastBarNumber != lastRecordedBarNumber) || (lastBeatNumber != lastRecordedBeatInBar))
			{
				// Yes; Record the new bar/beat numbers
				lastRecordedBarNumber	= lastBarNumber;
				lastRecordedBeatInBar	= lastBeatNumber;
				
				// Now, we have the most recent bar# and the most recent beat#, 
				// and the fraction of a beat since the last beat.
				// We need to determine how long ago the last beat occurred, in samples.
				// To do that, we need to determine the samples per beat,
				// which is the samples per second (sample rate) divided by the beats per second.
				//	The beats per second equals the quarter notes per second times the beats per quarter note.
				//	The quarter notes per second equals the tempo divided by 60, and
				//	the beats per quarter note equals time signature denominator divided by 4. So...
				float		qNotesPerSecond		= data.processContext->tempo / 60.0;
				float		beatsPerSecond			= qNotesPerSecond * beatsPerQNote;
				float		samplesPerBeat			= data.processContext->sampleRate / beatsPerSecond;
				//
				float		samplesSinceLastBeat	= samplesPerBeat * currentBeatFraction;
				Steinberg::uint16	samplesSinceBeatInt	= (Steinberg::uint16)samplesSinceLastBeat;
				long		sampleAtBeat			= samplePos - samplesSinceBeatInt;
				//	Now we have the sample position of the last beat, which we use to mark it on our sample-based graph

ErezEitan007
Posts: 4
Joined: Tue Jun 27, 2017 7:30 am

Re: Get Current BarsBeatsPosition

Post by ErezEitan007 » Sun Jul 09, 2017 11:33 am

Thanks Yvan and Howard.

Like Howard mentioned, this is only partial information.
In addition to the provided information we also need the exact bar number.

We need this information for cases our synced period is above 1 bar (e.g 2 bars period).

ErezEitan007
Posts: 4
Joined: Tue Jun 27, 2017 7:30 am

Re: Get Current BarsBeatsPosition

Post by ErezEitan007 » Mon Jul 24, 2017 6:36 am

Hi,
So i wonder is there any progress with this issue?

peter
Posts: 1
Joined: Sun Apr 14, 2019 9:31 am

Re: Get Current BarsBeatsPosition

Post by peter » Thu May 16, 2019 4:40 pm

howardantares wrote:
Fri Jul 07, 2017 2:28 pm
Yeah, I forgot we do use that now, when hosts make it available (which some don't). Still a little complex, having to compute backwards into our graph from the current buffer start to when the most recent bar/beat occurred. And the code assumes that there hasn't been a time sig or tempo change since the last bar. If it helps, here's the code we use:

Code: Select all

if (data.processContext != NULL)
	{
		//
		Steinberg::uint32	state	= data.processContext->state;
		if (	isSamplePosKnown &&
				((state & ProcessContext::kPlaying) != 0) &&
				((state & ProcessContext::kProjectTimeMusicValid) != 0) &&
				((state & ProcessContext::kBarPositionValid) != 0) &&
				((state & ProcessContext::kTempoValid) != 0) &&
				((state & ProcessContext::kTimeSigValid) != 0) )
		{
			// Compute last bar#, and fraction of a bar since then
			float		beatsPerQNote			= (float)(data.processContext->timeSigDenominator) / 4.0;
			float		barsPerQNote			= beatsPerQNote / data.processContext->timeSigNumerator;
			float		lastBarNumberFloat	= data.processContext->barPositionMusic * barsPerQNote; //barPositionMusic is in qNotes!
			float		barNumberIntPart		= floor( lastBarNumberFloat ); // -2.3 becomes -3.0, as we want!
			int32		lastBarNumber			= (int32)barNumberIntPart;

			/* TODO: what if this is not zero?
			float		barNumberFraction		= (lastBarNumberFloat >= 0) ? 
														lastBarNumberFloat - barNumberIntPart :	// if >= 0
														barNumberIntPart - lastBarNumberFloat;		// if < 0
			*/

			// Compute last beat# in current bar, and fraction of a beat since then
			float		qNotesBackToLastBar	= data.processContext->projectTimeMusic - data.processContext->barPositionMusic;
			float		currentBeatFloat		= qNotesBackToLastBar * beatsPerQNote;
			float		currentBeatIntPart	= floor( currentBeatFloat ); // always >= 0
			float		currentBeatFraction	= currentBeatFloat - currentBeatIntPart;
			
			Steinberg::uint16	lastBeatNumber			= (Steinberg::uint16)currentBeatIntPart;
			
			// Increment bar and beat, since calculations is 0-based, but numbers are 1-based!
			lastBarNumber++;
			lastBeatNumber++;
			// Are we at a new bar or beat?
			if ((lastBarNumber != lastRecordedBarNumber) || (lastBeatNumber != lastRecordedBeatInBar))
			{
				// Yes; Record the new bar/beat numbers
				lastRecordedBarNumber	= lastBarNumber;
				lastRecordedBeatInBar	= lastBeatNumber;
				
				// Now, we have the most recent bar# and the most recent beat#, 
				// and the fraction of a beat since the last beat.
				// We need to determine how long ago the last beat occurred, in samples.
				// To do that, we need to determine the samples per beat,
				// which is the samples per second (sample rate) divided by the beats per second.
				//	The beats per second equals the quarter notes per second times the beats per quarter note.
				//	The quarter notes per second equals the tempo divided by 60, and
				//	the beats per quarter note equals time signature denominator divided by 4. So...
				float		qNotesPerSecond		= data.processContext->tempo / 60.0;
				float		beatsPerSecond			= qNotesPerSecond * beatsPerQNote;
				float		samplesPerBeat			= data.processContext->sampleRate / beatsPerSecond;
				//
				float		samplesSinceLastBeat	= samplesPerBeat * currentBeatFraction;
				Steinberg::uint16	samplesSinceBeatInt	= (Steinberg::uint16)samplesSinceLastBeat;
				long		sampleAtBeat			= samplePos - samplesSinceBeatInt;
				//	Now we have the sample position of the last beat, which we use to mark it on our sample-based graph
It seems like the information we get is the same as is sent as smpte. A context should never have to be tracked, that is the hole point of it. A pointer to next and previous context's should be nice. Like nextChord and previousChord. A musical context would be good. This smtpe is for video sync, it's not that useful for most vst plugins. But information about the music. LIke if it is chorus, intro, verse etc is very useful for "agents" trying to help. Like groveagent and toontrack stuff.

Post Reply