Saturday, August 1, 2026

Adding waveforms to the Gakken (Simple Saw Animator)

     As part of our ongoing series on the Gakken SX-150 mk II, I've been thinking about various ways it can be enhanced. One obvious shortcoming is the complete lack of waveform options. We have a saw; that's it. There's no second oscillator, nor sub oscillator.

Hip to Be Square

    A simple addition is a square waveform. All we need to do is compare the saw to a midpoint voltage. If the saw is above the midpoint, the output is high, else it's low. This raises the question: what is the midpoint? We can find this empirically, by measuring the waveform with an oscilloscope, but there's no guarantee a different Gakken will have the same midpoint. The midpoint might also drift with time, or old batteries. It's best not to build the circuit around an unknown like that, so let's remove it by adding a highpass filter and rebiasing the saw.

Saw to Square conversion

    There it is, rebiased around 2.5V. If we'd like to change the width of the pulse, we can vary the voltage at the inverting input of the opamp.

Pulse width modulation

    So, we get Pulse Width Modulation (PWM) for free, just by providing a voltage. We do have to be careful to match the range of the CV to the amplitude of the saw, or the PWM range won't be what's expected.

You're Thinking of Someone With Two Knives

    Wouldn't it be nice if we had a second oscillator to thicken up the sound? Well, maybe we can fake a second saw wave. Back in 1978, Bernie Hutchins published a "waveform animator" that does just that. 

    It works by comparing a saw (or triangle) waveform to a fixed voltage, then summing the saw and the output of the comparator. The comparator output shifts a chunk of the saw up, and the rest of it down, in a way that effectively changes the phase of the saw. It's as if it moved forward/backward in time relative to the original, just like a second saw would do if it were a slightly different pitch.

Fig 2 from Electro Notes #87

    It's a really great trick, and it only has the small catch that the resulting waveform now has a DC offset, due to the comparator output being lopsided. This is accounted for by mixing in some of the CV that drives the comparator.

From All Angles

    Now that we know it's possible to fake a second saw, we can riff on the idea, and maybe make something that's more in the minimalist spirit of the Gakken.

    The original designed mixed an equal proportion of the comparator's PWM output with the saw to get the phase shifted saw. We don't have a use for it by itself, and we really just want the mix of the two saws. Turn out we can get the same result by just dropping the amplitude of the PWM signal. It yields the same proportion of phase-shifted saw to original saw.

    Here's a comparison between two actual saws and our half-amplitude-PWM circuit:

Two saws vs one saw + PWM

    Neat, huh? The PWM signal (red) slides a segment of the saw upwards to represent our phantom, second saw. This has saddled us with the DC offset problem discussed earlier, but we have an otherwise perfect emulation of two saws. 

    We can see the waveform starts with a full amplitude saw that breaks into two uneven peaks. Those peaks then level out into a saw that's twice the frequency but half the amplitude, then the process reverses.

Two Are Better Than One

    The original wave animator circuit was meant to be duplicated multiple times to get additional shifted copies of the wave. There would be a new LFO, inverting amp, comparator, and summing amp per copy. That's a bit excessive for our little Gakken, but we can take inspiration from the idea.

    Mixing in one PWM signal gave us a second saw, so maybe we can tack on another PWM signal to get another saw. If we invert the phase of our existing PWM to make this "new" PWM signal, it'll simply cancel out in the mix, returning us to a single saw.

    If we invert the saw instead, we get a different PWM signal, one with pulses that "grow" in the opposite direction and offset a different portion of the saw. If we make sure it has the same pulse width, but opposite polarity of the first PWM signal, it will even cancel out the DC offset that we introduced.

PWM #2 generated from an inverted saw

    We can see from the "PWM Mix" signal that the combination of the two signals is balanced around a midpoint with an even amount of time spent above and below.

    If we mix in a specific amount of the inverted saw, we can see the multi-saw waveform emerge, this time with an additional peak.

The full saw animator

    There we have our full saw animator built around just 3 op-amps. The fourth is left as an optional buffer.

There's What's Right and There's What's Right

    Clearly it's easy to add square waves, so let's come up with another one. Adding a square sub oscillator is an obvious DIY move. All we need is some sort of counter and a reasonable pulse to feed it, then out comes a square wave an octave down. The counter is performing a divide by two operation on the number of incoming pulses. One pulse out for every two in. This amounts to a divide by two operation being performed on the frequency of the incoming pulses also.

Adding a d-type latch to generate a sub octave

    We tap off of one of our PWM signals so that we can get a clean pulse for our counter. Using an inverter keeps the sub aligned with the falling edge of the saw, rather than the other edge of the PWM pulse. This is because the counter only counts on the rising edge of the clock.

Never the Twain Shall Meet

    Much like the saw, things get interesting when we mix our waveforms together in specific ratios. Here's the sub mixed with both PWM signals.

Pulse and sub mix

    Look at that. We get a new waveform, a stepped saw that's an octave down. This is similar to the Korg Poly-800's saw that it builds from different octaves of square waves.

Submerge

    Now that we have our square sub oscillator, we can combine it with our saw to get a triangle sub oscillator. All we have to do is invert the saw when the sub is low, giving us two back-to-back right triangles that form an isosceles triangle.

    We already have an inverting amplifier that gives us an inverted saw. We could use an analog switch to toggle between the inverted and non-inverted saws, but the non-inverted one isn't buffered and would get rebiased as we connect and disconnect it.

    We can instead borrow a trick used in attenuverters. Rich Holmes has a nice breakdown of how they work here, and we'll borrow one of his images:

Simple attenuverter - richardsholmes.com

    We can imagine the pot with the wiper at the bottom (counterclockwise) extreme. The non-inverting input (pin 3) of the opamp is shorted to ground, and we get an inverted output. At the other extreme, pin 3 instead sees the full input voltage, and we got a non-inverted output.

    We can use a SPDT switch to do the same thing, connect the non-inverting input to ground or the saw wave, alternately. This input pin pulls virtually no current, so it doesn't upset the bias of the saw.

sub triangle wave

    There is a small hiccup where the saw is inverted, but this is typically inaudible due to how narrow it is.

    Now we have a saw, two pulse waves, a square sub, and a triangle sub. Depending on how we mix them, we can also get two flavors of animated "super" saw (one PWM or two), a stepped sub saw, and a regular sub saw. It's worth pointing out that the triangle sub conflicts with the animated saw, since it robs us of the inverted saw half the time. The combination does still produce an interesting, half-animated triangle though.

Flashing WeAct Studio RA4M1 with the Arduino R4 bootloader

     I've been using an Arduino R4 minima in my Gakken SX-150 project, but I ran out of IO pins. The RA4M1 IC itself has plenty, but only a handful are broken out on the Arduino board. Luckily, there's an alternative board that exposes nearly every IO pin, the WeAct Studio RA4M1.




    The board is pretty spartan, adding little more than a few LEDs, buttons, and a voltage regulator. This gives us the essentials without robbing us of the extra IO we're after. One problem though, it doesn't have out-of-the-box compatibility with the Arduino IDE, despite sharing the same microcontroller.


Arduino Compatibility

    What makes an Arduino an Arduino, and what is this board missing? In a word, the bootloader. The Arduino R4 boards come preprogrammed with a bootloader that allows them to talk to the IDE, and load new sketches. Fortunately, this bootloader is freely available and can be flashed onto the WeAct board.


Setup

    First we need a tool that lets us program the RA4M1 chip. This is imaginatively named "Renesas Flash Programmer", and can be found here: https://www.renesas.com/en/software-tool/renesas-flash-programmer-programming-gui

    Next we need the Arduino R4 Minima bootloader from here: https://github.com/arduino/ArduinoCore-renesas/blob/main/bootloaders/UNO_R4/dfu_minima.hex

    Then connect the WeAct via USBC. It should start flashing a blue LED. This is the "blink" program that it comes with. This is a good sign, and shows that the board is working. We need to stop it though, and get into programming mode. This requires a "secret" button sequence: hold down the "MD" button and press "RES". If done correctly, the LED will stop flashing.

    Now open the Programmer program and select "RA" for the microcontroller, and "COM port" for the tool. It should automatically detect a com port and display it to the right of the "Tool Details..." button.


    Verify that the port is detected as an RA Boot device



    Click the "Add/Remove Files..." button and select the hex file we downloaded


    Click the large "Start" button and wait for confirmation that it was successful.


     Done!


Using the Bootloader

    Now that we have the bootloader, we can use the board as if it were an Arduino R4 Minima. It should appear in the list of boards as an R4 Minima, and respond to programming the same way.  



The Catch

    If you upload the standard "Blink" sketch via the Arduino IDE, you'll find that it doesn't actually blink (flash the LED). This isn't due to any bootloader or firmware problems; the LED is attached to a different pin than on the R4.

    While the microcontroller is compatible with that of the R4, the board is different. The IO pins don't adhere to the Arduino D0-D13/A0-A6 numbering, and many of them aren't supported by the traditional Arduino pinMode()/digitalWrite()/digitalRead() functions. The pin are still very much usable though!

    One solution, offered by WeAct, is to use a new set of functions: R_IOPORT_PinCfg()/R_IOPORT_PinWrite()/R_IOPORT_PinRead()

    These are demonstrated in their "Blink.ino" sketch on the WeAct github: https://github.com/WeActStudio/WeActStudio.RA4M1_64Pin_CoreBoard/blob/master/Examples/Arduino/Blink/Blink.ino