Skip to content

Commit

Permalink
Merge branch 'main' into rename-stepwise
Browse files Browse the repository at this point in the history
  • Loading branch information
yaxu committed Feb 2, 2025
2 parents afad575 + ce9d230 commit 6c8f09c
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 7 deletions.
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ pnpm-lock.yaml
pnpm-workspace.yaml
**/dev-dist
website/.astro
!tidal-drum-machines.json
!tidal-drum-machines-alias.json
12 changes: 12 additions & 0 deletions packages/repl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,15 @@ or
The `.editor` property on the `strudel-editor` web component gives you the instance of [StrudelMirror](https://github.com/tidalcycles/strudel/blob/a46bd9b36ea7d31c9f1d3fca484297c7da86893f/packages/codemirror/codemirror.mjs#L124) that runs the REPL.

For example, you could use `setCode` to change the code from the outside, `start` / `stop` to toggle playback or `evaluate` to evaluate the code.

## Development: How to Test

```sh
cd packages/repl
pnpm build
cd ../.. # back to root folder
# edit ./examples/buildless/web-component-no-iframe.html
# use <script src="/packages/repl/dist/index.js"></script>
pnpx serve # from root folder
# go to http://localhost:3000/examples/buildless/web-component-no-iframe
```
7 changes: 6 additions & 1 deletion packages/repl/prebake.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { noteToMidi, valueToMidi, Pattern, evalScope } from '@strudel/core';
import { registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
import { aliasBank, registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
import * as core from '@strudel/core';

export async function prebake() {
Expand All @@ -21,6 +21,9 @@ export async function prebake() {
);
// load samples
const ds = 'https://raw.githubusercontent.com/felixroos/dough-samples/main/';

// TODO: move this onto the strudel repo
const ts = 'https://raw.githubusercontent.com/todepond/samples/main/';
await Promise.all([
modulesLoading,
registerSynthSounds(),
Expand All @@ -38,6 +41,8 @@ export async function prebake() {
// samples(`${ds}/mridangam.json`),
samples(`https://raw.githubusercontent.com/yaxu/mrid/main/strudel.json`),
]);

aliasBank(`${ts}/tidal-drum-machines-alias.json`);
}

const maxPan = noteToMidi('C8');
Expand Down
4 changes: 2 additions & 2 deletions packages/soundfonts/sfumato.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { getAudioContext, registerSound } from '@strudel/webaudio';
import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato';

Pattern.prototype.soundfont = function (sf, n = 0) {
return this.onTrigger((t, h, ct) => {
return this.onTrigger((time_deprecate, h, ct, cps, targetTime) => {
const ctx = getAudioContext();
const note = getPlayableNoteValue(h);
const preset = sf.presets[n % sf.presets.length];
const deadline = ctx.currentTime + t - ct;
const deadline = targetTime;
const args = [ctx, preset, noteToMidi(note), deadline];
const stop = startPresetNote(...args);
stop(deadline + h.duration);
Expand Down
67 changes: 64 additions & 3 deletions packages/superdough/superdough.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,72 @@ import { loadBuffer } from './sampler.mjs';
export const soundMap = map();

export function registerSound(key, onTrigger, data = {}) {
soundMap.setKey(key, { onTrigger, data });
soundMap.setKey(key.toLowerCase(), { onTrigger, data });
}

function aliasBankMap(aliasMap) {
// Make all bank keys lower case for case insensitivity
for (const key in aliasMap) {
aliasMap[key.toLowerCase()] = aliasMap[key];
}

// Look through every sound...
const soundDictionary = soundMap.get();
for (const key in soundDictionary) {
// Check if the sound is part of a bank...
const [bank, suffix] = key.split('_');
if (!suffix) continue;

// Check if the bank is aliased...
const aliasValue = aliasMap[bank];
if (aliasValue) {
if (typeof aliasValue === 'string') {
// Alias a single alias
soundDictionary[`${aliasValue}_${suffix}`.toLowerCase()] = soundDictionary[key];
} else if (Array.isArray(aliasValue)) {
// Alias multiple aliases
for (const alias of aliasValue) {
soundDictionary[`${alias}_${suffix}`.toLowerCase()] = soundDictionary[key];
}
}
}
}

// Update the sound map!
// We need to destructure here to trigger the update
soundMap.set({ ...soundDictionary });
}

async function aliasBankPath(path) {
const response = await fetch(path);
const aliasMap = await response.json();
aliasBankMap(aliasMap);
}

/**
* Register an alias for a bank of sounds.
* Optionally accepts a single argument map of bank aliases.
* Optionally accepts a single argument string of a path to a JSON file containing bank aliases.
* @param {string} bank - The bank to alias
* @param {string} alias - The alias to use for the bank
*/
export async function aliasBank(...args) {
switch (args.length) {
case 1:
if (typeof args[0] === 'string') {
return aliasBankPath(args[0]);
} else {
return aliasBankMap(args[0]);
}
case 2:
return aliasBankMap({ [args[0]]: args[1] });
default:
throw new Error('aliasMap expects 1 or 2 arguments, received ' + args.length);
}
}

export function getSound(s) {
return soundMap.get()[s];
return soundMap.get()[s.toLowerCase()];
}

const defaultDefaultValues = {
Expand Down Expand Up @@ -314,14 +375,14 @@ export function resetGlobalEffects() {
}

export const superdough = async (value, t, hapDuration) => {
const ac = getAudioContext();
t = typeof t === 'string' && t.startsWith('=') ? Number(t.slice(1)) : ac.currentTime + t;
let { stretch } = value;
if (stretch != null) {
//account for phase vocoder latency
const latency = 0.04;
t = t - latency;
}
const ac = getAudioContext();
if (typeof value !== 'object') {
throw new Error(
`expected hap.value to be an object, but got "${value}". Hint: append .note() or .s() to the end`,
Expand Down
68 changes: 68 additions & 0 deletions website/public/tidal-drum-machines-alias.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"AJKPercusyn": "Percysyn",
"AkaiLinn": "Linn",
"AkaiMPC60": "MPC60",
"AkaiXR10": "XR10",
"AlesisHR16": "HR16",
"AlesisSR16": "SR16",
"BossDR110": "DR110",
"BossDR220": "DR220",
"BossDR55": "DR55",
"BossDR550": "DR550",
"CasioRZ1": "RZ1",
"CasioSK1": "SK1",
"CasioVL1": "VL1",
"DoepferMS404": "MS404",
"EmuDrumulator": "Drumulator",
"EmuSP12": "SP12",
"KorgDDM110": "DDM110",
"KorgKPR77": "KPR77",
"KorgKR55": "KR55",
"KorgKRZ": "KRZ",
"KorgM1": "M1",
"KorgMinipops": "Minipops",
"KorgPoly800": "Poly800",
"KorgT3": "T3",
"Linn9000": "9000",
"LinnLM1": "LM1",
"LinnLM2": "LM2",
"MoogConcertMateMG1": "ConcertMateMG1",
"OberheimDMX": "DMX",
"RhodesPolaris": "Polaris",
"RhythmAce": "Ace",
"RolandCompurhythm1000": "Compurhythm1000",
"RolandCompurhythm78": "Compurhythm78",
"RolandCompurhythm8000": "Compurhythm8000",
"RolandD110": "D110",
"RolandD70": "D70",
"RolandDDR30": "DDR30",
"RolandJD990": "JD990",
"RolandMC202": "MC202",
"RolandMC303": "MC303",
"RolandMT32": "MT32",
"RolandR8": "R8",
"RolandS50": "S50",
"RolandSH09": "SH09",
"RolandSystem100": "System100",
"RolandTR505": "TR505",
"RolandTR606": "TR606",
"RolandTR626": "TR626",
"RolandTR707": "TR707",
"RolandTR727": "TR727",
"RolandTR808": "TR808",
"RolandTR909": "TR909",
"SakataDPM48": "DPM48",
"SequentialCircuitsDrumtracks": "CircuitsDrumtracks",
"SequentialCircuitsTom": "CircuitsTom",
"SimmonsSDS400": "SDS400",
"SimmonsSDS5": "SDS5",
"SoundmastersR88": "R88",
"UnivoxMicroRhythmer12": "MicroRhythmer12",
"ViscoSpaceDrum": "SpaceDrum",
"XdrumLM8953": "LM8953",
"YamahaRM50": "RM50",
"YamahaRX21": "RX21",
"YamahaRX5": "RX5",
"YamahaRY30": "RY30",
"YamahaTG33": "TG33"
}
4 changes: 3 additions & 1 deletion website/src/repl/prebake.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Pattern, noteToMidi, valueToMidi } from '@strudel/core';
import { registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
import { aliasBank, registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
import { registerSamplesFromDB } from './idbutils.mjs';
import './piano.mjs';
import './files.mjs';
Expand Down Expand Up @@ -121,6 +121,8 @@ export async function prebake() {
},
),
]);

aliasBank(`${baseNoTrailing}/tidal-drum-machines-alias.json`);
}

const maxPan = noteToMidi('C8');
Expand Down

0 comments on commit 6c8f09c

Please sign in to comment.