-
-
Save felixroos/929a8d9c303748179c6bca835e6a16ab to your computer and use it in GitHub Desktop.
midimoog.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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