Integration Guide

Complete guide to using DSonic in your projects

Integration Guide

Complete guide to using DSonic in your projects

Overview

DSonic is a Web Audio drum synthesizer with two primary use cases:

  1. Strudel Integration - Use DSonic as a sound source in Strudel live-coding patterns
  2. Standalone Usage - Use DSonic directly in any web application via the Web Audio API
License Note: DSonic is MIT licensed. When integrating with Strudel (AGPL-3.0), the Strudel license terms apply to the combined work if you distribute it.

Architecture

DSonic provides two synthesis systems:

System Description Sound Names
Voice-based Two-layer (oscillator + noise) with waveguide resonator dsonic, dsonic_kick, dsonic_snare, etc.
Engine-based 12 specialized algorithms optimized for specific drum types dsonic_akick, dsonic_hsnare, dsonic_fmperc, etc.

Prerequisites

For Strudel Integration

  • Familiarity with Strudel pattern syntax (strudel.cc/learn)
  • Understanding of Strudel's audio architecture
  • Modern browser with Web Audio API support

For Standalone Usage

  • Node.js 18+ and npm (for npm installation)
  • ES modules-compatible bundler (Vite, webpack, esbuild, etc.)
  • Basic understanding of Web Audio API concepts (AudioContext, AudioNode)
  • TypeScript support recommended (types are included)

Strudel Integration: CDN Script

CDN Script Tag Easy

Load DSonic directly in the browser without a build step. Best for quick prototyping.

Basic Setup

Add DSonic after Strudel's scripts in your HTML:

HTML
<!-- Load Strudel REPL -->
<script src="https://unpkg.com/@strudel/repl@latest"></script>

<!-- Load DSonic -->
<script type="module">
  import { registerDSonic } from 'https://unpkg.com/dsonic@latest/dist/dsonic.js';

  // Wait for Strudel to initialize, then register DSonic
  setTimeout(() => {
    registerDSonic();
  }, 1000);
</script>

<!-- Strudel editor component -->
<strudel-editor>
s("dsonic_kick").freq(55).decay(0.3)
</strudel-editor>

Complete Example

HTML
<!DOCTYPE html>
<html>
<head>
  <title>DSonic + Strudel</title>
</head>
<body>
  <script src="https://unpkg.com/@strudel/repl@latest"></script>

  <strudel-editor id="editor">
// DSonic drum pattern
stack(
  s("dsonic_akick").freq(50).decay(0.4),
  s("dsonic_hsnare").struct("~ x").decay(0.15),
  s("dsonic_hhat*4").decay(0.05)
)
  </strudel-editor>

  <script type="module">
    import { registerDSonic } from 'https://unpkg.com/dsonic@latest/dist/dsonic.js';

    // Poll for Strudel's registerSound function
    const waitForStrudel = () => {
      if (typeof registerSound === 'function') {
        registerDSonic();
        console.log('DSonic ready!');
      } else {
        setTimeout(waitForStrudel, 100);
      }
    };
    waitForStrudel();
  </script>
</body>
</html>
Version Pinning: For production, pin DSonic to a specific version (e.g., dsonic@0.1.0) to prevent breaking changes.

Strudel Integration: npm Package

npm Installation Intermediate

Use with a bundler for optimal bundle size and type safety. Best for production applications.

Installation

BASH
npm install dsonic @strudel/core @strudel/webaudio

Vite Configuration

JAVASCRIPT
// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  build: { target: 'es2020' },
  optimizeDeps: {
    include: ['dsonic', '@strudel/core', '@strudel/webaudio'],
  },
});

Main Script

JAVASCRIPT
// src/main.js
import { registerDSonic } from 'dsonic';
import { repl } from '@strudel/repl';

const editor = repl({ id: 'editor', defaultOutput: 'speakers' });

editor.scheduler.on('ready', () => {
  registerDSonic();
});

Strudel Integration: Custom REPL

Custom UI with @strudel/web Advanced

Build your own interface without Strudel's default editor. Full control over the UI.

Minimal Custom Player

JAVASCRIPT
import { getAudioContext, initAudioOnFirstClick } from '@strudel/webaudio';
import { evaluate, Scheduler } from '@strudel/core';
import { registerDSonic } from 'dsonic';

initAudioOnFirstClick();
const scheduler = new Scheduler({ getAudioContext, interval: 0.05, ahead: 0.15 });
registerDSonic();

async function playPattern(code) {
  const { pattern } = await evaluate(code);
  scheduler.setPattern(pattern);
  scheduler.start();
}

Strudel Pattern Examples

Basic Drum Kit

JAVASCRIPT
// Four-on-the-floor pattern
stack(
  s("dsonic_akick").freq(50).decay(0.35),
  s("dsonic_hsnare").struct("~ x").decay(0.15),
  s("dsonic_hhat*4").decay(0.05),
  s("dsonic_hclap").struct("~ ~ ~ x").decay(0.2)
)

Available Sound Names

Voice-based Engine-based
dsonicdsonic_akick
dsonic_kickdsonic_membrane
dsonic_snaredsonic_hsnare
dsonic_hihatdsonic_hclap
dsonic_openhatdsonic_hhat
dsonic_clapdsonic_hcymbal
dsonic_tomdsonic_htom
dsonic_ridedsonic_hrim
dsonic_crashdsonic_shaker
dsonic_rimshotdsonic_fold
dsonic_noisedsonic_impact
dsonic_fmperc

Standalone Usage: Setup

Use DSonic directly without Strudel for custom applications, games, or any Web Audio project.

npm Installation

BASH
npm install dsonic

TypeScript Configuration

JSON
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler"
  }
}

Standalone Usage: API

DrumSynth (Voice-based)

JAVASCRIPT
import { DrumSynth, getTemplateParams, setAudioContext } from 'dsonic';

const audioContext = new AudioContext();
setAudioContext(audioContext);

const synth = new DrumSynth(audioContext);
const kickParams = getTemplateParams('kick');
const { node, stop } = synth.trigger(audioContext.currentTime, kickParams);

DrumSynth Methods

MethodDescription
trigger(time, params)Trigger a voice. Returns { node, stop }
setMasterGain(gain)Set master output level (0-1)
setWaveguide(params)Configure shared waveguide resonator
stopAll()Stop all playing voices
getOutput()Get the output AudioNode for routing

Standalone Usage: Engines

Engine-based synthesis provides 12 specialized drum algorithms:

Using createEngine()

JAVASCRIPT
import { createEngine, getAudioContext } from 'dsonic';

const ctx = getAudioContext();
const kick = createEngine(ctx, 'analog_kick', {
  bodyPitch: 50,
  bodyDecay: 0.35,
  pitchEnvAmt: 36,
});

kick.getOutput().connect(ctx.destination);
kick.trigger(ctx.currentTime);
setTimeout(() => kick.dispose(), 1000);

Engine Types

TypeClassUse Case
'analog_kick'AnalogKickEngine808/909-style kicks
'membrane'DualMembraneEnginePhysical snare
'hybrid_snare'HybridSnareEngineAnalog body + noise
'clap'ClapEngineMulti-hit handclaps
'hat'HatEngineMetallic hi-hats
'cymbal'CymbalEngineCrashes, rides
'tom'TomCongaEngineToms, congas
'rim'RimClaveEngineRimshots, claves
'shaker'ShakerEngineGranular shakers
'fold'FoldWavetableEngineWaveshaping drums
'impact'ImpactEngineMulti-layer percussion
'fm'FMPercEngine4-operator FM

Configuration

Audio Context Management

JAVASCRIPT
import { getAudioContext, setAudioContext } from 'dsonic';

const myContext = new AudioContext({ sampleRate: 48000 });
setAudioContext(myContext);

Waveguide Configuration

JAVASCRIPT
import { setWaveguide } from 'dsonic';

setWaveguide({
  tune: 0.5,
  decay: 0.6,
  body: 0.4,
  mode: 'tube'
});

Troubleshooting

No Sound Output

AudioContext suspended: Browsers require user interaction before playing audio. Ensure you create/resume AudioContext in a click handler.
JAVASCRIPT
document.getElementById('play').onclick = async () => {
  const ctx = getAudioContext();
  if (ctx.state === 'suspended') await ctx.resume();
};

registerSound Not Found

Wait for Strudel to initialize before registering DSonic:

JAVASCRIPT
function waitForStrudel(callback) {
  if (typeof registerSound === 'function') callback();
  else setTimeout(() => waitForStrudel(callback), 100);
}
waitForStrudel(() => registerDSonic());

Memory Leaks

Always dispose engines after use:

JAVASCRIPT
const engine = createEngine(ctx, 'analog_kick', params);
engine.trigger(ctx.currentTime);
setTimeout(() => engine.dispose(), 1000);

Getting Help