JSFiddle - React, Tailwind, and code Playground
HTML
<pre>
== Voice Component Modeling (VCM) for Solaris ==
The Solaris sequencer can be programmed with VCM for pitch and shape,
but not for attacks and decays of envelope.
This program simulates a seq in Key Step mode,
by receiving NoteOn events and emitting CCs (20 and 21)
to change attacks and decays of vcf and vca envelopes.
You'll need a special purpose preset (see Solaris' forum).
1. plug the Solaris usb midi to this computer
2. on the Solaris, set CC0 to 20 and CC1 to 21
(2.1 test: check or uncheck volume to better assess/hear<br> that the Solaris unit is actually receiving CC data)
3. check or uncheck the VCM box to modulate attacks and decays<br> of vca and vcf envelopes
4. try changing offset and slope
5. try changing the values in the arrays on top of the source file
</pre>
<input type="checkbox" id="VCM" name="VCM" checked>
<label for="VCM">VCM</label>
<input type="checkbox" id="volume" name="volume" unchecked>
<label for="volume">volume instead of CC0</label>
<br>
<label for="offset">offset</label>
<input type="range" id="offset" name="offset" min="0" max="10" value="5" step="1" oninput="this.nextElementSibling.value = this.value">
<output>5</output>
<br>
<label for="slolpe">slope</label>
<input type="range" id="slope" name="slope" min="0" max="20" value="3" step="1" oninput="this.nextElementSibling.value = this.value">
<output>3</output>
JavaScript
// change these values according to your taste
const attacks = [2,-2,3,1,4,1,-1,-5,3,1];
const decays = [2,2,-3,1,-4,1,1,-5,-2,1];
//const offset = 5; // should be more than the lowest value in attacks or decays
//const slope = 10;
// -------
var input = null;
var output = null;
var index = 0;
function sendCC( cc, value ) {
const CCmsg = [0xB0, cc, value];
output.send( CCmsg );
}
function onMIDISuccess( midiAccess ) {
const portID = 'John Bowen Solaris Synthesizer';
input = midiAccess.inputs.get(portID);
output = midiAccess.outputs.get(portID);
console.log( "solaris MIDI ready!" );
input.onmidimessage = (msg) => {
const VCMCheckBox = document.querySelector('input[id="VCM"]');
const noteon = (msg.data[0] & 0xf0)==0x90;
if (noteon && VCMCheckBox.checked) {
var cc = 20;
const volumeCheckBox = document.querySelector('input[id="volume"]');
if (volumeCheckBox.checked) {
cc=7; // 7: main volume
}
const offset = parseInt(document.querySelector('input[id="offset"]').value);
const slope = parseInt(document.querySelector('input[id="slope"]').value);
sendCC (cc, slope*(offset+attacks[index]));
sendCC (21, slope*(offset+decays[index]));
index += 1;
if (index>9) index = 0;
//console.log(index);
}
/*if ( (msg.data[0] & 0xf0)==0xf0) {
var i;
for (i=1; msg.data[i]!=0xf7; i+=1);
//console.log(JSON.stringify(msg.data.slice(1,i)));
}*/
}
}
function onMIDIFailure(msg) {
console.log( "Failed to get MIDI access - " + msg );
}
navigator.requestMIDIAccess( { sysex: true } ).then( onMIDISuccess, onMIDIFailure );