Creating synth presets in Clojure

To speed up the creation of and maintenance of synth presets for rogue I created a little tool called rogue-presets. It is written in Clojure and provides a declarative way to write synth presets for the rogue synth.

The basic idea is that incremental changes to the synth defaults are stacked and merged and written out into LV2 preset files.

Here is a simple example

(def two_oscs
  (merge defaults
         (osc1 :level 1 :level_a 0.5)
         (osc2 :level 1 :level_a 0.5)))

(defpreset lead-pulse1 "Pulse Lead 1"
  two_oscs
  (osc1 :type pulse :width 0.25 :fine -0.05)
  (osc2 :type pulse :width 0.75 :fine 0.05)
  (filter1 :freq 440 :type lp_12db :q 0.2 :level 1)
  (env1 :attack 0.01 :curve 0.7)
  (env2 :attack 0.1 :sustain 0.25 :curve 0.7)
  (modulations [mod_env2 mod_flt1_freq 0.6])
  (reverb-fx))

and here a more complex one

(defpreset pad-arctic "Arctic Pad"
  defaults
  (osc1 :type fm1 :level 1)
  (osc2 :type saw :level 1 :coarse 12 :out_mod 2 :level_a 1) 
  (filter1 :type svf_lp :freq 220 :q 0.3 :level 1)
  (env1 :attack 0.3 :sustain 0.6 :release 1.2 :curve 0.7)
  (env2 :attack 1 :sustain 1 :release 1.22 :curve 0.7)
  (lfo1 :type lfo_tri :freq 2)
  (reverb-fx :bandwidth 0.75 :tail 1 :damping 0.25 :blend 0.75)
  (modulations [mod_lfo1 mod_osc1_pitch 0.2]
               [mod_lfo1 mod_flt1_freq 0.2]
               [mod_lfo1 mod_osc2_amp 0.2]
               [mod_env2 mod_flt1_freq 0.8]))

The general order is base settings, oscillators (osc1-4), filters (filter1-2), envelopes (env1-4), lfos (lfo1-4), effects and modulations.

The modulations section contains triples of source, target and amount. For example [mod_lfo1 mod_osc1_pitch 0.2] declares that lfo1 modulates the pitch of osc1 by 0.2.

I am still experimenting with this approach, but it feels promising.

rogue stabilizing

My current freetime project rogue is stabilizing. I converted the grid based UI into something more classical. The top bar copies a Minimoog style division and the lower level features tabs for common settings, envelopes, lfos, the modulation matrix and effects.

Screenshot from 2013-08-10 17:40:27

I am not yet very happy with the colours of the GUI, but the division makes IMHO more sense than a grid. Waldorf Largo uses a similar layout but with different knob sizes and lots of eye candy.

Featurewise osc sync and global lfo usage are still missing. Most of the other pieces are already there.

See the project page for usage instructions https://github.com/timowest/rogue/blob/master/README.md

Full visualizations

The component visualizations for oscillators, filters, envelopes and LFOs are now ready. The real DSP elements are used in the GUI to provide a realistic rendering of the component output. For oscillators and lfos a single wavecycle is shown and for envelopes a scaled envelope cycle from attack to finish is drawn.

For the filters fftw is used to calculate the FFT of the filter impulse response and a scaled version of the power spectrum is then drawn. I have yet to test if the FFT calculation is fast enough, but it looks quite decent.

In addition to the component visualizations, labels with knob values have been added. Now the exact values of all the ports are visible in the UI. It makes the UI a bit more crowded, but is hopefully more useful then the browser approach of ElectraX. The knob + name + value combination is also used in Curve.

Here is a screenshot

rogue

Sketching a new UI

After having worked out most of the lower level audio processing components in rogue I started to improve the GUI.

I wanted to customize the appearance of the Gtk GUI, but had some problems to apply theming so I considered looking at Qt as an alternative. I was quickly convinced by Qt and converted the full GUI to Qt.

All in all the advantages of Qt over Gtk are

  • easier theming, at least compared to Gtk 2.*
  • better designer tools
  • a dial widget to start from
  • C++ based programming model

Some disadvantages are

  • integer range for dial widget
  • build time metamodel and C++ syntax extensions

For the UI the main inspirations are ElectraX and Curve.

The UI is quite flat and I tried to make it usable and informative. Here is a sketch of the current state

rogue

I might still slim it down to something like this

rogue

The modulation part is not yet very usable and there is lots of empty space, but otherwise I am quite content with the current state.

Plotting waveforms

I am currently working on a new softsynth project and wanted to get some more immediate feedback of code changes to waveforms shapes, since most of the synthesis used in rogue are related to phase/waveform shaping.

Instead of plotting the waveforms via scripting tools like python or ruby, I decided to use Javascript for it. I set up a minimal table structure in the HTML document and plotted the waveforms via jquery, Flot and various phase to wave functions.

The HTML file is available here and it looks like this

waveforms

The waveforms are categorized by synthesis types: VA for virtual analog, PD for Casio CZ style phase distortion, EL for various electronic waveforms and AS for additive synthesis.

The width controls the pulse width or distortion of the waveform and the tone field controls the brightness for additive synthesis. This combination gives me the possibility to try out new waveforms easily.

The functions used in the plot are referenced in the HTML document and take three arguments, the phase, the width and the tone. All parameters are from 0 to 1. The waveform plots are for 1.5 cycles.

Typed Lisp adventure

After having been inspired by overtone and extempore to try out a Lisp dialect for DSP coding I wondered if it would be possible to use a Lisp language directly in synth plugins without a host environment.

My second (or third) language in daytime programming is Clojure, which I am very content with, so I wanted to use something similar in my “freetime” for DSP programming. I initally tried some Scheme dialects such a Chicken, Gambit and Bigloo, but became a little annoyed by the verbose syntax and the lack of proper abstractions for collection like types.

On GitHub I stumbled upon a few statically typed Lisp dialects and was especially convinced by looking at extempore that writing a statically typed LISP was possible and for some programming domains even useful. So I decided to write something similar like extempore, but with Clojure syntax instead of Scheme and without a host environment but gcc based compilation instead. I named the exercise symbol.

I considered using LLVM as the compilation backend briefly, but found especially closure handling too difficult to handle, since I hadn’t any prior experience in compiler programming. I went with using C++11 as the target language since it has some nice features such as templates, closures, direct C bindings and fast compilers.

Next I began to sketch the architecture for my language compiler. After a few iterations and studying various Clojure/script compilation projects I went with

  • reading via a customized Clojure Lisp reader
  • macro expansion, using Clojure macros
  • form normalization via various function based rules
  • type inference using core.logic
  • serialization to C++
  • compilation via g++

The most challenging part was probably the type inference. Having used logic programming actively 10 years ago it was a little difficult to get into logic programming concepts again, but after a few core.logic performance issues, most things went quite smoothly.

I was able to infer variable types based on assignments and function argument and return types via body expressions using a simplified version of the type inference. In addition to Hindley-Milner type inference I also extended the set of literals of the syntax via a custom reader to support integer and float literals in addition to ones Clojure supports.

I was quite successful with porting simple extempore examples to symbol, but struggled with more complex programs. I also couldn’t decide whether to include garbage collection or not. Using smart C++ pointers might have been a good alternative, but might have been difficult for type inference, so I continued with raw pointers and without garbage collection.

I tried to use C++ bindings directly via gccxml which dumps the intermediate format of the gcc compilation via XML, but had some issues with it. gccxml doesn’t support templates and the XML format was difficult to transform into a form that was compatible with the types of the type inference.

Another difficult issue was to map both stack and heap allocation to the minimal syntax of symbol. After a while I gave up and began to use C++ directly for DSP programming. All in all this was a really interesting experience to sketch a new language, or better a compilation chain, since what I did could also be described as mapping a subset of Clojure syntax to C++. I might continue with symbol once I am more familiar with C++, but for now it’s suspended.

Various syntax examples are available here.

Diving into D

After having used C++ and Faust for a while to write Synth plugins I decided to try out some alternatives. My main requirements for the language were automatic memory management, easy to use bidirectional C interfacing for using and exposing C libraries and support for functional programming. I considered amongst others OCaml, Haskell, D and Vala as language options. After a small evaluation of the options I decided to focus on D. OCaml didn’t look like a proper evolution over Standard ML, Haskell too demanding to learn and Vala with too many Gnome dependencies.

D is a statically typed C-based language with the ambitious goal to provide a better C++. It feels more consistent than C++, but sits oddly between a system and application level language. As a small exercise I ported the STK library to D to get a better feel of the language features. I named the port synd.

What I liked were the module system, properties, type inference and integrated support for unit tests. What I found confusing were mutability of ranges, initialization of members and the quite heterogeneous community. Missing support for shared library creation in Linux is a showstopper for now.

I am still trying to figure out whether to use closures for lower level elements or Class based objects. The FP approach allows for more consistent types and composition of elements whereas the OOP approach offers better separation between configuration and other method calls.

Cascaded delegate construction would also work in D. And it works quite well for elements where only static and sample based configuration parameters are used. For configuration updates let’s say every 32 samples something else would need to be used.

Both extempore and Overtone look like good sources of inspiration for doing functional audio coding.