mirror of
https://github.com/ksherlock/ensoniq-buddy.git
synced 2024-06-04 21:29:27 +00:00
add some more stuff
This commit is contained in:
parent
320054cc37
commit
92dbd1904c
5
Makefile
5
Makefile
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
all: js/application.js js/preact.min.js | js
|
all: js/application.js js/preact.min.js | js
|
||||||
|
|
||||||
js/application.js : src/main.jsx src/application.jsx
|
js/application.js : src/main.jsx src/application.jsx src/note_input.jsx src/radio_group.jsx
|
||||||
esbuild --bundle --jsx-factory=preact.h --format=esm src/main.jsx --outfile=js/application.js
|
esbuild --bundle --jsx-factory=preact.h --jsx-fragment=preact.Fragment --format=esm \
|
||||||
|
src/main.jsx --outfile=js/application.js
|
||||||
|
|
||||||
|
|
||||||
js/preact.min.js : node_modules/preact/dist/preact.min.js
|
js/preact.min.js : node_modules/preact/dist/preact.min.js
|
||||||
|
|
|
@ -14,4 +14,16 @@ html {
|
||||||
}
|
}
|
||||||
sub {
|
sub {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend a {
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: .5em;
|
||||||
|
}
|
||||||
|
legend a:last-of-type {
|
||||||
|
margin-right: .5em;
|
||||||
|
}
|
||||||
|
legend a.selected {
|
||||||
|
color: blue;
|
||||||
}
|
}
|
|
@ -1,11 +1,14 @@
|
||||||
|
|
||||||
// var h = preact.h;
|
// var h = preact.h;
|
||||||
|
|
||||||
|
import { NoteInput, NoteFrequency } from './note_input';
|
||||||
|
import { RadioGroup } from './radio_group';
|
||||||
|
|
||||||
|
|
||||||
function calc_sr(osc) {
|
function calc_sr(osc) {
|
||||||
// iigs is ~7.14Mhz / 8. Mirage is 8Mhz / 8
|
// iigs is ~7.14Mhz / 8. Mirage is 8Mhz / 8
|
||||||
return (28.63636*1000*1000/32) / (osc + 2);
|
// return (28.63636*1000*1000/32) / (osc + 2);
|
||||||
|
return (28_636_360/32) / (osc + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calc_shift(res,ws) {
|
function calc_shift(res,ws) {
|
||||||
|
@ -18,12 +21,22 @@ function log2(x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var _onames = [];
|
||||||
function Oscillators(props) {
|
function Oscillators(props) {
|
||||||
|
|
||||||
var options = []
|
if (!_onames.length) {
|
||||||
for (var i = 1; i < 33; ++i) {
|
for (var i = 1; i < 33; ++i) {
|
||||||
options.push(<option value={i} key={i}>{i}</option>);
|
var x = (calc_sr(i) / 1000 ).toFixed(2) + " kHz";
|
||||||
|
_onames.push(x)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
var options = _onames.map( (x, ix) => {
|
||||||
|
var i = ix + 1;
|
||||||
|
return <option value={i} key={i}>{i} – {x}</option>
|
||||||
|
});
|
||||||
|
// for (var i = 1; i < 33; ++i) {
|
||||||
|
// options.push(<option value={i} key={i}>{i}</option>);
|
||||||
|
// }
|
||||||
return <select value={props.value} onChange={props.onChange}>{options}</select>;
|
return <select value={props.value} onChange={props.onChange}>{options}</select>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +118,53 @@ function SampleDisplay(props) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SineWave() {
|
||||||
|
|
||||||
|
var rv = [];
|
||||||
|
for (n = 0; n < 256; ++n) {
|
||||||
|
var x = 128 + Math.round(127 * Math.sin(n * Math.PI / 128));
|
||||||
|
var y = x.toString(16); if (y.length < 2) y = "0" + y;
|
||||||
|
rv.push( y );
|
||||||
|
if ((n & 0x07) == 0x07) rv.push("\n");
|
||||||
|
else rv.push(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<code>
|
||||||
|
<pre>
|
||||||
|
{rv}
|
||||||
|
</pre>
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function NoteDisplay(props) {
|
||||||
|
|
||||||
|
|
||||||
|
var { osc, wave, note } = props;
|
||||||
|
|
||||||
|
const sr = calc_sr(osc);
|
||||||
|
const note_frq = NoteFrequency(note);
|
||||||
|
|
||||||
|
const f = note_frq / (sr / (1 << (8 + wave)));
|
||||||
|
|
||||||
|
var best_res = 0;
|
||||||
|
var best_freq = 0;
|
||||||
|
for (var res = 0; res < 8; ++res) {
|
||||||
|
var tmp = f * (1 << calc_shift(res, wave));
|
||||||
|
if (tmp >= 0x10000) break;
|
||||||
|
best_res = res;
|
||||||
|
best_freq = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>Resolution: {best_res}</div>
|
||||||
|
<div>Frequency: {Math.round(best_freq)}</div>
|
||||||
|
<SineWave />
|
||||||
|
</>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// oscillators generate addresses, not samples.
|
// oscillators generate addresses, not samples.
|
||||||
// accumulator is 24-bit.
|
// accumulator is 24-bit.
|
||||||
|
@ -122,8 +181,10 @@ export class Application extends preact.Component {
|
||||||
this._waveChange = this.waveChange.bind(this);
|
this._waveChange = this.waveChange.bind(this);
|
||||||
this._resChange = this.resChange.bind(this);
|
this._resChange = this.resChange.bind(this);
|
||||||
this._freqChange = this.freqChange.bind(this);
|
this._freqChange = this.freqChange.bind(this);
|
||||||
|
this._noteChange = this.noteChange.bind(this);
|
||||||
|
this._tabChange = this.tabChange.bind(this);
|
||||||
|
|
||||||
this.state = { osc: 32, wave: 0, res: 0, freq: 512 };
|
this.state = { osc: 32, wave: 0, res: 0, freq: 512, tab: 0, note: 4*12 };
|
||||||
}
|
}
|
||||||
|
|
||||||
oscChange(e) {
|
oscChange(e) {
|
||||||
|
@ -152,12 +213,22 @@ export class Application extends preact.Component {
|
||||||
this.setState( { freq: v } );
|
this.setState( { freq: v } );
|
||||||
}
|
}
|
||||||
|
|
||||||
form() {
|
tabChange(v) {
|
||||||
|
this.setState({ tab: v });
|
||||||
|
}
|
||||||
|
|
||||||
|
noteChange(v) {
|
||||||
|
this.setState({ note: v });
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleChildren() {
|
||||||
|
|
||||||
var { osc, wave, res, freq } = this.state;
|
var { osc, wave, res, freq } = this.state;
|
||||||
|
|
||||||
|
var shift = calc_shift(res, wave);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="form">
|
<>
|
||||||
<div>
|
<div>
|
||||||
<label>Oscillators</label> <Oscillators value={osc} onChange={this._oscChange} />
|
<label>Oscillators</label> <Oscillators value={osc} onChange={this._oscChange} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -170,36 +241,53 @@ export class Application extends preact.Component {
|
||||||
<div>
|
<div>
|
||||||
<label>Frequency</label> <Frequency value={freq} onChange={this._freqChange} />
|
<label>Frequency</label> <Frequency value={freq} onChange={this._freqChange} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<SampleDisplay freq={freq} shift={shift} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
noteChildren() {
|
||||||
|
|
||||||
var { osc, wave, res, freq } = this.state;
|
var { osc, wave, note } = this.state;
|
||||||
|
|
||||||
var shift = calc_shift(res, wave);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
{ this.form() }
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
Scan Rate: { (calc_sr(osc) / 1000 ).toFixed(2) } kHz
|
<label>Oscillators</label> <Oscillators value={osc} onChange={this._oscChange} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Wave Size</label> <WaveSize value={wave} onChange={this._waveChange} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Note</label> <NoteInput value={note} onChange={this._noteChange} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SampleDisplay freq={freq} shift={shift} />
|
<NoteDisplay osc={osc} note={note} wave={wave} />
|
||||||
</div>
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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.noteChildren(); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RadioGroup value={tab} options={["Sample", "Note"]} onClick={this._tabChange }>
|
||||||
|
{ children }
|
||||||
|
</RadioGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
window.addEventListener('load', function(){
|
|
||||||
|
|
||||||
preact.render(
|
|
||||||
<Application />,
|
|
||||||
document.getElementById('application')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
90
src/note_input.jsx
Normal file
90
src/note_input.jsx
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
|
||||||
|
const _notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
|
||||||
|
|
||||||
|
const _base = [ 27.5, 55, 110, 220, 440, 880, ]
|
||||||
|
|
||||||
|
function split_value(value) {
|
||||||
|
return [ value % 12, (value / 12) >> 0 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NoteName(value) {
|
||||||
|
|
||||||
|
var [note, octave] = split_value(value);
|
||||||
|
|
||||||
|
return _notes[note] + ' ' + octave;
|
||||||
|
}
|
||||||
|
|
||||||
|
export 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NoteInput 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 } = this.props;
|
||||||
|
|
||||||
|
var notes = _notes.map( (x, ix) => {
|
||||||
|
return <option key={ix} value={ix}>{x}</option>;
|
||||||
|
});
|
||||||
|
|
||||||
|
var octaves = [];
|
||||||
|
for (var i = 0; i < 8; ++i) {
|
||||||
|
octaves.push(
|
||||||
|
<option key={i} value={i}>{i}</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var [note, octave] = split_value(value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<select onChange={this._noteChange} value={note}>{notes}</select>
|
||||||
|
{ ' ' }
|
||||||
|
<select onChange={this._octaveChange} value={octave}>{octaves}</select>
|
||||||
|
{ ' ' }
|
||||||
|
{ NoteFrequency(value).toFixed(2) } Hz
|
||||||
|
</>);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
src/radio_group.jsx
Normal file
23
src/radio_group.jsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
|
||||||
|
export function RadioGroup(props) {
|
||||||
|
|
||||||
|
var { options, value, onClick } = props;
|
||||||
|
var legend = [];
|
||||||
|
if (options) {
|
||||||
|
|
||||||
|
legend = options.map( (o, ix) => {
|
||||||
|
let _onClick = function(e) { e.preventDefault(); onClick(ix); }
|
||||||
|
return <a onClick={ _onClick } class={ ix == value ? "selected" : ""}>{o}</a>;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<fieldset class="radio-group" id="form">
|
||||||
|
<legend>{legend}</legend>
|
||||||
|
{props.children}
|
||||||
|
</fieldset>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user