Compare commits

..

13 Commits

Author SHA1 Message Date
Felix Roos 11be5db628 Publish
- @strudel.cycles/core@0.0.2
 - @strudel.cycles/eval@0.0.2
 - @strudel.cycles/midi@0.0.2
 - @strudel.cycles/mini@0.0.2
 - @strudel.cycles/tonal@0.0.2
 - @strudel.cycles/tone@0.0.2
 - @strudel.cycles/xen@0.0.2
2022-03-27 23:44:26 +02:00
Felix Roos 779d303572 simplify import 2022-03-27 23:43:30 +02:00
Felix Roos 788f344012 simplify onEvent call 2022-03-27 23:43:20 +02:00
Felix Roos 33c9326427 add missing dependency 2022-03-27 23:43:06 +02:00
Felix Roos 9ef57152e4 add duration getter 2022-03-27 23:42:47 +02:00
Felix Roos f8f2fb608d add tonal example 2022-03-27 22:49:06 +02:00
Felix Roos 1cf6b37ee4 add mini example 2022-03-27 22:41:37 +02:00
Felix Roos 76822717f4 add eval example 2022-03-27 22:35:55 +02:00
Felix Roos 4142b113e9 add core example 2022-03-27 22:25:48 +02:00
Felix Roos 3c123538e9 repl readme 2022-03-27 22:21:51 +02:00
Felix Roos 73996997e5 add install commands 2022-03-27 22:17:07 +02:00
Felix Roos c4d14594ce remove node 14 test 2022-03-27 22:12:05 +02:00
Felix Roos 657960024d independent mode 2022-03-27 21:52:26 +02:00
27 changed files with 2962 additions and 75 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [14, 16, 17] node-version: [16, 17]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
-8
View File
@@ -19,11 +19,3 @@ cd repl
npm install npm install
npm run start npm run start
``` ```
## Build
```bash
cd repl
npm run build
npm run static # <- test static build
```
+1 -1
View File
@@ -2,5 +2,5 @@
"packages": [ "packages": [
"packages/*" "packages/*"
], ],
"version": "0.0.1" "version": "independent"
} }
+33
View File
@@ -1,3 +1,36 @@
# @strudel.cycles/core # @strudel.cycles/core
This package contains the bare essence of strudel. This package contains the bare essence of strudel.
## Install
```sh
npm i @strudel.cycles/core --save
```
## Example
```js
import { sequence, State, TimeSpan } from '@strudel.cycles/core';
const pattern = sequence('a', ['b', 'c']);
const events = pattern.query(new State(new TimeSpan(0, 2)));
const spans = events.map(
(event) => `${event.value}: ${event.whole.begin.toFraction()} - ${event.whole.end.toFraction()} `,
);
```
spans:
```log
a: 0 - 1/2
b: 1/2 - 3/4
c: 3/4 - 1
a: 1 - 3/2
b: 3/2 - 7/4
c: 7/4 - 2
```
[play with @strudel.cycles/core on codesandbox](https://codesandbox.io/s/strudel-core-test-qmz6qr?file=/src/index.js).
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/core", "name": "@strudel.cycles/core",
"version": "0.0.1", "version": "0.0.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/core", "name": "@strudel.cycles/core",
"version": "0.0.1", "version": "0.0.2",
"description": "Port of Tidal Cycles to JavaScript", "description": "Port of Tidal Cycles to JavaScript",
"main": "strudel.mjs", "main": "strudel.mjs",
"type": "module", "type": "module",
+4 -1
View File
@@ -138,6 +138,10 @@ class Hap {
} }
} }
get duration() {
return this.whole.end.sub(this.whole.begin).valueOf();
}
withSpan(func) { withSpan(func) {
// Returns a new event with the function f applies to the event timespan. // Returns a new event with the function f applies to the event timespan.
const whole = this.whole ? func(this.whole) : undefined const whole = this.whole ? func(this.whole) : undefined
@@ -1034,7 +1038,6 @@ Pattern.prototype.bootstrap = function() {
} }
return [functionName, curry(composable, makeComposable)]; return [functionName, curry(composable, makeComposable)];
})); }));
// note: this === Pattern.prototypetgh6z // note: this === Pattern.prototypetgh6z
this.patternified.forEach((prop) => { this.patternified.forEach((prop) => {
// the following will patternify all functions in Pattern.prototype.patternified // the following will patternify all functions in Pattern.prototype.patternified
+33
View File
@@ -3,6 +3,39 @@
This package contains the strudel code transformer and evaluator. This package contains the strudel code transformer and evaluator.
It allows creating strudel patterns from input code that is optimized for minimal keystrokes and human readability. It allows creating strudel patterns from input code that is optimized for minimal keystrokes and human readability.
## Install
```sh
npm i @strudel.cycles/eval --save
```
## Example
```js
import { evaluate, extend } from '@strudel.cycles/eval';
import * as strudel from '@strudel.cycles/core';
extend(strudel); // add strudel to eval scope
async function run(code) {
const { pattern } = await evaluate(code);
const events = pattern.firstCycle();
console.log(events.map((e) => e.show()).join('\n'));
}
run('sequence([a3, [b3, c4]])');
```
yields:
```js
(0/1 -> 1/2, 0/1 -> 1/2, a3)
(1/2 -> 3/4, 1/2 -> 3/4, b3)
(3/4 -> 1/1, 3/4 -> 1/1, c4)
```
[play with @strudel.cycles/eval on codesandbox](https://codesandbox.io/s/strudel-eval-example-ndz1d8?file=/src/index.js)
## Dev Notes ## Dev Notes
shift-traverser is currently monkey patched because its package.json uses estraverse@^4.2.0, shift-traverser is currently monkey patched because its package.json uses estraverse@^4.2.0,
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/eval", "name": "@strudel.cycles/eval",
"version": "0.0.1", "version": "0.0.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/eval", "name": "@strudel.cycles/eval",
"version": "0.0.1", "version": "0.0.2",
"description": "Code evaluator for strudel", "description": "Code evaluator for strudel",
"main": "evaluate.mjs", "main": "evaluate.mjs",
"directories": { "directories": {
@@ -28,7 +28,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "^0.0.1", "@strudel.cycles/core": "^0.0.2",
"estraverse": "^5.3.0", "estraverse": "^5.3.0",
"shift-ast": "^6.1.0", "shift-ast": "^6.1.0",
"shift-codegen": "^7.0.3", "shift-codegen": "^7.0.3",
+6
View File
@@ -1,3 +1,9 @@
# @strudel.cycles/midi # @strudel.cycles/midi
This package adds midi functionality to strudel Patterns. This package adds midi functionality to strudel Patterns.
## Install
```sh
npm i @strudel.cycles/midi --save
```
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/midi", "name": "@strudel.cycles/midi",
"version": "0.0.1", "version": "0.0.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/midi", "name": "@strudel.cycles/midi",
"version": "0.0.1", "version": "0.0.2",
"description": "Midi API for strudel", "description": "Midi API for strudel",
"main": "midi.mjs", "main": "midi.mjs",
"repository": { "repository": {
@@ -21,7 +21,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/tone": "^0.0.1", "@strudel.cycles/tone": "^0.0.2",
"tone": "^14.7.77", "tone": "^14.7.77",
"webmidi": "^2.5.2" "webmidi": "^2.5.2"
} }
+34
View File
@@ -1,3 +1,37 @@
# @strudel.cycles/mini # @strudel.cycles/mini
This package contains the mini notation parser and pattern generator. This package contains the mini notation parser and pattern generator.
## Install
```sh
npm i @strudel.cycles/mini --save
```
## Example
```js
import { mini } from '@strudel.cycles/mini';
const pattern = mini('a [b c*2]');
const events = pattern.firstCycle().map((e) => e.show());
console.log(events);
document.getElementById('app').innerHTML = events.join('<br/>');
```
yields:
```log
(0/1 -> 1/2, 0/1 -> 1/2, a)
(1/2 -> 3/4, 1/2 -> 3/4, b)
(3/4 -> 7/8, 3/4 -> 7/8, c)
(7/8 -> 1/1, 7/8 -> 1/1, c)
```
[Play with @strudel.cycles/mini codesandbox](https://codesandbox.io/s/strudel-mini-example-oe9wcu?file=/src/index.js)
## Mini Notation API
See "Mini Notation" in the [Strudel Tutorial](https://strudel.tidalcycles.org/tutorial/)
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/mini", "name": "@strudel.cycles/mini",
"version": "0.0.1", "version": "0.0.2",
"description": "Mini notation for strudel", "description": "Mini notation for strudel",
"main": "mini.mjs", "main": "mini.mjs",
"type": "module", "type": "module",
@@ -25,7 +25,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/eval": "^0.0.1", "@strudel.cycles/eval": "^0.0.2",
"@strudel.cycles/tone": "^0.0.1" "@strudel.cycles/tone": "^0.0.2"
} }
} }
+31
View File
@@ -1,3 +1,34 @@
# @strudel.cycles/tonal # @strudel.cycles/tonal
This package adds tonal / harmonic functions to strudel Patterns. This package adds tonal / harmonic functions to strudel Patterns.
## Install
```sh
npm i @strudel.cycles/tonal --save
```
## Example
```js
import { sequence } from '@strudel.cycles/core';
import '@strudel.cycles/tonal';
const pattern = sequence(0, [1, 2]).scale('C major');
const events = pattern.firstCycle().map((e) => e.show());
```
yields:
```js
(0/1 -> 1/2, 0/1 -> 1/2, C3)
(1/2 -> 3/4, 1/2 -> 3/4, D3)
(3/4 -> 1/1, 3/4 -> 1/1, E3)
```
[play with @strudel.cycles/tonal codesandbox](https://codesandbox.io/s/strudel-tonal-example-rgc5if?file=/src/index.js)
## Tonal API
See "Tonal API" in the [Strudel Tutorial](https://strudel.tidalcycles.org/tutorial/)
+2756
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/tonal", "name": "@strudel.cycles/tonal",
"version": "0.0.1", "version": "0.0.2",
"description": "Tonal functions for strudel", "description": "Tonal functions for strudel",
"main": "tonal.mjs", "main": "tonal.mjs",
"type": "module", "type": "module",
@@ -25,6 +25,8 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "^0.0.1" "@strudel.cycles/core": "^0.0.2",
"@tonaljs/tonal": "^4.6.5",
"webmidi": "^3.0.15"
} }
} }
+1 -3
View File
@@ -1,9 +1,7 @@
import { Note, Interval, Scale } from '@tonaljs/tonal'; import { Note, Interval, Scale } from '@tonaljs/tonal';
import { Pattern as _Pattern } from '@strudel.cycles/core/strudel.mjs'; import { Pattern } from '@strudel.cycles/core';
import { mod } from '@strudel.cycles/core/util.mjs'; import { mod } from '@strudel.cycles/core/util.mjs';
const Pattern = _Pattern; // as any;
// transpose note inside scale by offset steps // transpose note inside scale by offset steps
// function scaleTranspose(scale: string, offset: number, note: string) { // function scaleTranspose(scale: string, offset: number, note: string) {
export function scaleTranspose(scale, offset, note) { export function scaleTranspose(scale, offset, note) {
+6
View File
@@ -2,6 +2,12 @@
This package adds Tone.js functions to strudel Patterns. This package adds Tone.js functions to strudel Patterns.
## Install
```sh
npm i @strudel.cycles/tone --save
```
## Dev Notes ## Dev Notes
- `@tonejs/piano` has peer dependency on `webmidi@^2.5.1`! A newer version of webmidi will break. - `@tonejs/piano` has peer dependency on `webmidi@^2.5.1`! A newer version of webmidi will break.
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/tone", "name": "@strudel.cycles/tone",
"version": "0.0.1", "version": "0.0.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/tone", "name": "@strudel.cycles/tone",
"version": "0.0.1", "version": "0.0.2",
"description": "Tone.js API for strudel", "description": "Tone.js API for strudel",
"main": "tone.mjs", "main": "tone.mjs",
"type": "module", "type": "module",
@@ -22,7 +22,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "^0.0.1", "@strudel.cycles/core": "^0.0.2",
"@tonejs/piano": "^0.2.1", "@tonejs/piano": "^0.2.1",
"chord-voicings": "^0.0.1", "chord-voicings": "^0.0.1",
"tone": "^14.7.77" "tone": "^14.7.77"
+1 -34
View File
@@ -1,4 +1,4 @@
import { Pattern as _Pattern } from '@strudel.cycles/core'; import { Pattern } from '@strudel.cycles/core';
import * as _Tone from 'tone'; import * as _Tone from 'tone';
// import Tone from here, to make sure to get the same AudioContext // import Tone from here, to make sure to get the same AudioContext
@@ -41,11 +41,8 @@ defaultSynth.set({
// what about // what about
// https://www.charlie-roberts.com/gibberish/playground/ // https://www.charlie-roberts.com/gibberish/playground/
const Pattern = _Pattern;
// with this function, you can play the pattern with any tone synth // with this function, you can play the pattern with any tone synth
Pattern.prototype.tone = function (instrument) { Pattern.prototype.tone = function (instrument) {
// instrument.toDestination();
return this._withEvent((event) => { return this._withEvent((event) => {
const onTrigger = (time, event) => { const onTrigger = (time, event) => {
let note; let note;
@@ -74,36 +71,6 @@ Pattern.prototype.tone = function (instrument) {
note = getPlayableNoteValue(event); note = getPlayableNoteValue(event);
instrument.triggerAttackRelease(note, event.duration, time, velocity); instrument.triggerAttackRelease(note, event.duration, time, velocity);
} }
/* switch (instrument.constructor.name) {
case 'PluckSynth':
note = getPlayableNoteValue(event);
instrument.triggerAttack(note, time);
break;
case 'NoiseSynth':
instrument.triggerAttackRelease(event.duration, time); // noise has no value
break;
case 'Piano':
note = getPlayableNoteValue(event);
instrument.keyDown({ note, time, velocity });
instrument.keyUp({ note, time: time + event.duration, velocity });
break;
case 'Sampler':
note = getPlayableNoteValue(event);
instrument.triggerAttackRelease(note, event.duration, time, velocity);
break;
case 'Players':
if (!instrument.has(event.value)) {
throw new Error(`name "${event.value}" not defined for players`);
}
const player = instrument.player(event.value);
// velocity ?
player.start(time);
player.stop(time + event.duration);
break;
default:
note = getPlayableNoteValue(event);
instrument.triggerAttackRelease(note, event.duration, time, velocity);
} */
}; };
return event.setContext({ ...event.context, instrument, onTrigger }); return event.setContext({ ...event.context, instrument, onTrigger });
}); });
+6
View File
@@ -1,3 +1,9 @@
# @strudel.cycles/xen # @strudel.cycles/xen
This package adds xenharmonic / microtonal functions to strudel Patterns. This package adds xenharmonic / microtonal functions to strudel Patterns.
## Install
```sh
npm i @strudel.cycles/xen --save
```
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/xen", "name": "@strudel.cycles/xen",
"version": "0.0.1", "version": "0.0.2",
"description": "Xenharmonic API for strudel", "description": "Xenharmonic API for strudel",
"main": "xen.mjs", "main": "xen.mjs",
"scripts": { "scripts": {
@@ -24,6 +24,6 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "^0.0.1" "@strudel.cycles/core": "^0.0.2"
} }
} }
+27 -1
View File
@@ -1,6 +1,32 @@
# Strudel REPL # Strudel REPL
TBD This is the REPL for Strudel. REPL stands for
- Read
- Evaluate
- Play!
- Loop
The REPL is deployed at [strudel.tidalcycles.org](https://strudel.tidalcycles.org/).
## Run REPL locally
```bash
# from project root
npm install
npx lerna bootstrap
cd repl
npm install
npm run start
```
## Build REPL
```bash
cd repl
npm run build # <- builds repl + tutorial to ../docs
npm run static # <- test static build
```
## Dev Notes ## Dev Notes
+2 -8
View File
@@ -42,16 +42,10 @@ function useCycle(props) {
?.filter((event) => event.part.begin.equals(event.whole.begin)) ?.filter((event) => event.part.begin.equals(event.whole.begin))
.forEach((event) => { .forEach((event) => {
Tone.getTransport().schedule((time) => { Tone.getTransport().schedule((time) => {
const toneEvent = { onEvent(time, event);
time: event.whole.begin.valueOf(),
duration: event.whole.end.sub(event.whole.begin).valueOf(),
value: event.value,
context: event.context,
};
onEvent(time, toneEvent);
Tone.Draw.schedule(() => { Tone.Draw.schedule(() => {
// do drawing or DOM manipulation here // do drawing or DOM manipulation here
onDraw?.(time, toneEvent); onDraw?.(time, event);
}, time); }, time);
}, event.part.begin.valueOf()); }, event.part.begin.valueOf());
}); });