mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-26 13:08:28 +00:00
document setSound api
This commit is contained in:
parent
41d82eaadf
commit
ff1e6714c6
@ -18,6 +18,9 @@ export const soundMap = map();
|
|||||||
export function setSound(key, onTrigger, data = {}) {
|
export function setSound(key, onTrigger, data = {}) {
|
||||||
soundMap.setKey(key, { onTrigger, data });
|
soundMap.setKey(key, { onTrigger, data });
|
||||||
}
|
}
|
||||||
|
export function getSound(s) {
|
||||||
|
return soundMap.get()[s];
|
||||||
|
}
|
||||||
export const resetLoadedSounds = () => soundMap.set({});
|
export const resetLoadedSounds = () => soundMap.set({});
|
||||||
|
|
||||||
let audioContext;
|
let audioContext;
|
||||||
@ -166,8 +169,8 @@ export const webaudioOutput = async (hap, deadline, hapDuration, cps) => {
|
|||||||
let sourceNode;
|
let sourceNode;
|
||||||
if (source) {
|
if (source) {
|
||||||
sourceNode = source(t, hap.value);
|
sourceNode = source(t, hap.value);
|
||||||
} else if (soundMap.get()[s]) {
|
} else if (getSound(s)) {
|
||||||
const { onTrigger } = soundMap.get()[s];
|
const { onTrigger } = getSound(s);
|
||||||
const soundHandle = await onTrigger(t, hap.value, onended);
|
const soundHandle = await onTrigger(t, hap.value, onended);
|
||||||
if (soundHandle) {
|
if (soundHandle) {
|
||||||
sourceNode = soundHandle.node;
|
sourceNode = soundHandle.node;
|
||||||
|
|||||||
@ -73,6 +73,7 @@ export const SIDEBAR: Sidebar = {
|
|||||||
],
|
],
|
||||||
Development: [
|
Development: [
|
||||||
{ text: 'REPL', link: 'technical-manual/repl' },
|
{ text: 'REPL', link: 'technical-manual/repl' },
|
||||||
|
{ text: 'Sounds', link: 'technical-manual/sounds' },
|
||||||
{ text: 'Packages', link: 'technical-manual/packages' },
|
{ text: 'Packages', link: 'technical-manual/packages' },
|
||||||
{ text: 'Docs', link: 'technical-manual/docs' },
|
{ text: 'Docs', link: 'technical-manual/docs' },
|
||||||
{ text: 'Testing', link: 'technical-manual/testing' },
|
{ text: 'Testing', link: 'technical-manual/testing' },
|
||||||
|
|||||||
75
website/src/pages/technical-manual/sounds.mdx
Normal file
75
website/src/pages/technical-manual/sounds.mdx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
title: Sounds
|
||||||
|
layout: ../../layouts/MainLayout.astro
|
||||||
|
---
|
||||||
|
|
||||||
|
import { MiniRepl } from '../../docs/MiniRepl';
|
||||||
|
|
||||||
|
# Sounds
|
||||||
|
|
||||||
|
Let's take a closer look about how sounds are implemented in the webaudio output.
|
||||||
|
|
||||||
|
## Registering a sound via setSound
|
||||||
|
|
||||||
|
All sounds are registered in the sound map, using the the `setSound` function:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function setSound(
|
||||||
|
name: string, // The name of the sound that should be given to `s`, e.g. `mysaw`
|
||||||
|
// The function called by the scheduler to trigger the sound:
|
||||||
|
(
|
||||||
|
time: number, // The audio context time the sound should start
|
||||||
|
value: object, // The value of the `Hap`
|
||||||
|
onended: () => void // A callback that should be fired when the sound has ended
|
||||||
|
) => {
|
||||||
|
node: AudioNode, // node to connect to rest of the effects chain
|
||||||
|
stop: (time:number) => void // a function that will stop the sound
|
||||||
|
},
|
||||||
|
data: object // meta data, only for ui logic in sounds tab
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
When `setSound` is called, it registers `{ onTrigger, data }` under the given `name` in a [nanostore map](https://github.com/nanostores/nanostores#maps).
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
This might be a bit abstract, so here is a minimal example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
setSound(
|
||||||
|
'mysaw',
|
||||||
|
(time, value, onended) => {
|
||||||
|
let { freq } = value; // destructure control params
|
||||||
|
const ctx = getAudioContext();
|
||||||
|
// create oscillator
|
||||||
|
const o = new OscillatorNode(ctx, { type: 'sawtooth', frequency: Number(freq) });
|
||||||
|
o.start(time);
|
||||||
|
// add gain node to level down osc
|
||||||
|
const g = new GainNode(ctx, { gain: 0.3 });
|
||||||
|
// connect osc to gain
|
||||||
|
const node = o.connect(g);
|
||||||
|
// this function can be called from outside to stop the sound
|
||||||
|
const stop = (time) => o.stop(time);
|
||||||
|
// ended will be fired when stop has been fired
|
||||||
|
o.addEventListener('ended', () => {
|
||||||
|
o.disconnect();
|
||||||
|
g.disconnect();
|
||||||
|
onended();
|
||||||
|
});
|
||||||
|
return { node, stop };
|
||||||
|
},
|
||||||
|
{ type: 'synth' },
|
||||||
|
);
|
||||||
|
// use the sound
|
||||||
|
freq(220, 440, 330).s('mysaw');
|
||||||
|
```
|
||||||
|
|
||||||
|
You can actually use this code in the [REPL](https://strudel.tidalcycles.org/) and it'll work.
|
||||||
|
After evaluating the code, you should see `mysaw` in listed in the sounds tab.
|
||||||
|
|
||||||
|
## Playing sounds
|
||||||
|
|
||||||
|
Now here is what happens when a sound is played:
|
||||||
|
When the webaudio output plays a `Hap`, it will lookup and call the `onTrigger` function for the given `s`.
|
||||||
|
The returned `node` can then be connected to the rest of the standard effects chain
|
||||||
|
Having the stop function separate allows playing sounds via midi too, where you don't know how long the noteon will last
|
||||||
Loading…
x
Reference in New Issue
Block a user