mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-31 00:34:25 -04:00
Merge pull request #1357 from tidalcycles/bbfixes_2
Byte Beat improvements -> 2
This commit is contained in:
@@ -451,13 +451,26 @@ export const { drive } = registerControl('drive');
|
||||
* @name byteBeatExpression
|
||||
* @synonyms bbexpr
|
||||
*
|
||||
* @param {number | Pattern} byteBeatExpression pattern the output channels
|
||||
* @param {number | Pattern} byteBeatExpression bitwise expression for creating bytebeat
|
||||
* @example
|
||||
* s("bytebeat").bbexpr('t*(t>>15^t>>66)')
|
||||
*
|
||||
*/
|
||||
export const { byteBeatExpression, bbexpr } = registerControl('byteBeatExpression', 'bbexpr');
|
||||
|
||||
/**
|
||||
* Create byte beats with custom expressions
|
||||
*
|
||||
* @name byteBeatStartTime
|
||||
* @synonyms bbst
|
||||
*
|
||||
* @param {number | Pattern} byteBeatStartTime in seconds
|
||||
* @example
|
||||
* note("{c g a b c d}%16").s("bytebeat").bbexpr('t&t>>8').bbst("<0 300>")
|
||||
*
|
||||
*/
|
||||
export const { byteBeatStartTime, bbst } = registerControl('byteBeatStartTime', 'bbst');
|
||||
|
||||
/**
|
||||
* Allows you to set the output channels on the interface
|
||||
*
|
||||
|
||||
@@ -476,7 +476,6 @@ export const superdough = async (value, t, hapDuration, cps) => {
|
||||
let {
|
||||
s = getDefaultValue('s'),
|
||||
bank,
|
||||
byteBeatExpression,
|
||||
source,
|
||||
gain = getDefaultValue('gain'),
|
||||
postgain = getDefaultValue('postgain'),
|
||||
|
||||
@@ -165,7 +165,9 @@ export function registerSynthSounds() {
|
||||
'((t^t/2+t+64)%7 * 24)',
|
||||
];
|
||||
const { n = 0 } = value;
|
||||
const { byteBeatExpression = defaultBeats[n % defaultBeats.length] } = value;
|
||||
const frequency = getFrequencyFromValue(value);
|
||||
const { byteBeatExpression = defaultBeats[n % defaultBeats.length], byteBeatStartTime } = value;
|
||||
|
||||
const ac = getAudioContext();
|
||||
|
||||
let { duration } = value;
|
||||
@@ -176,7 +178,6 @@ export function registerSynthSounds() {
|
||||
);
|
||||
const holdend = begin + duration;
|
||||
const end = holdend + release + 0.01;
|
||||
const frequency = getFrequencyFromValue(value);
|
||||
|
||||
let o = getWorklet(
|
||||
ac,
|
||||
@@ -191,7 +192,7 @@ export function registerSynthSounds() {
|
||||
},
|
||||
);
|
||||
|
||||
o.port.postMessage(byteBeatExpression);
|
||||
o.port.postMessage({ codeText: byteBeatExpression, startTimeSeconds: byteBeatStartTime, frequency });
|
||||
|
||||
let envGain = gainNode(1);
|
||||
envGain = o.connect(envGain);
|
||||
|
||||
@@ -762,59 +762,72 @@ class PulseOscillatorProcessor extends AudioWorkletProcessor {
|
||||
|
||||
registerProcessor('pulse-oscillator', PulseOscillatorProcessor);
|
||||
|
||||
/** BYTE BEATS */
|
||||
const chyx = {
|
||||
/*bit*/ bitC: function (x, y, z) {
|
||||
return x & y ? z : 0;
|
||||
},
|
||||
/*bit reverse*/ br: function (x, size = 8) {
|
||||
if (size > 32) {
|
||||
throw new Error('br() Size cannot be greater than 32');
|
||||
} else {
|
||||
let result = 0;
|
||||
for (let idx = 0; idx < size - 0; idx++) {
|
||||
result += chyx.bitC(x, 2 ** idx, 2 ** (size - (idx + 1)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
/*sin that loops every 128 "steps", instead of every pi steps*/ sinf: function (x) {
|
||||
return Math.sin(x / (128 / Math.PI));
|
||||
},
|
||||
/*cos that loops every 128 "steps", instead of every pi steps*/ cosf: function (x) {
|
||||
return Math.cos(x / (128 / Math.PI));
|
||||
},
|
||||
/*tan that loops every 128 "steps", instead of every pi steps*/ tanf: function (x) {
|
||||
return Math.tan(x / (128 / Math.PI));
|
||||
},
|
||||
/*converts t into a string composed of it's bits, regex's that*/ regG: function (t, X) {
|
||||
return X.test(t.toString(2));
|
||||
},
|
||||
};
|
||||
|
||||
// Create shortened Math functions
|
||||
let mathParams, byteBeatHelperFuncs;
|
||||
function getByteBeatFunc(codetext) {
|
||||
if ((mathParams || byteBeatHelperFuncs) == null) {
|
||||
mathParams = Object.getOwnPropertyNames(Math);
|
||||
byteBeatHelperFuncs = mathParams.map((k) => Math[k]);
|
||||
const chyxNames = Object.getOwnPropertyNames(chyx);
|
||||
const chyxFuncs = chyxNames.map((k) => chyx[k]);
|
||||
mathParams.push('int', 'window', ...chyxNames);
|
||||
byteBeatHelperFuncs.push(Math.floor, globalThis, ...chyxFuncs);
|
||||
}
|
||||
return new Function(...mathParams, 't', `return 0,\n${codetext || 0};`).bind(globalThis, ...byteBeatHelperFuncs);
|
||||
}
|
||||
|
||||
class ByteBeatProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
this.codeText = '0';
|
||||
this.port.onmessage = (event) => {
|
||||
const chyx = {
|
||||
/*bit*/ bitC: function (x, y, z) {
|
||||
return x & y ? z : 0;
|
||||
},
|
||||
/*bit reverse*/ br: function (x, size = 8) {
|
||||
if (size > 32) {
|
||||
throw new Error('br() Size cannot be greater than 32');
|
||||
} else {
|
||||
let result = 0;
|
||||
for (let idx = 0; idx < size - 0; idx++) {
|
||||
result += chyx.bitC(x, 2 ** idx, 2 ** (size - (idx + 1)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
/*sin that loops every 128 "steps", instead of every pi steps*/ sinf: function (x) {
|
||||
return Math.sin(x / (128 / Math.PI));
|
||||
},
|
||||
/*cos that loops every 128 "steps", instead of every pi steps*/ cosf: function (x) {
|
||||
return Math.cos(x / (128 / Math.PI));
|
||||
},
|
||||
/*tan that loops every 128 "steps", instead of every pi steps*/ tanf: function (x) {
|
||||
return Math.tan(x / (128 / Math.PI));
|
||||
},
|
||||
/*converts t into a string composed of it's bits, regex's that*/ regG: function (t, X) {
|
||||
return X.test(t.toString(2));
|
||||
},
|
||||
/*corrupt sound"crpt": function(x,y=8) {return chyx.br(chyx.br(x,y)+t,y)^chyx.br(t,y)},
|
||||
decorrupt sound"decrpt": function(x,y=8) {return chyx.br(chyx.br(x^chyx.br(t,y),y)-t,y)},*/
|
||||
};
|
||||
// Create shortened Math functions
|
||||
const mathParams = Object.getOwnPropertyNames(Math);
|
||||
const values = mathParams.map((k) => Math[k]);
|
||||
const chyxNames = Object.getOwnPropertyNames(chyx);
|
||||
const chyxFuncs = chyxNames.map((k) => chyx[k]);
|
||||
mathParams.push('int', 'window', ...chyxNames);
|
||||
values.push(Math.floor, globalThis, ...chyxFuncs);
|
||||
let { codeText } = event.data;
|
||||
const { startTimeSeconds, frequency } = event.data;
|
||||
if (startTimeSeconds != null) {
|
||||
const t = startTimeSeconds * sampleRate;
|
||||
this.t = t;
|
||||
this.t = (t / (sampleRate / 256)) * frequency;
|
||||
}
|
||||
|
||||
//Optimization pulled from dollchan.net, it seemed important
|
||||
//Optimization pulled from dollchan.net: https://github.com/Chasyxx/EnBeat_NEW, it seemed important
|
||||
//Optimize code like eval(unescape(escape`XXXX`.replace(/u(..)/g,"$1%")))
|
||||
this.codeText = event.data
|
||||
codeText = codeText
|
||||
.trim()
|
||||
.replace(
|
||||
/^eval\(unescape\(escape(?:`|\('|\("|\(`)(.*?)(?:`|'\)|"\)|`\)).replace\(\/u\(\.\.\)\/g,["'`]\$1%["'`]\)\)\)$/,
|
||||
(match, m1) => unescape(escape(m1).replace(/u(..)/g, '$1%')),
|
||||
);
|
||||
|
||||
this.func = new Function(...mathParams, 't', `return 0,\n${this.codeText || 0};`).bind(globalThis, ...values);
|
||||
this.func = getByteBeatFunc(codeText);
|
||||
};
|
||||
this.t = null;
|
||||
this.func = null;
|
||||
@@ -861,23 +874,17 @@ class ByteBeatProcessor extends AudioWorkletProcessor {
|
||||
if (this.t == null) {
|
||||
this.t = params.begin[0] * sampleRate;
|
||||
}
|
||||
|
||||
let codeText = this.codeText;
|
||||
// this.func = Function('t', 'return ' + codeText);
|
||||
const output = outputs[0];
|
||||
|
||||
for (let i = 0; i < output[0].length; i++) {
|
||||
let t = Math.floor(this.t);
|
||||
const detune = getParamValue(i, params.detune);
|
||||
const freq = applySemitoneDetuneToFrequency(getParamValue(i, params.frequency), detune / 100);
|
||||
|
||||
t = (t / (sampleRate / 256)) * freq;
|
||||
|
||||
let t = (this.t / (sampleRate / 256)) * freq;
|
||||
const funcValue = this.func(t);
|
||||
let signal = (funcValue & 255) / 127.5 - 1;
|
||||
const out = signal * 0.2;
|
||||
|
||||
for (let c = 0; c < output.length; c++) {
|
||||
output[c][i] = out;
|
||||
output[c][i] = clamp(out, -0.2, 0.2);
|
||||
}
|
||||
this.t = this.t + 1;
|
||||
}
|
||||
|
||||
@@ -1525,6 +1525,75 @@ exports[`runs examples > example "byteBeatExpression" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "byteBeatStartTime" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 1/16 → 1/8 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 1/8 → 3/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 3/16 → 1/4 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 1/4 → 5/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 5/16 → 3/8 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 3/8 → 7/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 7/16 → 1/2 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 1/2 → 9/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 9/16 → 5/8 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 5/8 → 11/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 11/16 → 3/4 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 3/4 → 13/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 13/16 → 7/8 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 7/8 → 15/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 15/16 → 1/1 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 1/1 → 17/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 17/16 → 9/8 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 9/8 → 19/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 19/16 → 5/4 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 5/4 → 21/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 21/16 → 11/8 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 11/8 → 23/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 23/16 → 3/2 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 3/2 → 25/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 25/16 → 13/8 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 13/8 → 27/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 27/16 → 7/4 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 7/4 → 29/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 29/16 → 15/8 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 15/8 → 31/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 31/16 → 2/1 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 2/1 → 33/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 33/16 → 17/8 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 17/8 → 35/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 35/16 → 9/4 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 9/4 → 37/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 37/16 → 19/8 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 19/8 → 39/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 39/16 → 5/2 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 5/2 → 41/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 41/16 → 21/8 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 21/8 → 43/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 43/16 → 11/4 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 11/4 → 45/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 45/16 → 23/8 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 23/8 → 47/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 47/16 → 3/1 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:0 ]",
|
||||
"[ 3/1 → 49/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 49/16 → 25/8 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 25/8 → 51/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 51/16 → 13/4 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 13/4 → 53/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 53/16 → 27/8 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 27/8 → 55/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 55/16 → 7/2 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 7/2 → 57/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 57/16 → 29/8 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 29/8 → 59/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 59/16 → 15/4 | note:d s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 15/4 → 61/16 | note:c s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 61/16 → 31/8 | note:g s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 31/8 → 63/16 | note:a s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
"[ 63/16 → 4/1 | note:b s:bytebeat byteBeatExpression:t&t>>8 byteBeatStartTime:300 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "cat" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/1 | note:e5 ]",
|
||||
|
||||
Reference in New Issue
Block a user