Hardware finished, softare running ok with some things to fix, like init values.

pull/1/head
Pierre-Loup Martin 4 years ago
parent 0a38957623
commit 6f573d753b
  1. 8
      README.MD
  2. 381
      minimoog_mega_1/minimoog_mega_1.ino
  3. 25
      minimoog_mega_2/minimoog_mega_2.ino
  4. 88
      minimoog_teensy/audio_setup.h
  5. 262
      minimoog_teensy/minimoog_teensy.ino
  6. 9
      misc/lateral panel pinout.txt
  7. 606
      panels/svg/minimoog - panneau lateral.svg

@ -0,0 +1,8 @@
# TeensyMoog
## What is it ?
_Teensymoog_ is a synth, inspired by the legendary minimoog.
It aims at looking and functionning as close as possible of the orinal, but using digital tools, namely Teensy and Arduino boards.
It uses three boards, one Teensy 4.0 that handles the heavy computing (sound generation), and two Arduino Mega (chinese copies in a small form factor), that are used as "port expander", which read keys, switches and potentiometers and send their value on change to the Teensy.

@ -36,17 +36,17 @@
* glide pot A2 CC 5
* pitchbend wheel pot A3 pitchbend change
* modulation wheel pot A4 CC 1
* modulation mix 1 switch 2 CC 117
* modulation mix 2 switch 3 CC 118
* modulation mix 1 switch 3 CC 117
* modulation mix 2 switch 2 CC 118
* osc modulation switch 4 CC 115
* glide switch 5 CC 65
* LFO waveform switch 6 CC 119
* Oscillators
* osc 1 range switch A5 CC 102
* osc 1 waveform switch A6 CC 103
* osc 2 range switch A7 CC 104
* osc 2 waveform switch A8 CC 105
* osc 3 range switch A9 CC 106
* osc 1 waveform switch A8 CC 103
* osc 2 range switch A6 CC 104
* osc 2 waveform switch A9 CC 105
* osc 3 range switch A7 CC 106
* osc 3 waveform switch A10 CC 107
* osc 3 control switch 7 CC 108
* Mixer
@ -54,31 +54,39 @@
* osc 2 mix pot A12 CC 86
* osc 3 mix pot A13 CC 87
* noise mix pot A14 CC 88
* external mix pot A15 CC 89
* feedback mix pot A15 CC 89
* osc 1 switch 8 Directly added to mix
* osc 2 switch 9 ditto
* osc 3 switch 10 ditto
* noise switch 11 ditto
* external switch 12 ditto
* noise color switch 13 CC 114
* feedback switch 12 ditto
* noise color switch 17 CC 114 // led on 13 lowers tension
* Other
* function switch 14 CC 113
* transpose + switch 52 CC 112
* transpose - switch 53 CC 112
* transpose + switch 15 CC 112
* transpose - switch 16 CC 112
* Communication
* TX1 to mega 2 18
* RX1 from mega 2 19
* TX1 to teensy 18
* RX1 from teensy 19
*/
// includes
#include "MIDI.h"
#include "PushButton.h"
#include "ExpFilter.h"
#include "defs.h"
// Constants
const uint8_t NUM_KEYS = 30;
const uint8_t MIDI_OFFSET = 23; // to be modified
// Digital pin definition
const uint8_t MIDI_OFFSET = 47; // to be maybe modified
const uint8_t NUM_SWITCHES = 15;
const uint8_t NUM_POTS = 16;
const uint8_t NUM_SELECTORS = 6;
const uint8_t POT_FILTER_COEF = 15;
// Digital pin definition
const uint8_t KEYS[NUM_KEYS] = {
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
@ -86,25 +94,27 @@ const uint8_t KEYS[NUM_KEYS] = {
};
PushButton keys[NUM_KEYS];
/*
const uint8_t PIN_MOD_MIX_1 = 2;
const uint8_t PIN_MOD_MIX_2 = 3;
const uint8_t PIN_OSC_MOD = 4;
const uint8_t PIN_GLIDE = 5;
const uint8_t PIN_DECAY = 6;
const uint8_t PIN_LFO_WAVEFORM = 7;
const uint8_t PIN_LFO_WAVEFORM = 6;
const uint8_t PIN_OSC3_CTRL = 7;
const uint8_t PIN_MIX_OSC_1 = 9;
const uint8_t PIN_MIX_OSC_2 = 10;
const uint8_t PIN_MIX_OSC_3 = 11;
const uint8_t PIN_MIX_OSC_NOISE = 12;
const uint8_t PIN_MIX_OSC_EXT = 13;
const uint8_t PIN_MIX_OSC_NOISE_COLOR = 14;
const uint8_t PIN_MIX_OSC_1 = 8;
const uint8_t PIN_MIX_OSC_2 = 9;
const uint8_t PIN_MIX_OSC_3 = 10;
const uint8_t PIN_MIX_OSC_NOISE = 11;
const uint8_t PIN_MIX_OSC_EXT = 12;
const uint8_t PIN_MIX_OSC_NOISE_COLOR = 13;
const uint8_t PIN_FUNCTION = 14;
const uint8_t PIN_TRANSPOSE_PLUS = 52;
const uint8_t PIN_TRANSPOSE_MINUS = 53;
*/
// Analog pin definition
/*
const uint8_t APIN_LFO_RATE = A0;
const uint8_t APIN_MOD_MIX = A1;
const uint8_t APIN_GLIDE = A2;
@ -123,49 +133,27 @@ const uint8_t APIN_MIX_OSC_2 = A12;
const uint8_t APIN_MIX_OSC_3 = A13;
const uint8_t APIN_MIX_NOISE = A14;
const uint8_t APIN_MIX_EXT = A15;
*/
const uint8_t APIN[NUM_POTS] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15};
// Vars
uint16_t potState[NUM_POTS];
const uint8_t PIN[NUM_SWITCHES] = {3, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 17, 14, 15, 16};
PushButton switches[NUM_SWITCHES];
ExpFilter pots[NUM_POTS];
uint8_t selectors[NUM_SELECTORS];
// Keyboard
bool keyState[NUM_KEYS] = {};
// Modulation
uint16_t lfoRate = 0;
uint16_t modMix = 0;
uint16_t glide = 0;
uint16_t pitchWheel = 0;
uint16_t modWheel = 0;
bool modMix1 = 0;
bool modMix2 = 0;
bool oscMod = 0;
bool glideEn = 0;
bool decayEn = 0;
bool lfoWaveform = 0;
// Oscillators
uint8_t osc1Range = 0;
uint8_t osc1Waveform = 0;
uint8_t osc2Range = 0;
uint8_t osc2Waveform = 0;
uint8_t osc3Range = 0;
uint8_t osc3Waveform = 0;
bool osc3Control = 0;
bool keyState[NUM_KEYS];
// Mixer
uint16_t osc1Mix = 0;
uint16_t osc2Mix = 0;
uint16_t osc3Mix = 0;
uint16_t feedbackMix = 0;
uint16_t noiseMix = 0;
bool osc1MixSw = 0;
bool osc2MixSw = 0;
bool osc3MixSw = 0;
bool feedbackMixSw = 0;
bool noiseMixSw = 0;
// Miscellaneous
bool function = 0;
uint16_t mix[5];
bool mixSw[5];
// Misc
uint8_t defaultVelocity = 96;
bool update = 0;
@ -176,46 +164,62 @@ struct midiSettings : public midi::DefaultSettings{
};
// The one we use on synth
//MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial1, midi1, midiSettings);
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial1, midi1, midiSettings);
// For debug purposes
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, midi1, midiSettings);
//MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, midi1, midiSettings);
void setup(){
// initialisation
// Serial is for debug
//Serial.begin(115200);
midi1.setHandleControlChange(handleControlChange);
midi1.begin(1);
// Serial 1 is for sending and receiving messages to and from Teensy
// Serial1.begin(115200);
// Serial 2 is for sending and receiving messages to and from Mega 2
// Serial2.begin(115200);
// keys
/*
for(uint8_t i = 0; i < NUM_KEYS; ++i){
keyState[i] = 0;
pinMode(KEYS[i], INPUT_PULLUP);
}
*/
midi1.turnThruOff();
// Key initialisation
for(uint8_t i = 0; i < NUM_KEYS; ++i){
keys[i].begin(KEYS[i], INPUT_PULLUP);
keys[i].setDebounceDelay(1);
keys[i].setDebounceDelay(12);
}
// Switches initialisation
for(uint8_t i = 0; i < NUM_SWITCHES; ++i){
switches[i].begin(PIN[i], INPUT_PULLUP);
switches[i].setDebounceDelay(1);
}
// potentiometers initialisation
for (uint8_t i = 0; i < NUM_POTS; ++i){
pots[i].begin(analogRead(APIN[i]));
pots[i].setCoef(POT_FILTER_COEF);
}
}
void loop(){
midi1.read();
updateKeys();
updateControls();
updateSwitches();
updateControls();
update = 0;
}
void sendLongControlChange(uint8_t controlChange, uint16_t value, uint8_t channel = 1){
uint8_t valueHigh = value >> 7;
uint8_t valueLow = value & 0x7F;
midi1.sendControlChange(controlChange, valueHigh, channel);
midi1.sendControlChange(controlChange + 32, valueLow, channel);
}
void updateMix(uint8_t ch, bool fromSw = 0){
uint16_t value = 0;
if(mixSw[ch]){
value = mix[ch];
}
if(value || fromSw) sendLongControlChange(CC_OSC1_MIX + ch, value, 1);
}
void updateKeys(){
// reading keys
for(uint8_t i = 0; i < NUM_KEYS; ++i){
@ -248,13 +252,228 @@ void updateKeys(){
}
void updateControls(){
void updateSwitches(){
for(uint8_t i = 0; i < NUM_SWITCHES; ++i){
uint8_t change = 0;
switches[i].update();
if(switches[i].justPressed()){
change = 127;
} else if(switches[i].justReleased()){
change = 0;
} else if(update){
change = (uint8_t)switches[i].isPressed();
change *= 127;
} else {
// If no change, skip midi update.
continue;
}
int8_t controlChange = -1;
switch(i){
case 0:
// pin 2
controlChange = CC_MOD_MIX_1;
break;
case 1:
// pin 3
controlChange = CC_MOD_MIX_2;
break;
case 2:
// pin 4
controlChange = CC_OSC_MOD;
break;
case 3:
// pin 5
controlChange = CC_PORTAMENTO_ON_OFF;
break;
case 4:
// pin 6
controlChange = CC_LFO_SHAPE;
break;
case 5:
// pin 7
controlChange = CC_OSC3_CTRL;
break;
case 6:
// pin 8
mixSw[0] = (bool)change;
updateMix(0, 1);
continue;
case 7:
// pin 9
mixSw[1] = (bool)change;
updateMix(1, 1);
continue;
case 8:
// pin 10
mixSw[2] = (bool)change;
updateMix(2, 1);
continue;
case 9:
// pin 11
mixSw[3] = (bool)change;
updateMix(3, 1);
continue;
case 10:
// pin 12
mixSw[4] = (bool)change;
updateMix(4, 1);
continue;
case 11:
// pin 13
controlChange = CC_NOISE_COLOR;
break;
case 12:
// pin 14
controlChange = CC_FUNCTION;
break;
case 13:
// pin 15
controlChange = CC_TRANSPOSE;
if(change == 0) continue;
change = 127;
break;
case 14:
// pin 16
controlChange = CC_TRANSPOSE;
if(change == 127) continue;
change = 0;
break;
default:
continue;
}
midi1.sendControlChange(controlChange, change, 1);
}
}
void updateSwitches(){
void updateControls(){
for(uint8_t i = 0; i < NUM_POTS; ++i){
uint16_t value = 0;
value = pots[i].filter(analogRead(APIN[i]));
if((value != potState[i]) || update){
potState[i] = value;
} else {
// If not change, skip midi update
continue;
}
int8_t controlChange = -1;
switch(i){
case 0:
controlChange = CC_LFO_RATE;
break;
case 1:
controlChange = CC_MODULATION_MIX;
break;
case 2:
controlChange = CC_PORTAMENTO_TIME;
break;
case 3:
midi1.sendPitchBend((int16_t)value - 512, 1);
continue;
case 4:
controlChange = CC_MOD_WHEEL;
break;
case 5:
// rotary selector : value must be divided by ~170
controlChange = CC_OSC1_RANGE;
value /= 170;
value = 5 - value;
// We have to check if the value after dividing is different from the previous one !
if(value == selectors[0]){
continue;
} else {
selectors[0] = value;
}
break;
case 6:
controlChange = CC_OSC2_RANGE;
value /= 170;
value = 5 - value;
if(value == selectors[1]){
continue;
} else {
selectors[1] = value;
}
break;
case 7:
controlChange = CC_OSC3_RANGE;
value /= 170;
value = 5 - value;
if(value == selectors[2]){
continue;
} else {
selectors[2] = value;
}
break;
case 8:
controlChange = CC_OSC1_WAVEFORM;
value /= 170;
if(value == selectors[3]){
continue;
} else {
selectors[3] = value;
}
break;
case 9:
controlChange = CC_OSC2_WAVEFORM;
value /= 170;
if(value == selectors[4]){
continue;
} else {
selectors[4] = value;
}
break;
case 10:
controlChange = CC_OSC3_WAVEFORM;
value /= 170;
if(value == selectors[5]){
continue;
} else {
selectors[5] = value;
}
break;
case 11:
// mix is to be sent only if switch is on.
// controlChange = CC_OSC1_MIX;
mix[0] = value;
updateMix(0);
continue;
case 12:
// controlChange = CC_OSC2_MIX;
mix[1] = value;
updateMix(1);
continue;
case 13:
// controlChange = CC_OSC3_MIX;
mix[2] = value;
updateMix(2);
continue;
case 14:
// controlChange = CC_NOISE_MIX;
mix[3] = value;
updateMix(3);
continue;
case 15:
// controlChange = CC_FEEDBACK_MIX;
mix[4] = value;
updateMix(4);
continue;
default:
continue;
}
if( controlChange < 32){
sendLongControlChange(controlChange, value, 1);
} else {
midi1.sendControlChange(controlChange, value, 1);
}
}
}
void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){

@ -52,8 +52,6 @@
* Communication
* TX1 to teensy 18
* RX1 from teensy 19
* TX2 to mega 1 16
* RX2 from mega 1 17
*/
// includes
@ -68,12 +66,16 @@ const uint8_t NUM_SWITCHES = 3;
const uint8_t NUM_POTS = 15;
const uint8_t POT_FILTER_COEF = 10;
// Note : pins are defined via tables, to improve code efficiency.
// Digital pin definition
const uint8_t PIN_FILTER_MOD = 2;
/*
const uint8_t PIN_KEYBOARD_CTRL_1 = 3;
const uint8_t PIN_KEYBOARD_CTRL_2 = 4;
*/
// Analog pin definition
/*
const uint8_t APIN_GLOBAL_TUNE = A0;
const uint8_t APIN_OSC2_TUNE = A1;
const uint8_t APIN_OSC3_TUNE = A2;
@ -89,11 +91,12 @@ const uint8_t APIN_ATTACK = A11;
const uint8_t APIN_DECAY = A12;
const uint8_t APIN_SUSTAIN = A13;
const uint8_t APIN_RELEASE = A14;
*/
const uint8_t apin[NUM_POTS] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14};
const uint8_t APIN[NUM_POTS] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14};
// Variables
uint16_t potState[NUM_POTS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint16_t potState[NUM_POTS];
PushButton switches[NUM_SWITCHES];
ExpFilter pots[NUM_POTS];
@ -118,7 +121,7 @@ void setup(){
}
for (uint8_t i = 0; i < NUM_POTS; ++i){
pots[i].begin(analogRead(apin[i]));
pots[i].begin(analogRead(APIN[i]));
pots[i].setCoef(POT_FILTER_COEF);
}
@ -139,7 +142,7 @@ void updateControls(){
for(uint8_t i = 0; i < NUM_POTS; ++i){
uint16_t value = 0;
value = pots[i].filter(analogRead(apin[i]));
value = pots[i].filter(analogRead(APIN[i]));
if((value != potState[i]) || update){
potState[i] = value;
} else {
@ -147,7 +150,7 @@ void updateControls(){
continue;
}
uint8_t controlChange = 0;
int8_t controlChange = -1;
switch(i){
case 0:
@ -157,6 +160,9 @@ void updateControls(){
controlChange = CC_OSC2_TUNE;
break;
case 2:
// This one has a problem : sends CC10 (instead of CC13) then CC45 as should be.
// or maybe pure data has a bug that shifts bits.
// It seems it's a bug of pure data : 13 are replaced by 10 also for values...
controlChange = CC_OSC3_TUNE;
break;
case 3:
@ -199,6 +205,7 @@ void updateControls(){
continue;
}
uint8_t valueHigh = value >> 7;
uint8_t valueLow = value & 0x7F;
midi1.sendControlChange(controlChange, valueHigh, 1);
@ -223,7 +230,7 @@ void updateSwitches(){
continue;
}
uint8_t controlChange = 0;
int8_t controlChange = -1;
switch(i){
case 0:

@ -5,53 +5,53 @@
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioSynthWaveformDc dcFilterEnvelope; //xy=169.76666259765625,540.0000305175781
AudioSynthWaveformDc dcOscTune; //xy=228.76666259765625,149
AudioSynthWaveformDc dcKeyTrack; //xy=231.76666259765625,113
AudioSynthWaveformDc dcPitchBend; //xy=234.7666778564453,184.00001525878906
AudioSynthWaveformDc dcFilter; //xy=336.76666259765625,595.0000305175781
AudioSynthNoisePink pinkNoise; //xy=358.76666259765625,320
AudioSynthNoiseWhite whiteNoise; //xy=361.76666259765625,284
AudioSynthWaveformDc dcLfoFreq; //xy=365.76666259765625,376
AudioEffectEnvelope filterEnvelope; //xy=367.76666259765625,540.0000305175781
AudioSynthWaveformDc dcFilterKeyTrack; //xy=369.76666259765625,629.0000305175781
AudioAmplifier ampPitchBend; //xy=407.7666778564453,184.00001525878906
AudioMixer4 noiseMixer; //xy=544.7666625976562,317
AudioSynthWaveformModulated lfoWaveform; //xy=548.7666625976562,374
AudioAmplifier ampOsc3Mod; //xy=549.7666625976562,437
AudioAmplifier ampModEg; //xy=559.7666625976562,475
AudioMixer4 mainTuneMixer; //xy=631.7666625976562,133
AudioMixer4 modMix2; //xy=755.7666015625,470
AudioMixer4 modMix1; //xy=756.7666015625,399
AudioSynthWaveformDc dcOsc3; //xy=758.7667541503906,193.00001525878906
AudioMixer4 osc3ControlMixer; //xy=933.7667236328125,199
AudioMixer4 modMixer; //xy=945.7666015625,448
AudioSynthWaveformDc dcOsc2Tune; //xy=1105.566650390625,155.56666564941406
AudioSynthWaveformDc dcOsc3Tune; //xy=1106.36669921875,221.56666564941406
AudioAmplifier ampModWheel; //xy=1159.7666015625,448
AudioMixer4 osc3TuneMixer; //xy=1289.36669921875,217.56666564941406
AudioMixer4 osc2TuneMixer; //xy=1290.566650390625,153.56666564941406
AudioSynthWaveformDc dcPulse; //xy=1306.566665649414,65.56666564941406
AudioSynthWaveformModulated osc1Waveform; //xy=1523.7666015625,114
AudioSynthWaveformModulated osc2Waveform; //xy=1524.7666015625,151
AudioSynthWaveformModulated osc3Waveform; //xy=1524.7666015625,188
AudioMixer4 oscMixer; //xy=1710.7666015625,157
AudioMixer4 globalMixer; //xy=1919.7666015625,204
AudioAmplifier ampPreFilter; //xy=2083.7666015625,203
AudioMixer4 filterMixer; //xy=2101.7666625976562,446
AudioFilterStateVariable vcf; //xy=2270.7666625976562,440
AudioMixer4 bandMixer; //xy=2441.566665649414,435.56666564941406
AudioEffectEnvelope mainEnvelope; //xy=2620.7664794921875,436
AudioEffectBitcrusher bitCrushOutput; //xy=2856.5662841796875,433.566650390625
AudioOutputI2S i2s; //xy=3046.7659912109375,435
AudioSynthWaveformDc dcFilterEnvelope; //xy=169,540
AudioSynthWaveformDc dcOscTune; //xy=228,149
AudioSynthWaveformDc dcKeyTrack; //xy=231,113
AudioSynthWaveformDc dcPitchBend; //xy=234,184
AudioSynthWaveformDc dcFilter; //xy=336,595
AudioSynthNoisePink pinkNoise; //xy=358,320
AudioSynthWaveformDc dcLfoFreq; //xy=360,369
AudioSynthNoiseWhite whiteNoise; //xy=361,284
AudioEffectEnvelope filterEnvelope; //xy=367,540
AudioSynthWaveformDc dcFilterKeyTrack; //xy=369,629
AudioAmplifier ampPitchBend; //xy=407,184
AudioMixer4 noiseMixer; //xy=544,317
AudioSynthWaveformModulated lfoWaveform; //xy=549,369
AudioAmplifier ampOsc3Mod; //xy=549,437
AudioAmplifier ampModEg; //xy=559,475
AudioMixer4 mainTuneMixer; //xy=631,133
AudioMixer4 modMix2; //xy=755,470
AudioMixer4 modMix1; //xy=756,399
AudioSynthWaveformDc dcOsc3; //xy=758,193
AudioMixer4 osc3ControlMixer; //xy=933,199
AudioMixer4 modMixer; //xy=945,448
AudioSynthWaveformDc dcOsc2Tune; //xy=1105,155
AudioSynthWaveformDc dcOsc3Tune; //xy=1106,221
AudioAmplifier ampModWheel; //xy=1159,448
AudioMixer4 osc3TuneMixer; //xy=1289,217
AudioMixer4 osc2TuneMixer; //xy=1290,153
AudioSynthWaveformDc dcPulse; //xy=1306,65
AudioSynthWaveformModulated osc1Waveform; //xy=1523,114
AudioSynthWaveformModulated osc2Waveform; //xy=1524,151
AudioSynthWaveformModulated osc3Waveform; //xy=1524,188
AudioMixer4 oscMixer; //xy=1710,157
AudioMixer4 globalMixer; //xy=1919,204
AudioAmplifier ampPreFilter; //xy=2083,203
AudioMixer4 filterMixer; //xy=2101,446
AudioFilterStateVariable vcf; //xy=2270,440
AudioMixer4 bandMixer; //xy=2441,435
AudioEffectEnvelope mainEnvelope; //xy=2620,436
AudioEffectBitcrusher bitCrushOutput; //xy=2856,433
AudioOutputI2S i2s; //xy=3046,435
AudioConnection patchCord1(dcFilterEnvelope, filterEnvelope);
AudioConnection patchCord2(dcOscTune, 0, mainTuneMixer, 1);
AudioConnection patchCord3(dcKeyTrack, 0, mainTuneMixer, 0);
AudioConnection patchCord4(dcPitchBend, ampPitchBend);
AudioConnection patchCord5(dcFilter, 0, filterMixer, 2);
AudioConnection patchCord6(pinkNoise, 0, noiseMixer, 1);
AudioConnection patchCord7(whiteNoise, 0, noiseMixer, 0);
AudioConnection patchCord8(dcLfoFreq, 0, lfoWaveform, 0);
AudioConnection patchCord7(dcLfoFreq, 0, lfoWaveform, 0);
AudioConnection patchCord8(whiteNoise, 0, noiseMixer, 0);
AudioConnection patchCord9(filterEnvelope, 0, filterMixer, 1);
AudioConnection patchCord10(filterEnvelope, ampModEg);
AudioConnection patchCord11(dcFilterKeyTrack, 0, filterMixer, 3);
@ -87,10 +87,10 @@ AudioConnection patchCord40(globalMixer, ampPreFilter);
AudioConnection patchCord41(ampPreFilter, 0, vcf, 0);
AudioConnection patchCord42(filterMixer, 0, vcf, 1);
AudioConnection patchCord43(vcf, 0, bandMixer, 0);
AudioConnection patchCord44(vcf, 2, bandMixer, 1);
AudioConnection patchCord44(vcf, 1, bandMixer, 1);
AudioConnection patchCord45(bandMixer, mainEnvelope);
AudioConnection patchCord46(mainEnvelope, 0, globalMixer, 1);
AudioConnection patchCord47(mainEnvelope, bitCrushOutput);
AudioConnection patchCord46(mainEnvelope, bitCrushOutput);
AudioConnection patchCord47(mainEnvelope, 0, globalMixer, 1);
AudioConnection patchCord48(bitCrushOutput, 0, i2s, 0);
AudioConnection patchCord49(bitCrushOutput, 0, i2s, 1);
// GUItool: end automatically generated code

@ -24,6 +24,24 @@
* All user inputs are handled and send to the teensy board using midi commands
*/
/*
* Pinout
*
* RX from mega 1 (through tension divider) 0
* TX to mega 1 (serial 1) 1
* mega 1 reset 2
*
* RX from mega 2 (through tension divider) 16
* TX to mega 2 (serial 4) 17
* mega 2 reset 18
*
* I2S OUT1A 7
* I2S LRCLK1 20
* I2S BCLK1 21
*
* D+ & D- are also used to break the USB port to the rear panel
*/
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
@ -33,7 +51,7 @@
#include "audio_setup.h"
#include "defs.h"
//#include "MIDI.h"
#include "MIDI.h"
// constants
const uint8_t KEYTRACK_MAX = 10;
@ -47,14 +65,28 @@ const float NOTE_RATIO = 1.0594630943593;
const float HALFTONE_TO_DC = (float)1 / (MAX_OCTAVE * 12);
const float FILTER_HALFTONE_TO_DC = (float)1 / (FILTER_MAX_OCTAVE * 12);
const float MAX_MIX = 0.8;
const float MAX_MIX = 0.9;
const uint16_t RESO = 1024;
const uint16_t HALF_RESO = RESO / 2;
const int16_t PITCH_BEND_MIN = -168;
const int16_t PITCH_BEND_MAX = 134;
const int16_t PITCH_BEND_NEUTRAL = PITCH_BEND_MIN + (PITCH_BEND_MAX - PITCH_BEND_MIN) / 2;
const int16_t PITCH_BEND_COURSE = PITCH_BEND_MAX - PITCH_BEND_MIN;
const uint16_t MOD_WHEEL_MIN = 360;
const uint16_t MOD_WHEEL_MAX = 666;
const uint16_t MOD_WHEEL_NEUTRAL = MOD_WHEEL_MIN + (MOD_WHEEL_MAX - MOD_WHEEL_MIN) / 2;
const uint16_t MOD_WHEEL_COURSE = MOD_WHEEL_MAX - MOD_WHEEL_MIN;
const uint8_t MEGA1_RST = 2;
const uint8_t MEGA2_RST = 18;
// variables
uint8_t midiChannel = 1;
int8_t transposeOffset = 5;
uint16_t glide = 0;
bool glideEn = 0;
@ -80,6 +112,9 @@ uint8_t waveforms[6] = {WAVEFORM_SINE, WAVEFORM_TRIANGLE, WAVEFORM_SAWTOOTH,
uint8_t keyTrackIndex = 0;
uint8_t keyTrack[KEYTRACK_MAX] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// double CC track
uint8_t ccTempValue[32];
enum keyMode_t{
KEY_FIRST = 0,
KEY_LAST,
@ -89,25 +124,49 @@ enum keyMode_t{
keyMode_t keyMode = KEY_LAST;
struct midiSettings : public midi::DefaultSettings{
// static const bool UseRunningStatus = true;
static const long BaudRate = 115200;
};
//MIDI_CREATE_DEFAULT_INSTANCE();
//MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, usbMIDI);
// The one we use on synth
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial1, midi1, midiSettings);
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial4, midi2, midiSettings);
void setup() {
// midi settings, start and callback usbMIDI.begin(1); usbMIDI.setHandleNoteOn(handleNoteOn) usbMIDI.setHandleNoteOff(handleNoteOff) usbMIDI.setHandlePitchBend(handlePitchBend) usbMIDI.setHandleControlChange(handleControlChange);
// Mega resets
pinMode(MEGA1_RST, OUTPUT);
pinMode(MEGA2_RST, OUTPUT);
digitalWrite(MEGA1_RST, 0);
digitalWrite(MEGA2_RST, 0);
usbMIDI.setHandleNoteOn(handleNoteOn);
usbMIDI.setHandleNoteOff(handleNoteOff);
usbMIDI.setHandlePitchChange(handlePitchBend);
usbMIDI.setHandleControlChange(handleControlChange);
// midi settings, start and callback
midi1.begin(1);
midi1.turnThruOff();
midi1.setHandleNoteOn(handleNoteOn);
midi1.setHandleNoteOff(handleNoteOff);
midi1.setHandlePitchBend(handlePitchBend);
midi1.setHandleControlChange(handleControlChange);
Serial.begin(115200);
// Serial.println("started...");
midi2.begin(1);
midi2.turnThruOff();
midi2.setHandleControlChange(handleControlChange);
/*
Serial.begin(115200);
Serial.println("started...");
*/
AudioMemory(200);
digitalWrite(MEGA1_RST, 1);
digitalWrite(MEGA2_RST, 1);
delay(500);
midi1.sendControlChange(CC_ASK_FOR_DATA, 127, 1);
midi2.sendControlChange(CC_ASK_FOR_DATA, 127, 1);
// audio settings
// dc
dcKeyTrack.amplitude(0.0);
@ -122,11 +181,10 @@ void setup() {
dcOsc3Tune.amplitude(0.0);
dcPulse.amplitude(-0.95);
// amp
ampPitchBend.gain(3 * HALFTONE_TO_DC * 2);
ampModWheel.gain(0);
ampPreFilter.gain(0.7);
ampPreFilter.gain(1.0);
ampModEg.gain(0.01);
ampOsc3Mod.gain(1);
@ -207,18 +265,22 @@ void setup() {
bitCrushOutput.bits(16);
bitCrushOutput.sampleRate(44100.0);
usbMIDI.sendControlChange(CC_ASK_FOR_DATA, 127, 1);
delay(500);
midi1.sendControlChange(CC_ASK_FOR_DATA, 127, 1);
midi2.sendControlChange(CC_ASK_FOR_DATA, 127, 1);
}
void loop() {
usbMIDI.read();
midi1.read();
midi2.read();
}
void noteOn(uint8_t note, uint8_t velocity, bool trigger = 1){
float duration = (float)glideEn * (float)glide * 30.0;
float level = (float)note * HALFTONE_TO_DC;
float filterLevel = (float)note * FILTER_HALFTONE_TO_DC;
float duration = (float)glideEn * (float)glide * 3.75;
float level = ((float)note + 12 * transpose) * HALFTONE_TO_DC;
float filterLevel = ((float)note + 12 * transpose) * FILTER_HALFTONE_TO_DC;
AudioNoInterrupts();
dcKeyTrack.amplitude(level, duration);
@ -265,6 +327,11 @@ int8_t keyTrackRemoveNote(uint8_t note){
}
void handleNoteOn(uint8_t channel, uint8_t note, uint8_t velocity){
/*
Serial.print("note ");
Serial.print(note);
Serial.println(" on");
*/
switch(keyMode){
// When KEY_FIRST, we play the note only if there is not one already playing
case KEY_FIRST:
@ -294,6 +361,11 @@ void handleNoteOn(uint8_t channel, uint8_t note, uint8_t velocity){
}
void handleNoteOff(uint8_t channel, uint8_t note, uint8_t velocity){
/*
Serial.print("note ");
Serial.print(note);
Serial.println(" off");
*/
switch(keyMode){
case KEY_FIRST:
/* if(keyTrackRemoveNote(note) == 0){
@ -318,185 +390,228 @@ void handleNoteOff(uint8_t channel, uint8_t note, uint8_t velocity){
}
void handlePitchBend(uint8_t channel, int16_t bend){
dcPitchBend.amplitude(((float)bend - 64) / 128);
dcPitchBend.amplitude(((float)bend - PITCH_BEND_NEUTRAL) / PITCH_BEND_COURSE);
// Pitch bend goes from -168 to 134.
// neutral at -11 from up, -24 from down. :/
/*
Serial.print("pitch bend :");
Serial.println(bend);
*/
}
void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){
// Serial.println("control change");
/*
Serial.print("control change ");
Serial.println(command);
*/
uint16_t longValue = 0;
if(command < 32){
ccTempValue[command] = value;
/*
Serial.print("value : ");
Serial.print(value << 7);
Serial.print(" (sent : ");
Serial.print(value);
Serial.println(')');
*/
} else if(command < 64){
longValue = (uint16_t)ccTempValue[command - 32];
longValue <<= 7;
longValue += value;
/*
Serial.print("value : ");
Serial.print(longValue);
Serial.print(" (sent : ");
Serial.print(value);
Serial.println(')');
*/
} else {
/*
Serial.print("value : ");
Serial.println(value);
*/
}
switch(command){
case CC_MOD_WHEEL: // CC_1
ampModWheel.gain((float)value / 12 / 127);
case CC_MOD_WHEEL:
// CC_1
break;
case CC_MODULATION_MIX: // CC_3
AudioNoInterrupts();
modMixer.gain(0, (float)value / 127);
modMixer.gain(1, (127 - (float)value) / 127);
AudioInterrupts();
case CC_MODULATION_MIX:
// CC_3
break;
case CC_PORTAMENTO_TIME:
// CC_5
glide = value;
break;
case CC_OSC_TUNE:
// CC_9
dcOscTune.amplitude(HALFTONE_TO_DC * 2 * ((float)value - 64) / 127);
break;
case CC_OSC2_TUNE:
// CC_12
dcOsc2Tune.amplitude(HALFTONE_TO_DC * 12 * 2 * ((float)value - 64) / 127);
break;
case CC_OSC3_TUNE:
// CC_13
dcOsc3Tune.amplitude(HALFTONE_TO_DC * 12 * 2 * ((float)value - 64) / 127);
break;
case CC_OSC1_MIX:
// CC_14
oscMixer.gain(0, MAX_MIX * (float)value / 127);
break;
case CC_OSC2_MIX:
// CC_15
oscMixer.gain(1, MAX_MIX * (float)value / 127);
break;
case CC_OSC3_MIX:
// CC_16
oscMixer.gain(2, MAX_MIX * (float)value / 127);
break;
case CC_NOISE_MIX:
// CC_17
oscMixer.gain(3, MAX_MIX * (float)value / 127);
break;
case CC_FEEDBACK_MIX:
// CC_18
globalMixer.gain(1, MAX_MIX * (float)value / 127);
break;
case CC_FILTER_BAND:
// CC_19
AudioNoInterrupts();
bandMixer.gain(0, ((float)value - 127) / 127);
bandMixer.gain(1, (float)value / 127);
AudioInterrupts();
break;
case CC_FILTER_CUTOFF_FREQ:
// CC_20
// vcf.frequency((float)value * 32);
dcFilter.amplitude(((float)value - 64) / 127);
break;
case CC_FILTER_EMPHASIS:
// CC_21
vcf.resonance(0.7 + (float)value / 29.53);
break;
case CC_FILTER_CONTOUR:
// CC_22
filterMixer.gain(1, (float)value / 127);
break;
case CC_FILTER_ATTACK:
// CC_23
filterEnvelope.attack((float)value * 40);
break;
case CC_FILTER_DECAY:
// CC_24
filterDecay = value * 40;
AudioNoInterrupts();
filterEnvelope.decay(filterDecay);
if(decay) filterEnvelope.release(filterDecay);
AudioInterrupts();
break;
case CC_FILTER_SUSTAIN:
// CC_25
filterEnvelope.sustain((float)value / 127);
break;
case CC_FILTER_RELEASE:
// CC_26
filterEnvelope.release((float)value / 127);
break;
case CC_EG_ATTACK:
// CC_27
mainEnvelope.attack((float)value * 40);
break;
case CC_EG_DECAY:
// CC_28
egDecay = value * 40;
AudioNoInterrupts();
mainEnvelope.decay(egDecay);
if(decay) mainEnvelope.release(egDecay);
AudioInterrupts();
break;
case CC_EG_SUSTAIN:
// CC_29
mainEnvelope.sustain((float)value / 127);
break;
case CC_LFO_RATE:
// CC_31
dcLfoFreq.amplitude((float)value / 127);
break;
case CC_MOD_WHEEL_LSB:
// CC_33
ampModWheel.gain(((float)longValue - 1 - MOD_WHEEL_MIN) / 12 / MOD_WHEEL_COURSE);
// Mod wheel goes from 360 to 666.
/*
Serial.print("mod wheel : ");
Serial.println(longValue);
*/
break;
case CC_MODULATION_MIX_LSB:
// CC_35
AudioNoInterrupts();
modMixer.gain(0, (float)longValue / RESO);
modMixer.gain(1, (RESO - (float)longValue) / RESO);
AudioInterrupts();
break;
case CC_PORTAMENTO_TIME_LSB:
// CC_37
glide = longValue;
break;
case CC_OSC_TUNE_LSB:
// CC_41
dcOscTune.amplitude(HALFTONE_TO_DC * 2 * ((float)longValue - HALF_RESO) / RESO);
break;
case CC_OSC2_TUNE_LSB:
// CC_44
dcOsc2Tune.amplitude(HALFTONE_TO_DC * 12 * 2 * ((float)longValue - HALF_RESO) / RESO);
break;
case CC_OSC3_TUNE_LSB:
// CC_45
dcOsc3Tune.amplitude(HALFTONE_TO_DC * 12 * 2 * ((float)longValue - HALF_RESO) / RESO);
break;
case CC_OSC1_MIX_LSB:
// CC_46
oscMixer.gain(0, MAX_MIX * (float)longValue / RESO);
break;
case CC_OSC2_MIX_LSB:
// CC_47
oscMixer.gain(1, MAX_MIX * (float)longValue / RESO);
break;
case CC_OSC3_MIX_LSB:
// CC_48
oscMixer.gain(2, MAX_MIX * (float)longValue / RESO);
break;
case CC_NOISE_MIX_LSB:
// CC_49
oscMixer.gain(3, MAX_MIX * (float)longValue / RESO);
break;
case CC_FEEDBACK_MIX_LSB:
// CC_50
globalMixer.gain(1, MAX_MIX * (float)longValue / RESO);
break;
case CC_FILTER_BAND_LSB:
// CC_51
AudioNoInterrupts();
bandMixer.gain(0, ((float)longValue - RESO) / RESO);
bandMixer.gain(1, (float)longValue / RESO);
AudioInterrupts();
break;
case CC_FILTER_CUTOFF_FREQ_LSB:
// CC_52
dcFilter.amplitude(((float)longValue - HALF_RESO) / RESO);
break;
case CC_FILTER_EMPHASIS_LSB:
// CC_53
vcf.resonance(0.7 + (float)longValue / 237.90);
break;
case CC_FILTER_CONTOUR_LSB:
// CC_54
filterMixer.gain(1, (float)longValue / RESO);
break;
case CC_FILTER_ATTACK_LSB:
// CC_55
filterEnvelope.attack((float)longValue * 5.0);
break;
case CC_FILTER_DECAY_LSB:
// CC_56
filterEnvelope.decay((float)longValue * 5.0);
break;
case CC_FILTER_SUSTAIN_LSB:
// CC_57
filterEnvelope.sustain((float)longValue / RESO);
break;
case CC_EG_ATTACK_LSB:
case CC_FILTER_RELEASE_LSB:
// CC_58
filterEnvelope.release((float)longValue * 5.0);
break;
case CC_EG_DECAY_LSB:
case CC_EG_ATTACK_LSB:
// CC_59
mainEnvelope.attack((float)longValue * 5.0);
break;
case CC_EG_SUSTAIN_LSB:
case CC_EG_DECAY_LSB:
// CC_60
mainEnvelope.decay((float)longValue * 5.0);
break;
case CC_LFO_RATE_LSB:
case CC_EG_SUSTAIN_LSB:
// CC_61
mainEnvelope.sustain((float)longValue / RESO);
break;
case CC_EG_RELEASE_LSB:
// CC_62
mainEnvelope.release((float)longValue * 5.0);
break;
case CC_LFO_RATE_LSB:
// CC_63
dcLfoFreq.amplitude((float)longValue / RESO);
break;
case CC_PORTAMENTO_ON_OFF:
// CC_65
if(value > 63){
if(value < 64){
glideEn = 1;
} else {
glideEn = 0;
@ -608,6 +723,7 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){
mainTuneMixer.gain(3, 0);
}
break;
/*
case CC_DECAY_SW:
// CC_116
AudioNoInterrupts();
@ -622,6 +738,7 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){
}
AudioInterrupts();
break;
*/
case CC_MOD_MIX_1:
// CC_117
AudioNoInterrupts();
@ -646,12 +763,21 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){
}
AudioInterrupts();
break;
/* case CC_LFO_SHAPE: // CC_119
case CC_LFO_SHAPE:
// CC_119
AudioNoInterrupts();
if(value > 63){
lfoWaveform.begin(WAVEFORM_TRIANGLE);
lfoWaveform.offset(0.0);
lfoWaveform.amplitude(1.0);
} else {
lfoWaveform.begin(WAVEFORM_SQUARE);
lfoWaveform.offset(0.5);
lfoWaveform.amplitude(0.5);
}
AudioInterrupts();
break;
*/ default:
default:
break;
}
}

@ -0,0 +1,9 @@
0 GND
1 5V
2 pitch bend
3 mod wheel
4 LFO rate
5 glide
6 LFO shape
7 function
8 not used

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 58 KiB

Loading…
Cancel
Save