// var h = preact.h; import { calc_sr, calc_shift, log2 } from './utils'; import { NoteInput, NoteFrequency } from './note_input'; import { WaveData } from './wave_data'; import { Oscillators, WaveSize, Resolution, Frequency, Assembler, WaveShape, CheckBox } from './input'; import { DurationInput, DurationSplit } from './duration_input'; const C4 = 4*12; function nmultiply(x) { if (x == 0) return 0; if (x == 1) return n; return <>{x} * n; // return paren ? ({x} * n) : {x} * n; } function simplify(res, freq) { while (res && !(freq & 0x01)) { freq >>= 1; --res; } return [res, freq]; } function SampleDisplay(props) { var { shift, freq } = props; if (freq == 0) return []; var freq2 = log2(freq); var fspan = {freq}; var fspann = freq == 1 ? n : <>({fspan} * n); var rv = []; rv.push(
Samplen = RAM[ {fspann} >> {shift} ]
); rv.push(
Samplen = RAM[ {fspann} / {1 << shift} ]
); if (freq2) { if (freq2 >= shift) { rv.push(
Samplen = RAM[ { nmultiply(freq / ( 1 << shift)) } ]
); } else { rv.push(
Samplen = RAM[ { nmultiply(freq >> freq2) } >> {shift - freq2} ]
); rv.push(
Samplen = RAM[ { nmultiply(freq >> freq2) } / { 1 << (shift - freq2) } ]
); } } return rv; } /* function NoteDisplay(props) { var { osc, note } = props; const wave = 0; // 256 const sr = calc_sr(osc); const note_frq = NoteFrequency(note); const f = note_frq / (sr / (1 << (8 + wave))); // best_res = 7 - Math.ceil(Math.log2(f)) ? // best_freq = f * (1 << calc_shift(best_res, 0)) ? 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 >= 0x10000) break; best_res = res; best_freq = tmp; } [best_res, best_freq] = simplify(best_res, best_freq); return ( <>
Wave Size: 256
Resolution: {best_res}
Frequency: {best_freq}
); } */ function NoteDisplay(props) { const { osc, note } = props; return PitchDisplay({osc: osc, pitch: NoteFrequency(note)}); } function PitchDisplay(props) { var { osc, pitch } = props; const wave = 0; // 256 const sr = calc_sr(osc); const f = pitch / (sr / (1 << (8 + wave))); // best_res = 7 - Math.ceil(Math.log2(f)) ? // best_freq = f * (1 << calc_shift(best_res, 0)) ? 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 >= 0x10000) break; best_res = res; best_freq = tmp; } [best_res, best_freq] = simplify(best_res, best_freq); return ( <>
Wave Size: 256
Resolution: {best_res}
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
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 >= 0x10000) 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 ( <>
Resolution: {best_res}
Frequency: {best_freq}
); } function HyperDisplay(props) { var { pitch, freq } = props; // 26_320 = SR w/ 32 oscillators. // 261.63 = C4 // 3072 = 12 * 256 (12 = octave) // "The high byte of this word is a semitone value; the low byte is a fractional semitone." const r = (freq * 261.63 )/ (26_320 * pitch); const offset = Math.round(3072 * Math.log2(r)); const relative = offset < 0 ? -offset + 0x8000 : offset; return (
Relative: {relative}
); } function TimerDisplay(props) { var {osc, duration } = props; const [time, units] = DurationSplit(duration); const sr = calc_sr(osc); const cycles = time * sr; // (f * 256) / shift = cycles // f * 256 = cycles * shift // f = (cycles * shift) / 256 // should calculate min. wave size. eg, 256k sample has min. shift / 512, 32768 has min shift of / 2 const size = 0; // 256 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 >= 0x10000) continue; // break; 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 *= 1000; break; case "ticks": actual *= 60; break; } return ( <>
Time: { actual ? (actual / sr).toFixed(2) + " " + units : "N/A" }
Resolution: {best_res ? best_res : "N/A"}
Frequency: {best_freq ? best_freq : "N/A"}
); } // oscillators generate addresses, not samples. // accumulator is 24-bit. // frequency is 16-bit. // accumulator n = freq * n // sample n = memory[(freq * n) >> res. shift] export class Application 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 ( <>
); } noteChildren() { var { osc, wave, note } = this.state; return ( <>
); } pitchChildren() { var { osc, wave, pitch } = this.state; return ( <>
Hz
); } waveChildren() { var { assembler, shape } = this.state; return ( <>
); } resampleChildren() { var { osc, in_freq, in_size } = this.state; // freq not limited to 65,535 ? return ( <>
); } timerChildren() { var { osc, duration } = this.state; return ( <>
); } hyperChildren() { var { in_freq, note, indeterminate } = this.state; if (indeterminate) note = C4; return ( <>
); } render() { var { osc, wave, res, freq, tab } = this.state; // var shift = calc_shift(res, wave); 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 ; }); return (
{children}
); } }