Compare commits

...

9 Commits

Author SHA1 Message Date
Felix Roos 5887d4b999 Merge branch 'main' into dirtify-plain-values 2022-08-03 22:29:49 +02:00
Felix Roos 6211be5cc7 Merge remote-tracking branch 'origin/main' into dirtify-plain-values 2022-05-03 08:13:43 +02:00
Felix Roos 6855311d2d Merge remote-tracking branch 'origin/HEAD' into dirtify-plain-values 2022-04-16 10:30:00 +02:00
Felix Roos d2b060a057 fix import 2022-04-14 00:10:29 +02:00
Felix Roos 3f550cc6ce Merge remote-tracking branch 'origin/main' into dirtify-plain-values 2022-04-14 00:05:06 +02:00
Felix Roos 727fc2c049 fix notes inside object 2022-04-13 19:19:30 +02:00
Felix Roos c0f006eef1 objectify in osc 2022-04-13 19:01:46 +02:00
Felix Roos adb13cc458 add .superdirt 2022-04-13 18:58:47 +02:00
Felix Roos 1ab3c16045 add dirtify + objectify 2022-04-13 18:58:38 +02:00
4 changed files with 80 additions and 4 deletions
+5 -1
View File
@@ -10,7 +10,7 @@ import Hap from './hap.mjs';
import State from './state.mjs';
import { unionWithObj } from './value.mjs';
import { isNote, toMidi, compose, removeUndefineds, flatten, id, listRange, curry, mod } from './util.mjs';
import { isNote, toMidi, compose, removeUndefineds, flatten, id, listRange, curry, mod, objectify } from './util.mjs';
import drawLine from './drawLine.mjs';
/** @class Class representing a pattern. */
@@ -546,6 +546,10 @@ export class Pattern {
return this._fromBipolar().range(min, max);
}
union(other) {
return this._opleft(other, (a) => (b) => Object.assign({}, objectify(a), objectify(b)));
}
_bindWhole(choose_whole, func) {
const pat_val = this;
const query = function (state) {
+29 -1
View File
@@ -6,7 +6,7 @@ This program is free software: you can redistribute it and/or modify it under th
import { strict as assert } from 'assert';
import { pure } from '../pattern.mjs';
import { isNote, tokenizeNote, toMidi, fromMidi, mod, compose, getFrequency } from '../util.mjs';
import { isNote, tokenizeNote, toMidi, fromMidi, mod, compose, getFrequency, dirtify } from '../util.mjs';
describe('isNote', () => {
it('should recognize notes without accidentals', () => {
@@ -118,3 +118,31 @@ describe('compose', () => {
assert.equal(compose(addS('a'), addS('b'))('x'), 'xab');
});
});
describe('dirtify', () => {
it('should offset plain number', () => {
assert.deepStrictEqual(dirtify(61), { n: 1 });
assert.deepStrictEqual(dirtify(60), { n: 0 });
});
it('should parse note string as midi number', () => {
assert.deepStrictEqual(dirtify('c4'), { n: 0 });
assert.deepStrictEqual(dirtify('c5'), { n: 12 });
});
it('should use non note string as sound', () => {
assert.deepStrictEqual(dirtify('bd'), { s: 'bd' });
});
it('should keep objects as is', () => {
assert.deepStrictEqual(dirtify({ s: 'bd' }), { s: 'bd' });
assert.deepStrictEqual(dirtify({ n: 7 }), { n: 7 });
assert.deepStrictEqual(dirtify({ n: 7, room: 0.5 }), { n: 7, room: 0.5 });
});
it('should parse notes inside object', () => {
assert.deepStrictEqual(dirtify({ n: 'c3', s: 'supersaw' }), { n: -12, s: 'supersaw' });
});
it('should dirtify .value', () => {
assert.deepStrictEqual(dirtify({ value: 61 }), { n: 1 });
assert.deepStrictEqual(dirtify({ value: 'c5' }), { n: 12 });
assert.deepStrictEqual(dirtify({ value: 'bd' }), { s: 'bd' });
assert.deepStrictEqual(dirtify({ value: 61, room: 0.5 }), { n: 1, room: 0.5 });
});
});
+40
View File
@@ -119,3 +119,43 @@ export function curry(func, overload) {
}
return fn;
}
// this functions just makes sure non objects values are wrapped in { value }
export function objectify(value) {
if (typeof value === 'object' && !Array.isArray(value)) {
return value; // do nothing if its already an object
}
return { value };
}
// maybe move this to osc?
// turns value into object that is the right format superdirt osc
export function dirtify(val) {
const obj = objectify(val);
if (obj.n && typeof obj.n === 'string') {
return { ...obj, ...dirtify(obj.n) };
}
const { value, ...rest } = obj;
if (typeof value === 'undefined') {
return rest;
}
const isNumber = typeof value === 'number';
const isMidi = typeof value === 'string' && isNote(value);
if (isNumber || isMidi) {
const numberOffset = -60; // tidal 0 = midi 60
const n = (isNumber ? value : toMidi(value)) + numberOffset;
if (rest.n) {
console.warn(`dirtify: n is already defined as "${rest.n}", overwriting with value "${n}"`);
}
return { ...rest, n };
}
if (typeof value === 'string') {
// not a note => should be a sound
return { ...rest, s: value };
}
console.warn(`dirtify: ignored value "${value}"`);
// what lands here?
// throw new Error('cannot objectify: ' + value);
return {};
}
+6 -2
View File
@@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
*/
import OSC from 'osc-js';
import { Pattern } from '@strudel.cycles/core';
import { Pattern, objectify } from '@strudel.cycles/core';
const comm = new OSC();
comm.open();
@@ -30,7 +30,7 @@ Pattern.prototype.osc = function () {
if (startedAt < 0) {
startedAt = Date.now() - currentTime * 1000;
}
const controls = Object.assign({}, { cps, cycle, delta }, hap.value);
const controls = Object.assign({}, { cps, cycle, delta }, objectify(hap.value));
const keyvals = Object.entries(controls).flat();
const ts = Math.floor(startedAt + (time + latency) * 1000);
const message = new OSC.Message('/dirt/play', ...keyvals);
@@ -41,3 +41,7 @@ Pattern.prototype.osc = function () {
return hap.setContext({ ...hap.context, onTrigger });
});
};
Pattern.prototype.superdirt = function () {
return this.withValue(dirtify).osc();
};