Welcome

Welcome to Teragon Audio, provider of audio plugins, utilities, and guides for those looking to develop their own audio software. This is the development blog, if you are looking for the official website please visit http://www.teragonaudio.com.
Showing posts with label teragonguicomponents. Show all posts
Showing posts with label teragonguicomponents. Show all posts

Death to boilerplate

I made some good progress on ExtraNotes yesterday, it can now save the note correctly and serialize the image data to a base64-encoded string. It's pretty much ready to be released, but when I was testing it I realized what a pain in the ass it's going to be to make it compatible with all hosts. Text input in VSTs is always somewhat tricky, since many hosts like to intercept the keystrokes for themselves. Anyways, I'm just going to test under the ones that I already have, and wait for the bug reports to trickle in. :)

In doing the XML serialization work, I had the idea to make a common base class for the Teragon plugins, since they all have a bunch of identical boilerplate code in them. This wasn't such a bother for the parameter handling, since all of those functions were simple one-liners, but the serialization routine was starting to get rather complex and it pained me to keep copy-pasting it between plugins. So, I introduced a new abstract base class which extends AudioProcessor and takes care of all the PluginParameters related stuff. Doing this eliminates a ton of boilerplate code from all the plugins, making them much simpler to maintain and understand.

Also, today I fixed a nasty bug in NotNotchFilter where a small (but audible) click could be heard when moving from bypass to filter states. The reason for this is that the first "tick" of the knob ended up being a few hundred Hertz, which is quite an extreme difference to apply suddenly to a filter. Exponential scaling didn't work very well in practice for NotNotchFilter, because the frequency range goes from 0-20kHz, so the first half of the knob's motion would only cover ~10Hz, and the second half would race through all remaining frequencies.

So today, I busted open the venerable yet forgotten "Grapher" program which ships with Mac OSX. I discovered (or perhaps forgot) that one of the lesser-known features of this program is that you can generate a point set, and then interpolate through them. So I crafted a curve which would work well with the knob's range, and generated a 5th-degree polynomial equation to fit the points. The result is that now the knob is very comfortable to use, and the click is gone! I'll probably need to generate another set of curves for HiLoFilter, which has a similar problem but a different knob action.
Yay for math!

PluginParameters improvements, and introducing ExtraNotes

This morning I intended to "briefly explore" a concurrency bug in PluginParameters which had been bothering me ever since I started porting TeragonGuiComponents over to Windows. Although the demo ran great, and the framework required very little work to port to Windows, I was annoyed that the demo app was crashing on shutdown. This might normally be forgivable for a desktop app, but for a plugin this means that removing it from a channel will crash the host, so it's kind of a big deal.

Anyways, my "brief exploration" resulted in a full day of hacking PluginParameters, but at least now I've bumped the version to 3.0 and fixed a ton of bugs in the process. Also I renamed several classes in the library, since some classes were starting to get quite verbose (namely, ThreadsafePluginParameterSet is now ConcurrentParameterSet, which is still quite long but overall better). Unfortunately some concurrency bugs are still lurking in the framework, mostly having to do with calling set() or delete on a ConcurrentParameterSet directly after creating it. I would really like PluginParameters to be able to guarantee to the user that it is ready to do anything after the constructor returns, but unfortunately this is in practice very difficult to accomplish.

The good news is that in practice, a plugin should never need to call set() or delete on a parameter set immediately after creating it. However, I dislike shipping code with known bugs, no matter how small.

Anyways, I also made some progress yesterday on ExtraNotes, which is the renamed version of AUNotes. This will actually be the second time I've renamed the plugin; the name before AUNotes was "Notepad", which I think is far too generic and has poor search visibility. This name change reflects something bigger and more exciting -- the dropping of the "AU" from the plugin.

ExtraNotes will actually have an AudioUnit version, but unlike its predecessors, it will be available for other plugin containers (namely VST) and operating systems. A Windows/Linux port of this plugin has been on my wishlist for many years now, and I'm glad that I could finally do this using Juce and TeragonGuiComponents. Here's some preview screenshots:

Editing a note
Images are finally supported!
Yes, that's right! ExtraNotes will support importing images and store them in the note for you! This has been a looooong requested user feature, and using the Juce image framework, it actually wasn't terribly difficult to accomplish. The plugin will support two "tabs", so you can have both text and a single image. You can also import a text file from disk into the text tab, in the exact same way that you can load an image to the image tab.

Currently the plugin does not serialize the image during state save/restore, and although the text notes should, it's completely untested. I'm not sure how well Juce's XML serializer will deal with raw binary data like this, and I might need to serialize the image myself into a series of integers (yuck, let's hope it doesn't come to that).

So yeah, today I had originally planned to do Windows porting, and to be fair I did do some. The PluginParameters test suite now builds and runs on Windows, which is a big improvement, and the TeragonGuiComponents demo also is running on Windows without crashing (yay). However I probably won't have time to build Windows versions of the other plugins I did over Christmas, which means that I will probably end up doing a huge batch of releases sometime shortly after New Years.

We wish you a GUI Christmas

Please forgive the kitschy title, I have never really gotten much into the Christmas spirit. Anyways, I'm stuck in Stockholm this Christmas, thanks to a last-minute flight cancellation, but I'm making the best of it. Hence, the enormous progress made on TeragonGuiComponents and associated plugins in the last few days. And really, a few uninterrupted days of coding, what more could I possibly ask for?

Yesterday I made big progress doing GUI work for several plugins. Now that I've pinned down a good workflow for doing layout with Pixelmator/Introjucer, I can really just bang them out. Specifically, I finished new GUIs for BeatCounter, HiLoFilter, and NotNotchFilter. I did some casual testing with 64-bit Ableton Live and all of the plugins seem to perform beautifully with their new shiny GUIs. I expect that I will have released new versions of each of these plugins by the end of the week.

I also busted out the old Windows laptop and fixed a few minor issues and got TeragonGuiComponents building with Visual Studio 2013. However, my idea of a nice and relaxing Christmas doesn't exactly include fighting with the retardedness that is Windows development, so I'll likely wait a few days before attempting to port and release the above plugins.

Today I made a GUI for ChaosChimp, a plugin I haven't talked about much here. It's still in beta but will be ready for a 1.0 release soon. Inspired by the Netflix Chaos Monkey, the plugin is designed to make bad things happen to your sequencer. Why on earth would anybody want this? Well, I see ChaosChimp having two main uses:

  1. Providing a tool for sequencer developers to simulate naughty plugins in their host.
  2. For DJs/Performers to simulate bad things happening to their computer and react accordingly.
That second point is originally why I developed the software. As technology improves, music setups become more complex, and the more complex things get, the more likely they can go wrong. Having backup plans can be the difference between a small glitch and an embarrassing evening.

For instance, one of the things ChaosChimp can do is attempt to crash the host. An easy "backup" for this is having an iPod (or whatever) playing on shuffle on a muted mixer channel. So instead of freaking out when something crashes, one can calmly cross-fade to the MP3 player and restart the sequencer in the meantime. It won't be the best mix of the evening, but it sure beats 60 seconds of silence, right? :)

Anyways, ChaosChimp currently has five different chaos providers, and some basic controls to how often and long the chaos lasts. Before today, this could only be controlled with the sequencer's built-in sliders, but with the new TeragonGuiComponents I was able to whip up a fully-functional GUI in about 2 hours (yes, I timed it).

Enter the chimp
Expect a 1.0 version (along with the releases of the other plugins) sometime after Christmas.

TeragonGuiComponents hits 1.0!

Today I am pleased to announce the first official release of TeragonGuiComponents! I spent some time today busting a ton of bugs and polishing up each of the widgets, the documentation, the demo app, and graphic resources. Here's the new demo app:


Forgive the cheesy window decorations, that's just the way Juce renders standalone apps and this won't be present for VST plugins. I will be making an official page on the Teragon site soon, in the meantime you can grab the 1.0 code from GitHub and check out the components and graphics.

In case I haven't given him enough credit (and he really deserves more!), the graphics were done by Max Rudberg, who agreed on licensing the work as Creative Commons. If you would like to use the graphics in other projects, you are free to do so but please give both Max & I credit (I == Teragon Audio, in this case).

Text for everybody!

Today I implemented a StatusBar component in TeragonGuiComponents, which shows the current value of a parameter as it is being modified or moused over. The component was quite easy to write thanks to the flexible architecture of PluginParameters and the power of Juce. The entire implementation is only 71 lines of code!

In these 71 lines, the component takes in a PluginParameterSet and registers itself as a listener on all parameters. However, it only shows updates for parameters which are not BooleanParameters (since the button states are already quite obvious IMHO), and have at least one other component listening (to avoid displaying updates for internal parameters). The status bar is two lines and displays the parameter name on top with the formatted value on the bottom.

In addition to displaying parameter values when a component is being modified, it can also display the current value when the user mouses over the control. For this part to work, it requires all parameters in the GUI to add the StatusBar as a listener after construction. This could theoretically be done automatically, but doing so would require things to be instantiated in a certain order, which is difficult to guarantee when building GUIs using the Introjucer.

As a final touch, the text field is cleared after about a second of visibility, along with a subtle fade-out.

I have decided to postpone building any bitmap fonts for the time being, given that I got relatively nice results out of Juce's default monospace typeface. I think that I'll implement this in the future should the need arise, which primarily means overriding juce::Font and adding proper ellipsizing rather than scrunching the text together in a nasty mess.

More GUI improvements

Spent a bit of time last night ironing out bugs in TeragonGuiComponents, namely those mentioned in the previous post. I'm pleased to report that everything is running silky smooth! The concurrency issues turned out to be an easy Juce-related fix (it was apparently upset about me delivering GUI updates from the non-GUI thread), and the glitchy controls were a simple matter of unifying all components to use ranges of 0.0-1.0, similar to VSTGUI.

Next, I will make a few minor cleanups in TeragonGuiComponents, and then tag it with a 1.0 release and start building (and finishing) GUIs for the plugins! However, there are still a few unresolved issues, namely typefaces and parameter values.

In the former case, Juce has extremely ugly typeface rendering (but shhhhh, don't tell Jules I said that!), and I need a solution for fonts. Non-fixed-width fonts are going to be difficult, since Juce's internal typeface classes are a bit lacking and I'm not too eager to use a third-party TrueType library. However, such fonts are mostly needed in the background image, so they can just be added in Photoshop.

For fixed-width fonts, I'll probably go for some LCD-ish solution and build a filmstrip, this approach has served me well in the past. However my past plugins only supported basic ASCII typefaces, and this is kind of stupid today. I'd prefer to have a typeface with full UTF-8 support, but I need to first see how large such a filmstrip would be.

For parameter values, I was thinking about having tooltips, but then I realized that this would again rely on Juce's ugly font rendering. Instead I think I will make another component to show parameter status, in a matter similar to the Virus Control plugin (the 2-line LCD display on the bottom). No Virus users (or at least none that I knew of) ever complained about this UI pattern, it allowed us to make very simple knobs and a minimal UI while still having very technical information available in the plugin.

Back in the saddle

After a very long (and necessary) break, I've started doing a bit of Teragon hacking again. I've picked up mostly where I left off, which is at TeragonGuiComponents. After making a release of PluginParameters with the new multi-threaded features, I have started updating the demo app in TeragonGuiComponents to use the new threadsafe API. I'm still finalizing the component API, but I have also introduced a common base class for components in the package which removes a lot of boilerplate and duplicate code.

After two evenings of work, I have got the demo app building and partially running with the multithreaded parameter sets! However, the key word here is "partially"; unfortunately components which share the same parameter "fight" to update the value, which is a sign that the parameter value is not being passed correctly to the components. Also I got a ghost crash which seems to have been spawned by the event dispatched thread, though the stacktrace doesn't indicate any traces of my own code, which is a bit odd.

Anyways, my goal for the evening was just to get everything updated and compiling again, so I haven't even started digging into debugging these problems. I don't think it will be so hard to fix these errors, but then again, everything involving multithreaded code tends to be a rabbit-hole of debugging. Let's hope that isn't the case this time. During the summer, I already put in the hard hours getting PluginParameters to be threadsafe, and once I reached the end of that journey I was 99% certain it was threadsafe, given the usage parameters which I defined in the documentation. If there are other race conditions or problems, it's likely not to be a simple one-liner fix in PluginParameters, so let's hope it doesn't come to that.

Also, on a frustrating sidenote, I fixed another compiler error in tinythread, only to discover that all of my previous pull requests on gitorious have remained unmerged. I guess I'm not terribly surprised, given that when I forked tinythread, I recall seeing at least one very ancient pull request sitting in the queue. However, I naively hoped that the author would take a look at my fixes/improvements and merge them in, but this hasn't been the case. If the author doesn't seem interested in maintaining this project, I'll likely move my fork from gitorious to github, since gitorious is a bit awkward to work with.