Plots and animations of the Braids wavetables

Cwejman, Livewire, TipTop Audio, Doepfer etc... Get your euro on!

Moderators: Kent, luketeaford, Joe.

Post Reply
User avatar
hermbot
Ultra Wiggler
Posts: 762
Joined: Sat Jul 16, 2016 7:42 pm
Location: Wisconsin

Plots and animations of the Braids wavetables

Post by hermbot » Sun Dec 11, 2016 11:02 am

I bought a Braids off of a fellow wiggler not too long ago and while waiting for it to arrive in the mail I decided to do some source diving. One set of oscillator types that caught my eye were the various wavetables. I’ve always thought wavetable synths were neat and having the source code openly available meant I could see exactly what Braids has inside.

The concept of a wavetable synth is very interesting. Rather than computing or generating waves in realtime, pre-calculated values are read from a lookup table and assigned the requested pitch. Modern CPUs can handle wave generation without breaking a sweat but on small embedded systems those cycles add up, especially when trigonometric functions are involved (sin, cos, etc.) I’ve read that in some CPU-performance situations (microcontrollers, embedded firmware) the returned values of trig functions are pre-calculated and stored to save crunching later. Wavetables are a straightforward way to store complex waveforms without going through the process of synthesizing them on the fly.

I used Python for most of this because it makes reading text files and slicing up numerical arrays (using the Numpy library) very easy. I’m an engineer by trade and I’ve replaced MATLAB entirely with the Python scientific stack. It’s a wonderful tool. The bits of code I used are up on Github.

The files dealing with wavtables are resources.cc and digital_oscillator.cc. The first file is where many precalculated values are stored as constants, anything from the wavetables to envelopes and various shapes. The prefix “lut” denotes a look-up table, “wt” a wavetable. The second file, digital_oscillator, is the actual implementation and moving parts that create many of the sounds on Braids.

All of the wavetables are stored end-to-end in one large variable called wt_waves. This is what Braids is accessing in WLIN mode. Each wave is 129 samples long. The variables are unsigned 8-bit integers, so the amplitude values can range from 0 to 255. There are 20 individual named wavetables, some of which share a few of the waveforms. The variable itself is just a long series of numbers:

Code: Select all

const uint8_t wt_waves[] = {
     104,    105,    107,    108,
     110,    112,    115,    116,
     118,    122,    124,    124,
     126,    129,    131,    132,
     135,    137,    138,    140,
     143,    145,    145,    147,
     148,    149,    148,    148,
     148,    147,    146,    144,
     142,    139,    137,    133,
     127,    121,    116,    110…
… and so on, for another 8,000-ish lines.

In total there are 33,024 samples. Dividing those by 129 samples = 256 total waves. If that seems like a lot, remember that’s less than one second worth of CD-quality audio at a much lower bit depth! It seems like a strength of wavetables is the ability to pack a lot of data into a small amount of space.

How do we extract the individual waves from a single variable? How do we know where they go? This is defined in digital_oscillator.cc. Just before the function that actually generates the waves there are several lists defined like so:

Code: Select all

static const WavetableDefinition wavetable_definitions[] = {
// 01 male
{ 16 , { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15 } },
// 02 female
{ 16 , { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31 } },
// 03 choir
{ 16 , { 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 47 } },
…
The lists above are the “addresses” of each table. You can see that the male voice is made up of 16 waves. Each wavetable consists of 16, 8, or 4 waves. Some of them repeat their last values as they may have had less waves than any one of those container sizes.

There are 20 waves in total, with the following names:

Code: Select all

male
female
choir
space_voice
tampura
shamus
swept_string
bowed
cello
vibes
slap
piano
organ!
waves!
digital
drone 1
drone 2
metallic
fantasy
bell
In the WTBL mode the waves are swept left to right using the Timbre control in the order of the list above. The Color control moves from left to right within the selected table.


Most of the names are self explanatory. I don’t know what some of them mean, like shamus or tampura, and I’m not sure what makes organ and waves so exciting. I suppose waves could be exciting because it’s a way to get the most traditional square, saw, triangle, etc., which aren’t available in the other Braids modes.

After importing the wavetable list as a numpy array, a short function can grab any wave given its address:

Code: Select all

def get_wave(address, table, no_samples=129):
    start = address * no_samples
    return table[start:start + no_samples]
After wt_waves is a variable called wt_map. This represents the array of waves used in the WMAP setting. WMAP is a 16x16 grid of 256 tables, every wave that is defined by Braids. The list of addresses starts with the top left, goes across 16 waves, and then starts on the next row.

Finally we come to wt_code. The only place wt_code is used in the codebase is “void DigitalOscillator::RenderQuestionMark”, which appears to be related to the drum setup and generating random noises. It’s not really applicable here and to be honest I wasn’t able to figure out its purpose.

Now that we know all this information, what do we do with it? Make pretty pictures, of course. After defining all the wavetable addresses I wrote a one-liner to crossfade between each wave, allowing the tables to be swept through like Braids does:

Code: Select all

def crossfade(wave1, wave2, pct_wave1):
    """pct_wave1 needs to be a decimal value between 0 and 0.99."""
    return (wave1 * pct_wave1) + (wave2 * (1 - pct_wave1))
Then I used a library called matplotlib to plot all of the steps and store them as individual files. By plotting a known wave, crossfading it in several steps (I think I ended up on 20), I could save the actual waves and all the intermediate steps as individual files that worked as frames for animation. A few helper functions meant that I could plot all 20 wavetables, title them, and save them as their own directories with one script.

Getting the individual picture files to gifs from there, however, was a pain in the arse. There’s no clean way to do it programmatically with Python, as it turns out. I tried a few different methods and the least painful way was to use Windows Movie Maker and save each set of pictures as an .mp4 and then use an online converter to change them to gifs. This was after a false start with GIMP after I went through a lot of work and got most of the done before realizing that it had a cap on frame rate which meant they looked choppy and crappy no matter what I did.

In any case, here are two of the more interesting examples:

Image

Image

The full set of waves can be viewed here: Braids wavetable gifs

How helpful is this ultimately? Not terribly. I can see how the “waves” table could be useful and fun to watch, but after that they are just squiggly lines. Like most things related to music you’re usually better off using your ears.

Whilst trying to animate these I had a few happy accidents, including this neat plot which overlaid each wave from “waves” in the same plot rather than saving them as individual files.

Image
Click here for the full-sized image.

Finally, the WT4 setting map can be kind of useful as a rough guide, but there’s so much movement in a small knob twist that it’s hard to truly use it as a map and really dial in a wave you’ve spotted and recognize. But, again: pretty pictures.

Image
Click here for the full-sized image.

So while this is all of questionable usefulness, it got me familiar with how the Braids code is laid out and kept me busy over a few lunch breaks. It illustrates that new and different wavetables could loaded in quite easily by replacing the values in resources.cc.

User avatar
Matos
Modular masturbator
Posts: 3783
Joined: Tue Jul 05, 2011 4:03 am

Post by Matos » Sun Dec 11, 2016 12:14 pm

Really interesting work. You're much more productive on your work breaks than I.

User avatar
Dcramer
Super Deluxe Wiggler
Posts: 5647
Joined: Fri Mar 29, 2013 12:11 pm
Location: Canada

Post by Dcramer » Sun Dec 11, 2016 2:34 pm

That's awesome! :party:

User avatar
Timmy
Super Deluxe Wiggler
Posts: 1236
Joined: Fri May 06, 2016 7:08 pm
Location: Sydney, Australia

Post by Timmy » Sun Dec 11, 2016 3:39 pm

Fabulous work, very nice!

Just to note, you seem to be reading the wavetable arrays from the source code files, but they are already available as a file of bytes that are read by a python script which then dumps them into the resources.cc source file - see https://github.com/pichenettes/eurorack ... ms.py#L141 - it might be neater to read them from the binary files provided rather than having to parse the source files, but the result will be identical, of course.

An animated spectral analysis of the wavetables might also be interesting.

User avatar
hermbot
Ultra Wiggler
Posts: 762
Joined: Sat Jul 16, 2016 7:42 pm
Location: Wisconsin

Post by hermbot » Mon Dec 12, 2016 8:54 am

Hmm, somehow I missed that Python file. Thanks for the tip.

Spectral analysis could be done... like anything else, Python has a library for that. :)

User avatar
Placid Mouse
Wiggling with Experience
Posts: 347
Joined: Tue Aug 25, 2015 9:47 pm
Location: BC

Post by Placid Mouse » Mon Dec 12, 2016 9:33 am

Awesome work dude. Interesting reading what you've said about Python and MATLAB. All of my lecturer's/ professors at my old uni were obsessed with MATLAB, although I did get that it was totally awesome in terms of the IO stuff, it was annoying to have yet another language to learn just to do plots and things like that, stuff to diagram and explain my C++ code.

Could you recommend any resources for these Python tools? I've done a little bit of stuff in Python so this has caught my attention :woah:

Also would you say that using some of these Python tools could act as a good way to improve ones knowledge of the language as a whole?

dwp2659
Learning to Wiggle
Posts: 20
Joined: Sat Jun 07, 2014 10:56 am

Post by dwp2659 » Mon Dec 12, 2016 9:45 am

well done! software engineer here as well - gonna have to look into that python stack

fun stuff

User avatar
hermbot
Ultra Wiggler
Posts: 762
Joined: Sat Jul 16, 2016 7:42 pm
Location: Wisconsin

Post by hermbot » Mon Dec 12, 2016 12:51 pm

Thanks for the kind words, all.

Placid Mouse – yes, Matlab has a lot of inertia in the academic environment. Mathworks happily supplies professors and students with Matlab hoping that when they get to the workforce they will keep using it (and buying Matlab licenses!). The platform has many strong points, but after switching fully to Python I’ve not found myself limited at all, and I find the actual syntax / language to be much, much, much better to work with. (Also it’s free.)

As far as learning the language, the best way is usually to have a project in mind and see it through to completion. Getting the first 80% is usually easy and fun, the last 20% is the hair-pulling part that really makes you learn the nuts and bolts so you can complete your project and finish up all the un-fun parts that are required.

A good resource for that would be Automating the Boring Stuff With Python, or Learn Python The Hard Way, both of which are free resources. Python for Data Analysis has been very useful for what I’ve done at work.

Numpy and Scipy are the big libraries to work with. Numpy adds array and matrix math capabilities that replace Matlab’s matrices. Scipy has signal processing and a host of other useful tools. Matplotlib replicates plotting.

Anaconda is a the go-to distribution of Python for anyone doing scientific or numerical work, it has everything you want in it.
https://www.continuum.io/downloads

User avatar
Placid Mouse
Wiggling with Experience
Posts: 347
Joined: Tue Aug 25, 2015 9:47 pm
Location: BC

Post by Placid Mouse » Mon Dec 12, 2016 3:09 pm

Ace. I'll get on it tomorrow I'm a bit too tired for coding now!

Thanks Hermbot, you're a gent :miley:

User avatar
Placid Mouse
Wiggling with Experience
Posts: 347
Joined: Tue Aug 25, 2015 9:47 pm
Location: BC

Post by Placid Mouse » Mon Dec 12, 2016 3:14 pm

As far as learning the language, the best way is usually to have a project in mind and see it through to completion.
I totally get that, It's very similar advice I give to aspiring music producers. I've not been as disciplined with my coding, which arguably needs more discipline than making music. I'm yet to finish off a plugin I made, it works cross platform, the GUI is fine but it's still not fit for human ears!... It's just finding time. Long story short I need to stop making excuses!

Thanks again dude.

User avatar
franman69
Veteran Wiggler
Posts: 743
Joined: Fri Apr 08, 2016 7:53 pm
Location: Westchester County, NY
Contact:

Post by franman69 » Mon Dec 12, 2016 5:57 pm

Although I use WTX4 and WMAP all the time.. all I can say is Wow!

User avatar
baleen
Wiggling with Experience
Posts: 335
Joined: Sat May 21, 2016 1:55 pm
Location: sf ca

Post by baleen » Mon Dec 12, 2016 9:38 pm

holy shit this is good stuff. love the wavetables in Braids. need to work out a way to turn my Tides into Sheeps and really get the waves flowing.

User avatar
brandonlogic
Super Deluxe Wiggler
Posts: 3233
Joined: Tue Jan 27, 2015 9:17 am
Location: Milwaukee WI

Post by brandonlogic » Sun Jul 14, 2019 10:10 pm

Any way this could be turned into wav file compatible with the e352?

User avatar
hermbot
Ultra Wiggler
Posts: 762
Joined: Sat Jul 16, 2016 7:42 pm
Location: Wisconsin

Post by hermbot » Mon Jul 15, 2019 4:26 pm

brandonlogic wrote:Any way this could be turned into wav file compatible with the e352?
Yes, that would probably be pretty straightforward. I'm not familiar with the E352, do you have any specs on how that should be formatted?

User avatar
brandonlogic
Super Deluxe Wiggler
Posts: 3233
Joined: Tue Jan 27, 2015 9:17 am
Location: Milwaukee WI

Post by brandonlogic » Tue Jul 16, 2019 6:33 pm

hermbot wrote:
brandonlogic wrote:Any way this could be turned into wav file compatible with the e352?
Yes, that would probably be pretty straightforward. I'm not familiar with the E352, do you have any specs on how that should be formatted?

Awesome.

The E352 wavetables are 256 samples x 16-bits
wav files can be imported to the wave edit software to get them formatted correctly. the pdf manual has more info and is in the .zip file when you download the wave file.
http://synthtech.com/waveedit/

heres a section of the manual that applies. Image

User avatar
hermbot
Ultra Wiggler
Posts: 762
Joined: Sat Jul 16, 2016 7:42 pm
Location: Wisconsin

Post by hermbot » Wed Jul 17, 2019 12:58 pm

Interesting that the Plaits wavetables seem to be available but the Braids set isn't.

https://waveeditonline.com/

Anyway, I'll take a poke at this as time allows. I think I even had those exported as waves at some point as an experiment to load them into the Disting.

User avatar
brandonlogic
Super Deluxe Wiggler
Posts: 3233
Joined: Tue Jan 27, 2015 9:17 am
Location: Milwaukee WI

Post by brandonlogic » Wed Jul 17, 2019 4:57 pm

hermbot wrote:Interesting that the Plaits wavetables seem to be available but the Braids set isn't.

https://waveeditonline.com/

Anyway, I'll take a poke at this as time allows. I think I even had those exported as waves at some point as an experiment to load them into the Disting.
Cool thanks!!!
If you dont have time you could just send me the wav and i could try to get it in waveedit too

User avatar
brandonlogic
Super Deluxe Wiggler
Posts: 3233
Joined: Tue Jan 27, 2015 9:17 am
Location: Milwaukee WI

Post by brandonlogic » Fri Aug 16, 2019 10:24 am

hermbot wrote:Interesting that the Plaits wavetables seem to be available but the Braids set isn't.

https://waveeditonline.com/

Anyway, I'll take a poke at this as time allows. I think I even had those exported as waves at some point as an experiment to load them into the Disting.
just checking in, did you ever find those wave files?

User avatar
hermbot
Ultra Wiggler
Posts: 762
Joined: Sat Jul 16, 2016 7:42 pm
Location: Wisconsin

Post by hermbot » Fri Aug 16, 2019 3:58 pm

brandonlogic wrote:
hermbot wrote:Interesting that the Plaits wavetables seem to be available but the Braids set isn't.

https://waveeditonline.com/

Anyway, I'll take a poke at this as time allows. I think I even had those exported as waves at some point as an experiment to load them into the Disting.
just checking in, did you ever find those wave files?
I looked and looked but can't seem to find most of the ancillary files related to this project. (Good thing the code is on GitHub...) So any wavs I might have created are long gone.

Scipy should let me export those arrays, I can dust off my Python brain and see if I can get it working. If I do, I'll post here.

Post Reply

Return to “Eurorack Modules”