Fixed a ton more warnings in MrsWatson and actually attempted to fix some real bugs today! Inspired by a pull request I received, I changed the plugin chain so that each plugin has its own separate buffer for writing to. This should hopefully fix a lot of the problems which arise from channel count mismatches -- such as feeding a mono file to a 16-output effect plugin.
I felt a bit bad about re-writing the original pull request, since I consider it quite an honor to get a pull request from someone who cares enough about your project to fix bugs in it. However the original pull request had a few big problems, namely that it removed several unrelated tests in LinkedList (for reasons which were not entirely clear to me) and also that it was failing the test suite (the original author claimed it passed on his machine, I can believe that since I was testing on a different platform).
The author had planned to rewrite and resubmit the patch; instead I took his idea and made a much smaller patch. I've pinged him for feedback on the patch, let's hope that it fixes the bug and nobody's feelings are hurt. :)
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.
Picking up MrsWatson again
After a loooong break, I've started working on MrsWatson again, since the bug reports are starting to pile up and I've actually got some real pull requests coming in. My last attempt at MrsWatson hacking was quite frustrating, trying to port audiofile to Windows and rip out all the AIFF/WAVE code, which is still something that has to be done.
Anyways, I've started a bit more modestly this time, mostly by fixing a ton of inspections in AppCode, compiler warnings, and various TODOs. The code now compiles without any warnings on Linux, and a few "perhaps unfixable" warnings in Mac that need to be considered.
Anyways, I've started a bit more modestly this time, mostly by fixing a ton of inspections in AppCode, compiler warnings, and various TODOs. The code now compiles without any warnings on Linux, and a few "perhaps unfixable" warnings in Mac that need to be considered.
Release day!
As promised, I finally got around to polishing up and releasing all the plugins I've been working on during the holidays. Specifically, ChaosChimp, NotNotchFilter, and ExtraNotes all got updates pushed. I'm holding back on HiLoFilter because I'm still not happy about the clicking noise which happens around the dead zone.
Anyways, here are some screenshots from the final versions of all plugins. Click on the thumbnails to see a full-sized screenshot:
Anyways, here are some screenshots from the final versions of all plugins. Click on the thumbnails to see a full-sized screenshot:
![]() |
| BeatCounter 2.1 |
![]() |
| ChaosChimp 1.0.0 |
![]() |
| ExtraNotes 3.0.0 (text editor view) |
![]() |
| ExtraNotes 3.0.0 (image editor view) |
![]() |
| NotNotchFilter 2.0.0 |
BeatCounter 2.1 released!
The first of many plugin releases was completed today, I pushed out a zipfile with BeatCounter 2.1. Grab it from the product page, however keep in mind that the CDN takes awhile to propagate files, so mind the filename when unzipping to see that output folder has the correct version.
Filter tweaking
Spent some time tweaking filter curves for HiLoFilter, using the same polynomial interpolation trick I wrote about previously. Grapher is such a neat tool, but unfortunately it's soooo buggy. Oh well, once I get the formulas right, I won't need it anymore.
HiLoFilter is much more usable now, the curves are more performance oriented and give a bit more wiggle room where it matters. That is to say, on the high-pass filter, the curve lets the user select the lower frequency more precisely (and vise-versa). In the process, I've also reduced some of the clicking that HiLoFilter produces when shifting filter state, but unfortunately it's not completely eliminated. I'll need a lot more debugging time to figure out exactly why that is happening, because it's definitely there but not much harder to reproduce.
HiLoFilter is much more usable now, the curves are more performance oriented and give a bit more wiggle room where it matters. That is to say, on the high-pass filter, the curve lets the user select the lower frequency more precisely (and vise-versa). In the process, I've also reduced some of the clicking that HiLoFilter produces when shifting filter state, but unfortunately it's not completely eliminated. I'll need a lot more debugging time to figure out exactly why that is happening, because it's definitely there but not much harder to reproduce.
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.
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! |
The return of Arooo
Did a bit of work on ExtraNotes today; last night I had a revelation about how to solve the problem of the GUI not updating properly when audio playback is paused. The solution is actually quite simple -- ConcurrentParameterSet should have pause/resume methods which are called when the playback is paused/resumed, and when paused, all realtime parameter changes are executed right away. Since playback is paused, the risk of priority inversion (which, for the record, is the reason that ConcurrentParameterSet is so damn complex) does not exist and the parameter updates can be safely executed.
The solution worked like a charm, and I am thinking about doing a bit of minor re-architecting in PluginParameters so that other plugins can use this solution per-default. As it stands, the other plugins which use ConcurrentParameterSet don't really need to execute parameter changes when playback is paused, so it's not such a big deal.
Yeah, at this point I'm now sitting on 4 plugins which are essentially finished, but haven't been released. The reason I haven't done any proper releases of these plugins is mostly laziness -- doing releases means getting out a bunch of different laptops, making builds, doing sanity checks, making the zipfiles etc. It's not hard work, but it's labor-intensive and takes time. Since I've got such a great creative burst going these days, I'm reluctant to blow it on the mindless repetitiveness on releasing software. But I promise that will change soon, and shortly after New Year's, I will make a huge release day and push everything out "into the wild".
On the subject of creative streaks, I started looking at Arooo again, and am now hacking it into plugin form. Arooo is a standalone app I did at last year's MusicHackDay Stockholm, and it was primarily intended for trying to stop a bad habit that our puppy was developing -- howling when I left the house. The software would open the default audio device, look for sounds which roughly matched the frequency signature of the howls, and then play a nasty noise if detected. The hack was easily done in the required 24 hours for the hackathon, and it was fun to demo.
Surprisingly, when I put Arooo into action, it did very well. I set the program up to log events to the screen, and then recorded the audio when I was gone and cross-referenced them against each other. It showed real promise, detecting the input noises at very high reliability. I haven't done much with the software since then, but I have been meaning to generalize it and make it into plugin form. When finished, the plugin will:
The solution worked like a charm, and I am thinking about doing a bit of minor re-architecting in PluginParameters so that other plugins can use this solution per-default. As it stands, the other plugins which use ConcurrentParameterSet don't really need to execute parameter changes when playback is paused, so it's not such a big deal.
Yeah, at this point I'm now sitting on 4 plugins which are essentially finished, but haven't been released. The reason I haven't done any proper releases of these plugins is mostly laziness -- doing releases means getting out a bunch of different laptops, making builds, doing sanity checks, making the zipfiles etc. It's not hard work, but it's labor-intensive and takes time. Since I've got such a great creative burst going these days, I'm reluctant to blow it on the mindless repetitiveness on releasing software. But I promise that will change soon, and shortly after New Year's, I will make a huge release day and push everything out "into the wild".
On the subject of creative streaks, I started looking at Arooo again, and am now hacking it into plugin form. Arooo is a standalone app I did at last year's MusicHackDay Stockholm, and it was primarily intended for trying to stop a bad habit that our puppy was developing -- howling when I left the house. The software would open the default audio device, look for sounds which roughly matched the frequency signature of the howls, and then play a nasty noise if detected. The hack was easily done in the required 24 hours for the hackathon, and it was fun to demo.
Surprisingly, when I put Arooo into action, it did very well. I set the program up to log events to the screen, and then recorded the audio when I was gone and cross-referenced them against each other. It showed real promise, detecting the input noises at very high reliability. I haven't done much with the software since then, but I have been meaning to generalize it and make it into plugin form. When finished, the plugin will:
- Allow the user to load in an audio file for profiling
- Process audio in realtime, searching for signals which match the profile
- Set a "tolerance" for how close the input signal must match the profile
- Trigger an event when the input signal matches, which can include:
- Playing another sample (could be used to build a drum-replacement sampler)
- Playing a MIDI note
- Sending a MIDI CC message
- Executing a shell script
After one day of hacking, I made a basic GUI and re-architected some of the initial hackathon code to be a bit more generic. I still need to generalize the profiling algorithm, which was the key part of making Arooo work.
Nearing release day
My girlfriend is in town for New Year's, so I haven't been hacking much (gotta appreciate the better things in life, you know). We were also supposed to spend Christmas together, but due to some screwed-up travel plans things didn't work out... and hence, my huge hacking spree during the holidays. Anyways, I have done a bit of work on the plugins during her time here, since she also needs to study for exams.
I have managed to get all of the plugins building on Windows and Linux, and now have 32/64-bit builds on all three platforms. As usual, Windows proved to be the problem child of the lot, and I needed to make two more patches to tinythreadpp to get it building on 64-bit Windows. Actually building on Windows isn't nearly as painful as doing anything git-related on Windows, due to the horrendous command-line situation on that platform.
As expected, porting to Linux was trivial given that they built on Mac OSX; it was just a matter of pointing GCC to the correct source paths and sorting out the compile flags for C++11 support. At any rate, I just need to zip up and organize the binaries and then put out the word. Quite a nice way to start out 2014, I think.
Using the Renoise demo, I was able to test out the Linux plugins (MrsWatson has experimental GUI support, but it's not realtime, so it's not suitable for doing actual GUI testing). Although Renoise is in general a rather difficult host to learn, dropping the plugins on the master channel is not terribly difficult, and I was pleased to see how well things worked out of the box. Text editing, graphics importing, etc., all worked. Normally this GUI-type stuff is always a complete pain with Linux, but apparently not with Juce!
However, there is one problem, which is that the GUI for ExtraNotes should behave a bit differently than a realtime-audio plugin, and for this reason the GUI "seems" a bit unresponsive, even though it's simply because the realtime event loop isn't being processed. I need to solve this problem, which I don't think will be terribly difficult.
I have managed to get all of the plugins building on Windows and Linux, and now have 32/64-bit builds on all three platforms. As usual, Windows proved to be the problem child of the lot, and I needed to make two more patches to tinythreadpp to get it building on 64-bit Windows. Actually building on Windows isn't nearly as painful as doing anything git-related on Windows, due to the horrendous command-line situation on that platform.
As expected, porting to Linux was trivial given that they built on Mac OSX; it was just a matter of pointing GCC to the correct source paths and sorting out the compile flags for C++11 support. At any rate, I just need to zip up and organize the binaries and then put out the word. Quite a nice way to start out 2014, I think.
Using the Renoise demo, I was able to test out the Linux plugins (MrsWatson has experimental GUI support, but it's not realtime, so it's not suitable for doing actual GUI testing). Although Renoise is in general a rather difficult host to learn, dropping the plugins on the master channel is not terribly difficult, and I was pleased to see how well things worked out of the box. Text editing, graphics importing, etc., all worked. Normally this GUI-type stuff is always a complete pain with Linux, but apparently not with Juce!
However, there is one problem, which is that the GUI for ExtraNotes should behave a bit differently than a realtime-audio plugin, and for this reason the GUI "seems" a bit unresponsive, even though it's simply because the realtime event loop isn't being processed. I need to solve this problem, which I don't think will be terribly difficult.
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:
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.
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! |
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:
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:
- Providing a tool for sequencer developers to simulate naughty plugins in their host.
- 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.
Tags:
beatcounter,
chaoschimp,
hilofilter,
notnotchfilter,
teragonguicomponents
Posted:
Tuesday, December 24, 2013
More GUI stuff
I spent a bit of time in Pixelmator today cleaning up the template document. I think that the template was a good idea, as it allows one to do GUI layout very rapidly. Each component is now grouped, making it easier to move around and position relative to other components. I also added an alignment layer for each component, so one can quickly do pixel-perfect positioning from Introjucer.
The result of this work was redoing the demo app for TeragonGuiComponents and doing a new GUI for HiLoFilter. I decided to redo the demo app GUI because when working on the template document, I noticed that label opacity and component positioning were incorrect. The original GUI for HiLoFilter was made without the template document, and it was actually faster to redo it using the template then it would be to retrofit it with the alignment guides.
It took me some time to get HiLoFilter compiling again, it seems that every time I open up a plug-in, I run into problems with some library or another not compiling under whatever the latest version of Mac OS X is. However, it is fruitless to simply curse Apple, instead one must fix the errors and raise the minimum supported OS version. This means that when all of the plug-ins have been updated with their shiny new GUIs, the minimum required Mac OS version will be OS X 10.7 (Lion).
I personally wish that I could still support Snow Leopard, however Apple is making it increasingly difficult for users to lag behind on older versions of Mac OS, which I suppose isn't such a bad thing. However, I personally haven't made the upgrade to Mavericks myself, as I'm still waiting for many plug-ins and sequencers (namely Ableton Live) to be supported. It's a bit of a Catch-22 situation.
On the plus side, I will be able to ship the 64-bit versions of all plug-ins, thus ensuring that they will be compatible with the latest version of Logic Pro X.
The result of this work was redoing the demo app for TeragonGuiComponents and doing a new GUI for HiLoFilter. I decided to redo the demo app GUI because when working on the template document, I noticed that label opacity and component positioning were incorrect. The original GUI for HiLoFilter was made without the template document, and it was actually faster to redo it using the template then it would be to retrofit it with the alignment guides.
It took me some time to get HiLoFilter compiling again, it seems that every time I open up a plug-in, I run into problems with some library or another not compiling under whatever the latest version of Mac OS X is. However, it is fruitless to simply curse Apple, instead one must fix the errors and raise the minimum supported OS version. This means that when all of the plug-ins have been updated with their shiny new GUIs, the minimum required Mac OS version will be OS X 10.7 (Lion).
I personally wish that I could still support Snow Leopard, however Apple is making it increasingly difficult for users to lag behind on older versions of Mac OS, which I suppose isn't such a bad thing. However, I personally haven't made the upgrade to Mavericks myself, as I'm still waiting for many plug-ins and sequencers (namely Ableton Live) to be supported. It's a bit of a Catch-22 situation.
On the plus side, I will be able to ship the 64-bit versions of all plug-ins, thus ensuring that they will be compatible with the latest version of Logic Pro X.
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).
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.
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.
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.
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.
Coding break
Haven't had the chance to do much code these days, my wrists and fingers have been killing me.
HiLoFilter GUI preview
HiLoFilter will be the next plugin to receive a GUI with the new TeragonGuiComponents kit. Here's a preview of the layout:
Making PluginParameters threadsafe
One feature of TeragonGuiComponents is that it uses PluginParameters as the engine for syncing parameter changes. This is very convenient, as it means that all the controls automatically understand the correct parameter ranges, and can also be associated with a parameter needed by the audio engine.
However, PluginParameters is not really thread-safe, which so far hasn't been a big issue since it has been mostly used in GUI-less plugins. I'm not sure if anybody outside of Teragon is using the library, a few people have forked/starred it on GitHub but that doesn't mean much.
Each component "registers" for a parameter, meaning that it is capable of both setting parameter values and also updating the component graphic based on parameter state. Since the observer interface is pretty simple, it means that components will end up notifying themselves whenever they try to set a parameter! Furthermore, there is the ever-present risk of data corruption since the parameter is shared directly between the GUI and audio threads.
So, PluginParameters is currently being adapted for use in a multi-threaded environment. This is fairly non-trivial, since non-blocking data structures must be used instead of mutexes. Mutex blocks threaten to cause priority inversion, forcing the audio thread to wait on the slower GUI thread.
The new architecture will thus look something like this:
However, PluginParameters is not really thread-safe, which so far hasn't been a big issue since it has been mostly used in GUI-less plugins. I'm not sure if anybody outside of Teragon is using the library, a few people have forked/starred it on GitHub but that doesn't mean much.
Each component "registers" for a parameter, meaning that it is capable of both setting parameter values and also updating the component graphic based on parameter state. Since the observer interface is pretty simple, it means that components will end up notifying themselves whenever they try to set a parameter! Furthermore, there is the ever-present risk of data corruption since the parameter is shared directly between the GUI and audio threads.
So, PluginParameters is currently being adapted for use in a multi-threaded environment. This is fairly non-trivial, since non-blocking data structures must be used instead of mutexes. Mutex blocks threaten to cause priority inversion, forcing the audio thread to wait on the slower GUI thread.
The new architecture will thus look something like this:
- A new EventDispatcher class will be responsible for setting parameter values.
- A low-priority background thread will be used for asynchronous events. It will have its own dispatcher.
- The audio thread will also "own" a dispatcher, and it will process events synchronously during the process() call.
- Parameters can be set from either the realtime audio thread or the asynchronous background thread. In both cases, the dispatcher will notify all observers of the same type first, and then send the event to a non-blocking event queue on the other thread.
Preview of NotNotchFilter GUI
NotNotchFilter will have the honor of being the first plugin redone with the new TeragonGuiComponents graphics kit. Here's a preview screenshot:
A new look and feel for Teragon plugins
Earlier this year I started a project with Max Rudberg, a fantastic designer who was a former colleague of mine at a past job. The goal of our project was to make a set of themed components for building better GUIs in the Teragon plugins. Well, Max has delivered his kit, and I'm rather pleased with the results. Here's the final mockup Max made before exporting the components:
I have open-sourced the kit under a Creative-Commons license, you can find the components on the Teragon GitHub page.
The component project itself is built on Juce, which is the framework that I'm gradually migrating most of my plugins to. For all of Juce's awesomeness, it has a few annoyances when it comes to graphics:
![]() |
| GUI mockup |
The component project itself is built on Juce, which is the framework that I'm gradually migrating most of my plugins to. For all of Juce's awesomeness, it has a few annoyances when it comes to graphics:
- The fonts, oh the humanity! Juce's font rendering is very poor, for reasons that I've never completely understood. Typefaces, though legible, do not seem to be properly anti-aliased, and do not truncate (ie, ending words with "..."). Instead of truncation, Juce crams all the text together very tightly.
- Workarounds: I will build a filmstrip for fixed width fonts, probably based on Droid Sans Mono, and a custom component to render text. This approach worked reasonably well with older plugins such as KickMaker. Labels with dynamic width text will be embedded into the background image rather than rendered dynamically with Juce.
- Knobs are simplistic and bad looking, like most of the default components which provide very ugly but functional widgets. Juce's knob style is similar to Ableton Live's, which is to say a vector-based image drawn at rotation. For realistic (aka skeumorphic) knobs, a filmstrip must be used instead.
- Workaround: I've built a new knob class which can load in filmstrips. Also I made a few handy shell scripts for stitching filmstrips, since Max exported the knob animation as single frames (which was very nice of him, as I can now choose how smooth I want the animation to be).
- When you insert graphics into a Juce project, it amalgamates them into your editor C++ file. That is, it takes the PNG graphics and turns them into C++ static const char* objects which are compiled directly into the binary. This is extremely convenient, especially on Linux & Windows where one would otherwise need to store such resources somewhere in the filesystem. However, editing that code is a complete pain because the files tend to be huge. Also this makes sharing components between plugins difficult, since the same graphics need to be imported in every project.
- Workaround: I created a single resources C++ class which contains all graphics, and an accompanying cache class which lets you load widget graphics by name. This means that the editor class usually has only one embedded graphic -- the background image. Also this class can be easily used in different plugins, which means that there is some wasted space for any unused graphics but reduces the amount of headache between sharing these graphics.
Subscribe to:
Posts (Atom)












