SlideShare a Scribd company logo
Audio DSP
In ReasonML
Hi I’m Ken
@ken_wheeler
AUDIO DSP
DIGITAL SIGNAL
PROCESSING
• Audio Processing/Synthesis

• Statistics

• Medical Data

• Image/Video Processing

• ETC
DIGITAL SIGNAL
PROCESSING
WE’RE GONNA
BUILD A SYNTH
How do you create
sound, digitally?
[ ]
• The number of samples (data points) of audio per second

• The granularity/resolution of your signal

• 44.1kHz / 44100Hz = 44100 samples per second
Sample Rate
Audio DSP in ReasonML
• The number of samples for sound card to process at one
time

• Buffer === too small, computer can’t fill the buffers fast
enough, get glitching

• Buffer === too big, can experience latency in real time
performance (i.e: pressing a key on a MIDI keyboard)
Buffer Size
[ ]
[ ]
Sample Rate: 44100
Buffer Size: 1024
Sample Rate: 44100
Buffer Size: 1024
Sample Rate: 44100
Buffer Size: 1024
43.06 per second
Playing native audio with
ReasonML
Audio DSP in ReasonML
open Portaudio;
open Bigarray;
Portaudio.init();
let deviceId = Portaudio.get_default_output_device();
let device = Portaudio.get_device_info(deviceId);
let outparam =
    Some({
      channels: 2,
      device: deviceId,
      sample_format: format_float32,
      latency: device.d_default_low_output_latency,
    });
let stream = open_stream(None, outparam, sampleRate, bufferSize, []);
let dims = [|2 * bufferSize|];
let ba = Genarray.create(float32, c_layout, dims);
while (playing^ === true) {
  fill_ba(ba, dispatch, appStateRef^);
  Portaudio.write_stream_ba(stream, ba, 0, bufferSize);
};
FILLING OUR
BUFFERS
let mtime = ref(0.0);
let mdelta = 1. /. sampleRate;
let fill_ba = (ba) => {
/* Reset mtime if it gets too big */
  if (mtime^ > Float.max_float) {
    mtime := 0.;
  };
  /* Get Audio Data */
  let data = getData(mtime);
/* Increment time by sample */
  mtime := mtime^ +. mdelta;
/* Get stereo channel array indexes */
  let left = [|2 * i|];
  let right = [|2 * i + 1|];
  /* Set the data at the index */
  Genarray.set(ba, left, data);
  Genarray.set(ba, right, data);
};
WAVEFORMS
Audio DSP in ReasonML
OSCILLATORS
Oscillators emit waveform
values over time
Frequency (pitch) determines
how fast it oscillates
Audio DSP in ReasonML
Time determines where in
the cycle (period) you are
(phase)
Audio DSP in ReasonML
Period: One full oscillation cycle
Lets make a sine
wave
let getSine = (frequency, gain, phase, mtime)
 =>
  sin(
Float.pi *. 2. *. frequency *. mtime +. phase
) *. gain;
Gain: multiplier that makes
the signal louder or softer
(volume)
Square Wave
let getSquare = (frequency, gain, mtime) =>
  let fpt = 1. /. freq; 
  let hpt = fpt /. 2.;
  let lt = mod_float(mtime, fpt);
  (lt < hpt ? 1.0 : (-1.0)) *. gain
Saw Wave
let getSaw = (frequency, gain, mtime) =>
  let fpt = 1. /. freq; 
  let hpt = fpt /. 2.;
  let lt = mod_float(mtime, fpt);
  (lt /. fpt *. 2. -. 1.0) *. gain
How can we combine two
waves to make a new
sound?
You literally add them
together.
let dataPoint = sineWaveDataPoint
+ sawWaveDataPoint;
So how do we shape our
sound?
ENVELOPE
Envelopes change amplitude
over time to shape a signal
Attack - Initial ramp up of amplitude after Note On
Decay - Initial step down of amplitude
Sustain - Holds amplitude steady
Release - How long it takes for the amplitude to fade
out after Note Off
We can make an envelope
with a state machine
type stage =
  | Off
  | Attack
  | Decay
  | Sustain
  | Release;
type envelope = {
  minimumLevel: float,
  mutable currentStage: stage,
  mutable currentLevel: float,
  mutable multiplier: float,
  mutable currentSampleIndex: int,
  mutable nextStageSampleIndex: int,
};
let create = () => {
  minimumLevel: 0.0001,
  currentStage: Off,
  currentLevel: 0.0001,
  multiplier: 0.1,
  currentSampleIndex: 0,
  nextStageSampleIndex: 0,
};
let enterStage = (env, nextStage, params) => {
  env.currentStage = nextStage;
  env.currentSampleIndex = 0;
  env.nextStageSampleIndex = (
    switch (nextStage) {
    | Off => 0
    | Sustain => 0
    | _ =>
      let idx = find(stageOrder, nextStage, ~i=0);
      int_of_float(params[idx] *. sampleRate);
    }
  );
  switch (nextStage) {
  | Off =>
    env.currentLevel = 0.;
    env.multiplier = 1.0;
  | Attack =>
    env.currentLevel = env.minimumLevel;
    calculateMultiplier(env, env.currentLevel, 1.0, env.nextStageSample
Index);
  | Decay =>
    env.currentLevel = 1.0;
    calculateMultiplier(
      env,
      env.currentLevel,
      max(params[3], env.minimumLevel),
      env.nextStageSampleIndex,
    );
  | Sustain =>
    env.currentLevel = params[3];
    env.multiplier = 1.0;
  | Release =>
      let idx = find(stageOrder, nextStage, ~i=0);
      int_of_float(params[idx] *. sampleRate);
    }
  );
  switch (nextStage) {
  | Off =>
    env.currentLevel = 0.;
    env.multiplier = 1.0;
  | Attack =>
    env.currentLevel = env.minimumLevel;
    calculateMultiplier(env, env.currentLevel, 1.0, env.nextStageSample
Index);
  | Decay =>
    env.currentLevel = 1.0;
    calculateMultiplier(
      env,
      env.currentLevel,
      max(params[3], env.minimumLevel),
      env.nextStageSampleIndex,
    );
  | Sustain =>
    env.currentLevel = params[3];
    env.multiplier = 1.0;
  | Release =>
    calculateMultiplier(
      env,
      env.currentLevel,
      env.minimumLevel,
      env.nextStageSampleIndex,
    )
  };
  ();
};
let nextSample = (env, params) => {
  switch (env.currentStage) {
  | Off => ()
  | Sustain => ()
  | _ =>
    if (env.currentSampleIndex == env.nextStageSampleIndex) {
      let currentStageIndex = find(stageOrder, env.currentStage, ~i
=0);
      let newStage = (currentStageIndex + 1) mod 5;
      enterStage(env, stageOrder[newStage], params);
    };
    env.currentLevel = env.currentLevel *. env.multiplier;
    env.currentSampleIndex = env.currentSampleIndex + 1;
  };
  env.currentLevel;
};
Audio DSP in ReasonML
Envelopes are typically
triggered by MIDI or a
sequencer
I don’t have PortMIDI bindings, so I
built a sequencer:
Step Sequencer
Tempo (Beats Per Minute)
Beat (1/4 Note)
Step (1/16th Note)
How can we sequence our
sounds?
let steps = [|1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0|];
let currentSample = ref(0.0);
let fill_ba = (ba) => {
  let beatMs = 60000. /. tempo;
  let beatSeconds = beatMs /. 1000.;
  let stepSeconds = beatS /. 4.;
  let step = floor(stepSec *. sampleRate);
if (mod_float(currentSample^, step) == 0.0) {
    /* get current sequencer step for time */
    let stepIndex = int_of_float(currentSample^ /. step);
if (stepIndex !== 0 && steps[stepIndex - 1] === 1) {
     Envelope.enterStage(env, Attack, params);
};
};
/* Reset the sequencer step to 0 */
  if (currentSample^ > step *. 16.) {
    currentSample := 0.0;
  };
}
How about some FX?
How to make a bitcrusher
• A bitcrusher is a combination of adjust bit depth and
downsampling

• Bit depth - resolution of our waves 

• Downsampling - reducing the sample rate
Bitcrusher
Bit Depth
Downsampling
let bitcrusher = Bitcrusher.create(16., 12);
let data = (getWaveData() *. gain) 
|> Bitcrusher.process(bitcrusher);
type bitcrusher = {
  mutable bitDepth: float,
  mutable downSampling: int,
  mutable lastSample: float,
  mutable counter: int,
};
let create = (bitDepth, downSampling) => {
  bitDepth,
  downSampling,
  lastSample: 0.,
  counter: 0,
};
let bitcrush = (v, bitDepth) => {
  let bd = bitDepth -. 1.;
  let i = ref(floor(v *. (-2.) ** bd *. (-1
.)));
  if (v >= 1.0) {
    i := 2. ** bd -. 1.;
  } else if (v <= (-1.0)) {
    i := (-2.) ** bd;
  };
  let out = i^ /. (-2.) ** bd *. (-1.);
  out;
};
let process = (b: bitcrusher, input: float) => 
{
  b.counter = b.counter + 1;
  let out = ref(0.);
  if (b.counter < b.downSampling) {
    out := b.lastSample;
  } else {
    b.counter = 0;
    let sample = bitcrush(input, b.bitDepth);
    b.lastSample = sample;
    out := sample;
  };
  out^;
};
How to make a delay
Delay
(It’s basically an echo)
let bitcrusher = Bitcrusher.create(16., 12);
let data = (getWaveData() *. gain) 
|> Bitcrusher.process(bitcrusher)
|> Delay.process(delay);
Signal Chain
type delay = {
  mutable duration: float,
  mutable gain: float,
  delayBuffer: array(float),
  mutable currentSample: int,
};
let create = (duration, gain) => {
  duration,
  gain,
  delayBuffer: Array.make(int_of_float(sample
Rate *. 2.), 0.),
  currentSample: 0,
};
Delay Buffer
We use a circular buffer to schedule the
current signal to play at a later time
let process = (d: delay, input: float) => {
  /* Max buffer size */
  let max = int_of_float(sampleRate *. 2.) - 1;
  /* If we're at the end of the sample count, reset */
  if (d.currentSample > max) {
    d.currentSample = 0;
  };
  /* How many samples are we delaying */
  let delayIndex = int_of_float(sampleRate *. 2. *. d.duration);
  /* Get our insert index */
  let ii = d.currentSample + delayIndex;
  /
* If the index exceeds the buffer length, insert at beginning wi
th the difference */
  let insertIndex = ii < max + 1 ? ii : ii mod max;
  /* Fill our delay buffer */
  d.delayBuffer[insertIndex] = input;
  /* Mix delay buffer into input signal */
  let output = input +. d.delayBuffer[d.currentSample] *. d.gain
;
  /* Increment sample counter */
  d.currentSample = d.currentSample + 1;
  output;
};
DEMO TIME

More Related Content

PDF
Analog to digital conversion
PDF
It's so quiet. Let's make music.
PPTX
Week two a d conversion
DOCX
Basic principles of audio recording
PDF
The analog to digital conversion process
PPTX
Digital Audio
PPT
Chapter 02 audio recording - part i
PDF
NoiseGen at Arlington Ruby 2012
Analog to digital conversion
It's so quiet. Let's make music.
Week two a d conversion
Basic principles of audio recording
The analog to digital conversion process
Digital Audio
Chapter 02 audio recording - part i
NoiseGen at Arlington Ruby 2012

Similar to Audio DSP in ReasonML (20)

PPTX
Internet of Things (IoT)-Sensors & Actuators - IoT.pptx
PPTX
Sampling rate bit depth_lossey lossless
PPTX
Data Representation in Computers
PDF
Digital signal processing through speech, hearing, and Python
PPTX
Sampling rate bit depth
PDF
Use of an Oscilloscope - maXbox Starter33
DOCX
Digital audio
PDF
07_[15]_Lecture 7[updated].pdf
PDF
Dante Audio Networking Fundamentals
PPTX
Session3
PPTX
Sound digitalisation
PPTX
Chap65
PDF
Audio Signal Processing
PPTX
Digital Electronics for Audio
PPTX
Analogue to digital conversion
PPT
Lecture6 audio
PPT
Lecture6 audio
PPTX
Digital Technology
PPTX
How to play audio from a microcontroller
Internet of Things (IoT)-Sensors & Actuators - IoT.pptx
Sampling rate bit depth_lossey lossless
Data Representation in Computers
Digital signal processing through speech, hearing, and Python
Sampling rate bit depth
Use of an Oscilloscope - maXbox Starter33
Digital audio
07_[15]_Lecture 7[updated].pdf
Dante Audio Networking Fundamentals
Session3
Sound digitalisation
Chap65
Audio Signal Processing
Digital Electronics for Audio
Analogue to digital conversion
Lecture6 audio
Lecture6 audio
Digital Technology
How to play audio from a microcontroller
Ad

Recently uploaded (20)

PDF
Machine learning based COVID-19 study performance prediction
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Empathic Computing: Creating Shared Understanding
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Machine Learning_overview_presentation.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PPT
Teaching material agriculture food technology
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
Cloud computing and distributed systems.
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
cuic standard and advanced reporting.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
A comparative analysis of optical character recognition models for extracting...
PPTX
Spectroscopy.pptx food analysis technology
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
Machine learning based COVID-19 study performance prediction
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Empathic Computing: Creating Shared Understanding
The Rise and Fall of 3GPP – Time for a Sabbatical?
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Machine Learning_overview_presentation.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”
Teaching material agriculture food technology
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Network Security Unit 5.pdf for BCA BBA.
Review of recent advances in non-invasive hemoglobin estimation
Cloud computing and distributed systems.
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
MIND Revenue Release Quarter 2 2025 Press Release
Dropbox Q2 2025 Financial Results & Investor Presentation
cuic standard and advanced reporting.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
A comparative analysis of optical character recognition models for extracting...
Spectroscopy.pptx food analysis technology
Diabetes mellitus diagnosis method based random forest with bat algorithm
Ad

Audio DSP in ReasonML