This commit is contained in:
Felix Roos 2022-03-06 21:39:10 +01:00
parent ad42e5eb61
commit a2ab2b9da5
19 changed files with 72400 additions and 62 deletions

View file

@ -3,6 +3,9 @@ import "./tone.js";
import "./midi.js";
import "./voicings.js";
import "./tonal.js";
import "./xen.js";
import "./tune.js";
import "./tonal.js";
import gist from "./gist.js";
import shapeshifter from "./shapeshifter.js";
import {minify} from "./parse.js";

9
docs/dist/tonal.js vendored
View file

@ -1,13 +1,8 @@
import {Note, Interval, Scale} from "../_snowpack/pkg/@tonaljs/tonal.js";
import {Pattern as _Pattern} from "../_snowpack/link/strudel.js";
import {mod, tokenizeNote} from "../_snowpack/link/util.js";
const Pattern = _Pattern;
const mod = (n, m) => n < 0 ? mod(n + m, m) : n % m;
export function intervalDirection(from, to, direction = 1) {
const sign = Math.sign(direction);
const interval = sign < 0 ? Interval.distance(to, from) : Interval.distance(from, to);
return (sign < 0 ? "-" : "") + interval;
}
function scaleTranspose(scale, offset, note) {
export function scaleTranspose(scale, offset, note) {
let [tonic, scaleName] = Scale.tokenize(scale);
let {notes} = Scale.get(`${tonic} ${scaleName}`);
notes = notes.map((note2) => Note.get(note2).pc);

7
docs/dist/tone.js vendored
View file

@ -19,24 +19,28 @@ import {
Players
} from "../_snowpack/pkg/tone.js";
import {Piano} from "../_snowpack/pkg/@tonejs/piano.js";
import {getPlayableNoteValue} from "../_snowpack/link/util.js";
const Pattern = _Pattern;
Pattern.prototype.tone = function(instrument) {
return this._withEvent((event) => {
const onTrigger = (time, event2) => {
let note = event2.value;
let note;
let velocity = event2.context?.velocity ?? 0.75;
switch (instrument.constructor.name) {
case "PluckSynth":
note = getPlayableNoteValue(event2);
instrument.triggerAttack(note, time);
break;
case "NoiseSynth":
instrument.triggerAttackRelease(event2.duration, time);
break;
case "Piano":
note = getPlayableNoteValue(event2);
instrument.keyDown({note, time, velocity: 0.5});
instrument.keyUp({note, time: time + event2.duration, velocity});
break;
case "Sampler":
note = getPlayableNoteValue(event2);
instrument.triggerAttackRelease(note, event2.duration, time, velocity);
break;
case "Players":
@ -48,6 +52,7 @@ Pattern.prototype.tone = function(instrument) {
player.stop(time + event2.duration);
break;
default:
note = getPlayableNoteValue(event2);
instrument.triggerAttackRelease(note, event2.duration, time, velocity);
}
};

14
docs/dist/tune.js vendored Normal file
View file

@ -0,0 +1,14 @@
import Tune from "./tunejs.js";
import {Pattern} from "../_snowpack/link/strudel.js";
Pattern.prototype._tune = function(scale, tonic = 220) {
const tune = new Tune();
if (!tune.isValidScale(scale)) {
throw new Error('not a valid tune.js scale name: "' + scale + '". See http://abbernie.github.io/tune/scales.html');
}
tune.loadScale(scale);
tune.tonicize(tonic);
return this._asNumber()._withEvent((event) => {
return event.withValue(() => tune.note(event.value)).setContext({...event.context, type: "frequency"});
});
};
Pattern.prototype.define("tune", (scale, pat) => pat.tune(scale), {composable: true, patternified: true});

233
docs/dist/tunejs.js vendored Normal file

File diff suppressed because one or more lines are too long

28
docs/dist/tunes.js vendored
View file

@ -489,3 +489,31 @@ export const wavyKalimba = `sampler({
.legato("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
.fast(1)
})`;
export const jemblung = `() => {
const delay = new FeedbackDelay(1/8, .6).chain(vol(0.15), out());
const snare = noise({type:'white',...adsr(0,0.2,0)}).chain(lowpass(5000),vol(1.8),out());
const s = polysynth().set({...osc('sawtooth4'),...adsr(0.01,.2,.6,0.2)}).chain(vol(.23).connect(delay),out());
return stack(
stack(
"0 1 4 [3!2 5]".edit(
// chords
x=>x.add("0,3").duration("0.05!3 0.02"),
// bass
x=>x.add("-8").struct("x*8").duration(0.1)
),
// melody
"12 11*3 12 ~".duration(0.005)
)
.add("<0 1>")
.tune("jemblung2")
//.mul(22/5).round().xen("22edo")
//.mul(12/5).round().xen("12edo")
.tone(s),
// kick
"[c2 ~]*2".duration(0.05).tone(membrane().chain(out())),
// snare
"[~ c1]*2".early(0.001).tone(snare),
// hihat
"c2*8".tone(noise().chain(highpass(6000),vol(0.5).connect(delay),out())),
).slow(3)
}`;

View file

@ -1,5 +1,5 @@
import {useCallback, useState, useMemo} from "../_snowpack/pkg/react.js";
import {isNote} from "../_snowpack/pkg/tone.js";
import {getPlayableNoteValue} from "../_snowpack/link/util.js";
import {evaluate} from "./evaluate.js";
import useCycle from "./useCycle.js";
import usePostMessage from "./usePostMessage.js";
@ -54,11 +54,8 @@ function useRepl({tune, defaultSynth, autolink = true, onEvent, onDraw}) {
onEvent?.(event);
const {onTrigger, velocity} = event.context;
if (!onTrigger) {
const note = event.value;
if (!isNote(note)) {
throw new Error("not a note: " + note);
}
if (defaultSynth) {
const note = getPlayableNoteValue(event);
defaultSynth.triggerAttackRelease(note, event.duration, time, velocity);
} else {
throw new Error("no defaultSynth passed to useRepl.");

52
docs/dist/xen.js vendored Normal file
View file

@ -0,0 +1,52 @@
import {Pattern} from "../_snowpack/link/strudel.js";
import {mod} from "../_snowpack/link/util.js";
function edo(name) {
if (!/^[1-9]+[0-9]*edo$/.test(name)) {
throw new Error('not an edo scale: "' + name + '"');
}
const [_, divisions] = name.match(/^([1-9]+[0-9]*)edo$/);
return Array.from({length: divisions}, (_2, i) => Math.pow(2, i / divisions));
}
const presets = {
"12ji": [1 / 1, 16 / 15, 9 / 8, 6 / 5, 5 / 4, 4 / 3, 45 / 32, 3 / 2, 8 / 5, 5 / 3, 16 / 9, 15 / 8]
};
function withBase(freq, scale) {
return scale.map((r) => r * freq);
}
const defaultBase = 220;
function getXenScale(scale, indices) {
if (typeof scale === "string") {
if (/^[1-9]+[0-9]*edo$/.test(scale)) {
scale = edo(scale);
} else if (presets[scale]) {
scale = presets[scale];
} else {
throw new Error('unknown scale name: "' + scale + '"');
}
}
scale = withBase(defaultBase, scale);
if (!indices) {
return scale;
}
return scale.filter((_, i) => indices.includes(i));
}
function xenOffset(xenScale, offset, index = 0) {
const i = mod(index + offset, xenScale.length);
const oct = Math.floor(offset / xenScale.length);
return xenScale[i] * Math.pow(2, oct);
}
Pattern.prototype._xen = function(scaleNameOrRatios, steps) {
return this._asNumber()._withEvent((event) => {
const scale = getXenScale(scaleNameOrRatios);
steps = steps || scale.length;
const frequency = xenOffset(scale, event.value);
return event.withValue(() => frequency).setContext({...event.context, type: "frequency"});
});
};
Pattern.prototype.tuning = function(steps) {
return this._asNumber()._withEvent((event) => {
const frequency = xenOffset(steps, event.value);
return event.withValue(() => frequency).setContext({...event.context, type: "frequency"});
});
};
Pattern.prototype.define("xen", (scale, pat) => pat.xen(scale), {composable: true, patternified: true});