mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 21:58:31 +00:00
Merge remote-tracking branch 'origin/main' into workshop-new
This commit is contained in:
commit
576b88221d
246
test/metadata.test.mjs
Normal file
246
test/metadata.test.mjs
Normal file
@ -0,0 +1,246 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { getMetadata } from '../website/src/pages/metadata_parser';
|
||||
|
||||
describe.concurrent('Metadata parser', () => {
|
||||
it('loads a tag from inline comment', async () => {
|
||||
const tune = `// @title Awesome song`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
});
|
||||
});
|
||||
|
||||
it('loads many tags from inline comments', async () => {
|
||||
const tune = `// @title Awesome song
|
||||
// @by Sam`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads many tags from one inline comment', async () => {
|
||||
const tune = `// @title Awesome song @by Sam`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a tag from a block comment', async () => {
|
||||
const tune = `/* @title Awesome song */`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
});
|
||||
});
|
||||
|
||||
it('loads many tags from a block comment', async () => {
|
||||
const tune = `/*
|
||||
@title Awesome song
|
||||
@by Sam
|
||||
*/`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads many tags from many block comments', async () => {
|
||||
const tune = `/* @title Awesome song */
|
||||
/* @by Sam */`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads many tags from mixed comments', async () => {
|
||||
const tune = `/* @title Awesome song */
|
||||
// @by Sam
|
||||
`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a title tag with quotes syntax', async () => {
|
||||
const tune = `// "Awesome song"`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a title tag with quotes syntax among other tags', async () => {
|
||||
const tune = `// "Awesome song" made @by Sam`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a title tag with quotes syntax from block comment', async () => {
|
||||
const tune = `/* "Awesome song"
|
||||
@by Sam */`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam'],
|
||||
});
|
||||
});
|
||||
|
||||
it('does not load a title tag with quotes syntax after a prefix', async () => {
|
||||
const tune = `// I don't care about those "metadata".`;
|
||||
expect(getMetadata(tune)).toStrictEqual({});
|
||||
});
|
||||
|
||||
it('does not load a title tag with quotes syntax after an other comment', async () => {
|
||||
const tune = `// I don't care about those
|
||||
// "metadata"`;
|
||||
expect(getMetadata(tune)).toStrictEqual({});
|
||||
});
|
||||
|
||||
it('does not load a title tag with quotes syntax after other tags', async () => {
|
||||
const tune = `/*
|
||||
@by Sam aka "Lady Strudel"
|
||||
"Sandyyy"
|
||||
*/`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
by: ['Sam aka "Lady Strudel"', '"Sandyyy"'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a tag list with comma-separated values syntax', async () => {
|
||||
const tune = `// @by Sam, Sandy`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
by: ['Sam', 'Sandy'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a tag list with duplicate keys syntax', async () => {
|
||||
const tune = `// @by Sam
|
||||
// @by Sandy`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
by: ['Sam', 'Sandy'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a tag list with duplicate keys syntax, with prefixes', async () => {
|
||||
const tune = `// song @by Sam
|
||||
// samples @by Sandy`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
by: ['Sam', 'Sandy'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads many tag lists with duplicate keys syntax, within code', async () => {
|
||||
const tune = `note("a3 c#4 e4 a4") // @by Sam @license CC0
|
||||
s("bd hh sd hh") // @by Sandy @license CC BY-NC-SA`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
by: ['Sam', 'Sandy'],
|
||||
license: ['CC0', 'CC BY-NC-SA'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a tag list with duplicate keys syntax from block comment', async () => {
|
||||
const tune = `/* @by Sam
|
||||
@by Sandy */`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
by: ['Sam', 'Sandy'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a tag list with newline syntax', async () => {
|
||||
const tune = `/*
|
||||
@by Sam
|
||||
Sandy */`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
by: ['Sam', 'Sandy'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a multiline tag from block comment', async () => {
|
||||
const tune = `/*
|
||||
@details I wrote this song in February 19th, 2023.
|
||||
It was around midnight and I was lying on
|
||||
the sofa in the living room.
|
||||
*/`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
details:
|
||||
'I wrote this song in February 19th, 2023. ' +
|
||||
'It was around midnight and I was lying on the sofa in the living room.',
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a multiline tag from block comment with duplicate keys', async () => {
|
||||
const tune = `/*
|
||||
@details I wrote this song in February 19th, 2023.
|
||||
@details It was around midnight and I was lying on
|
||||
the sofa in the living room.
|
||||
*/`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
details:
|
||||
'I wrote this song in February 19th, 2023. ' +
|
||||
'It was around midnight and I was lying on the sofa in the living room.',
|
||||
});
|
||||
});
|
||||
|
||||
it('loads a multiline tag from inline comments', async () => {
|
||||
const tune = `// @details I wrote this song in February 19th, 2023.
|
||||
// @details It was around midnight and I was lying on
|
||||
// @details the sofa in the living room.
|
||||
*/`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
details:
|
||||
'I wrote this song in February 19th, 2023. ' +
|
||||
'It was around midnight and I was lying on the sofa in the living room.',
|
||||
});
|
||||
});
|
||||
|
||||
it('loads empty tags from inline comments', async () => {
|
||||
const tune = `// @title
|
||||
// @by`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: '',
|
||||
by: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads tags with whitespaces from inline comments', async () => {
|
||||
const tune = ` // @title Awesome song
|
||||
// @by Sam Tagada `;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam Tagada'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads tags with whitespaces from block comment', async () => {
|
||||
const tune = ` /* @title Awesome song
|
||||
@by Sam Tagada */ `;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: 'Awesome song',
|
||||
by: ['Sam Tagada'],
|
||||
});
|
||||
});
|
||||
|
||||
it('loads empty tags from block comment', async () => {
|
||||
const tune = `/* @title
|
||||
@by */`;
|
||||
expect(getMetadata(tune)).toStrictEqual({
|
||||
title: '',
|
||||
by: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('does not load tags if there is not', async () => {
|
||||
const tune = `note("a3 c#4 e4 a4")`;
|
||||
expect(getMetadata(tune)).toStrictEqual({});
|
||||
});
|
||||
|
||||
it('does not load code that looks like a metadata tag', async () => {
|
||||
const tune = `const str1 = '@title Awesome song'`;
|
||||
// need a lexer to avoid this one, but it's a pretty rare use case:
|
||||
// const tune = `const str1 = '// @title Awesome song'`;
|
||||
|
||||
expect(getMetadata(tune)).toStrictEqual({});
|
||||
});
|
||||
});
|
||||
@ -76,6 +76,7 @@ export const SIDEBAR: Sidebar = {
|
||||
{ text: 'Patterns', link: 'technical-manual/patterns' },
|
||||
{ text: 'Pattern Alignment', link: 'technical-manual/alignment' },
|
||||
{ text: 'Strudel vs Tidal', link: 'learn/strudel-vs-tidal' },
|
||||
{ text: 'Music metadata', link: 'learn/metadata' },
|
||||
{ text: 'CSound', link: 'learn/csound' },
|
||||
],
|
||||
'Pattern Functions': [
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
---
|
||||
import * as tunes from '../../../src/repl/tunes.mjs';
|
||||
import HeadCommon from '../../components/HeadCommon.astro';
|
||||
|
||||
import { getMetadata } from '../metadata_parser';
|
||||
---
|
||||
|
||||
<head>
|
||||
@ -12,7 +14,7 @@ import HeadCommon from '../../components/HeadCommon.astro';
|
||||
Object.entries(tunes).map(([name, tune]) => (
|
||||
<a class="rounded-md bg-slate-900 hover:bg-slate-700 cursor-pointer relative" href={`./#${btoa(tune)}`}>
|
||||
<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>
|
||||
<span class="bg-slate-800 p-2 rounded-md text-white">{getMetadata(tune)['title'] || name}</span>
|
||||
</div>
|
||||
<img src={`./img/example-${name}.png`} />
|
||||
</a>
|
||||
|
||||
@ -67,6 +67,9 @@ It is a handy way to quickly turn code on and off.
|
||||
Try uncommenting this line by deleting `//` and refreshing the pattern.
|
||||
You can also use the keyboard shortcut `cmd-/` to toggle comments on and off.
|
||||
|
||||
You might noticed that some comments in the REPL samples include some words starting with a "@", like `@by` or `@license`.
|
||||
Those are just a convention to define some information about the music. We will talk about it in the [Music metadata](/learn/metadata) section.
|
||||
|
||||
# Strings
|
||||
|
||||
Ok, so what about the content inside the quotes (e.g. `"c a f e"`)?
|
||||
|
||||
94
website/src/pages/learn/metadata.mdx
Normal file
94
website/src/pages/learn/metadata.mdx
Normal file
@ -0,0 +1,94 @@
|
||||
---
|
||||
title: Music metadata
|
||||
layout: ../../layouts/MainLayout.astro
|
||||
---
|
||||
|
||||
import { MiniRepl } from '../../docs/MiniRepl';
|
||||
import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
# Music metadata
|
||||
|
||||
You can optionally add some music metadata in your Strudel code, by using tags in code comments:
|
||||
|
||||
```js
|
||||
// @title Hey Hoo
|
||||
// @by Sam Tagada
|
||||
// @license CC BY-NC-SA
|
||||
```
|
||||
|
||||
Like other comments, those are ignored by Strudel, but it can be used by other tools to retrieve some information about the music.
|
||||
|
||||
It is for instance used by the [swatch tool](https://github.com/tidalcycles/strudel/tree/main/my-patterns) to display pattern titles in the [examples page](https://strudel.tidalcycles.org/examples/).
|
||||
|
||||
## Alternative syntax
|
||||
|
||||
You can also use comment blocks:
|
||||
|
||||
```js
|
||||
/*
|
||||
@title Hey Hoo
|
||||
@by Sam Tagada
|
||||
@license CC BY-NC-SA
|
||||
*/
|
||||
```
|
||||
|
||||
Or define multiple tags in one line:
|
||||
|
||||
```js
|
||||
// @title Hey Hoo @by Sam Tagada @license CC BY-NC-SA
|
||||
```
|
||||
|
||||
The `title` tag has an alternative syntax using quotes (must be defined at the very begining):
|
||||
|
||||
```js
|
||||
// "Hey Hoo" @by Sam Tagada
|
||||
```
|
||||
|
||||
## Tags list
|
||||
|
||||
Available tags are:
|
||||
|
||||
- `@title`: music title
|
||||
- `@by`: music author(s), separated by comma, eventually followed with a link in `<>` (ex: `@by John Doe <https://example.com>`)
|
||||
- `@license`: music license(s)
|
||||
- `@details`: some additional information about the music
|
||||
- `@url`: web page(s) related to the music (git repo, soundcloud link, etc.)
|
||||
- `@genre`: music genre(s) (pop, jazz, etc)
|
||||
- `@album`: music album name
|
||||
|
||||
## Multiple values
|
||||
|
||||
Some of them accepts several values, using the comma or new line separator, or duplicating the tag:
|
||||
|
||||
```js
|
||||
/*
|
||||
@by Sam Tagada
|
||||
Jimmy
|
||||
@genre pop, jazz
|
||||
@url https://example.com
|
||||
@url https://example.org
|
||||
*/
|
||||
```
|
||||
|
||||
You can also add optional prefixes and use tags where you want:
|
||||
|
||||
```js
|
||||
/*
|
||||
song @by Sam Tagada
|
||||
samples @by Jimmy
|
||||
*/
|
||||
...
|
||||
note("a3 c#4 e4 a4") // @by Sandy
|
||||
```
|
||||
|
||||
## Multiline
|
||||
|
||||
If a tag doesn't accept a list, it can take multi-line values:
|
||||
|
||||
```js
|
||||
/*
|
||||
@details I wrote this song in February 19th, 2023.
|
||||
It was around midnight and I was lying on
|
||||
the sofa in the living room.
|
||||
*/
|
||||
```
|
||||
@ -24,7 +24,7 @@ Instead of numbers, scientific interval notation can be used as well:
|
||||
|
||||
### scale(name)
|
||||
|
||||
Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranpose.
|
||||
Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranspose.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
|
||||
34
website/src/pages/metadata_parser.js
Normal file
34
website/src/pages/metadata_parser.js
Normal file
@ -0,0 +1,34 @@
|
||||
const ALLOW_MANY = ['by', 'url', 'genre', 'license'];
|
||||
|
||||
export function getMetadata(raw_code) {
|
||||
const comment_regexp = /\/\*([\s\S]*?)\*\/|\/\/(.*)$/gm;
|
||||
const comments = [...raw_code.matchAll(comment_regexp)].map((c) => (c[1] || c[2] || '').trim());
|
||||
const tags = {};
|
||||
|
||||
const [prefix, title] = (comments[0] || '').split('"');
|
||||
if (prefix.trim() === '' && title !== undefined) {
|
||||
tags['title'] = title;
|
||||
}
|
||||
|
||||
for (const comment of comments) {
|
||||
const tag_matches = comment.split('@').slice(1);
|
||||
for (const tag_match of tag_matches) {
|
||||
let [tag, tag_value] = tag_match.split(/ (.*)/s);
|
||||
tag = tag.trim();
|
||||
tag_value = (tag_value || '').replaceAll(/ +/g, ' ').trim();
|
||||
|
||||
if (ALLOW_MANY.includes(tag)) {
|
||||
const tag_list = tag_value
|
||||
.split(/[,\n]/)
|
||||
.map((t) => t.trim())
|
||||
.filter((t) => t !== '');
|
||||
tags[tag] = tag in tags ? tags[tag].concat(tag_list) : tag_list;
|
||||
} else {
|
||||
tag_value = tag_value.replaceAll(/\s+/g, ' ');
|
||||
tags[tag] = tag in tags ? tags[tag] + ' ' + tag_value : tag_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
@ -1,9 +1,11 @@
|
||||
import { getMetadata } from '../metadata_parser';
|
||||
|
||||
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]), //
|
||||
Object.entries(my)
|
||||
.filter(([name]) => name.endsWith('.txt'))
|
||||
.map(([name, raw]) => [getMetadata(raw)['title'] || name.split('/').slice(-1), raw]),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -121,8 +121,10 @@ stack(
|
||||
.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/
|
||||
// by Felix Roos
|
||||
export const caverave = `// "Caverave"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
const keys = x => x.s('sawtooth').cutoff(1200).gain(.5)
|
||||
.attack(0).decay(.16).sustain(.3).release(.1);
|
||||
|
||||
@ -184,8 +186,10 @@ export const barryHarris = `// adapted from a Barry Harris excercise
|
||||
.color('#00B8D4')
|
||||
`;
|
||||
|
||||
export const blippyRhodes = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const blippyRhodes = `// "Blippy Rhodes"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
samples({
|
||||
bd: 'samples/tidal/bd/BT0A0D0.wav',
|
||||
sn: 'samples/tidal/sn/ST0T0S3.wav',
|
||||
@ -226,8 +230,10 @@ stack(
|
||||
).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/
|
||||
// by Felix Roos
|
||||
export const wavyKalimba = `// "Wavy kalimba"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
samples({
|
||||
'kalimba': { c5:'https://freesound.org/data/previews/536/536549_11935698-lq.mp3' }
|
||||
})
|
||||
@ -256,8 +262,10 @@ stack(
|
||||
.delay(.2)
|
||||
`;
|
||||
|
||||
export const festivalOfFingers = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const festivalOfFingers = `// "Festival of fingers"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
const chords = "<Cm7 Fm7 G7 F#7>";
|
||||
stack(
|
||||
chords.voicings('lefthand').struct("x(3,8,-1)").velocity(.5).off(1/7,x=>x.transpose(12).velocity(.2)),
|
||||
@ -271,8 +279,10 @@ stack(
|
||||
.note().piano()`;
|
||||
|
||||
// iter, echo, echoWith
|
||||
export const undergroundPlumber = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos, inspired by Friendship - Let's not talk about it (1979) :)
|
||||
export const undergroundPlumber = `// "Underground plumber"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
// @details inspired by Friendship - Let's not talk about it (1979) :)
|
||||
|
||||
samples({ bd: 'bd/BT0A0D0.wav', sn: 'sn/ST0T0S3.wav', hh: 'hh/000_hh3closedhh.wav', cp: 'cp/HANDCLP0.wav',
|
||||
}, 'https://loophole-letters.vercel.app/samples/tidal/')
|
||||
@ -297,8 +307,10 @@ stack(
|
||||
.fast(2/3)
|
||||
.pianoroll({})`;
|
||||
|
||||
export const bridgeIsOver = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos, bassline by BDP - The Bridge Is Over
|
||||
export const bridgeIsOver = `// "Bridge is over"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos, bassline by BDP - The Bridge Is Over
|
||||
|
||||
samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'})
|
||||
stack(
|
||||
stack(
|
||||
@ -318,8 +330,10 @@ stack(
|
||||
.pianoroll()
|
||||
`;
|
||||
|
||||
export const goodTimes = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const goodTimes = `// "Good times"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
const scale = cat('C3 dorian','Bb2 major').slow(4);
|
||||
stack(
|
||||
"2*4".add(12).scale(scale)
|
||||
@ -361,8 +375,10 @@ stack(
|
||||
.pianoroll({maxMidi:100,minMidi:20})`;
|
||||
*/
|
||||
|
||||
export const echoPiano = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const echoPiano = `// "Echo piano"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
"<0 2 [4 6](3,4,2) 3*2>"
|
||||
.scale('D minor')
|
||||
.color('salmon')
|
||||
@ -408,8 +424,10 @@ stack(
|
||||
.legato(.5)
|
||||
).fast(2).note()`;
|
||||
|
||||
export const randomBells = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const randomBells = `// "Random bells"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
samples({
|
||||
bell: { c6: 'https://freesound.org/data/previews/411/411089_5121236-lq.mp3' },
|
||||
bass: { d2: 'https://freesound.org/data/previews/608/608286_13074022-lq.mp3' }
|
||||
@ -431,8 +449,10 @@ stack(
|
||||
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'})
|
||||
`;
|
||||
|
||||
export const waa2 = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const waa2 = `// "Waa2"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
n(
|
||||
"a4 [a3 c3] a3 c3"
|
||||
.sub("<7 12 5 12>".slow(2))
|
||||
@ -447,8 +467,10 @@ n(
|
||||
.room(.5)
|
||||
`;
|
||||
|
||||
export const hyperpop = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const hyperpop = `// "Hyperpop"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
const lfo = cosine.slow(15);
|
||||
const lfo2 = sine.slow(16);
|
||||
const filter1 = x=>x.cutoff(lfo2.range(300,3000));
|
||||
@ -498,8 +520,10 @@ stack(
|
||||
).slow(2)
|
||||
// strudel disable-highlighting`;
|
||||
|
||||
export const festivalOfFingers3 = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const festivalOfFingers3 = `// "Festival of fingers 3"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
"[-7*3],0,2,6,[8 7]"
|
||||
.echoWith(4,1/4, (x,n)=>x
|
||||
.add(n*7)
|
||||
@ -516,8 +540,10 @@ export const festivalOfFingers3 = `// licensed with CC BY-NC-SA 4.0 https://crea
|
||||
.note().piano()
|
||||
//.pianoroll({maxMidi:160})`;
|
||||
|
||||
export const meltingsubmarine = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const meltingsubmarine = `// "Melting submarine"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
await samples('github:tidalcycles/Dirt-Samples/master/')
|
||||
stack(
|
||||
s("bd:5,[~ <sd:1!3 sd:1(3,4,3)>],hh27(3,4,1)") // drums
|
||||
@ -554,8 +580,10 @@ stack(
|
||||
)
|
||||
.slow(3/2)`;
|
||||
|
||||
export const outroMusic = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const outroMusic = `// "Outro music"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
samples({
|
||||
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'],
|
||||
@ -583,8 +611,10 @@ samples({
|
||||
//.pianoroll({autorange:1,vertical:1,fold:0})
|
||||
`;
|
||||
|
||||
export const bassFuge = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const bassFuge = `// "Bass fuge"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
samples({ flbass: ['00_c2_finger_long_neck.wav','01_c2_finger_short_neck.wav','02_c2_finger_long_bridge.wav','03_c2_finger_short_bridge.wav','04_c2_pick_long.wav','05_c2_pick_short.wav','06_c2_palm_mute.wav'] },
|
||||
'github:cleary/samples-flbass/main/')
|
||||
samples({
|
||||
@ -609,8 +639,10 @@ x=>x.add(7).color('steelblue')
|
||||
.stack(s("bd:1*2,~ sd:0,[~ hh:0]*2"))
|
||||
.pianoroll({vertical:1})`;
|
||||
|
||||
export const chop = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const chop = `// "Chop"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
samples({ p: 'https://cdn.freesound.org/previews/648/648433_11943129-lq.mp3' })
|
||||
|
||||
s("p")
|
||||
@ -622,8 +654,10 @@ s("p")
|
||||
.sustain(.6)
|
||||
`;
|
||||
|
||||
export const delay = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const delay = `// "Delay"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
stack(
|
||||
s("bd <sd cp>")
|
||||
.delay("<0 .5>")
|
||||
@ -631,8 +665,10 @@ stack(
|
||||
.delayfeedback(".6 | .8")
|
||||
).sometimes(x=>x.speed("-1"))`;
|
||||
|
||||
export const orbit = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const orbit = `// "Orbit"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
stack(
|
||||
s("bd <sd cp>")
|
||||
.delay(.5)
|
||||
@ -645,8 +681,10 @@ stack(
|
||||
.orbit(2)
|
||||
).sometimes(x=>x.speed("-1"))`;
|
||||
|
||||
export const belldub = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const belldub = `// "Belldub"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
samples({ bell: {b4:'https://cdn.freesound.org/previews/339/339809_5121236-lq.mp3'}})
|
||||
// "Hand Bells, B, Single.wav" by InspectorJ (www.jshaw.co.uk) of Freesound.org
|
||||
stack(
|
||||
@ -678,8 +716,10 @@ stack(
|
||||
.mask("<1 0>/8")
|
||||
).slow(5)`;
|
||||
|
||||
export const dinofunk = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const dinofunk = `// "Dinofunk"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
samples({bass:'https://cdn.freesound.org/previews/614/614637_2434927-hq.mp3',
|
||||
dino:{b4:'https://cdn.freesound.org/previews/316/316403_5123851-hq.mp3'}})
|
||||
setVoicingRange('lefthand', ['c3','a4'])
|
||||
@ -699,8 +739,10 @@ note("Abm7".voicings('lefthand').struct("x(3,8,1)".slow(2))),
|
||||
note("<b4 eb4>").s('dino').delay(.8).slow(8).room(.5)
|
||||
)`;
|
||||
|
||||
export const sampleDemo = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const sampleDemo = `// "Sample demo"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
stack(
|
||||
// percussion
|
||||
s("[woodblock:1 woodblock:2*2] snare_rim:0,gong/8,brakedrum:1(3,8),~@3 cowbell:3")
|
||||
@ -715,8 +757,10 @@ stack(
|
||||
.release(.1).room(.5)
|
||||
)`;
|
||||
|
||||
export const holyflute = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const holyflute = `// "Holy flute"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
"c3 eb3(3,8) c4/2 g3*2"
|
||||
.superimpose(
|
||||
x=>x.slow(2).add(12),
|
||||
@ -728,8 +772,10 @@ export const holyflute = `// licensed with CC BY-NC-SA 4.0 https://creativecommo
|
||||
.pianoroll({fold:0,autorange:0,vertical:0,cycles:12,smear:0,minMidi:40})
|
||||
`;
|
||||
|
||||
export const flatrave = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const flatrave = `// "Flatrave"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
stack(
|
||||
s("bd*2,~ [cp,sd]").bank('RolandTR909'),
|
||||
|
||||
@ -751,8 +797,10 @@ stack(
|
||||
.decay(.05).sustain(0).delay(.2).degradeBy(.5).mask("<0 1>/16")
|
||||
)`;
|
||||
|
||||
export const amensister = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const amensister = `// "Amensister"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
await samples('github:tidalcycles/Dirt-Samples/master')
|
||||
|
||||
stack(
|
||||
@ -785,8 +833,10 @@ stack(
|
||||
n("0 1").s("east").delay(.5).degradeBy(.8).speed(rand.range(.5,1.5))
|
||||
).reset("<x@7 x(5,8,-1)>")`;
|
||||
|
||||
export const juxUndTollerei = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const juxUndTollerei = `// "Jux und tollerei"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
note("c3 eb3 g3 bb3").palindrome()
|
||||
.s('sawtooth')
|
||||
.jux(x=>x.rev().color('green').s('sawtooth'))
|
||||
@ -798,8 +848,10 @@ note("c3 eb3 g3 bb3").palindrome()
|
||||
.delay(.5).delaytime(.1).delayfeedback(.4)
|
||||
.pianoroll()`;
|
||||
|
||||
export const csoundDemo = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
export const csoundDemo = `// "CSound demo"
|
||||
// @license with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
await loadCsound\`
|
||||
instr CoolSynth
|
||||
iduration = p3
|
||||
@ -832,10 +884,10 @@ endin\`
|
||||
//.pianoroll()
|
||||
.csound('CoolSynth')`;
|
||||
|
||||
export const loungeSponge = `
|
||||
// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// by Felix Roos
|
||||
// livecode.orc by Steven Yi
|
||||
export const loungeSponge = `// "Lounge sponge"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos, livecode.orc by Steven Yi
|
||||
|
||||
await loadOrc('github:kunstmusik/csound-live-code/master/livecode.orc')
|
||||
|
||||
stack(
|
||||
@ -852,8 +904,10 @@ stack(
|
||||
s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909')
|
||||
)`;
|
||||
|
||||
export const arpoon = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// "Arpoon" by Felix Roos
|
||||
export const arpoon = `// "Arpoon"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
await samples('github:tidalcycles/Dirt-Samples/master')
|
||||
|
||||
"<<Am7 C^7> C7 F^7 [Fm7 E7b9]>".voicings('lefthand')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user