Tonic, a refreshingly crisp C++ audio patching library

Dear oF,

I’d like to announce Tonic, a new C++ audio library. Tonic is inspired by high level tools like Max/Msp, Pure Data and SuperCollider, but uses a beautifully simple and expressive C++ syntax. Tonic lets you describe complex synthesis and sequencing systems using a minimum of code. It’s powerful, flexible, efficient, and fun!

There’s an addon for Tonic here:
https://github.com/TonicAudio/ofxTonic

Those of us who’ve been building Tonic over the past six months really love it, and hope some of you will too. Please let us know if it’s useful to you, and what you might like to see in the future.

Cheers!

-Morgan

1 Like

This looks really great! Fills a much needed gap imo, cant wait to spend some time with it.

I see it has reverb and delay, does it have other effects like chorus/flanger/phasing?

All the effects classes are listed in Tonic.h
https://github.com/TonicAudio/ofxTonic/blob/master/src/Tonic.h

No dedicated chorus/flange/phase at this point. You can get a nice chorus effect by simply passing a signal through a delay line and modulating the time with a sine wave.

We also don’t have a sample player at this point, but most definitely plan to.

-Morgan

Yeah cool, I am really glad to see this. The reverb looks really nice. I have an app at the moment that is tied to core audio just to have a decent reverb plug, which bothers me because being tied to os x/ios is already proving to be somewhat of a headache.

How is the audio pull stuff handled? do sound sources have local buffers? one thing i have spent some time dancing around in my current code based on maxim is if i want one generator source hooked up to two different sound sources (eg one oscillator modulating parameters on two different filter instances so they are in sync), i need to update the generator once for the current audioRequested which writes to local/per gen instance buffer, then the sound sources pull from that buffer. Otherwise it runs at double speed if two things are pulling from it.

Tonic is smart about generator reuse. Samples are calculated only once per buffer, no matter how many different things they’re plugged in to, so a SineWave oscillator, for example, will run at the proper frequency no matter how many things it’s plugged in to.

Hopefully we’ll be able to attract more folks to the project and get lots of different effects contributed. Once you learn a couple tricks, it’s pretty easy to create new Generator and ControlGenerator subclasses.

Hi there! I’m Nick, the other half behind Tonic. Glad to see someone’s already finding it useful!

To elaborate on Morgan’s comment, you can make a flanger by using the Comb Filter generator(s) and sweeping the delay time, and you can make a chorus effect by using the Delay generator(s) and modulating the delay time(s) to get small pitch shifts. We might make simple implementations of these as their own generators at some point, too.

If there’s any other particular effects you’re dying for please let us know and we can add them to the list.

Cheers!

hey!

this is really great and much needed!!
are you planning on releasing a version for mobile? ios? android?

thanks!
.r

Distortion would be good too, and auto panner, but I guess you could easily just point a generator at pan settings for that one.

A sample player that supports different sample rates would be something I would need before I could convert my existing stuff, as it is all sample based for the basic sound generation. It would be cool if it supported different update()/pull() cycles as well so the same sample could be sent to different fx units. Or maybe a splitter plugin that has one input 2 outputs. It would be most useful on mobile apps as 44khz wavs can use up a lot of memory, and having a bunch of copies of the same sample in memory just so they can get diffent processing applied is not really optimal.

Far out guys Tonic sounds absolutely incredible! thank you so much for putting this out there. Finally an awesome sounding synthesis library for openFrameworks!

@pants – We’ll get to that sample player…
There’s no need for a splitter module. You can simply plug an object into multiple inputs, and it just works (assuming I’m understanding you question).

@joshuabatty Tonic started as an iOS project, actually. Check out the demo in the main tonic repo: https://github.com/TonicAudio/Tonic/tree/master/Demo/iOS/TonicDemo The addon should just work in iOS open frameworks. Let us know if it doesn’t.

Great thanks for that, I had actually compiled all the of the Tonic examples for oF before you pointed this out but is good to see it working on the iOS simulator.

I have a question though, I would like to integrate Tonic with my ofxMaxim software but need to find a way to assign the output of my Tonic synth to a double so I can mix them together.

At the moment all of the examples use
synth.fillBufferOfFloats(output, numFrames, nChannels);

having this in my patch with Maxim makes the audio kinda shit itself. Im looking through the Tonic library but cant easily see a method I can use that will let me assign the output of my synth to a float or a double. Is there a way to do this? Thanks.

@joshuabatty Tonic by design doesn’t output single values, it always operates on buffers of floats. This is much more efficient (though a little more complicated) than sample-at-a-time calculation, which is how Maxim does it. Eventually, the audio hardware needs buffers of values, not individual values any way, so somewhere, those individual values being output by ofMaxim are getting rolled in to a buffer. This stage might be the most logical spot to mix your signals.

If you post some code I may be able to more easily point you in the right direction.

@morgan. Ok thanks I have put together a small example project for you to look at. I have an ofxMaxim class that plays a sample and a ofxTonic class that is doing some synthesis. In my testApp I need to be able to mix the 2 classes audio together using ofxDspChain…

This is how I need it to work as in my application I have a lot of audio happening in different classes that need to be mixed together in test app and ofxDspChain is setup to do exactly that.

Would you be able to take a look at my simple example project and maybe offer some suggestions. This would be really beneficial. Maxim’s granular synthesis is really awesome and Tonic’s synthesis sounds incredible. With them playing nicely together one could write some amazing audio devices and applications using oF.

Thanks.

https://dl.dropboxusercontent.com/u/14581304/Tonic-%3EMaxim-Test.zip

@joshuabatty The call to synth.fillBufferOfFloats should happen just once, not inside the for loop. Try doing it like I have it below. It would be pretty easy to wrap the Maxim granular synthesis stuff in a Tonic Generator, so you could use Tonic’s nice patching syntax. We’ll put together some documentation/tutorials on that eventually, hopefully.

//--------------------------------------------------------------
void AudioTonic::audioRequested (float * output, int numFrames, int nChannels)
{
synth.fillBufferOfFloats(output, numFrames, nChannels);
}

@morganpackard Brilliant! thanks for having a look over that for me. Stupid mistake, i really should have picked up on that myself. taking it out of the for loop did the trick and now I can mix Maxim and Tonic together. Would be really interested eventually to see an example of Maxim being wrapped into a tonic generator but for my purposes right now I should be able to fully integrate Tonic into my application seamlessly enough. Thanks again.

Sweet! I didn’t have the patience to actually get your app to compile. Would love to see what you’re working on if you feel like sending me a mac binary that’ll run on 10.7.

-Morgan

Hi Morgan, I’ve attached a compiled binary for 10.7 that has Maxi granular and Tonic FM synth working together. I striped it right back so its a lot more basic than the final version but would like you to take a look at something.

In the bottom left GUI window I have buttons that allow you to change Tonic synthesis presets. When I change presets you can hear an audible *click* when the params instantly jump to a new position. Could be useful if Tonic implemented quick declicking float transitions to eliminate jumps that result in non 0 crossings… Are there any plans for implementing this sort of thing?

Thanks.

https://dl.dropboxusercontent.com/u/14581304/Tonic-Maxi.zip

Sorry one more thing. Is it possible to retrieve any of the generators as a float? Im trying to sync up say the value of Modulation Index or the Amplitude to then control visual parameters. Since Modulation Index and Amplitude also have applied to them LFO’s it would be nice to be able to get the value of the generator. Otherwise I can emulate the synthesis calculation in my draw code but because I am using a new sin() instead of SineWave() in tonic the phases are off and really cant achieve a convincing sync.

I know you said previously that Tonic doesn’t return any floats and only operates on buffers of floats but is there anyway this could be an option to do. As long as the user was prepared to cop whatever efficiency loss from calling a getter function then at least the tightest synchronisation would be able to occur between Tonic and any openGL animations. thoughts? …

@josh Excellent questions, and I’ve got good answers for you. Any chance you could post those questions to the Tonic audio google group?

https://groups.google.com/forum/#!forum/tonic-audio-users

@morgan… Awesome glad to hear there is some good news on this front, just posted the above questions in the google group. eagerly await your reply.