Merge remote-tracking branch 'origin/main' into workshop-new

This commit is contained in:
Felix Roos 2023-06-09 18:00:16 +02:00
commit 576b88221d
9 changed files with 499 additions and 63 deletions

246
test/metadata.test.mjs Normal file
View 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({});
});
});

View File

@ -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': [

View File

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

View File

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

View 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.
*/
```

View File

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

View 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;
}

View File

@ -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]),
);
}

View File

@ -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')