This commit is contained in:
Jade (Rose) Rowland
2025-05-29 02:27:55 +02:00
parent 6a83ede33d
commit 0287be547a
4 changed files with 75 additions and 55 deletions
+14 -1
View File
@@ -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
*
-1
View File
@@ -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'),
+4 -3
View File
@@ -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);
+57 -50
View File
@@ -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;
}