ChemiCalChems
ChemiCalChems

Reputation: 643

C++ Precise 44100Hz clock for real time audio synthesis

I am currently in the process of coding a MIDI synthesizer using my Raspberry Pi and its built-in UART input.

At some point in time, in order to enable live playback of MIDI input, I'll have to set up a sort of ring buffer to use with OpenAL, which should be pretty simple to do, just fill in a buffer, queue it in, wait for another buffer to be free to fill.

The problem I'm having right now is actually filling the buffers. I want to have a sample rate of 44100Hz, so CD quality. My plan is to have a clock running that calls the synthesizing function every tick, and writes a sample to memory based on the currently pressed keys, which I keep track of in another thread by listening to note on and note off events.

However, I'm noticing a problem here. Sleeping a thread for some time isn't precise at all, the thread is guaranteed to wake up after some time, but not exactly when that time has passed, so I don't really think that's a good way to go.

Is there some sort of tick generator that I could use that is precise enough for audio synthesis?

I know I'm probably reinventing the wheel here, as I could just grab a synthesizer and tweak to my own needs, but I'm interested in the whole process, so that's not quite an option.


I do realize it is possible that the whole writing a sample to memory every x is not a good idea either, but that's my best guess at the moment, so if you have any other suggestion, I'll be sure to take a look at it.

Upvotes: 0

Views: 1359

Answers (2)

Erik Alapää
Erik Alapää

Reputation: 2703

In addition to the answers and comments already given, read up on hard real-time in Linux. In particular, read up on the relatively new SCHED_DEADLINE scheduler and also Ingo Molnar's real-time patchset, of which 80% resides in the mainstream kernel.

Upvotes: 1

Humphrey Winnebago
Humphrey Winnebago

Reputation: 1702

You need a high-performance timer.

Sleeping, as you observed is not accurate. Usually, the implementation will guarantee to sleep for at least the specified amount of time, but is allowed to sleep for longer.

Additionally, the typical system clock is not high-res enough.

If you use C++'11, a high performance clock comes standard. See http://www.cplusplus.com/reference/chrono/high_resolution_clock/

That's the way I would go. If for some reason you can't use C++'11, there are options.

Windows exposes a high-performance clock through the Kernel32.dll, which provides these functions: QueryPerformanceFrequency QueryPerformanceCounter

Linux has sys/time.h, which gives you gettimeofday A quick google search for gettimeofday might get you some better alternatives.

Check out my cross-platform high-performance timer on my bitbucket https://bitbucket.org/akfreed/cppcrossplatform/src/e3f71e6d93de?at=default

Now you can poll the time in a tight loop.

This is very high precision. On my laptop, which is nothing special, (i3-5005U, dual 2GHz hyperthreaded) running Windows, i have a tick time of 513 nano. That is plenty of time to do do a function call in your 22.7 microsecond intervals. You could even do several atomic instructions and/or go out to main memory several times.

Upvotes: 1

Related Questions