Skip to content

Instantly share code, notes, and snippets.

@felixroos
Created June 10, 2020 19:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felixroos/929a8d9c303748179c6bca835e6a16ab to your computer and use it in GitHub Desktop.
Save felixroos/929a8d9c303748179c6bca835e6a16ab to your computer and use it in GitHub Desktop.
midimoog.ino
#include "MIDIUSB.h"
const int NControls = 44;
int connected[] = {
184, // polyphonic switch
185, // volume poti
186, // unison switch
187, // voice detune poti
191, // osc3 volume poti
193, // ext volume switch
195, // keyboard ctrl 1 switch
196, // amp attack poti
197, // filter mod switch
198, // osc1 switch
201, // osc2 tune poti
203, // osc1 range rotary switch
204, // noise volume poti
205, // osc2 switch
206, // osc3 switch
207, // noise switch
208, // osc2 range rotary switch
211, // vcf cutoff poti
213, // vcf decay poti
214, // osc2 vol poti
215, // osc1 vol poti
216, // osc2 waveform rotary switch
217, // osc3 waveform rotary switch
218, // vcf emphasis poti
221, // external volume poti
223, // keyboard ctrl 2 switch
224, // osc1 frequency sync switch
225, // osc3 tune poti
226, // osc1 waveform rotary switch
227, // osc3 range rotary switch
228, // white/pink switch
231, // effect 2 switch
232, // effect 1 switch
233, // osc2 ctrl switch
234, // master tune poti
235, // osc modulation switch
236, // glide poti
237, // mod mix poti
238, // osc3 ctrl switch
274, // vcf sustain poti
276, // vcf contour poti
277, // amp sustain poti
275, // amp decay poti
194 // vcf attack poti
};
int midiCh = 9;
int cc = 1;
int analogInput[NControls]; // holds aX for every index
int selectByte[NControls]; // holds select byte for every index (controls ic)
int midiPState[NControls]; // previous sent midi value for control i
int voltagePState[NControls]; // voltage of control i at last midi send
int NInverted = 23; // 21 potis + 2 inverted switches (osc control)
int inverted[] = {
185, // volume poti
187, // voice detune poti
191, // osc3 volume poti
196, // amp attack poti
201, // osc2 tune poti
204, // noise volume poti
211, // vcf cutoff poti
213, // vcf decay poti
214, // osc2 vol poti
215, // osc1 vol poti
218, // vcf emphasis poti
221, // external volume poti
225, // osc3 tune poti
234, // master tune poti
236, // glide poti
237, // mod mix poti
274, // vcf sustain poti
276, // vcf contour poti
277, // amp sustain poti
275, // amp decay poti
194, // vcf attack poti
233, // osc2 ctrl switch
238 // osc3 ctrl switch
};
int invertedInput[NControls]; // 1 for all indices that should have inverted midi values
int voltageChangeThreshold = 8;
int TIMEOUT = 300;
unsigned long PTime[NControls] = {0}; // previous time the voltage changed (more than threshold)
void setup() {
Serial.begin(9600);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
for(byte i = 0; i < NControls; i++) {
if(isInverted(connected[i])) {
invertedInput[i] = 1;
}
analogInput[i] = floor(connected[i]/10);
selectByte[i] = connected[i]%10;
}
}
void loop() {
boolean anythingChanged = false;
for(byte i = 0; i < NControls; i++) { // loop through all connected controls
// select correct byte for current control
digitalWrite(10, bitRead(selectByte[i],0));
digitalWrite(11, bitRead(selectByte[i],1));
digitalWrite(12, bitRead(selectByte[i],2));
int voltage = analogRead(analogInput[i]);
if(abs(voltage-voltagePState[i]) > voltageChangeThreshold) {
PTime[i] = millis();
}
if((millis() - PTime[i]) < TIMEOUT) {
// here the voltage changed significantly and "stayed there" for more than 300 clock cycles
int midiValue;
if(isInverted(connected[i])) {
midiValue = map(voltage, 0, 1023, 127, 0); // flipped last 2 numbers to invert
} else if(connected[i] == 227) {
midiValue = rotaryMidi(voltage, 6, 7, 1);
} else {
midiValue = map(voltage, 0, 1023, 0, 127);
}
// only send midi if it changes (0-127)
if(midiPState[i] != midiValue) {
anythingChanged = true;
//Serial.print("control ");
//Serial.print(connected[i]); // print changed id (analogInput+""+icInput) => icInput starts counting at 1
//Serial.print(", midi ");
//Serial.print(midiValue);
//Serial.print(" | ");
controlChange(midiCh, cc+i, midiValue); // send midi
MidiUSB.flush(); // force send midi immediately
voltagePState[i] = voltage; // remember last voltage where midi was sent
midiPState[i] = midiValue; // update last sent midi
}
}
}
if(anythingChanged) {
//Serial.println(" ");
}
}
void controlChange(byte channel, byte control, byte value) {
midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
MidiUSB.sendMIDI(event);
}
byte isInverted(int id) {
byte match = 0;
for (byte i = 0; i < NInverted; i++) {
if(inverted[i] == id) {
match = 1;
}
}
return match;
}
byte rotaryMidi(int voltage, int sourceSteps, int targetSteps, int offset) {
int maxVoltage = 1023;
//Serial.print(" ..");
//Serial.print((5*voltage)/maxVoltage);
//Serial.print(" > ");
int sourceStep = (int)(((5.0f*(float)voltage)/maxVoltage)+0.5f);
int midi = round((float)(sourceStep + offset) * (float)127/(targetSteps-1));
//Serial.print(sourceStep);
//Serial.print(" = ");
//Serial.println(midi);
return midi;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment