ensoniq-buddy/js/application.js

774 lines
22 KiB
JavaScript

// src/utils.js
function calc_sr(osc) {
return 28636360 / 32 / (osc + 2);
}
function calc_shift(res, ws) {
return res + 9 - ws;
}
function log2(x) {
var y = Math.log2(x);
return y >> 0 === y ? y : false;
}
// src/note_input.jsx
var _notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
function split_value(value) {
return [value % 12, value / 12 >> 0];
}
function NoteFrequency(value) {
var [note, octave] = split_value(value);
var n = (note + 3) % 12;
if (n >= 3)
octave -= 1;
var base = 27.5 * 2 ** octave;
return base * 2 ** (n / 12);
}
var NoteInput = class extends preact.Component {
constructor(props) {
super(props);
this._noteChange = this.noteChange.bind(this);
this._octaveChange = this.octaveChange.bind(this);
}
noteChange(e) {
e.preventDefault();
var [note, octave] = split_value(this.props.value);
note = +e.target.value;
this.change(note, octave);
}
octaveChange(e) {
e.preventDefault();
var [note, octave] = split_value(this.props.value);
octave = +e.target.value;
this.change(note, octave);
}
change(note, octave) {
var { onChange } = this.props;
if (onChange) {
var value = note + 12 * octave;
onChange(value);
}
}
render() {
var { onChange, value, disabled } = this.props;
var notes = _notes.map((x, ix) => {
return /* @__PURE__ */ preact.h("option", {
key: ix,
value: ix
}, x);
});
var octaves = [];
for (var i = 0; i < 9; ++i) {
octaves.push(
/* @__PURE__ */ preact.h("option", {
key: i,
value: i
}, i)
);
}
var [note, octave] = split_value(value);
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("select", {
onChange: this._noteChange,
value: note,
disabled
}, notes), " ", /* @__PURE__ */ preact.h("select", {
onChange: this._octaveChange,
value: octave,
disabled
}, octaves), " ", NoteFrequency(value).toFixed(2), " Hz");
}
};
// src/wave_data.jsx
function mod(a, b) {
return (a % b + b) % b;
}
function sine() {
const a = 127;
const p = 256;
var rv = [];
for (var n = 0; n < 256; ++n) {
var x = 128 + Math.round(a * Math.sin(n * Math.PI / 128));
rv.push(x || 1);
}
return rv;
}
function square() {
var rv = [];
for (var n = 0; n < 128; ++n)
rv.push(255);
for (var n = 0; n < 128; ++n)
rv.push(1);
return rv;
}
function triangle() {
var rv = [];
const a = 127;
const p = 256;
for (var n = 0; n < 256; ++n) {
var x = 128 + Math.round(4 * a / p * Math.abs(mod(n - p / 4, p) - p / 2)) - a;
rv.push(x || 1);
}
return rv;
}
function sawtooth() {
var rv = [];
const a = 127;
const p = 256;
for (var n = 0; n < 256; ++n) {
var x = 128 + Math.round(a * 2 * (n / p - Math.floor(0.5 + n / p)));
rv.push(x || 1);
}
return rv;
}
function WaveData(props) {
var { assembler, shape } = props;
var data;
switch (shape) {
case 0:
data = sine();
break;
case 1:
data = square();
break;
case 2:
data = triangle();
break;
case 3:
data = sawtooth();
break;
}
var hex = data.map((x) => x < 16 ? "0" + x.toString(16) : x.toString(16));
var code = [];
if (assembler == 0) {
for (var n = 0; n < 16; ++n) {
var line = " hex " + hex.slice(n * 16, n * 16 + 16).join("") + "\n";
code.push(line);
}
}
if (assembler == 1) {
for (var n = 0; n < 16; ++n) {
var line = " dc h'" + hex.slice(n * 16, n * 16 + 16).join("") + "'\n";
code.push(line);
}
}
if (assembler == 2) {
for (var n = 0; n < 32; ++n) {
var line = " dc.b $" + hex.slice(n * 8, n * 8 + 8).join(",$") + "\n";
code.push(line);
}
}
return /* @__PURE__ */ preact.h("code", null, /* @__PURE__ */ preact.h("pre", null, code));
}
// src/input.jsx
var _onames = [];
function Oscillators(props) {
if (!_onames.length) {
for (var i = 1; i < 33; ++i) {
var x = (calc_sr(i) / 1e3).toFixed(2) + " kHz";
_onames.push(x);
}
}
var options = _onames.map((x2, ix) => {
var i2 = ix + 1;
return /* @__PURE__ */ preact.h("option", {
value: i2,
key: i2
}, i2, " \u2013 ", x2);
});
return /* @__PURE__ */ preact.h("select", {
...props
}, options);
}
function WaveSize(props) {
var options = [];
for (var i = 8; i < 16; ++i) {
var ext = 1 << i;
var int = i - 8;
options.push(/* @__PURE__ */ preact.h("option", {
value: int,
key: int
}, ext));
}
return /* @__PURE__ */ preact.h("select", {
value: props.value,
onChange: props.onChange
}, options);
}
function Resolution(props) {
var options = [];
for (var i = 0; i < 8; ++i) {
options.push(/* @__PURE__ */ preact.h("option", {
value: i,
key: i
}, i));
}
return /* @__PURE__ */ preact.h("select", {
value: props.value,
onChange: props.onChange
}, options);
}
function Frequency(props) {
return /* @__PURE__ */ preact.h("input", {
type: "number",
min: "0",
max: "65535",
value: props.value,
onChange: props.onChange
});
}
function Assembler(props) {
var options = ["Merlin", "ORCA/M", "MPW"].map((o, ix) => {
return /* @__PURE__ */ preact.h("option", {
key: ix,
value: ix
}, o);
});
return /* @__PURE__ */ preact.h("select", {
...props
}, options);
}
function WaveShape(props) {
var options = ["Sine", "Square", "Triangle", "Sawtooth"].map((o, ix) => {
return /* @__PURE__ */ preact.h("option", {
key: ix,
value: ix
}, o);
});
return /* @__PURE__ */ preact.h("select", {
...props
}, options);
}
function CheckBox(props) {
return /* @__PURE__ */ preact.h("input", {
type: "checkbox",
...props
});
}
// src/duration_input.jsx
function split_value2(x) {
if (x === void 0 || x === null)
return ["", 0];
if (typeof x == "number")
return [x, 0];
var xx = x.split(":");
if (xx.length == 2)
return xx;
if (xx.length == 1)
return [x, 0];
return ["", 0];
}
function DurationToSeconds(x) {
let [time, unit] = split_value2(x);
switch (+unit) {
case 0:
return +time;
case 1:
return +time / 1e3;
case 2:
return +time / 60;
default:
return 0;
}
}
function DurationSplit(x) {
let [time, unit] = split_value2(x);
switch (+unit) {
case 0:
return [+time, "s"];
case 1:
return [+time / 1e3, "ms"];
case 2:
return [+time / 60, "ticks"];
default:
return [0, ""];
}
}
var DurationInput = class extends preact.Component {
constructor(props) {
super(props);
this._amtChange = this.amtChange.bind(this);
this._unitChange = this.unitChange.bind(this);
}
amtChange(e) {
e.preventDefault();
let { value } = this.props;
var [time, unit] = split_value2(value);
var new_time = e.target.value.replace(/^\s+|\s+$/g, "");
var n = Number(new_time);
if (Number.isNaN(n)) {
e.target.value = time;
return;
}
this.change(new_time, unit);
}
unitChange(e) {
e.preventDefault();
let { value } = this.props;
var [time, unit] = split_value2(value);
var new_unit = +e.target.value;
let s = DurationToSeconds(value);
if (new_unit == unit)
return;
var new_time = 0;
switch (new_unit) {
case 0:
new_time = s;
break;
case 1:
new_time = s * 1e3;
break;
case 2:
new_time = s * 60;
break;
}
this.change(new_time, new_unit);
}
change(time, unit) {
let { onChange } = this.props;
if (onChange) {
onChange(time + ":" + unit);
}
}
render() {
var { value, disabled } = this.props;
var [amt, unit] = split_value2(value);
var options = ["Seconds", "Milliseconds", "Ticks"].map((x, ix) => {
return /* @__PURE__ */ preact.h("option", {
key: ix,
value: ix
}, x);
});
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("input", {
type: "text",
value: amt,
disabled,
onChange: this._amtChange
}), " ", /* @__PURE__ */ preact.h("select", {
value: unit,
disabled,
onChange: this._unitChange
}, options));
}
};
// src/application.jsx
var C4 = 4 * 12;
function nmultiply(x) {
if (x == 0)
return 0;
if (x == 1)
return /* @__PURE__ */ preact.h("i", null, "n");
return /* @__PURE__ */ preact.h(preact.Fragment, null, x, " * ", /* @__PURE__ */ preact.h("i", null, "n"));
}
function simplify(res, freq) {
while (res && !(freq & 1)) {
freq >>= 1;
--res;
}
return [res, freq];
}
function SampleDisplay(props) {
var { shift, freq } = props;
if (freq == 0)
return [];
var freq2 = log2(freq);
var fspan = /* @__PURE__ */ preact.h("span", {
title: "Frequency"
}, freq);
var fspann = freq == 1 ? /* @__PURE__ */ preact.h("i", null, "n") : /* @__PURE__ */ preact.h(preact.Fragment, null, "(", fspan, " * ", /* @__PURE__ */ preact.h("i", null, "n"), ")");
var rv = [];
rv.push(
/* @__PURE__ */ preact.h("div", null, "Sample", /* @__PURE__ */ preact.h("sub", null, "n"), " = RAM[ ", fspann, " >> ", shift, " ]")
);
rv.push(
/* @__PURE__ */ preact.h("div", null, "Sample", /* @__PURE__ */ preact.h("sub", null, "n"), " = RAM[ ", fspann, " / ", 1 << shift, " ]")
);
if (freq2) {
if (freq2 >= shift) {
rv.push(
/* @__PURE__ */ preact.h("div", null, "Sample", /* @__PURE__ */ preact.h("sub", null, "n"), " = RAM[ ", nmultiply(freq / (1 << shift)), " ]")
);
} else {
rv.push(
/* @__PURE__ */ preact.h("div", null, "Sample", /* @__PURE__ */ preact.h("sub", null, "n"), " = RAM[ ", nmultiply(freq >> freq2), " >> ", shift - freq2, " ]")
);
rv.push(
/* @__PURE__ */ preact.h("div", null, "Sample", /* @__PURE__ */ preact.h("sub", null, "n"), " = RAM[ ", nmultiply(freq >> freq2), " / ", 1 << shift - freq2, " ]")
);
}
}
return rv;
}
function NoteDisplay(props) {
const { osc, note } = props;
return PitchDisplay({ osc, pitch: NoteFrequency(note) });
}
function PitchDisplay(props) {
var { osc, pitch } = props;
const wave = 0;
const sr = calc_sr(osc);
const f = pitch / (sr / (1 << 8 + wave));
var best_res = 0;
var best_freq = 0;
for (var res = 0; res < 8; ++res) {
const shift = 1 << calc_shift(res, wave);
const tmp = Math.round(f * shift);
if (tmp >= 65536)
break;
best_res = res;
best_freq = tmp;
}
[best_res, best_freq] = simplify(best_res, best_freq);
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h(RateDisplay, {
wave: 0,
osc,
freq: best_freq,
res: best_res
}), /* @__PURE__ */ preact.h("div", null, "Wave Size: 256"), /* @__PURE__ */ preact.h("div", null, "Resolution: ", best_res), /* @__PURE__ */ preact.h("div", null, "Frequency: ", best_freq));
}
function RateDisplay(props) {
const { osc, wave, freq, res } = props;
const sr = calc_sr(osc);
const shift = 1 << calc_shift(res, wave);
const size = 256 << wave;
const rate = sr / (size * shift / freq);
return /* @__PURE__ */ preact.h("div", null, "Rate: ", rate.toFixed(2), " Hz");
}
function ResampleDisplay(props) {
var { osc, size, freq } = props;
const sr = calc_sr(osc);
const f = freq / sr;
var best_res = 0;
var best_freq = 0;
for (var res = 0; res < 8; ++res) {
var tmp = Math.round(f * (1 << calc_shift(res, size)));
if (tmp >= 65536)
break;
best_res = res;
best_freq = tmp;
}
[best_res, best_freq] = simplify(best_res, best_freq);
var best_shift = calc_shift(best_res, size);
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, "Resolution: ", best_res), /* @__PURE__ */ preact.h("div", null, "Frequency: ", best_freq), /* @__PURE__ */ preact.h(SampleDisplay, {
freq: best_freq,
shift: best_shift
}));
}
function HyperDisplay(props) {
var { pitch, freq } = props;
const r = freq * 261.63 / (26320 * pitch);
const offset = Math.round(3072 * Math.log2(r));
const relative = offset < 0 ? -offset + 32768 : offset;
return /* @__PURE__ */ preact.h("div", null, "Relative: ", relative);
}
function TimerDisplay(props) {
var { osc, duration } = props;
const [time, units] = DurationSplit(duration);
const sr = calc_sr(osc);
const cycles = time * sr;
const size = 0;
var best_res = 0;
var best_freq = 0;
var actual = 0;
best = [];
for (var res = 0; res < 8; ++res) {
var shift = 1 << calc_shift(res, size);
var f = Math.round(shift * 256 / cycles);
if (f >= 65536)
continue;
actual = Math.ceil(256 * shift / f);
best_res = res;
best_freq = f;
}
[best_res, best_freq] = simplify(best_res, best_freq);
var best_shift = calc_shift(best_res, size);
switch (units) {
case "s":
break;
case "ms":
actual *= 1e3;
break;
case "ticks":
actual *= 60;
break;
}
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, "Time: ", actual ? (actual / sr).toFixed(2) + " " + units : "N/A"), /* @__PURE__ */ preact.h("div", null, "Resolution: ", best_res ? best_res : "N/A"), /* @__PURE__ */ preact.h("div", null, "Frequency: ", best_freq ? best_freq : "N/A"), /* @__PURE__ */ preact.h(SampleDisplay, {
freq: best_freq,
shift: best_shift
}));
}
var Application = class extends preact.Component {
constructor(props) {
super(props);
this._oscChange = this.oscChange.bind(this);
this._waveChange = this.waveChange.bind(this);
this._resChange = this.resChange.bind(this);
this._freqChange = this.freqChange.bind(this);
this._noteChange = this.noteChange.bind(this);
this._pitchChange = this.pitchChange.bind(this);
this._durationChange = this.durationChange.bind(this);
this._tabChange = this.tabChange.bind(this);
this._asmChange = this.asmChange.bind(this);
this._shapeChange = this.shapeChange.bind(this);
this._inFreqChange = this.inFreqChange.bind(this);
this._inSizeChange = this.inSizeChange.bind(this);
this._indeterminateChange = this.indeterminateChange.bind(this);
this.state = {
osc: 32,
wave: 0,
res: 0,
freq: 512,
tab: 0,
note: C4,
assembler: 0,
shape: 0,
in_freq: 44100,
in_size: 0,
indeterminate: false,
pitch: 440
};
}
oscChange(e) {
e.preventDefault();
var v = +e.target.value || 0;
this.setState({ osc: v });
}
waveChange(e) {
e.preventDefault();
var v = +e.target.value || 0;
this.setState({ wave: v });
}
resChange(e) {
e.preventDefault();
var v = +e.target.value || 0;
this.setState({ res: v });
}
pitchChange(e) {
e.preventDefault();
var v = +e.target.value;
if (v < 0)
v = 0;
if (v > 65535)
v = 65535;
this.setState({ pitch: v });
}
freqChange(e) {
e.preventDefault();
var v = +e.target.value >> 0;
if (v < 0)
v = 0;
if (v > 65535)
v = 65535;
this.setState({ freq: v });
}
inFreqChange(e) {
e.preventDefault();
var v = +e.target.value >> 0;
if (v < 0)
v = 0;
if (v > 65535)
v = 65535;
this.setState({ in_freq: v });
}
inSizeChange(e) {
e.preventDefault();
var v = +e.target.value || 0;
this.setState({ in_size: v });
}
tabChange(e) {
e.preventDefault();
var v = +e.target.value;
this.setState({ tab: v });
}
noteChange(v) {
this.setState({ note: v });
}
durationChange(v) {
this.setState({ duration: v });
}
asmChange(e) {
e.preventDefault();
var v = +e.target.value;
this.setState({ assembler: v });
}
shapeChange(e) {
e.preventDefault();
var v = +e.target.value;
this.setState({ shape: v });
}
indeterminateChange(e) {
e.preventDefault();
var v = !!e.target.checked;
this.setState({ indeterminate: v });
}
sampleChildren() {
var { osc, wave, res, freq } = this.state;
var shift = calc_shift(res, wave);
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Oscillators"), " ", /* @__PURE__ */ preact.h(Oscillators, {
value: osc,
onChange: this._oscChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Wave Size"), " ", /* @__PURE__ */ preact.h(WaveSize, {
value: wave,
onChange: this._waveChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Resolution"), " ", /* @__PURE__ */ preact.h(Resolution, {
value: res,
onChange: this._resChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Frequency"), " ", /* @__PURE__ */ preact.h(Frequency, {
value: freq,
onChange: this._freqChange
})), /* @__PURE__ */ preact.h(RateDisplay, {
wave,
osc,
freq,
shift,
res
}), /* @__PURE__ */ preact.h(SampleDisplay, {
freq,
shift
}));
}
noteChildren() {
var { osc, wave, note } = this.state;
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Oscillators"), " ", /* @__PURE__ */ preact.h(Oscillators, {
value: osc,
onChange: this._oscChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Note"), " ", /* @__PURE__ */ preact.h(NoteInput, {
value: note,
onChange: this._noteChange
})), /* @__PURE__ */ preact.h(NoteDisplay, {
osc,
note,
wave
}));
}
pitchChildren() {
var { osc, wave, pitch } = this.state;
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Oscillators"), " ", /* @__PURE__ */ preact.h(Oscillators, {
value: osc,
onChange: this._oscChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Pitch"), " ", /* @__PURE__ */ preact.h(Frequency, {
value: pitch,
onChange: this._pitchChange
}), " Hz"), /* @__PURE__ */ preact.h(PitchDisplay, {
osc,
pitch,
wave
}));
}
waveChildren() {
var { assembler, shape } = this.state;
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Assembler"), " ", /* @__PURE__ */ preact.h(Assembler, {
value: assembler,
onChange: this._asmChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Wave Type"), " ", /* @__PURE__ */ preact.h(WaveShape, {
value: shape,
onChange: this._shapeChange
})), /* @__PURE__ */ preact.h(WaveData, {
assembler,
shape
}));
}
resampleChildren() {
var { osc, in_freq, in_size } = this.state;
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Oscillators"), " ", /* @__PURE__ */ preact.h(Oscillators, {
value: osc,
onChange: this._oscChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "In Frequency"), " ", /* @__PURE__ */ preact.h(Frequency, {
value: in_freq,
onChange: this._inFreqChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "In Size"), " ", /* @__PURE__ */ preact.h(WaveSize, {
value: in_size,
onChange: this._inSizeChange
})), /* @__PURE__ */ preact.h(ResampleDisplay, {
osc,
size: in_size,
freq: in_freq
}));
}
timerChildren() {
var { osc, duration } = this.state;
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Oscillators"), " ", /* @__PURE__ */ preact.h(Oscillators, {
value: osc,
onChange: this._oscChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Duration"), " ", /* @__PURE__ */ preact.h(DurationInput, {
value: duration,
onChange: this._durationChange
})), /* @__PURE__ */ preact.h(TimerDisplay, {
osc,
duration
}));
}
hyperChildren() {
var { in_freq, note, indeterminate } = this.state;
if (indeterminate)
note = C4;
return /* @__PURE__ */ preact.h(preact.Fragment, null, /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Oscillators"), " ", /* @__PURE__ */ preact.h(Oscillators, {
value: 32,
disabled: true
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "In Frequency"), " ", /* @__PURE__ */ preact.h(Frequency, {
value: in_freq,
onChange: this._inFreqChange
})), /* @__PURE__ */ preact.h("div", null, /* @__PURE__ */ preact.h("label", null, "Indeterminate"), /* @__PURE__ */ preact.h(CheckBox, {
checked: indeterminate,
onChange: this._indeterminateChange
})), /* @__PURE__ */ preact.h("div", {
style: indeterminate ? { display: "none" } : ""
}, /* @__PURE__ */ preact.h("label", null, "Pitch"), " ", /* @__PURE__ */ preact.h(NoteInput, {
value: note,
onChange: this._noteChange,
disabled: indeterminate
})), /* @__PURE__ */ preact.h(HyperDisplay, {
freq: in_freq,
pitch: NoteFrequency(note)
}));
}
render() {
var { osc, wave, res, freq, tab } = this.state;
var children;
switch (tab) {
case 0:
children = this.sampleChildren();
break;
case 1:
children = this.resampleChildren();
break;
case 2:
children = this.noteChildren();
break;
case 3:
children = this.pitchChildren();
break;
case 4:
children = this.waveChildren();
break;
case 5:
children = this.timerChildren();
break;
case 6:
children = this.hyperChildren();
break;
}
const Labels = ["Sample", "Resample", "Note", "Pitch", "Wave", "Timer", "HyperCard Pitch"];
var options = Labels.map((o, ix) => {
return /* @__PURE__ */ preact.h("option", {
key: ix,
value: ix
}, o);
});
return /* @__PURE__ */ preact.h("fieldset", null, /* @__PURE__ */ preact.h("legend", null, /* @__PURE__ */ preact.h("select", {
value: tab,
onChange: this._tabChange
}, options)), children);
}
};
// src/main.jsx
window.addEventListener("load", function() {
preact.render(
/* @__PURE__ */ preact.h(Application, null),
document.getElementById("application")
);
});