diceTone~, a stochastic synthesizer
DOWNLOAD PATCH AND DEPENDENCY (1KB)Description
diceTone~ is my attempt to create a synthesizer that generates timbres in a stochastic way by using waveshaping . To do that, a waveform, chosen by the user, serves as an input signal. The waveform is then sent to a shaping function that changes randomly over time, affecting the output signal and timbre.
It is well known that envelope also plays a big part in how we perceive timbre. This is the one of the reasons why I chose the method on this patch to change the input wave, making the initial, larger amplitude of a sharp attack alter how much of the shapping functions is used, momentarily altering the timbre. For the same reason, this patch also allows for the option of a randomized ADSR.
The patch is easy to use, and the pitch and volume can be easily controlled.
How the Patch Works
When a midi controller is plugged to the patch, midi notes are converted into frequencies and unnecessary midi data is stripped away with the [midiControl] patch (included on the download link above). The pitch information is sent the oscillator that corresponds to one of the waveshape options, and the velocity information will control the variable that determines the peak of the attack, a float variable ranging from 0 to 1.
Every time a new note is sent, the signal will be amplified to its maximum value, and fall to 80% of said value. The time that it takes for it to fall is randomly generated every time a note is played. This accounts for the aforementioned momentary timbre difference that occurs at each attack.
After a few calculations to size the soundwave correctly for the actual synthesis, the signal is sent to the array spect,through the object [tableread~ spect], where the actual waveshapping happens. The spect array is the shaping function, and it can be seen at any time on the left of the patch, on top of the array result that shows the final wave after the waveshaping has happened. Before being sent to the DAC and output, the signal passes through a final multiplication that controls the sound's ADSR.
In the rightmost part of the patch is the code that constantly changes the shaping function in random ways. To do that, three random numbers are generated, this is what they do:
- Determines the new value of one of the 25 datapoints in the shaping function, from -1 to 1.
- Determines how long it will take to achieve this value. The range for this variable can be changed by the user, and it affects how fast or slow the timbre will be constantly changing. After the user chooses this variable (n), the random number generated will be between n/10 and n, where the chosen n can be between 200 and 10,000. The default value of n is 400.
- Finally, the last random number determines which of the 25 datapoints will be altered.
Once a datapoint achieves its randomly selected value, another one will immediately start to go through the same process, so the timbre is always changing.
Around the middle part of the patch, we have the code that handles the ADSR. For that, 4 random numbers are created: attack and decay time (both ranging from 10 to 210 milliseconds), sustain level (as a percentage of the peak level of the envelope that happens right after the attack, varying between 50% and 95%), and release (ranging from 10 to 510 milliseconds). There are also number boxes that allow the user to change some of these ranges. These random numbers are generated by the [drunk] object rather than the widely used [random] object, since the gradual changes between the numbers sounded better for what I wanted, but that can be easily changed.
Further down, the code assures that the ADSR variables are handled correctly, triggering the right changes in envelope at the right time. It is then connected to the [*~] that is multiplying the output signal of the waveshaping.
How to use it
The controls and the arrays are on the left part of the patch in a little GUI. From top to bottom:
- On/off toggle
- Waveshape input: options being the sine wave, sawtooth wave, or triangular wave (ramp).The default is the sine wave.
- Rate of change: number n that determines how fast the random changes will occur in the shaping function, which will always be a random value in milliseconds between n/10 and n. n can be any number between 200, for very fast timbral changes, and 10,000 for very slow ones. I found both extremes problematic for short improvisations, since the lower value changes the timbre so quick that it loses its stochastic characteristics, and the higher extreme has the changes being too subtle. Still, I kept this range available so I can easily use it on future works, and the default rate of change is n=400, which for me felt like a sweet spot.
- spect and result arrays, for visualization only. spect is the shapping functions and result is the final signal before ADSR.
- Randomize ADSR toggle: off by default.
- ADSR controls: these will be overridden if the randomize ADSR toggle is on. The default value is 30 milliseconds for the attack, decay, and release time, as well as 30% of the peak level for the sustain level.
Future Improvements
There are some improvements that I want to make on this patch in the future, but still haven't been implemented because I wanted to avoid too many abstractions in it, and because it serves my current purpose as it is. These improvements are:
- Implement similar ideas to generate pitchless, noise based and percussive sounds in addition to the pitched ones.
- Being able to toggle different processes for the random changes in the spectrum of the chosen waveform. I like how the waveshaping method sounds, but it would be nice to also have less "squary" and harsh signals as the result when I want to.
- Being able to toggle between [random] and [drunk] objects for any part of the patch, whenever I want, while keeping the patch running with the current variables.
- Add filters to the decay part of the envelope, so there is a randomized change of timbre just like it happens during the attack.