Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into phaser
Browse files Browse the repository at this point in the history
  • Loading branch information
felixroos committed Nov 13, 2023
2 parents 858a026 + d25851a commit b7dd9b7
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 74 deletions.
7 changes: 6 additions & 1 deletion packages/core/controls.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down
3 changes: 3 additions & 0 deletions packages/core/pattern.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
34 changes: 34 additions & 0 deletions packages/core/pianoroll.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion packages/csound/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
18 changes: 9 additions & 9 deletions packages/serial/serial.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 = '';
Expand Down Expand Up @@ -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 });
Expand Down
17 changes: 16 additions & 1 deletion packages/superdough/sampler.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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) {
Expand All @@ -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');
Expand Down Expand Up @@ -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();
Expand Down
33 changes: 33 additions & 0 deletions test/__snapshots__/examples.test.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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 ]",
Expand Down
46 changes: 23 additions & 23 deletions website/src/pages/de/workshop/first-effects.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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 ✨🪩

</Box>
Expand All @@ -42,9 +42,9 @@ lpf = **l**ow **p**ass **f**ilter
<Box>

- 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.

</Box>

Expand Down Expand Up @@ -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)

</Box>
Expand All @@ -99,13 +99,13 @@ Lass uns die obigen Beispiele kombinieren:

<Box>

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.

</Box>

**Den Sound formen mit ADSR Hüllkurve**
**Den Sound formen mit ADSR-Hüllkurve**

<MiniRepl
hideHeader
Expand All @@ -120,14 +120,14 @@ Die 3 Teile (Drums, Bass, Akkorde) sind genau wie vorher, nur in einem `stack`,

<Box>

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?

</Box>

Expand All @@ -142,7 +142,7 @@ Kannst du erraten was die einzelnen Werte machen?

</QA>

**adsr Kurznotation**
**adsr-Kurznotation**

<MiniRepl
hideHeader
Expand All @@ -169,9 +169,9 @@ Kannst du erraten was die einzelnen Werte machen?

Probier verschiedene `delay` Werte zwischen 0 und 1. Übrigens: `.5` ist kurz für `0.5`.

Was passiert wenn du `.delay(".8:.125")` schreibst? Kannst du erraten was die zweite Zahl macht?
Was passiert, wenn du `.delay(".8:.125")` schreibst? Kannst du erraten, was die zweite Zahl macht?

Was passiert wenn du `.delay(".8:.06:.8")` schreibst? Kannst du erraten was die dritte Zahl macht?
Was passiert, wenn du `.delay(".8:.06:.8")` schreibst? Kannst du erraten, was die dritte Zahl macht?

</Box>

Expand All @@ -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)

</QA>

Expand All @@ -203,7 +203,7 @@ Füg auch ein Delay hinzu!

</Box>

**kleiner dub tune**
**kleiner Dub-Tune**

<MiniRepl
hideHeader
Expand Down Expand Up @@ -238,7 +238,7 @@ Für echten Dub fehlt noch der Bass:

<Box>

Füg `.hush()` ans ende eines Patterns im stack...
Füg `.hush()` ans Ende eines Patterns im stack...

</Box>

Expand All @@ -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:

<MiniRepl hideHeader client:visible tune={`sound("bd*2,~ rim").slow(2)`} />

<Box>

Ä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]>")` ?

</Box>

Übrigens, innerhalb der Mini-Notation, `fast` ist `*` und `slow` ist `/`.
Übrigens, innerhalb der Mini-Notation: `fast` ist `*` und `slow` ist `/`.

<MiniRepl hideHeader client:visible tune={`sound("[bd*2,~ rim]*<1 [2 4]>")`} />

## 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:

<MiniRepl hideHeader client:visible tune={`sound("hh*16").gain(sine)`} punchcard punchcardLabels={false} />

Expand All @@ -296,7 +296,7 @@ Signale bewegen sich standardmäßig zwischen 0 und 1. Wir können das mit `rang

<MiniRepl hideHeader client:visible tune={`sound("hh*8").lpf(saw.range(500, 2000))`} />

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

<Box>

Expand All @@ -322,7 +322,7 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt.

## Rückblick

| name | example |
| Name | Beispiel |
| ----- | -------------------------------------------------------------------------------------------------- |
| lpf | <MiniRepl hideHeader client:visible tune={`note("c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
| vowel | <MiniRepl hideHeader client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
Expand All @@ -333,4 +333,4 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt.
| speed | <MiniRepl hideHeader client:visible tune={`s("bd rim").speed("<1 2 -1 -2>")`} /> |
| range | <MiniRepl hideHeader client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |

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).
Loading

0 comments on commit b7dd9b7

Please sign in to comment.