After the previous failure, I decided to document myself at a minimum. I mainly used this article from Rishikesh Daoo. I might consider reading some of his other articles as it’s quite insightful!

This basically told me that a nice ratio can be reached with 4 buffers that delay at different rates the sound.

So while I kept the previous algorithm, I just duplicated it 4 times with different offsets to the main delay offset. So instead of having only 1x repetition fading progressively, we have 4 of them:

0 is the original sound shape, {1,2,3,4} are each different delays that will repeat several times (b, c,…) while progressively adding. Note that 4c is the tiny jump.

By adjusting the delays time, we can get an “acceptable reverb effect” that covers very different types of reverb:

When the delay time is just under the signal frequency, we get a reversed delay (like if the reverb was applied from right to left). This transforms the shape of the resulting sound (as it reduces the “saw” effect):

I’m quite happy with this result, it can be found in the blog/002-reverb-effect branch of my project.

Next, I will probably add a UI so that testing sound can be more interactive. This is important as my aim is not to build a synth following the theory only, but more to explore sound design while building my synth. Soon too, I will need an envelope (and so a Voltage Control Oscillator) and midi assignments… Not sure in which order this will happen 😀

Until then, stay safe and curious!

Continue Reading

Go Synth — Reverb Effect

Find the related code in the branch 002-reverb-effect

On my way to have fun, a reverb is more important than the actual capability to play different notes 😀

So I gave it a try, without reading documentation. I want to challenge my capabilities to reverse engineer a reverb.

So a reverb effect is similar to the change of your voice you can hear when you are in a big hall or a church. It is not a “delay” — that echo of your voice from a distant mountain, you know? It is much shorter.

My first assumption was: If I can create a buffer and apply a small percent of the oldest part of this buffer to the sound, I would offset this small percentage and it should be working… Or is it?

After some tweaks to ensure the reverb effect is also applied in the reverb buffer, I got the expected result:

My main oscillator is a SAW, so it should normally just go up and then reset to -1. With the reverb effect applied, we can see an offset repetition and fade every time it gets repeated.

So visually, it is a WIN! 🎉

…well… until you realize it just does not sound like a reverb effect… at all! At best I got a short time vibrato when changing the frequency… Hum… NOT APPROVED!

My next tentative is to store in the buffer ONLY the reverberation (and not the final oscillation level). This way, I can have 2 different rates. I can apply a 20% rate on the first reverb calculation and then make a 95% rate on the reverb itself. This will enable the reverb effect to last longer.

Indeed, in the previous picture, we can see the reverb effect fade too quickly — that is my hypothesis why we just do not hear it much 🤔

That’s somehow a little bit better… But definitely does not sound like a reverb!

I will have to start documenting myself a little big I guess…

See ya for the next one!

Experience: my face became a meme | Life and style | The Guardian
Continue Reading

Go-Synth — First sound!

Find the related code in the branch blog/001-simple-saw-oscillator

The only rule I have set for this project was: “it has to sound good and since the beginning!”.

So instead of building a whole structure, UI, and other things, I will first build a sound and then extends its properties.

Normal developers would create a base architecture to welcome chromatic notes to adjust the frequency, a voltage control, the oscillator, and eventually an envelope system.

Well, that’s NOT how I will plan this project. I have 2 priorities:

  • A SAW oscillator — because saw shape is damn good!
  • A reverb effect — who want a synth with no reverb?!

Yesterday, I was so happy as I could code the Saw Oscillator right the first time! Or did I? Let’s see that.

How do we even design a sound oscilloscope?

func OscFunc(stat float64, delta float64) float64 {
	// Do something and return the current shape level
	return r

If you have experience in Game Development, this will sound familiar. As for game movements, to ensure the “speed” of rendering the sound (or the movement) is NOT affected by the speed of your CPU, we need to work with delta increments.

That is, instead of describing the next position every millisecond, we describe the next position after a delta time. This time is the time elapsed since the previous description.

You can imagine a loop that calls our OscFunc every time the CPU can afford to do so. As the frequency to call this function might vary, we need to integrate the “delta” of time elapsed when we shape our sound.

My first attempt was pretty basic, but the generated sounds immediately told me “IT WORKS”!

func SawFunc(stat float64, delta float64) float64 {
	_, r := math.Modf(stat + delta)
	return r

Yeah, it’s just an addition! The math.Modf ensures that we only take values between 0 and 1:
math.Modf(0.5) == 0.5

math.Modf(1.5) == 0.5

math.Modf(1.15) == 0.15

math.Modf(2) == 0

math.Modf(2.3) == 0.3

It was only after I observed a record of that sound, I realized that I still messed up a detail: Wave should oscillate from -1 to 1, not from 0 to 1!

It just required a minor code change to fix it and have a perfect SAW oscillator that would serve as base sound for the next challenges of this project!

func SawFunc(stat float64, delta float64) float64 {
	_, r := math.Modf(stat + delta)
	return r*2.0 - 1.0

Okay! Now it’s working like a charm! Time to write some tests and I can close this topic!

Many challenges on this project will NOT be test driven. Indeed, my aim is to have fun and to explore possibilities, I do not expect a predictable result for a given feature and I totally allow myself to change the expectations based on what I discover on my way. Tests enables to stay in a given way, so I would only write tests when I found which way I want the feature to take.

That’s it for today! See ya for the next one!

Continue Reading