Skip to content

Commit

Permalink
chore: drum examples
Browse files Browse the repository at this point in the history
  • Loading branch information
danigb committed Sep 4, 2024
1 parent 16904de commit f6fd0ff
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 65 deletions.
34 changes: 15 additions & 19 deletions packages/synthlet/operators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { AdInputParams, createAdNode } from "@synthlet/ad";
import { createClipAmpNode } from "@synthlet/clip-amp";
import { createImpulseNode } from "@synthlet/impulse";
import { createNoiseNode } from "@synthlet/noise";
import { createParamNode, ParamType, ParamWorkletNode } from "@synthlet/param";
import {
createParamNode,
ParamInputParams,
ParamType,
ParamWorkletNode,
} from "@synthlet/param";
import { createPolyblepOscillatorNode } from "@synthlet/polyblep-oscillator";
import { DisposableAudioNode, ParamInput } from "./src/_worklet";
import {
Expand Down Expand Up @@ -31,6 +36,9 @@ export function createOperators(context: AudioContext) {
};
};

const param = (value?: ParamInput, params?: Partial<ParamInputParams>) =>
add(createParamNode(context, { input: value, ...params }));

return {
// Connect
serial: (...nodes: AudioNode[]) =>
Expand All @@ -43,24 +51,12 @@ export function createOperators(context: AudioContext) {
nodes.forEach((node) => node.connect(destination));
return destination;
},
// Parameters
param: (value?: ParamInput) =>
add(createParamNode(context, { input: value })),
dbToGain: (value?: ParamInput) =>
add(
createParamNode(context, { input: value, type: ParamType.DB_TO_GAIN })
),
volume: (offset?: ParamInput) =>
add(createParamNode(context, { offset, type: ParamType.DB_TO_GAIN })),
linear: (min: ParamInput, max: ParamInput, value?: ParamInput) =>
add(
createParamNode(context, {
input: value,
type: ParamType.LINEAR,
min,
max,
})
),

param: Object.assign(param, {
db: (db?: number) => param(db, { type: ParamType.DB_TO_GAIN }),
lin: (min: ParamInput, max: ParamInput, value?: ParamInput) =>
param(value, { type: ParamType.LINEAR, min, max }),
}),

// Oscillators
sine: (frequency?: ParamInput, detune?: ParamInput) =>
Expand Down
46 changes: 19 additions & 27 deletions packages/synthlet/src/synths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type DrumNode = AudioNode & {
trigger: AudioParam;
volume: AudioParam;
tone: AudioParam;
decay: AudioParam;
dispose(): void;
};
export type KickDrumNode = DrumNode & {};
Expand All @@ -13,22 +14,21 @@ export function KickDrum(context: AudioContext): KickDrumNode {
const op = createOperators(context);

const trigger = op.param();
const volume = op.volume();
const tone = op.linear(30, 100, 0.2);
const decay = op.param(0.8);
const volume = op.param.db();
const tone = op.param.lin(30, 100, 0.2);

const toneEnv = op.ad(trigger, 0.1, 0.5, { offset: 40, gain: 50 });
const toneEnv = op.ad(trigger, 0.1, decay, { offset: tone, gain: 50 });

const out = op.serial(
op.mix([op.sine(tone), op.pulse(trigger)], op.ad(trigger, 0.01, 0.1)),
op.mix(
[op.sine(toneEnv), op.pulse(trigger)],
op.perc(trigger, 0.01, decay)
),
op.softClip(3, 0.5, ClipType.Tanh)
);

return Object.assign(out, {
trigger: trigger.input,
volume: volume.input,
tone: tone.input,
dispose: op.disposer(out),
});
return op.synth(out, { trigger, volume, tone, decay });
}

export type SnareDrumNode = DrumNode & {};
Expand All @@ -37,31 +37,28 @@ export function SnareDrum(context: AudioContext): SnareDrumNode {
const op = createOperators(context);

const trigger = op.param();
const volume = op.volume();
const volume = op.param.db();
const decay = op.param();
const tone = op.param();

const out = op.mix(
[
op.serial(op.white(), op.ad(trigger)),
op.mix([op.sine(100), op.sine(200)], op.ad(trigger)),
op.serial(op.white(), op.perc(trigger, 0.01, decay)),
op.mix([op.sine(100), op.sine(200)], op.perc(trigger, 0.01, decay)),
],
op.amp(volume)
);

return Object.assign(out, {
trigger: trigger.input,
volume: volume.input,
tone: tone.input,
dispose: op.disposer(out),
});
return op.synth(out, { trigger, volume, tone, decay });
}

export function ClaveDrum(context: AudioContext): DrumNode {
const op = createOperators(context);

const volume = op.volume();
const volume = op.param.db();
const trigger = op.param();
const tone = op.linear(1200, 1800, 0.6);
const decay = op.param();
const tone = op.param.lin(1200, 1800, 0.6);

const out = op.serial(
op.tri(tone),
Expand All @@ -70,10 +67,5 @@ export function ClaveDrum(context: AudioContext): DrumNode {
op.amp(volume)
);

return Object.assign(out, {
trigger: trigger.input,
volume: volume.input,
tone: tone.input,
dispose: op.disposer(out),
});
return op.synth(out, { trigger, volume, tone, decay });
}
16 changes: 8 additions & 8 deletions site/components/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { useEffect, useState } from "react";

export function Slider({
label,
min,
max,
initial,
min = 0,
max = 1,
initial = 0,
onChange,
step = 1,
step,
transform = (x) => x,
inputClassName,
labelClassName,
Expand All @@ -15,9 +15,9 @@ export function Slider({
initialize,
}: {
label: string;
min: number;
max: number;
initial: number;
min?: number;
max?: number;
initial?: number;
onChange: (value: number) => void;
transform?: (value: number) => number;
step?: number;
Expand All @@ -42,7 +42,7 @@ export function Slider({
type="range"
min={min}
max={max}
step={step}
step={step ?? "any"}
value={value}
onChange={(e) => {
const value = e.target.valueAsNumber;
Expand Down
36 changes: 25 additions & 11 deletions site/examples/DrumExample.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
"use client";

import { Slider } from "@/components/Slider";
import { useState } from "react";
import { ClaveDrum, KickDrum, SnareDrum } from "synthlet";
import { CreateSynth, Synth, useSynth } from "./useSynth";

type DrumSynth = Synth & {
trigger: AudioParam;
volume: AudioParam;
tone: AudioParam;
decay: AudioParam;
dispose(): void;
};

function getSynth(instrumentName: string) {
Expand Down Expand Up @@ -51,7 +56,7 @@ function DrumExampleUI<T extends DrumSynth>({
}: {
instrumentName: string;
onClose: () => void;
createSynth: CreateSynth<T>;
createSynth: CreateSynth<DrumSynth>;
}) {
const [selectedNoiseType, setSelectedNoiseType] = useState(0);
const [volume, setVolume] = useState(-60);
Expand All @@ -62,19 +67,28 @@ function DrumExampleUI<T extends DrumSynth>({
<div className="bg-fd-card text-fd-foreground p-2 border rounded">
<div className="text-xl mb-4">{instrumentName} example</div>

<div className="flex items-center gap-2 mb-4">
<div>Tone:</div>
<input
type="range"
min={0}
max={1}
step={0.01}
onChange={(e) => {
(synth as any).tone.value = e.target.valueAsNumber;
<div className="flex items-center gap-2">
<Slider
label="Tone"
labelClassName="w-20 text-right mr-2"
onChange={(value) => {
synth.tone.value = value;
}}
/>
</div>
<div className="flex items-center gap-2 mb-4">
<div className="flex gap-2">
<Slider
label="Decay"
labelClassName="w-20 text-right mr-2"
initial={0.4}
initialize
units="s"
onChange={(value) => {
synth.decay.value = value;
}}
/>
</div>
<div className="flex items-center gap-2 my-4">
<button
className="border px-2 py-1 rounded bg-fd-primary text-fd-primary-foreground"
onMouseDown={() => {
Expand Down

0 comments on commit f6fd0ff

Please sign in to comment.