mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-22 02:58:32 +00:00
Merge branch 'main' into docs
This commit is contained in:
commit
6961388545
16
my-patterns/README.md
Normal file
16
my-patterns/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# my-patterns
|
||||||
|
|
||||||
|
This directory can be used to save your own patterns.
|
||||||
|
|
||||||
|
0. fork the strudel repo
|
||||||
|
1. Save one or more .txt files here.
|
||||||
|
2. and run `npm run repl`
|
||||||
|
3. open `http://localhost:3000/my-patterns` !
|
||||||
|
|
||||||
|
## deploy
|
||||||
|
|
||||||
|
1. in your fork, go to settings -> pages and select "Github Actions" as source
|
||||||
|
2. edit `website/public/CNAME` to contain `<your-username>.github.io/strudel`
|
||||||
|
3. edit `website/astro.config.mjs` to use site: `<your-username>.github.io/strudel` and base `/strudel`
|
||||||
|
4. go to Actions -> "Build and Deploy" and click "Run workflow"
|
||||||
|
5. view your patterns at `<your-username>.github.io/strudel/my-patterns`
|
||||||
@ -4,7 +4,7 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
|
|||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Pattern, toMidi, getDrawContext, freqToMidi } from './index.mjs';
|
import { Pattern, toMidi, getDrawContext, freqToMidi, isNote } from './index.mjs';
|
||||||
|
|
||||||
const scale = (normalized, min, max) => normalized * (max - min) + min;
|
const scale = (normalized, min, max) => normalized * (max - min) + min;
|
||||||
const getValue = (e) => {
|
const getValue = (e) => {
|
||||||
@ -12,13 +12,19 @@ const getValue = (e) => {
|
|||||||
if (typeof e.value !== 'object') {
|
if (typeof e.value !== 'object') {
|
||||||
value = { value };
|
value = { value };
|
||||||
}
|
}
|
||||||
let { note, n, freq } = value;
|
let { note, n, freq, s } = value;
|
||||||
if (freq) {
|
if (freq) {
|
||||||
note = freqToMidi(freq);
|
return freqToMidi(freq);
|
||||||
}
|
}
|
||||||
value = note ?? n ?? e.value;
|
note = note ?? n;
|
||||||
if (typeof value === 'string') {
|
if (typeof note === 'string') {
|
||||||
value = toMidi(value);
|
return toMidi(note);
|
||||||
|
}
|
||||||
|
if (typeof note === 'number') {
|
||||||
|
return note;
|
||||||
|
}
|
||||||
|
if (s) {
|
||||||
|
return '_' + s;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
@ -143,7 +149,7 @@ Pattern.prototype.pianoroll = function ({
|
|||||||
maxMidi = max;
|
maxMidi = max;
|
||||||
valueExtent = maxMidi - minMidi + 1;
|
valueExtent = maxMidi - minMidi + 1;
|
||||||
}
|
}
|
||||||
foldValues = values.sort((a, b) => a - b);
|
foldValues = values.sort((a, b) => String(a).localeCompare(String(b)));
|
||||||
barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent;
|
barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -215,7 +221,8 @@ export function pianoroll({
|
|||||||
maxMidi = max;
|
maxMidi = max;
|
||||||
valueExtent = maxMidi - minMidi + 1;
|
valueExtent = maxMidi - minMidi + 1;
|
||||||
}
|
}
|
||||||
foldValues = values.sort((a, b) => a - b);
|
// foldValues = values.sort((a, b) => a - b);
|
||||||
|
foldValues = values.sort((a, b) => String(a).localeCompare(String(b)));
|
||||||
barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent;
|
barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent;
|
||||||
|
|
||||||
ctx.fillStyle = background;
|
ctx.fillStyle = background;
|
||||||
|
|||||||
@ -32,7 +32,7 @@ function peg$padEnd(str, targetLength, padString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
peg$SyntaxError.prototype.format = function(sources) {
|
peg$SyntaxError.prototype.format = function(sources) {
|
||||||
var str = "peg error: " + this.message;
|
var str = "Error: " + this.message;
|
||||||
if (this.location) {
|
if (this.location) {
|
||||||
var src = null;
|
var src = null;
|
||||||
var k;
|
var k;
|
||||||
@ -271,8 +271,8 @@ function peg$parse(input, options) {
|
|||||||
var peg$f4 = function(a) { return { weight: a} };
|
var peg$f4 = function(a) { return { weight: a} };
|
||||||
var peg$f5 = function(a) { return { replicate: a } };
|
var peg$f5 = function(a) { return { replicate: a } };
|
||||||
var peg$f6 = function(p, s, r) { return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } };
|
var peg$f6 = function(p, s, r) { return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } };
|
||||||
var peg$f7 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:a } } } };
|
var peg$f7 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'slow' } } } };
|
||||||
var peg$f8 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:"1/"+a } } } };
|
var peg$f8 = function(a) { return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'fast' } } } };
|
||||||
var peg$f9 = function(a) { return { operator : { type_: "fixed-step", arguments_ :{ amount:a } } } };
|
var peg$f9 = function(a) { return { operator : { type_: "fixed-step", arguments_ :{ amount:a } } } };
|
||||||
var peg$f10 = function(a) { return { operator : { type_: "degradeBy", arguments_ :{ amount:(a? a : 0.5) } } } };
|
var peg$f10 = function(a) { return { operator : { type_: "degradeBy", arguments_ :{ amount:(a? a : 0.5) } } } };
|
||||||
var peg$f11 = function(s, o) { return new ElementStub(s, o);};
|
var peg$f11 = function(s, o) { return new ElementStub(s, o);};
|
||||||
|
|||||||
@ -116,10 +116,10 @@ slice_bjorklund = "(" ws p:number ws comma ws s:number ws comma? ws r:number? ws
|
|||||||
{ return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } }
|
{ return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } }
|
||||||
|
|
||||||
slice_slow = "/"a:number
|
slice_slow = "/"a:number
|
||||||
{ return { operator : { type_: "stretch", arguments_ :{ amount:a } } } }
|
{ return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'slow' } } } }
|
||||||
|
|
||||||
slice_fast = "*"a:number
|
slice_fast = "*"a:number
|
||||||
{ return { operator : { type_: "stretch", arguments_ :{ amount:"1/"+a } } } }
|
{ return { operator : { type_: "stretch", arguments_ :{ amount:a, type: 'fast' } } } }
|
||||||
|
|
||||||
slice_fixed_step = "%"a:number
|
slice_fixed_step = "%"a:number
|
||||||
{ return { operator : { type_: "fixed-step", arguments_ :{ amount:a } } } }
|
{ return { operator : { type_: "fixed-step", arguments_ :{ amount:a } } } }
|
||||||
|
|||||||
@ -23,8 +23,12 @@ const applyOptions = (parent) => (pat, i) => {
|
|||||||
if (operator) {
|
if (operator) {
|
||||||
switch (operator.type_) {
|
switch (operator.type_) {
|
||||||
case 'stretch': {
|
case 'stretch': {
|
||||||
const speed = Fraction(operator.arguments_.amount).inverse();
|
const legalTypes = ['fast', 'slow'];
|
||||||
return reify(pat).fast(speed);
|
const { type, amount } = operator.arguments_;
|
||||||
|
if (!legalTypes.includes(type)) {
|
||||||
|
throw new Error(`mini: stretch: type must be one of ${legalTypes.join('|')} but got ${type}`);
|
||||||
|
}
|
||||||
|
return reify(pat)[type](amount);
|
||||||
}
|
}
|
||||||
case 'bjorklund':
|
case 'bjorklund':
|
||||||
return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation);
|
return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation);
|
||||||
@ -74,32 +78,32 @@ function resolveReplications(ast) {
|
|||||||
// could this be made easier?!
|
// could this be made easier?!
|
||||||
ast.source_ = ast.source_.map((child) => {
|
ast.source_ = ast.source_.map((child) => {
|
||||||
const { replicate, ...options } = child.options_ || {};
|
const { replicate, ...options } = child.options_ || {};
|
||||||
if (replicate) {
|
if (!replicate) {
|
||||||
return {
|
return child;
|
||||||
...child,
|
}
|
||||||
options_: { ...options, weight: replicate },
|
return {
|
||||||
source_: {
|
...child,
|
||||||
type_: 'pattern',
|
options_: { ...options, weight: replicate },
|
||||||
arguments_: {
|
source_: {
|
||||||
alignment: 'h',
|
type_: 'pattern',
|
||||||
},
|
arguments_: {
|
||||||
source_: [
|
alignment: 'h',
|
||||||
{
|
},
|
||||||
type_: 'element',
|
source_: [
|
||||||
source_: child.source_,
|
{
|
||||||
location_: child.location_,
|
type_: 'element',
|
||||||
options_: {
|
source_: child.source_,
|
||||||
operator: {
|
location_: child.location_,
|
||||||
type_: 'stretch',
|
options_: {
|
||||||
arguments_: { amount: Fraction(replicate).inverse().toString() },
|
operator: {
|
||||||
},
|
type_: 'stretch',
|
||||||
|
arguments_: { amount: replicate, type: 'fast' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
},
|
],
|
||||||
};
|
},
|
||||||
}
|
};
|
||||||
return child;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -339,8 +339,8 @@ exports[`renders tunes > tune: blippyRhodes 1`] = `
|
|||||||
"[ 2/3 → 43/60 | note:G3 s:rhodes clip:1 room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]",
|
"[ 2/3 → 43/60 | note:G3 s:rhodes clip:1 room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]",
|
||||||
"[ 5/6 → 53/60 | note:G3 s:rhodes clip:1 room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]",
|
"[ 5/6 → 53/60 | note:G3 s:rhodes clip:1 room:0.5 delay:0.3 delayfeedback:0.4 delaytime:0.08333333333333333 gain:0.5 ]",
|
||||||
"[ (0/1 → 2/3) ⇝ 4/3 | note:c2 gain:0.3 s:sawtooth cutoff:600 ]",
|
"[ (0/1 → 2/3) ⇝ 4/3 | note:c2 gain:0.3 s:sawtooth cutoff:600 ]",
|
||||||
"[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:c2 gain:0.3 s:sawtooth cutoff:600 ]",
|
|
||||||
"[ (0/1 → 2/3) ⇝ 4/3 | note:36.02 gain:0.3 s:sawtooth cutoff:600 ]",
|
"[ (0/1 → 2/3) ⇝ 4/3 | note:36.02 gain:0.3 s:sawtooth cutoff:600 ]",
|
||||||
|
"[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:c2 gain:0.3 s:sawtooth cutoff:600 ]",
|
||||||
"[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:36.02 gain:0.3 s:sawtooth cutoff:600 ]",
|
"[ 0/1 ⇜ (2/3 → 1/1) ⇝ 4/3 | note:36.02 gain:0.3 s:sawtooth cutoff:600 ]",
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
@ -8127,10 +8127,10 @@ exports[`renders tunes > tune: loungeSponge 1`] = `
|
|||||||
|
|
||||||
exports[`renders tunes > tune: meltingsubmarine 1`] = `
|
exports[`renders tunes > tune: meltingsubmarine 1`] = `
|
||||||
[
|
[
|
||||||
"[ (0/1 → 1/1) ⇝ 3/2 | s:bd speed:0.7519542165100574 ]",
|
"[ (0/1 → 1/1) ⇝ 3/2 | s:bd:5 speed:0.7519542165100574 ]",
|
||||||
"[ (3/4 → 1/1) ⇝ 3/2 | s:sd speed:0.7931522866332671 ]",
|
"[ (3/4 → 1/1) ⇝ 3/2 | s:sd:1 speed:0.7931522866332671 ]",
|
||||||
"[ 3/8 → 3/4 | s:hh speed:0.7285963821098448 ]",
|
"[ 3/8 → 3/4 | s:hh27 speed:0.7285963821098448 ]",
|
||||||
"[ (3/4 → 1/1) ⇝ 9/8 | s:hh speed:0.77531205091027 ]",
|
"[ (3/4 → 1/1) ⇝ 9/8 | s:hh27 speed:0.77531205091027 ]",
|
||||||
"[ (0/1 → 1/1) ⇝ 3/2 | n:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]",
|
"[ (0/1 → 1/1) ⇝ 3/2 | n:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]",
|
||||||
"[ (0/1 → 1/1) ⇝ 3/2 | n:33.17988554127514 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]",
|
"[ (0/1 → 1/1) ⇝ 3/2 | n:33.17988554127514 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]",
|
||||||
"[ (0/1 → 1/1) ⇝ 3/2 | n:55.129885541275144 s:sawtooth gain:0.16 cutoff:500 attack:1 ]",
|
"[ (0/1 → 1/1) ⇝ 3/2 | n:55.129885541275144 s:sawtooth gain:0.16 cutoff:500 attack:1 ]",
|
||||||
|
|||||||
@ -31,6 +31,7 @@ export default defineConfig({
|
|||||||
tailwind(),
|
tailwind(),
|
||||||
],
|
],
|
||||||
site: `https://strudel.tidalcycles.org`,
|
site: `https://strudel.tidalcycles.org`,
|
||||||
|
base: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
14
website/src/pages/embed.astro
Normal file
14
website/src/pages/embed.astro
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
import HeadCommon from '../components/HeadCommon.astro';
|
||||||
|
import { Repl } from '../repl/Repl.jsx';
|
||||||
|
---
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<HeadCommon />
|
||||||
|
<title>Strudel REPL</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<Repl client:only="react" embedded />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
29
website/src/pages/my-patterns/[name].png.js
Normal file
29
website/src/pages/my-patterns/[name].png.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { createCanvas } from 'canvas';
|
||||||
|
import { pianoroll } from '@strudel.cycles/core';
|
||||||
|
import { evaluate } from '@strudel.cycles/transpiler';
|
||||||
|
import '../../../../test/runtime.mjs';
|
||||||
|
import { getMyPatterns } from './list.json';
|
||||||
|
|
||||||
|
export async function get({ params, request }) {
|
||||||
|
const patterns = await getMyPatterns();
|
||||||
|
const { name } = params;
|
||||||
|
const tune = patterns[name];
|
||||||
|
const { pattern } = await evaluate(tune);
|
||||||
|
const haps = pattern.queryArc(0, 4);
|
||||||
|
const canvas = createCanvas(800, 800);
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
pianoroll({ time: 4, haps, ctx, playhead: 1, fold: 1, background: 'transparent', playheadColor: 'transparent' });
|
||||||
|
const buffer = canvas.toBuffer('image/png');
|
||||||
|
return {
|
||||||
|
body: buffer,
|
||||||
|
encoding: 'binary',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const patterns = await getMyPatterns();
|
||||||
|
return Object.keys(patterns).map((name) => ({
|
||||||
|
params: {
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
32
website/src/pages/my-patterns/index.astro
Normal file
32
website/src/pages/my-patterns/index.astro
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
import { getMyPatterns } from './list.json';
|
||||||
|
|
||||||
|
import { Content } from '../../../../my-patterns/README.md';
|
||||||
|
|
||||||
|
const myPatterns = await getMyPatterns();
|
||||||
|
---
|
||||||
|
|
||||||
|
<body class="bg-slate-800">
|
||||||
|
{
|
||||||
|
Object.keys(myPatterns).length === 0 && (
|
||||||
|
<div class="prose prose-invert p-2">
|
||||||
|
<Content />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-2 p-2 select-none">
|
||||||
|
{
|
||||||
|
Object.entries(myPatterns).map(([name, tune]) => (
|
||||||
|
<a
|
||||||
|
class="rounded-md bg-slate-900 hover:bg-slate-700 cursor-pointer relative"
|
||||||
|
href={`../#${btoa(tune as string)}`}
|
||||||
|
>
|
||||||
|
<div class="absolute w-full h-full flex justify-center items-center">
|
||||||
|
<span class="bg-slate-800 p-2 rounded-md text-white">{name}</span>
|
||||||
|
</div>
|
||||||
|
<img src={`./${name}.png`} />
|
||||||
|
</a>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
15
website/src/pages/my-patterns/list.json.js
Normal file
15
website/src/pages/my-patterns/list.json.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export function getMyPatterns() {
|
||||||
|
const my = import.meta.glob('../../../../my-patterns/**', { as: 'raw', eager: true });
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(my) //
|
||||||
|
.filter(([name]) => name.endsWith('.txt')) //
|
||||||
|
.map(([name, raw]) => [name.split('/').slice(-1), raw]), //
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get() {
|
||||||
|
const all = await getMyPatterns();
|
||||||
|
return {
|
||||||
|
body: JSON.stringify(all),
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import AcademicCapIcon from '@heroicons/react/20/solid/AcademicCapIcon';
|
import AcademicCapIcon from '@heroicons/react/20/solid/AcademicCapIcon';
|
||||||
import CommandLineIcon from '@heroicons/react/20/solid/CommandLineIcon';
|
import ArrowPathIcon from '@heroicons/react/20/solid/ArrowPathIcon';
|
||||||
import LinkIcon from '@heroicons/react/20/solid/LinkIcon';
|
import LinkIcon from '@heroicons/react/20/solid/LinkIcon';
|
||||||
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
||||||
import SparklesIcon from '@heroicons/react/20/solid/SparklesIcon';
|
import SparklesIcon from '@heroicons/react/20/solid/SparklesIcon';
|
||||||
@ -9,10 +9,9 @@ import React, { useContext } from 'react';
|
|||||||
// import { ReplContext } from './Repl';
|
// import { ReplContext } from './Repl';
|
||||||
import './Repl.css';
|
import './Repl.css';
|
||||||
|
|
||||||
const isEmbedded = window.location !== window.parent.location;
|
|
||||||
|
|
||||||
export function Header({ context }) {
|
export function Header({ context }) {
|
||||||
const {
|
const {
|
||||||
|
embedded,
|
||||||
started,
|
started,
|
||||||
pending,
|
pending,
|
||||||
isDirty,
|
isDirty,
|
||||||
@ -25,32 +24,37 @@ export function Header({ context }) {
|
|||||||
isZen,
|
isZen,
|
||||||
setIsZen,
|
setIsZen,
|
||||||
} = context;
|
} = context;
|
||||||
|
const isEmbedded = embedded || window.location !== window.parent.location;
|
||||||
// useContext(ReplContext)
|
// useContext(ReplContext)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
id="header"
|
id="header"
|
||||||
className={cx(
|
className={cx(
|
||||||
'py-1 flex-none w-full md:flex text-black justify-between z-[100] text-lg select-none sticky top-0',
|
'py-1 flex-none w-full text-black justify-between z-[100] text-lg select-none sticky top-0',
|
||||||
!isZen && 'bg-header',
|
!isZen && !isEmbedded && 'bg-header',
|
||||||
|
isEmbedded ? 'flex' : 'md:flex',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="px-4 flex space-x-2 pt-2 md:pt-0 select-none">
|
<div className="px-4 flex space-x-2 md:pt-0 select-none">
|
||||||
{/* <img
|
{/* <img
|
||||||
src={logo}
|
src={logo}
|
||||||
className={cx('Tidal-logo', isEmbedded ? 'w-8 h-8' : 'w-10 h-10', started && 'animate-pulse')} // 'bg-[#ffffff80] rounded-full'
|
className={cx('Tidal-logo', isEmbedded ? 'w-8 h-8' : 'w-10 h-10', started && 'animate-pulse')} // 'bg-[#ffffff80] rounded-full'
|
||||||
alt="logo"
|
alt="logo"
|
||||||
/> */}
|
/> */}
|
||||||
<h1
|
<h1
|
||||||
|
onClick={() => {
|
||||||
|
if (isEmbedded) window.open(window.location.href.replace('embed', ''));
|
||||||
|
}}
|
||||||
className={cx(
|
className={cx(
|
||||||
isEmbedded ? 'text-l' : 'text-xl',
|
isEmbedded ? 'text-l cursor-pointer' : 'text-xl',
|
||||||
// 'bg-clip-text bg-gradient-to-r from-primary to-secondary text-transparent font-bold',
|
// 'bg-clip-text bg-gradient-to-r from-primary to-secondary text-transparent font-bold',
|
||||||
'text-white font-bold flex space-x-2 items-center',
|
'text-white font-bold flex space-x-2 items-center',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx('mt-[1px]', started && 'animate-spin', 'cursor-pointer')}
|
className={cx('mt-[1px]', started && 'animate-spin', 'cursor-pointer')}
|
||||||
onClick={() => setIsZen((z) => !z)}
|
onClick={() => !isEmbedded && setIsZen((z) => !z)}
|
||||||
>
|
>
|
||||||
🌀
|
🌀
|
||||||
</div>
|
</div>
|
||||||
@ -65,12 +69,13 @@ export function Header({ context }) {
|
|||||||
<div className="flex max-w-full overflow-auto text-white ">
|
<div className="flex max-w-full overflow-auto text-white ">
|
||||||
<button
|
<button
|
||||||
onClick={handleTogglePlay}
|
onClick={handleTogglePlay}
|
||||||
|
title={started ? 'stop' : 'play'}
|
||||||
className={cx(!isEmbedded ? 'p-2' : 'px-2', 'hover:text-tertiary', !started && 'animate-pulse')}
|
className={cx(!isEmbedded ? 'p-2' : 'px-2', 'hover:text-tertiary', !started && 'animate-pulse')}
|
||||||
>
|
>
|
||||||
{!pending ? (
|
{!pending ? (
|
||||||
<span className={cx('flex items-center space-x-1', isEmbedded ? 'w-16' : 'w-16')}>
|
<span className={cx('flex items-center space-x-1', isEmbedded ? '' : 'w-16')}>
|
||||||
{started ? <StopCircleIcon className="w-5 h-5" /> : <PlayCircleIcon className="w-5 h-5" />}
|
{started ? <StopCircleIcon className="w-6 h-6" /> : <PlayCircleIcon className="w-6 h-6" />}
|
||||||
<span>{started ? 'stop' : 'play'}</span>
|
{!isEmbedded && <span>{started ? 'stop' : 'play'}</span>}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<>loading...</>
|
<>loading...</>
|
||||||
@ -78,46 +83,54 @@ export function Header({ context }) {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleUpdate}
|
onClick={handleUpdate}
|
||||||
|
title="update"
|
||||||
className={cx(
|
className={cx(
|
||||||
'flex items-center space-x-1',
|
'flex items-center space-x-1',
|
||||||
!isEmbedded ? 'p-2' : 'px-2',
|
!isEmbedded ? 'p-2' : 'px-2',
|
||||||
!isDirty || !activeCode ? 'opacity-50' : 'hover:text-tertiary',
|
!isDirty || !activeCode ? 'opacity-50' : 'hover:text-tertiary',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<CommandLineIcon className="w-5 h-5" />
|
{/* <CommandLineIcon className="w-6 h-6" /> */}
|
||||||
<span>update</span>
|
<ArrowPathIcon className="w-6 h-6" />
|
||||||
|
{!isEmbedded && <span>update</span>}
|
||||||
</button>
|
</button>
|
||||||
{!isEmbedded && (
|
{!isEmbedded && (
|
||||||
<button className="hover:text-tertiary p-2 flex items-center space-x-1" onClick={handleShuffle}>
|
<button
|
||||||
<SparklesIcon className="w-5 h-5" />
|
title="shuffle"
|
||||||
|
className="hover:text-tertiary p-2 flex items-center space-x-1"
|
||||||
|
onClick={handleShuffle}
|
||||||
|
>
|
||||||
|
<SparklesIcon className="w-6 h-6" />
|
||||||
<span> shuffle</span>
|
<span> shuffle</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{!isEmbedded && (
|
{!isEmbedded && (
|
||||||
<button
|
<button
|
||||||
|
title="share"
|
||||||
className={cx(
|
className={cx(
|
||||||
'cursor-pointer hover:text-tertiary flex items-center space-x-1',
|
'cursor-pointer hover:text-tertiary flex items-center space-x-1',
|
||||||
!isEmbedded ? 'p-2' : 'px-2',
|
!isEmbedded ? 'p-2' : 'px-2',
|
||||||
)}
|
)}
|
||||||
onClick={handleShare}
|
onClick={handleShare}
|
||||||
>
|
>
|
||||||
<LinkIcon className="w-5 h-5" />
|
<LinkIcon className="w-6 h-6" />
|
||||||
<span>share{lastShared && lastShared === (activeCode || code) ? 'd!' : ''}</span>
|
<span>share{lastShared && lastShared === (activeCode || code) ? 'd!' : ''}</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{!isEmbedded && (
|
{!isEmbedded && (
|
||||||
<a
|
<a
|
||||||
|
title="learn"
|
||||||
href="./learn/getting-started"
|
href="./learn/getting-started"
|
||||||
className={cx('hover:text-tertiary flex items-center space-x-1', !isEmbedded ? 'p-2' : 'px-2')}
|
className={cx('hover:text-tertiary flex items-center space-x-1', !isEmbedded ? 'p-2' : 'px-2')}
|
||||||
>
|
>
|
||||||
<AcademicCapIcon className="w-5 h-5" />
|
<AcademicCapIcon className="w-6 h-6" />
|
||||||
<span>learn</span>
|
<span>learn</span>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
{isEmbedded && (
|
{/* {isEmbedded && (
|
||||||
<button className={cx('hover:text-tertiary px-2')}>
|
<button className={cx('hover:text-tertiary px-2')}>
|
||||||
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL">
|
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL">
|
||||||
🚀 open
|
🚀
|
||||||
</a>
|
</a>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@ -130,10 +143,10 @@ export function Header({ context }) {
|
|||||||
}}
|
}}
|
||||||
title="Reset"
|
title="Reset"
|
||||||
>
|
>
|
||||||
💔 reset
|
💔
|
||||||
</a>
|
</a>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { Footer } from './Footer';
|
|||||||
import { Header } from './Header';
|
import { Header } from './Header';
|
||||||
import { prebake } from './prebake.mjs';
|
import { prebake } from './prebake.mjs';
|
||||||
import * as tunes from './tunes.mjs';
|
import * as tunes from './tunes.mjs';
|
||||||
|
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
||||||
|
|
||||||
initAudioOnFirstClick();
|
initAudioOnFirstClick();
|
||||||
|
|
||||||
@ -101,7 +102,8 @@ const { code: randomTune, name } = getRandomTune();
|
|||||||
|
|
||||||
export const ReplContext = createContext(null);
|
export const ReplContext = createContext(null);
|
||||||
|
|
||||||
export function Repl() {
|
export function Repl({ embedded = false }) {
|
||||||
|
const isEmbedded = embedded || window.location !== window.parent.location;
|
||||||
const [view, setView] = useState(); // codemirror view
|
const [view, setView] = useState(); // codemirror view
|
||||||
const [lastShared, setLastShared] = useState();
|
const [lastShared, setLastShared] = useState();
|
||||||
const [activeFooter, setActiveFooter] = useState('');
|
const [activeFooter, setActiveFooter] = useState('');
|
||||||
@ -232,6 +234,7 @@ export function Repl() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const context = {
|
const context = {
|
||||||
|
embedded,
|
||||||
started,
|
started,
|
||||||
pending,
|
pending,
|
||||||
isDirty,
|
isDirty,
|
||||||
@ -269,7 +272,16 @@ export function Repl() {
|
|||||||
{error && (
|
{error && (
|
||||||
<div className="text-red-500 p-4 bg-lineblack animate-pulse">{error.message || 'Unknown Error :-/'}</div>
|
<div className="text-red-500 p-4 bg-lineblack animate-pulse">{error.message || 'Unknown Error :-/'}</div>
|
||||||
)}
|
)}
|
||||||
<Footer context={context} />
|
{isEmbedded && !started && (
|
||||||
|
<button
|
||||||
|
onClick={() => handleTogglePlay()}
|
||||||
|
className="text-white text-2xl fixed left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] z-[1000] m-auto p-4 bg-black rounded-md flex items-center space-x-2"
|
||||||
|
>
|
||||||
|
<PlayCircleIcon className="w-6 h-6" />
|
||||||
|
<span>play</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{!isEmbedded && <Footer context={context} />}
|
||||||
</div>
|
</div>
|
||||||
</ReplContext.Provider>
|
</ReplContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -24,7 +24,7 @@ stack(
|
|||||||
"Ab5 [F5@2 C5] C6@2",
|
"Ab5 [F5@2 C5] C6@2",
|
||||||
"A5 [F5@2 C5] [D5@2 F5] F5",
|
"A5 [F5@2 C5] [D5@2 F5] F5",
|
||||||
"[C5@2 F5] [Bb5 A5 G5] F5@2"
|
"[C5@2 F5] [Bb5 A5 G5] F5@2"
|
||||||
),
|
).color('#FFEBB5'),
|
||||||
seq(
|
seq(
|
||||||
"[F4,Bb4,D5] [[D4,G4,Bb4]@2 [Bb3,D4,F4]] [[G3,C4,E4]@2 [[Ab3,F4] [A3,Gb4]]] [Bb3,E4,G4]",
|
"[F4,Bb4,D5] [[D4,G4,Bb4]@2 [Bb3,D4,F4]] [[G3,C4,E4]@2 [[Ab3,F4] [A3,Gb4]]] [Bb3,E4,G4]",
|
||||||
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, Bb3, Db3] [F3, Bb3, Db3]]",
|
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, Bb3, Db3] [F3, Bb3, Db3]]",
|
||||||
@ -43,7 +43,7 @@ stack(
|
|||||||
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
|
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
|
||||||
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
|
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
|
||||||
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]"
|
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]"
|
||||||
),
|
).color('#54C571'),
|
||||||
seq(
|
seq(
|
||||||
"[G3 G3 C3 E3]",
|
"[G3 G3 C3 E3]",
|
||||||
"[F2 D2 G2 C2]",
|
"[F2 D2 G2 C2]",
|
||||||
@ -62,8 +62,9 @@ stack(
|
|||||||
"[Ab2 Ab2 G2 [C2 D2 E2]]",
|
"[Ab2 Ab2 G2 [C2 D2 E2]]",
|
||||||
"[F2 A2 Bb2 B2]",
|
"[F2 A2 Bb2 B2]",
|
||||||
"[G2 C2 F2 F2]"
|
"[G2 C2 F2 F2]"
|
||||||
)
|
).color('#0077C9')
|
||||||
).note().slow(51);
|
).note().slow(51)
|
||||||
|
//.pianoroll({fold:1})
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const giantSteps = `// John Coltrane - Giant Steps
|
export const giantSteps = `// John Coltrane - Giant Steps
|
||||||
@ -76,22 +77,23 @@ stack(
|
|||||||
"[D5 Bb4] [G4 Eb4] F#4 [G4 F4]",
|
"[D5 Bb4] [G4 Eb4] F#4 [G4 F4]",
|
||||||
"Bb4 [B4 A4] D5 [D#5 C#5]",
|
"Bb4 [B4 A4] D5 [D#5 C#5]",
|
||||||
"F#5 [G5 F5] Bb5 [F#5 F#5]",
|
"F#5 [G5 F5] Bb5 [F#5 F#5]",
|
||||||
),
|
).color('#F8E71C'),
|
||||||
// chords
|
// chords
|
||||||
seq(
|
seq(
|
||||||
"[B^7 D7] [G^7 Bb7] Eb^7 [Am7 D7]",
|
"[B^7 D7] [G^7 Bb7] Eb^7 [Am7 D7]",
|
||||||
"[G^7 Bb7] [Eb^7 F#7] B^7 [Fm7 Bb7]",
|
"[G^7 Bb7] [Eb^7 F#7] B^7 [Fm7 Bb7]",
|
||||||
"Eb^7 [Am7 D7] G^7 [C#m7 F#7]",
|
"Eb^7 [Am7 D7] G^7 [C#m7 F#7]",
|
||||||
"B^7 [Fm7 Bb7] Eb^7 [C#m7 F#7]"
|
"B^7 [Fm7 Bb7] Eb^7 [C#m7 F#7]"
|
||||||
).voicings('lefthand'),
|
).voicings('lefthand').color('#7ED321'),
|
||||||
// bass
|
// bass
|
||||||
seq(
|
seq(
|
||||||
"[B2 D2] [G2 Bb2] [Eb2 Bb3] [A2 D2]",
|
"[B2 D2] [G2 Bb2] [Eb2 Bb3] [A2 D2]",
|
||||||
"[G2 Bb2] [Eb2 F#2] [B2 F#2] [F2 Bb2]",
|
"[G2 Bb2] [Eb2 F#2] [B2 F#2] [F2 Bb2]",
|
||||||
"[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]",
|
"[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]",
|
||||||
"[B2 F#2] [F2 Bb2] [Eb2 Bb3] [C#2 F#2]"
|
"[B2 F#2] [F2 Bb2] [Eb2 Bb3] [C#2 F#2]"
|
||||||
)
|
).color('#00B8D4')
|
||||||
).slow(20).note()`;
|
).slow(20).note()
|
||||||
|
//.pianoroll({fold:1})`;
|
||||||
|
|
||||||
export const zeldasRescue = `// Koji Kondo - Princess Zelda's Rescue
|
export const zeldasRescue = `// Koji Kondo - Princess Zelda's Rescue
|
||||||
stack(
|
stack(
|
||||||
@ -101,7 +103,8 @@ stack(
|
|||||||
[B3@2 D4] [A3@2 [G3 A3]] [B3@2 D4] [A3]
|
[B3@2 D4] [A3@2 [G3 A3]] [B3@2 D4] [A3]
|
||||||
[B3@2 D4] [A4@2 G4] D5@2
|
[B3@2 D4] [A4@2 G4] D5@2
|
||||||
[D5@2 [C5 B4]] [[C5 B4] G4@2] [C5@2 [B4 A4]] [[B4 A4] E4@2]
|
[D5@2 [C5 B4]] [[C5 B4] G4@2] [C5@2 [B4 A4]] [[B4 A4] E4@2]
|
||||||
[D5@2 [C5 B4]] [[C5 B4] G4 C5] [G5] [~ ~ B3]\`,
|
[D5@2 [C5 B4]] [[C5 B4] G4 C5] [G5] [~ ~ B3]\`
|
||||||
|
.color('#9C7C38'),
|
||||||
// bass
|
// bass
|
||||||
\`[[C2 G2] E3@2] [[C2 G2] F#3@2] [[C2 G2] E3@2] [[C2 G2] F#3@2]
|
\`[[C2 G2] E3@2] [[C2 G2] F#3@2] [[C2 G2] E3@2] [[C2 G2] F#3@2]
|
||||||
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
|
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
|
||||||
@ -109,17 +112,19 @@ stack(
|
|||||||
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
|
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
|
||||||
[[F2 C3] E3@2] [[E2 B2] D3@2] [[D2 A2] C3@2] [[C2 G2] B2@2]
|
[[F2 C3] E3@2] [[E2 B2] D3@2] [[D2 A2] C3@2] [[C2 G2] B2@2]
|
||||||
[[F2 C3] E3@2] [[E2 B2] D3@2] [[Eb2 Bb2] Db3@2] [[D2 A2] C3 [F3,G2]]\`
|
[[F2 C3] E3@2] [[E2 B2] D3@2] [[Eb2 Bb2] Db3@2] [[D2 A2] C3 [F3,G2]]\`
|
||||||
|
.color('#4C4646')
|
||||||
).transpose(12).slow(48)
|
).transpose(12).slow(48)
|
||||||
.superimpose(x=>x.add(0.06)) // add slightly detuned voice
|
.superimpose(x=>x.add(0.06)) // add slightly detuned voice
|
||||||
.note()
|
.note()
|
||||||
.gain(.1)
|
.gain(.1)
|
||||||
.s('triangle')
|
.s('triangle')
|
||||||
.room(1)
|
.room(1)
|
||||||
`;
|
//.pianoroll({fold:1})`;
|
||||||
|
|
||||||
export const caverave = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
export const caverave = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
// by Felix Roos
|
// by Felix Roos
|
||||||
const keys = x => x.s('sawtooth').cutoff(1200).gain(.5).attack(0).decay(.16).sustain(.3).release(.1);
|
const keys = x => x.s('sawtooth').cutoff(1200).gain(.5)
|
||||||
|
.attack(0).decay(.16).sustain(.3).release(.1);
|
||||||
|
|
||||||
const drums = stack(
|
const drums = stack(
|
||||||
s("bd*2").mask("<x@7 ~>/8").gain(.8),
|
s("bd*2").mask("<x@7 ~>/8").gain(.8),
|
||||||
@ -129,26 +134,31 @@ const drums = stack(
|
|||||||
|
|
||||||
const thru = (x) => x.transpose("<0 1>/8").transpose(-1);
|
const thru = (x) => x.transpose("<0 1>/8").transpose(-1);
|
||||||
const synths = stack(
|
const synths = stack(
|
||||||
"<eb4 d4 c4 b3>/2".scale(timeCat([3,'C minor'],[1,'C melodic minor'])
|
"<eb4 d4 c4 b3>/2"
|
||||||
|
.scale(timeCat([3,'C minor'],[1,'C melodic minor'])
|
||||||
.slow(8)).struct("[~ x]*2")
|
.slow(8)).struct("[~ x]*2")
|
||||||
.layer(
|
.layer(
|
||||||
x=>x.scaleTranspose(0).early(0),
|
x=>x.scaleTranspose(0).early(0),
|
||||||
x=>x.scaleTranspose(2).early(1/8),
|
x=>x.scaleTranspose(2).early(1/8),
|
||||||
x=>x.scaleTranspose(7).early(1/4),
|
x=>x.scaleTranspose(7).early(1/4),
|
||||||
x=>x.scaleTranspose(8).early(3/8)
|
x=>x.scaleTranspose(8).early(3/8)
|
||||||
).apply(thru).note().apply(keys).mask("<~ x>/16"),
|
).apply(thru).note().apply(keys).mask("<~ x>/16")
|
||||||
|
.color('darkseagreen'),
|
||||||
note("<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".apply(thru))
|
note("<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".apply(thru))
|
||||||
.struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2))
|
.struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2))
|
||||||
.s('sawtooth').attack(0.001).decay(0.2).sustain(1).cutoff(500),
|
.s('sawtooth').attack(0.001).decay(0.2).sustain(1).cutoff(500)
|
||||||
"<Cm7 Bb7 Fm7 G7b13>/2".struct("~ [x@0.2 ~]".fast(2)).voicings('lefthand')
|
.color('brown'),
|
||||||
|
"<Cm7 Bb7 Fm7 G7b13>/2".struct("~ [x@0.2 ~]".fast(2))
|
||||||
|
.voicings('lefthand')
|
||||||
.apply(thru).every(2, early(1/8)).note().apply(keys).sustain(0)
|
.apply(thru).every(2, early(1/8)).note().apply(keys).sustain(0)
|
||||||
.delay(.4).delaytime(.12)
|
.delay(.4).delaytime(.12)
|
||||||
.mask("<x@7 ~>/8".early(1/4))
|
.mask("<x@7 ~>/8".early(1/4))
|
||||||
)
|
)
|
||||||
stack(
|
stack(
|
||||||
drums.fast(2),
|
drums.fast(2).color('tomato'),
|
||||||
synths
|
synths
|
||||||
).slow(2)`;
|
).slow(2)
|
||||||
|
//.pianoroll({fold:1})`;
|
||||||
|
|
||||||
export const sampleDrums = `samples({
|
export const sampleDrums = `samples({
|
||||||
bd: 'bd/BT0A0D0.wav',
|
bd: 'bd/BT0A0D0.wav',
|
||||||
@ -157,10 +167,11 @@ export const sampleDrums = `samples({
|
|||||||
}, 'https://loophole-letters.vercel.app/samples/tidal/')
|
}, 'https://loophole-letters.vercel.app/samples/tidal/')
|
||||||
|
|
||||||
stack(
|
stack(
|
||||||
"<bd!3 bd(3,4,2)>",
|
"<bd!3 bd(3,4,2)>".color('#F5A623'),
|
||||||
"hh*4",
|
"hh*4".color('#673AB7'),
|
||||||
"~ <sn!3 sn(3,4,1)>"
|
"~ <sn!3 sn(3,4,1)>".color('#4CAF50')
|
||||||
).s()
|
).s()
|
||||||
|
.pianoroll({fold:1})
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const barryHarris = `// adapted from a Barry Harris excercise
|
export const barryHarris = `// adapted from a Barry Harris excercise
|
||||||
@ -170,6 +181,7 @@ export const barryHarris = `// adapted from a Barry Harris excercise
|
|||||||
.transpose("<0 1 2 1>/8")
|
.transpose("<0 1 2 1>/8")
|
||||||
.slow(2)
|
.slow(2)
|
||||||
.note().piano()
|
.note().piano()
|
||||||
|
.color('#00B8D4')
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const blippyRhodes = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
export const blippyRhodes = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
@ -192,7 +204,7 @@ samples({
|
|||||||
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', cat('Db major','Db mixolydian')])
|
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', cat('Db major','Db mixolydian')])
|
||||||
|
|
||||||
stack(
|
stack(
|
||||||
s("<bd sn> <hh hh*2 hh*3>"),
|
s("<bd sn> <hh hh*2 hh*3>").color('#00B8D4'),
|
||||||
"<g4 c5 a4 [ab4 <eb5 f5>]>"
|
"<g4 c5 a4 [ab4 <eb5 f5>]>"
|
||||||
.scale(scales)
|
.scale(scales)
|
||||||
.struct("x*8")
|
.struct("x*8")
|
||||||
@ -205,13 +217,14 @@ stack(
|
|||||||
.room(.5)
|
.room(.5)
|
||||||
.delay(.3)
|
.delay(.3)
|
||||||
.delayfeedback(.4)
|
.delayfeedback(.4)
|
||||||
.delaytime(1/12).gain(.5),
|
.delaytime(1/12).gain(.5).color('#7ED321'),
|
||||||
"<c2 c3 f2 [[F2 C2] db2]>"
|
"<c2 c3 f2 [[F2 C2] db2]>"
|
||||||
.legato("<1@3 [.3 1]>")
|
.legato("<1@3 [.3 1]>")
|
||||||
.slow(2).superimpose(x=>x.add(.02))
|
.slow(2).superimpose(x=>x.add(.02))
|
||||||
.note().gain(.3)
|
.note().gain(.3)
|
||||||
.s('sawtooth').cutoff(600),
|
.s('sawtooth').cutoff(600).color('#F8E71C'),
|
||||||
).fast(3/2)`;
|
).fast(3/2)
|
||||||
|
//.pianoroll({fold:1})`;
|
||||||
|
|
||||||
export const wavyKalimba = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
export const wavyKalimba = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
// by Felix Roos
|
// by Felix Roos
|
||||||
@ -505,13 +518,9 @@ export const festivalOfFingers3 = `// licensed with CC BY-NC-SA 4.0 https://crea
|
|||||||
|
|
||||||
export const meltingsubmarine = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
export const meltingsubmarine = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
// by Felix Roos
|
// by Felix Roos
|
||||||
samples({
|
await samples('github:tidalcycles/Dirt-Samples/master/')
|
||||||
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
|
|
||||||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
|
||||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
|
||||||
stack(
|
stack(
|
||||||
s("bd,[~ <sd!3 sd(3,4,2)>],hh(3,4)") // drums
|
s("bd:5,[~ <sd:1!3 sd:1(3,4,2)>],hh27(3,4)") // drums
|
||||||
.speed(perlin.range(.7,.9)) // random sample speed variation
|
.speed(perlin.range(.7,.9)) // random sample speed variation
|
||||||
//.hush()
|
//.hush()
|
||||||
,"<a1 b1*2 a1(3,8) e2>" // bassline
|
,"<a1 b1*2 a1(3,8) e2>" // bassline
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user