This week, for my design challenge project, I've been attempting to get started on the sound synthesis engine for my synth, as well as setting up an audio output on my BeagleBone Black. There have been quite a few frustrating evenings in doing this, and while I now finally have synthesised sound coming out of my BBB, it looks like I may need to rethink what library I'm going to use to make my synthesis engine, or redesign and simplify my original idea for the synthesis engine.
USB audio on the BeagleBone Black
Initially I was planning on building my own DAC for the audio output on my BBB, however after looking into the audio IO options on the board I decided that taking advantage of the USB audio support would be the best option.
I tried out a couple of USB audio adapters to use with my BBB, and finally settled on an EC Technology adapter. At first I bought this budget adapter, however the sound quality was really terrible, whereas the EC Technology one sounds just as good (if not a little better) than the built-in soundcard in my MacBook.
A quick visual review of USB audio adapters I tried out
To set up USB audio as the default sound device on my BBB I used this guide. ALSA was already installed on my BBB, and contrary to the guide all I had to do was disable HDMI to make USB audio the system default. This was done by adding the following line to my /boot/uEnv.txt file:
After doing that and rebooting my BBB, any audio I played on my BBB was coming out of the USB audio adapter. However if you're attempting to do that same I recommend reading the whole guide incase you need to do the extra steps.
The Synthesis Library
As stated in the proposal for my project, I've been planning on using the C++ audio synthesis/DSP library Maximilian to develop the synthesis engine. While I have never used it before, I was drawn to this particular library for a few reasons:
- It is supported on Linux, which is obviously very important for this design challenge
- It uses C++, which is my preferred language
- It looks easy to use and comes with a lot of code examples
- It seems to still be support and regularly updated
As stated in my last blogpost, I've been using a cross-compiler on OS X for compiling my BBB programs on so far, however when it came to attempting to cross-compile Maximilian example code everything became a lot more difficult. As Maximilian (and I'm guessing all Linux-based audio libraries and applications) requires the OSS or ALSA library to be compiled, one of these frameworks libraries needed to be installed and configured in such a way so that my cross-compiler could use it. After many attempts at doing this, getting fairly close using the advanced sysroot installation guide for my cross-compiler, I wasn't able to successfully compile the Maximilian example project.
So I went onto plan B - compiling the code on the BBB itself. This process involves editing the code on my MacBook, followed by scp'ing it onto the BBB, and then using the standard GCC compiler on the board. My first attempt at this didn't work, and came up with the following compilation errors for a number of variables:
maximilian.h:412:18: error: ISO C++ forbids initialization of member 'x' [-fpermissive]
maximilian.h:412:18: error: making 'x' static [-fpermissive]
maximilian.h:412:18: error: ISO C++ forbids in-class initialization of non-const static member 'x'
I'm not completely sure why the compiler thinks these variables are static, and everything compiles fine on both OS X and Intel Linux, however I fixed this by simply removing the initialisation of these variables in the hope that doing so won't break the library in anyway. After doing this the Maximilian program compiled, and I was able to run it and get example sound coming out of the USB audio.
The first few Maximilian examples I tried worked fine on the BBB, however it wasn't until I tried the polysynth example that I discovered something I hadn't yet considered - Maximilian may not be optimised for single-board computers such as the BBB, or least the more complex examples. When running the unedited polysynth example with no GCC optimisation the audio was very glitchy and the program was using 99% of the CPU - a program that runs without issue on my MacBook. Even when adding the -O3 optimisation flag (full optimisation for performance) to the compile command the audio would still glitch, and after finding this guide on getting and setting BBB CPU speed I found my BBB was already running at it's max 1000MHz frequency.
This led me on to test the limits of what I could do with Maximilian before I start getting audio artefacts and a ridiculous CPU usage. The polysynth example is a good program to test with as it includes a fairly large number of synth components (18 oscillators, 6 filters, and 6 envelopes) which provides 6 note polyphony (with each note containing 2 oscillators and an LFO), and is a good simple example of the synthesis engine I was hoping to develop for this project. This is what my tests found, all with full performance optimisation:
- I can get up to 4 note polyphony of the polysynth example before getting glitches
- Removing all filters drops the CPU usage down to 30-40%, and allows me to increase polyphony up to at least 16 without getting glitches
Going forward, this gives me the following options:
- Use Maximilian but with a redesigned, simplified sound engine (e.g. a low polyphony number, a single global filter instead of an individual filter for each note).
- Attempt to optimise Maximilian for the BBB, somehow...
- Use another library or framework for creating my synthesis engine
At this point in time I still want to experiment a bit more with Maximilian to see if I can get it to work for me without having to simply my synthesis engine design too much, however there is another similar looking library, STK, that I may test to see if it offers better performance. Either way, it is good to finally hear synthesised sound coming out of my BeagleBone Black!