Quantising audio playback / very simple sequencer

Hello,

Could anyone suggest a way of doing a simple 16th quantise on audio clip playback?

My maths are shoddy and I can’t get my head around how to work out tempo and 16th divisions of a beat - to play sounds with quantised timing…

Hoping someone has done this kind of thing before and can help.

Thanks,

James

Hallo,

I’ve tried to get this working with limited understanding. I’ve got as far as working out printing ‘beat’ to the console window, but I get groups of four beats at 120bpm, and then a pause before the next group of four. Can anyone tell me what I’m doing wrong?

function Awake()
{
	beat = 60.0/120.0;
	print("Beat is: " + beat);
}


function FixedUpdate () 
{
	time += Time.deltaTime;
	
	if (time >= beat)
	{
		print("beat");
		
		time = 0.0;
	}
}

Is it because Unity isn’t running fast enough to keep the timing?

If so, should I learn C++/contract a C++ programmer and build a plugin to keep the timing solid?

Thanks

Unity is far more than fast enough to keep up. That code works fine here, though it should be Update and not FixedUpdate.

–Eric

Thanks for the reply. Neither FixedUpdate or Update give anything near musical timing.

It should be a solid beat you can tap your foot to. Is that what you’re getting?

I’m also finding it hard to track down information on the web about keeping good musical timing. I’ve only found one book on the subject, which was written 12 years ago and was for Windows 95:

I’m guessing it will help me understand the principles, but whether it’ll help me build a plugin for Unity I don’t know.

I think that trying to achieve timing that is suitable for music performance will be hard to achieve in the Update loop (which is for graphics processing and game logic). You probably won’t get millisecond precision, which is really what you want.

Perhaps there is the possibility of creating a .Net assembly that uses threading to run separate the music loop from the game loop. C++ would be even better I guess.

(I could be entirely wrong, as I haven’t done serious testing. Right now I’m just sending data through OSC to a supercollider server for some prototyping.)

Yep. If you’re doing a lot of other stuff that affects the framerate, the timing might be slightly off if the fps gets low enough.

–Eric

@Tinus - Supercollider, my favourite.

I’ve contacted Unity Studios to see if I can contract them to build a C++ plugin so that musical timing is achieved.

@Eric - Even with an empty project and a near top of the range PC, the timing is terrible here :frowning:

It’s fine on my Mac, which was top of the range about 4.5 years ago. :wink: Have you tried with actual sound instead of printing? Logging output might be messing things up.

–Eric

Actually the timing is pretty tight playing just one audio clip, but things start to slip when there’s more than 5 sounds being triggered. I wanted to implement a simple quantise to make sure that sounds are only played during a 16th of a beat.

Thanks for suggesting I ignore the printing speed though, as it does seem to be getting a lower priority than audio playback (obvious when you think about it!).

Cheers,

James

The code “works”, but it doesn’t do what you want it to do. :?

By resetting “time” to zero as you do, you are ensuring that the “beat” is being printed later than it should be. It’s as if you effectively decrease your bpm by a random value that is constantly changing, because of the imprecision of either Update or FixedUpdate, which unfortunately are all we have right now.

So, it’s completely possible to write different code, that tracks how many beats have passed, but that’s not going to be useful for any sort of quantizing operation. It’s only good for numeric feedback.

Unity has no ability to “keep up”, on anyone’s system, from any time in the future, with your code. However, even with more appropriate code, what you are trying to do simply doesn’t work in Unity yet without plugins.

I think the trouble is that the execution of the Update functions is always going to be tied to the speed of the renderer. What you could do is start your own update loop for musical timing and have that running as a coroutine and use Time.time for timing instead of Time.deltaTime (which is pegged to the Update functions).

private bool beat = false;
	
private float bPM;
	
public void Start()
{
	bPM = 60.0f/120.0f;
	StartCoroutine(Beat(bPM));
}
	
void OnGUI()
{
	if (beat)
	{
		GUI.Box( new Rect(20, Screen.height - 40, 20, 20), "");
	}
}
	
private IEnumerator Beat(float beatsPerMinute)
{
	while (Application.isPlaying)
	{
		if (Time.time % beatsPerMinute <= 0.1f)
		{
			beat = true;
		}
		else { beat = false;}
		yield return new WaitForSeconds(0f);
	}
}

This is basically what a C++ plugin for quantising musical timing would do anyway, the only question is whether the time value you use to track the beats is regular enough (in C++ you could peg it to the processor ticks, which is the best you can do on a computer and more than sufficient for musical timing).

The only reason I can see that the above code wouldn’t work is if the way Time.time is incremented is also tied to Update and rendering. I don’t know if this is the case or not, but maybe someone else might have a better idea.

Cheers folks :slight_smile:

So how many people would like to see an API for rock solid timing built into Unity?

We could chip together and contract Unity Studios to do it?

We’re a minority, I think, so I don’t give us much of a chance. And I still think it’s possible to code it without official support, it’ll just take some work (have you tried dawvee’s approach?)

Besides, I would start demanding proper DSP support for audio synthesis and processing the minute they gave me built-in timing. :wink:

I’ve elaborated the above script a bit, so now it fires an OnBeat method once every beat (and an OnSwingBeat method that fires at an adjustable proportion after OnBeat). As you can see in the code, you would put functions like playing sounds into the OnBeat or OnSwingBeat methods, and you could use counters inside OnBeat() to construct a full transport.

I haven’t tested this out too extensively, but it seems to keep decent time. I’d have to test it on different machines under different loads to be sure, though.

bool beat = false;

private float bPM;
private float swing;
	
public void Start()
{
	bPM = 60.0f/120.0f;
	swing = 1f/3f;
	StartCoroutine(Beat());
}

void OnGUI()
{
	if (beat)
	{
		GUI.Box( new Rect(20, Screen.height - 40, 20, 20), "");
	}
}

private IEnumerator Beat()
{
	bool newBeat = false;
	while (Application.isPlaying)
	{
		if (Time.time % bPM < 0.01f  !newBeat)
		{
			newBeat = true;
			OnBeat();
		}
		else if (Time.time % bPM >= (bPM * swing)  newBeat) 
		{ 
			newBeat = false;
			OnSwingBeat();
		}
		yield return new WaitForSeconds(0f);
	}
}
	
public void OnBeat()
{
//	audio.Play();
	beat = true;
}
	
public void OnSwingBeat()
{
	beat = false;
}

Sweet, I’ll give it a try :slight_smile:

Sure, we’re in the minority, but Unity Studios do contract work. If we’re willing to put some money behind it, it may not be too expensive for them to implement.

I’m awaiting a response from them…

Thanks again for this though!

hmm, is it possible to call functions located in a JavaScript from a C# script?

I’m trying to do so, and it’s throwing an error saying there’s no member of Component called Beat.

GameObject.Find("Main").GetComponent("Main").Beat();

You can call a C# script from javascript if you put it in your Standard Assets folder, but it’s probably easier to have a javascript version if you want to extend it or add functionality. So, javascript version attached. :slight_smile:

142159–5194–$quantise_210.js (656 Bytes)

awesome, thanks very much for this.

Unusually, it’s giving me the same behaviour as the print() test I was doing at the start - a group of three beats, then a pause, then another three beats, then two, then two, then three - completely random.

Hmm, I think C++ must be the way to go, but I really appreciate your help!