diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 8779c4a9b..a03658a8b 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -923,7 +923,12 @@ const generic_params = [ * */ ['lsize'], - // label for pianoroll + /** + * Sets the displayed text for an event on the pianoroll + * + * @name label + * @param {string} label text to display + */ ['activeLabel'], [['label', 'activeLabel']], // ['lfo'], diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 370776f30..f30d21c81 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2191,6 +2191,9 @@ export const duration = register('duration', function (value, pat) { /** * Sets the color of the hap in visualizations like pianoroll or highlighting. + * @name color + * @synonyms colour + * @param {string} color Hexadecimal or CSS color name */ // TODO: move this to controls https://github.com/tidalcycles/strudel/issues/288 export const { color, colour } = register(['color', 'colour'], function (color, pat) { diff --git a/packages/core/pianoroll.mjs b/packages/core/pianoroll.mjs index f3d2c38a2..c10460a49 100644 --- a/packages/core/pianoroll.mjs +++ b/packages/core/pianoroll.mjs @@ -56,6 +56,40 @@ Pattern.prototype.pianoroll = function (options = {}) { // this function allows drawing a pianoroll without ties to Pattern.prototype // it will probably replace the above in the future + +/** + * Displays a midi-style piano roll + * + * @name pianoroll + * @param {Object} options Object containing all the optional following parameters as key value pairs: + * @param {integer} cycles number of cycles to be displayed at the same time - defaults to 4 + * @param {number} playhead location of the active notes on the time axis - 0 to 1, defaults to 0.5 + * @param {boolean} vertical displays the roll vertically - 0 by default + * @param {boolean} labels displays labels on individual notes (see the label function) - 0 by default + * @param {boolean} flipTime reverse the direction of the roll - 0 by default + * @param {boolean} flipValues reverse the relative location of notes on the value axis - 0 by default + * @param {number} overscan lookup X cycles outside of the cycles window to display notes in advance - 1 by default + * @param {boolean} hideNegative hide notes with negative time (before starting playing the pattern) - 0 by default + * @param {boolean} smear notes leave a solid trace - 0 by default + * @param {boolean} fold notes takes the full value axis width - 0 by default + * @param {string} active hexadecimal or CSS color of the active notes - defaults to #FFCA28 + * @param {string} inactive hexadecimal or CSS color of the inactive notes - defaults to #7491D2 + * @param {string} background hexadecimal or CSS color of the background - defaults to transparent + * @param {string} playheadColor hexadecimal or CSS color of the line representing the play head - defaults to white + * @param {boolean} fill notes are filled with color (otherwise only the label is displayed) - 0 by default + * @param {boolean} fillActive active notes are filled with color - 0 by default + * @param {boolean} stroke notes are shown with colored borders - 0 by default + * @param {boolean} strokeActive active notes are shown with colored borders - 0 by default + * @param {boolean} hideInactive only active notes are shown - 0 by default + * @param {boolean} colorizeInactive use note color for inactive notes - 1 by default + * @param {string} fontFamily define the font used by notes labels - defaults to 'monospace' + * @param {integer} minMidi minimum note value to display on the value axis - defaults to 10 + * @param {integer} maxMidi maximum note value to display on the value axis - defaults to 90 + * @param {boolean} autorange automatically calculate the minMidi and maxMidi parameters - 0 by default + * + * @example + * note("C2 A2 G2").euclid(5,8).s('piano').clip(1).color('salmon').pianoroll({vertical:1, labels:1}) + */ export function pianoroll({ time, haps, diff --git a/packages/csound/index.mjs b/packages/csound/index.mjs index 31ffa83a5..3063febc1 100644 --- a/packages/csound/index.mjs +++ b/packages/csound/index.mjs @@ -137,7 +137,7 @@ export async function loadOrc(url) { export const csoundm = register('csoundm', (instrument, pat) => { let p1 = instrument; if (typeof instrument === 'string') { - p1 = `"{instrument}"`; + p1 = `"${instrument}"`; } init(); // not async to support csound inside other patterns + to be able to call pattern methods after it return pat.onTrigger((tidal_time, hap) => { diff --git a/packages/serial/serial.mjs b/packages/serial/serial.mjs index c4e52d4d2..652b60546 100644 --- a/packages/serial/serial.mjs +++ b/packages/serial/serial.mjs @@ -6,23 +6,23 @@ This program is free software: you can redistribute it and/or modify it under th import { Pattern, isPattern } from '@strudel.cycles/core'; -var writeMessage; +var writeMessagers = {}; var choosing = false; -export async function getWriter(br = 38400) { +export async function getWriter(name, br) { if (choosing) { return; } choosing = true; - if (writeMessage) { - return writeMessage; + if (name in writeMessagers) { + return writeMessagers[name]; } if ('serial' in navigator) { const port = await navigator.serial.requestPort(); await port.open({ baudRate: br }); const encoder = new TextEncoder(); const writer = port.writable.getWriter(); - writeMessage = function (message, chk) { + writeMessagers[name] = function (message, chk) { const encoded = encoder.encode(message); if (!chk) { writer.write(encoded); @@ -63,10 +63,10 @@ function crc16(data) { return crc & 0xffff; } -Pattern.prototype.serial = function (br = 38400, sendcrc = false, singlecharids = false) { +Pattern.prototype.serial = function (br = 115200, sendcrc = false, singlecharids = false, name = 'default') { return this.withHap((hap) => { - if (!writeMessage) { - getWriter(br); + if (!(name in writeMessagers)) { + getWriter(name, br); } const onTrigger = (time, hap, currentTime) => { var message = ''; @@ -108,7 +108,7 @@ Pattern.prototype.serial = function (br = 38400, sendcrc = false, singlecharids const offset = (time - currentTime + latency) * 1000; window.setTimeout(function () { - writeMessage(message, chk); + writeMessagers[name](message, chk); }, offset); }; return hap.setContext({ ...hap.context, onTrigger, dominantTrigger: true }); diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index cbc591fb0..b8f10d5da 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -57,7 +57,6 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol const bufferSource = ac.createBufferSource(); bufferSource.buffer = buffer; const playbackRate = 1.0 * Math.pow(2, transpose / 12); - // bufferSource.playbackRate.value = Math.pow(2, transpose / 12); bufferSource.playbackRate.value = playbackRate; return bufferSource; }; @@ -240,6 +239,8 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { begin = 0, loopEnd = 1, end = 1, + vib, + vibmod = 0.5, } = value; // load sample if (speed === 0) { @@ -255,6 +256,19 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, bank, resolveUrl); + // vibrato + let vibratoOscillator; + if (vib > 0) { + vibratoOscillator = getAudioContext().createOscillator(); + vibratoOscillator.frequency.value = vib; + const gain = getAudioContext().createGain(); + // Vibmod is the amount of vibrato, in semitones + gain.gain.value = vibmod * 100; + vibratoOscillator.connect(gain); + gain.connect(bufferSource.detune); + vibratoOscillator.start(0); + } + // asny stuff above took too long? if (ac.currentTime > t) { logger(`[sampler] still loading sound "${s}:${n}"`, 'highlight'); @@ -286,6 +300,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { envelope.connect(out); bufferSource.onended = function () { bufferSource.disconnect(); + vibratoOscillator?.stop(); envelope.disconnect(); out.disconnect(); onended(); diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 8c49000a2..a12fcb655 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -3467,6 +3467,39 @@ exports[`runs examples > example "phasersweep" example index 0 1`] = ` ] `; +exports[`runs examples > example "pianoroll" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | note:C2 s:piano clip:1 ]", + "[ (1/4 → 1/3) ⇝ 3/8 | note:C2 s:piano clip:1 ]", + "[ 1/4 ⇜ (1/3 → 3/8) | note:A2 s:piano clip:1 ]", + "[ 3/8 → 1/2 | note:A2 s:piano clip:1 ]", + "[ (5/8 → 2/3) ⇝ 3/4 | note:A2 s:piano clip:1 ]", + "[ 5/8 ⇜ (2/3 → 3/4) | note:G2 s:piano clip:1 ]", + "[ 3/4 → 7/8 | note:G2 s:piano clip:1 ]", + "[ 1/1 → 9/8 | note:C2 s:piano clip:1 ]", + "[ (5/4 → 4/3) ⇝ 11/8 | note:C2 s:piano clip:1 ]", + "[ 5/4 ⇜ (4/3 → 11/8) | note:A2 s:piano clip:1 ]", + "[ 11/8 → 3/2 | note:A2 s:piano clip:1 ]", + "[ (13/8 → 5/3) ⇝ 7/4 | note:A2 s:piano clip:1 ]", + "[ 13/8 ⇜ (5/3 → 7/4) | note:G2 s:piano clip:1 ]", + "[ 7/4 → 15/8 | note:G2 s:piano clip:1 ]", + "[ 2/1 → 17/8 | note:C2 s:piano clip:1 ]", + "[ (9/4 → 7/3) ⇝ 19/8 | note:C2 s:piano clip:1 ]", + "[ 9/4 ⇜ (7/3 → 19/8) | note:A2 s:piano clip:1 ]", + "[ 19/8 → 5/2 | note:A2 s:piano clip:1 ]", + "[ (21/8 → 8/3) ⇝ 11/4 | note:A2 s:piano clip:1 ]", + "[ 21/8 ⇜ (8/3 → 11/4) | note:G2 s:piano clip:1 ]", + "[ 11/4 → 23/8 | note:G2 s:piano clip:1 ]", + "[ 3/1 → 25/8 | note:C2 s:piano clip:1 ]", + "[ (13/4 → 10/3) ⇝ 27/8 | note:C2 s:piano clip:1 ]", + "[ 13/4 ⇜ (10/3 → 27/8) | note:A2 s:piano clip:1 ]", + "[ 27/8 → 7/2 | note:A2 s:piano clip:1 ]", + "[ (29/8 → 11/3) ⇝ 15/4 | note:A2 s:piano clip:1 ]", + "[ 29/8 ⇜ (11/3 → 15/4) | note:G2 s:piano clip:1 ]", + "[ 15/4 → 31/8 | note:G2 s:piano clip:1 ]", +] +`; + exports[`runs examples > example "pick" example index 0 1`] = ` [ "[ 0/1 → 1/2 | note:g ]", diff --git a/website/src/pages/de/workshop/first-effects.mdx b/website/src/pages/de/workshop/first-effects.mdx index 7719249aa..b408a343e 100644 --- a/website/src/pages/de/workshop/first-effects.mdx +++ b/website/src/pages/de/workshop/first-effects.mdx @@ -25,7 +25,7 @@ import Box from '@components/Box.astro'; lpf = **l**ow **p**ass **f**ilter -- Ändere `lpf` in 200. Hörst du wie der Bass dumpfer klingt? Es klingt so ähnlich als würde die Musik hinter einer geschlossenen Tür laufen 🚪 +- Ändere `lpf` in 200. Hörst du, wie der Bass dumpfer klingt? Es klingt so, als würde die Musik hinter einer geschlossenen Tür spielen 🚪 - Lass uns nun die Tür öffnen: Ändere `lpf` in 5000. Der Klang wird dadurch viel heller und schärfer ✨🪩 @@ -42,9 +42,9 @@ lpf = **l**ow **p**ass **f**ilter - Füg noch mehr `lpf` Werte hinzu -- Das pattern in `lpf` ändert nicht den Rhythmus der Bassline +- Das Pattern in `lpf` ändert nicht den Rhythmus der Basslinie -Später sehen wir wie man mit Wellenformen Dinge automatisieren kann. +Später sehen wir, wie man mit Wellenformen Dinge automatisieren kann. @@ -73,7 +73,7 @@ Später sehen wir wie man mit Wellenformen Dinge automatisieren kann. Bei Rhythmen ist die Dynamik (= Veränderungen der Lautstärke) sehr wichtig. -- Entferne `.gain(...)` und achte darauf wie es viel flacher klingt. +- Entferne `.gain(...)` und achte darauf, wie es viel flacher klingt. - Mach es rückgängig (strg+z dann strg+enter) @@ -99,13 +99,13 @@ Lass uns die obigen Beispiele kombinieren: -Versuche die einzelnen Teile innerhalb `stack` zu erkennen, schau dir an wie die Kommas gesetzt sind. +Versuche die einzelnen Teile innerhalb von `stack` zu erkennen. Schau dir an wie die Kommas gesetzt sind. -Die 3 Teile (Drums, Bass, Akkorde) sind genau wie vorher, nur in einem `stack`, getrennt durch Kommas +Die 3 Teile (Drums, Bass, Akkorde) sind genau wie vorher, nur in einem `stack`, getrennt durch Kommas. -**Den Sound formen mit ADSR Hüllkurve** +**Den Sound formen mit ADSR-Hüllkurve** -Versuche herauszufinden was die Zahlen machen. Probier folgendes: +Versuche herauszufinden, was die Zahlen machen. Probier folgendes: - attack: `.5` vs `0` - decay: `.5` vs `0` - sustain: `1` vs `.25` vs `0` - release: `0` vs `.5` vs `1` -Kannst du erraten was die einzelnen Werte machen? +Kannst du erraten, was die einzelnen Werte machen? @@ -142,7 +142,7 @@ Kannst du erraten was die einzelnen Werte machen? -**adsr Kurznotation** +**adsr-Kurznotation** @@ -181,7 +181,7 @@ Was passiert wenn du `.delay(".8:.06:.8")` schreibst? Kannst du erraten was die - a: Lautstärke des Delays - b: Verzögerungszeit -- c: Feedback (je kleiner desto schneller verschwindet das Delay) +- c: Feedback (je kleiner, desto schneller verschwindet das Delay) @@ -203,7 +203,7 @@ Füg auch ein Delay hinzu! -**kleiner dub tune** +**kleiner Dub-Tune** -Füg `.hush()` ans ende eines Patterns im stack... +Füg `.hush()` ans Ende eines Patterns im stack... @@ -258,25 +258,25 @@ Füg `.hush()` ans ende eines Patterns im stack... **fast and slow = schnell und langsam** -Mit `fast` und `slow` kann man das tempo eines patterns außerhalb der Mini-Notation ändern: +Mit `fast` und `slow` kann man das Tempo eines Patterns außerhalb der Mini-Notation ändern: -Ändere den `slow` Wert. Tausche `slow` durch `fast`. +Ändere den `slow`-Wert. Ersetze `slow` durch `fast`. -Was passiert wenn du den Wert automatisierst? z.b. `.fast("<1 [2 4]>")` ? +Was passiert, wenn du den Wert automatisierst? z.b. `.fast("<1 [2 4]>")` ? -Übrigens, innerhalb der Mini-Notation, `fast` ist `*` und `slow` ist `/`. +Übrigens, innerhalb der Mini-Notation: `fast` ist `*` und `slow` ist `/`. ")`} /> ## Automation mit Signalen -Anstatt Werte schrittweise zu automatisieren können wir auch sogenannte Signale benutzen: +Anstatt Werte schrittweise zu automatisieren, können wir auch sogenannte Signale benutzen: @@ -296,7 +296,7 @@ Signale bewegen sich standardmäßig zwischen 0 und 1. Wir können das mit `rang -`range` ist nützlich wenn wir Funktionen mit einem anderen Wertebereich als 0 und 1 automatisieren wollen (z.b. lpf) +`range` ist nützlich wenn wir Funktionen mit einem anderen Wertebereich als 0 und 1 automatisieren wollen (z.b. `lpf`) @@ -322,7 +322,7 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt. ## Rückblick -| name | example | +| Name | Beispiel | | ----- | -------------------------------------------------------------------------------------------------- | | lpf | ")`} /> | | vowel | ")`} /> | @@ -333,4 +333,4 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt. | speed | ")`} /> | | range | | -Lass uns nun die für Tidal typischen [Pattern Effekte anschauen](/de/workshop/pattern-effects). +Lass uns nun die für Tidal typischen [Pattern-Effekte anschauen](/de/workshop/pattern-effects). diff --git a/website/src/pages/de/workshop/pattern-effects.mdx b/website/src/pages/de/workshop/pattern-effects.mdx index b701958a8..703358819 100644 --- a/website/src/pages/de/workshop/pattern-effects.mdx +++ b/website/src/pages/de/workshop/pattern-effects.mdx @@ -1,5 +1,5 @@ --- -title: Pattern Effekte +title: Pattern-Effekte layout: ../../../layouts/MainLayout.astro --- @@ -7,11 +7,11 @@ import { MiniRepl } from '@src/docs/MiniRepl'; import Box from '@components/Box.astro'; import QA from '@components/QA'; -# Pattern Effekte +# Pattern-Effekte -Bis jetzt sind die meisten Funktionen die wir kennengelernt haben ähnlich wie Funktionen in anderen Musik Programmen: Sequencing von Sounds, Noten und Effekten. +Bis jetzt sind die meisten Funktionen, die wir kennengelernt haben, ähnlich wie Funktionen in anderen Musik Programmen: Sequencing von Sounds, Noten und Effekten. -In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich oder auch enzigartig sind. +In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich oder auch einzigartig sind. **rev = rückwärts abspielen** @@ -21,7 +21,7 @@ In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich -So würde man das ohne jux schreiben: +So würde man das ohne `jux` schreiben: -Lass uns visualisieren was hier passiert: +Lass uns visualisieren, was hier passiert: -Das hat den gleichen Effekt wie: +Das hat den gleichen Effekt, wie: "` -In der notation `x=>x.`, das `x` ist das Pattern das wir bearbeiten. +In der Notation `x=>x.`, ist `x` das Pattern, das wir bearbeiten. -`off` ist auch nützlich für sounds: +`off` ist auch nützlich für Sounds: x.`, das `x` ist das Pattern das wir bearbeiten. .off(1/8, x=>x.speed(1.5).gain(.25))`} /> -| name | description | example | +| Name | Beschreibung | Beispiel | | ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | | rev | rückwärts | | -| jux | ein stereo-kanal modifizieren | | -| add | addiert zahlen oder noten | ")).scale("C:minor")`} /> | -| ply | multipliziert jedes element x mal | ")`} /> | -| off | verzögert eine modifizierte kopie | x.speed(2))`} /> | +| jux | einen Stereo-Kanal modifizieren | | +| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | +| ply | multipliziert jedes Element x mal | ")`} /> | +| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | diff --git a/website/src/pages/de/workshop/recap.mdx b/website/src/pages/de/workshop/recap.mdx index db392b8b0..c0d577d16 100644 --- a/website/src/pages/de/workshop/recap.mdx +++ b/website/src/pages/de/workshop/recap.mdx @@ -7,19 +7,19 @@ import { MiniRepl } from '../../../docs/MiniRepl'; # Workshop Rückblick -Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen. +Diese Seite ist eine Auflistung aller im Workshop vorgestellten Funktionen. ## Mini Notation -| Concept | Syntax | Example | +| Konzept | Syntax | Beispiel | | --------------------- | -------- | -------------------------------------------------------------------------------- | -| Sequence | space | | -| Sample Nummer | :x | | +| Sequenz | space | | +| Sample-Nummer | :x | | | Pausen | ~ | | -| Unter-Sequences | \[\] | | -| Unter-Unter-Sequences | \[\[\]\] | | +| Unter-Sequenzen | \[\] | | +| Unter-Unter-Sequenzen | \[\[\]\] | | | Schneller | \* | | -| Slow down | \/ | | +| Verlangsamen | \/ | | | Parallel | , | | | Alternieren | \<\> | ")`} /> | | Verlängern | @ | | @@ -27,23 +27,23 @@ Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen. ## Sounds -| Name | Description | Example | +| Name | Beschreibung | Beispiel | | ----- | -------------------------- | ---------------------------------------------------------------------------------- | -| sound | spielt den sound mit namen | | -| bank | wählt die soundbank | | -| n | wählt sample mit nummer | | +| sound | spielt den Sound mit Namen | | +| bank | wählt die Soundbank | | +| n | wählt Sample mit Nummer | | -## Notes +## Noten -| Name | Description | Example | +| Name | Beschreibung | Beispiel | | --------- | ---------------------------------- | -------------------------------------------------------------------------------------------- | -| note | wählt note per zahl oder buchstabe | | -| n + scale | wählt note n in skala | | -| stack | spielt mehrere patterns parallel | | +| note | wählt Note per Zahl oder Buchstabe | | +| n + scale | wählt Note n in Skala | | +| stack | spielt mehrere Patterns parallel | | -## Audio Effekte +## Audio-Effekte -| name | example | +| Name | Beispiele | | ----- | -------------------------------------------------------------------------------------------------- | | lpf | ")`} /> | | vowel | ")`} /> | @@ -54,15 +54,15 @@ Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen. | speed | ")`} /> | | range | | -## Pattern Effects +## Pattern-Effekte -| name | description | example | +| Name | Beschreibung | Beispiel | | ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | -| cpm | tempo in cycles pro minute | | +| cpm | Tempo in Cycles pro Minute | | | fast | schneller | | | slow | langsamer | | | rev | rückwärts | | -| jux | ein stereo-kanal modifizieren | | -| add | addiert zahlen oder noten | ")).scale("C:minor")`} /> | -| ply | jedes element schneller machen | ")`} /> | -| off | verzögert eine modifizierte kopie | x.speed(2))`} /> | +| jux | einen Stereo-Kanal modifizieren | | +| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | +| ply | jedes Element schneller machen | ")`} /> | +| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> |