Skip to content

For more information about the examples, such as how the Python and Mojo files interact with each other, see the Examples Overview

BuchlaWaveFolder

This example demonstrates the Buchla 259-style wavefolder distortion on a sine wave.

The Buchla Wavefolder is a classic wave-shaping synthesis technique that adds harmonic complexity to audio signals by folding the waveform back on itself when it exceeds certain thresholds. This results in a rich, complex sound often used in electronic music synthesis. Derived from "Virual Analog Buchla 259e Wavefolder" by Esqueda, etc.

Use the BuchlaWaveFolder_AD version for Anti-Aliasing (ADAA) and Oversampling. The ADAA technique is based on Jatin Chowdhury's chow_dsp waveshapers.

It is recommended to plot the output waveform to get a sense of how the wavefolding process alters the sound.

Python Code

from mmm_python.MMMAudio import MMMAudio

# instantiate and load the graph
mmm_audio = MMMAudio(128, graph_name="BuchlaWaveFolder_AD", package_name="examples")

# to hear the version without Anti-Aliasing, use:
# mmm_audio = MMMAudio(128, graph_name="BuchlaWaveFolder", package_name="examples")
mmm_audio.start_audio() 

mmm_audio.stop_audio()
mmm_audio.plot(4000)

# plot the spectrum of the the plotted output
from numpy import fft
from matplotlib import pyplot as plt
spectrum = fft.rfft(mmm_audio.returned_samples[:, 0])
plt.plot(spectrum)
plt.show()

Mojo Code

from mmm_audio import *

struct BuchlaWaveFolder(Representable, Movable, Copyable):
    var world: UnsafePointer[MMMWorld]  
    var osc: Osc[2]
    var lag: Lag
    var m: Messenger


    fn __init__(out self, world: UnsafePointer[MMMWorld]):
        self.world = world
        # for efficiency we set the interpolation and oversampling in the constructor
        self.osc = Osc[2](self.world)
        self.lag = Lag(self.world, 0.1)
        self.m = Messenger(self.world)

    fn __repr__(self) -> String:
        return String("Default")

    fn next(mut self) -> SIMD[DType.float64, 2]:
        amp = self.lag.next(self.world[].mouse_x * 39.0) + 1

        sample = self.osc.next_vwt(40)
        sample = buchla_wavefolder(sample, amp)

        return sample