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 );