Wavetable Oscillator

The function osc implements a wavetable oscillator with a fixed table and supporting a variable frequency. In this example, the table is simply a sine wave. The osc function is used multiple times to create a complex sound. The additional function ramp helps to create a decaying sound.

The program has a parameter freq which controls the base frequency of the sound.

With the help of ffmpeg, you can write the output of this program into an audio file:

  1. Save the code into a file osc.arrp, then compile it:
    arrp osc.arrp -x osc
  2. Run the program and write its output through ffmpeg into file output.wav:
    ./osc -f raw freq=400 |
    ffmpeg -y -t 1 -ac 1 -ar 44.1k -f f64le -i pipe:0 file:output.wav
    
    If you want to use a different sample rate, change sample_rate variable in the code, and adjust the ffmpeg option -ar.

Implementation:

input freq : real64;
output audio_out : [~]real64;

sample_rate = 44100;

audio_out = 0.1 * sound(freq);

sound(freq) = y * amp where
{
  amp = ramp(1.0, 0.0, 1.0)^2;
  fmod = ramp(0.0, 1.0, 1.0)^2 * 40 + 4;
  f0 = osc(fmod) * freq * 0.1 + freq;
  y =
    0.1 * osc(f0) +
    0.5 * osc(2*f0) +
    0.2 * osc(3*f0);
};

ramp(start, stop, duration) =
  [t] -> start + min(1.0, t/(duration * sample_rate)) * (stop - start);

osc(freq) = y where {
  y[t] = interpolate(table, phase(freq/sample_rate)[t] * #table);
};

table_size = 500;
table = [i:table_size] -> sin(i/table_size*2*pi);

interpolate(table, i) = table[i0] * (1-d) + table[i1] * d where
{
    i0 =  int(i)    % #table;
    i1 = (int(i)+1) % #table;
    d  = i - floor(i);
};

phase(freq) = y where
{
    y[0] = 0.0;
    y[n] = wrap(y[n-1] + freq[n]);
    wrap(x) = if x < 1.0 then x else x - 1.0;
};

pi = 4*atan(1);