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))`} /> |