From 3a22ae1ac9dd158fa3ceaf3bf6c66bca0b1993f4 Mon Sep 17 00:00:00 2001 From: Pierre-Loup Martin Date: Sun, 22 Mar 2020 14:12:50 +0100 Subject: [PATCH] Added main volume control. Added 1 ms offset to attack an release, to avoid clipping with 0 value. It seems that it's already implemented in the Audio Library, so it needs mors investigation. Added filter mode function, to switch for band pass to a band stop filter with knob mid-course. Modified readme to specify libraries used. --- README.MD | 15 ++- minimoog_mega_1/defs.h | 4 +- minimoog_mega_2/defs.h | 6 +- minimoog_mega_2/minimoog_mega_2.ino | 11 +- minimoog_teensy/audio_setup.h | 87 ++++++++------- minimoog_teensy/defs.h | 4 +- minimoog_teensy/function settings.txt | 24 +++- minimoog_teensy/minimoog_teensy.ino | 155 +++++++++++++++++--------- 8 files changed, 196 insertions(+), 110 deletions(-) diff --git a/README.MD b/README.MD index ffbcf7b..795b55e 100644 --- a/README.MD +++ b/README.MD @@ -28,6 +28,14 @@ The main and lateral control panels, control panel bottom and rear enclosure are There was no sketch made for the walnut enclosure, but I should have done some : it's quite thin (around 7cm tall), and it gave me headaches to integrate some components in it. There is plenty of room, but I had to change things several time to accomodate the keyboard height, the front panel with sontrols and the rear panel with plugs... +#### Dependencies +Apart from Teensy audio, this program uses a few libraries. +[Arduino Midi library by FortySevenEffects](https://github.com/FortySevenEffects/arduino_midi_library), for internal communication between the boards. It's the one implemented by Teensy for usb MIDI, very complete. + +[PushButton](https://github.com/troisiemetype/PushButton) is used to debounce all switches, and detect changes. + +[expFilter](https://github.com/troisiemetype/expfilter) is used to smooth ADC readings. It gives a result close to a running average, but without the need of big tables to store results. + ## Function implemented As said above, the goal is to have something looking as close as possible to the original Minimoog. @@ -51,7 +59,7 @@ Maybe external input will be implemented once, but I wanted this feedback. the mixer is copy-paste on the original minimoog : a potentiometer for each of the five channels, and a switch for rapid on / off. ### Filter -The filter is (I believe) close from the minimoog one. Cutoff frequency and emphasis (resonance) are available. Their is an associated envelope generator that modulates the cutoff frequency. Their is also an addition compared to the minimoog : there is a knob to slide continuously from low pass to band pass, to high pass filter. +The filter is (I believe) close from the minimoog one. Cutoff frequency and emphasis (resonance) are available. Their is an associated envelope generator that modulates the cutoff frequency. Their is also an addition compared to the minimoog : there is a knob to slide continuously from low pass to band pass, to high pass filter. It can also slide continuously from low pass to high pass, thus resulting in a band stop filter at mid-course. (see _functions_ above) ### Envelope generator There are two envelope generators : one for the filter, the other for the global sound shape. On the original minimoog, decay can be used (_via_ a switch) to add release to notes. On this one a knob is there for, so this is a classic ADSR envelope. @@ -95,5 +103,10 @@ The detune table stores a fix detune coefficient for each of all 128 MIDI notes. Output resolution can be changed. The default is 16 bits, but any bitsize between 4 and 16 can be choose. The bitcrushing is applied at the end of the audio stream, just before the i2s / USB output. +#### Filter mode +The filter band knob slide continuously from low pass to high pass. It can be choosen wether : +* it slides from low pass to band pass for the lower half (high pass cut), and from band pass to high pass in the upper half (low pass cut), or +* it slides continuously from low pass to high pass, thus resulting in a band stop filter when knob is centered. (well, kind of : having a true band stop filter would mean to mix two different filters with frequency offsets. Here they overlap.) + #### MIDI channel setting The MIDI channel the synth listens and emit on when connected _via_ USB can be changed. Any channel from 1 to 16. \ No newline at end of file diff --git a/minimoog_mega_1/defs.h b/minimoog_mega_1/defs.h index 9d2c419..5abf9cb 100644 --- a/minimoog_mega_1/defs.h +++ b/minimoog_mega_1/defs.h @@ -160,7 +160,7 @@ // #define CC_FOOT_CTRL CC4 #define CC_PORTAMENTO_TIME CC5 // #define CC_DATA_ENTRY_MSB CC6 -// #define CC_CHANNEL_VOL CC7 +#define CC_CHANNEL_VOL CC7 // #define CC_BALANCE CC8 #define CC_OSC_TUNE CC9 // #define CC_PAN CC10 @@ -192,7 +192,7 @@ // #define CC_FOOT_CTRL_LSB CC36 #define CC_PORTAMENTO_TIME_LSB CC37 // #define CC_DATA_ENTRY_MSB_LSB CC38 -// #define CC_CHANNEL_VOL_LSB CC39 +#define CC_CHANNEL_VOL_LSB CC39 // #define CC_BALANCE_LSB CC40 #define CC_OSC_TUNE_LSB CC41 // #define CC_PAN_LSB CC42 diff --git a/minimoog_mega_2/defs.h b/minimoog_mega_2/defs.h index cbff6aa..5abf9cb 100644 --- a/minimoog_mega_2/defs.h +++ b/minimoog_mega_2/defs.h @@ -160,7 +160,7 @@ // #define CC_FOOT_CTRL CC4 #define CC_PORTAMENTO_TIME CC5 // #define CC_DATA_ENTRY_MSB CC6 -// #define CC_CHANNEL_VOL CC7 +#define CC_CHANNEL_VOL CC7 // #define CC_BALANCE CC8 #define CC_OSC_TUNE CC9 // #define CC_PAN CC10 @@ -192,7 +192,7 @@ // #define CC_FOOT_CTRL_LSB CC36 #define CC_PORTAMENTO_TIME_LSB CC37 // #define CC_DATA_ENTRY_MSB_LSB CC38 -// #define CC_CHANNEL_VOL_LSB CC39 +#define CC_CHANNEL_VOL_LSB CC39 // #define CC_BALANCE_LSB CC40 #define CC_OSC_TUNE_LSB CC41 // #define CC_PAN_LSB CC42 @@ -281,5 +281,3 @@ // #define CC_OMNI_MODE_ON CC125 // #define CC_MONO_MODE_ON CC126 // #define CC_POLY_MODE_ON CC127 - - diff --git a/minimoog_mega_2/minimoog_mega_2.ino b/minimoog_mega_2/minimoog_mega_2.ino index a9b79cb..a1ec251 100644 --- a/minimoog_mega_2/minimoog_mega_2.ino +++ b/minimoog_mega_2/minimoog_mega_2.ino @@ -49,6 +49,8 @@ * decay pot A12 CC 28 * sustain pot A13 CC 29 * release pot A14 CC 30 + * Mixer + * master volume pot A15 CC 07 * Communication * TX1 to teensy 18 * RX1 from teensy 19 @@ -63,8 +65,8 @@ // Constants const uint8_t NUM_SWITCHES = 3; -const uint8_t NUM_POTS = 15; -const uint8_t POT_FILTER_COEF = 15; +const uint8_t NUM_POTS = 16; +const uint8_t POT_FILTER_COEF = 20; // Note : pins are defined via tables, to improve code efficiency. // Digital pin definition @@ -93,7 +95,7 @@ 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, A15}; // Variables uint16_t potState[NUM_POTS]; @@ -214,6 +216,9 @@ void updateControls(){ case 14: controlChange = CC_EG_RELEASE; break; + case 15: + controlChange = CC_CHANNEL_VOL; + break; default: continue; diff --git a/minimoog_teensy/audio_setup.h b/minimoog_teensy/audio_setup.h index 5776013..aed4719 100644 --- a/minimoog_teensy/audio_setup.h +++ b/minimoog_teensy/audio_setup.h @@ -5,45 +5,47 @@ #include // GUItool: begin automatically generated code -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 +AudioSynthWaveformDc dcFilterEnvelope; //xy=101.75,518 +AudioSynthWaveformDc dcOscTune; //xy=160.75,127 +AudioSynthWaveformDc dcKeyTrack; //xy=163.75,91 +AudioSynthWaveformDc dcPitchBend; //xy=166.75,162 +AudioSynthWaveformDc dcFilter; //xy=268.75,573 +AudioSynthNoisePink pinkNoise; //xy=290.75,298 +AudioSynthWaveformDc dcLfoFreq; //xy=292.75,347 +AudioSynthNoiseWhite whiteNoise; //xy=293.75,262 +AudioEffectEnvelope filterEnvelope; //xy=299.75,518 +AudioSynthWaveformDc dcFilterKeyTrack; //xy=301.75,607 +AudioAmplifier ampPitchBend; //xy=339.75,162 +AudioMixer4 noiseMixer; //xy=476.75,295 +AudioSynthWaveformModulated lfoWaveform; //xy=481.75,347 +AudioAmplifier ampOsc3Mod; //xy=481.75,415 +AudioAmplifier ampModEg; //xy=491.75,453 +AudioMixer4 mainTuneMixer; //xy=563.75,111 +AudioMixer4 modMix2; //xy=687.75,448 +AudioMixer4 modMix1; //xy=688.75,377 +AudioSynthWaveformDc dcOsc3; //xy=690.75,171 +AudioMixer4 osc3ControlMixer; //xy=865.75,177 +AudioMixer4 modMixer; //xy=877.75,426 +AudioSynthWaveformDc dcOsc2Tune; //xy=1037.75,133 +AudioSynthWaveformDc dcOsc3Tune; //xy=1038.75,199 +AudioAmplifier ampModWheel; //xy=1091.75,426 +AudioMixer4 osc3TuneMixer; //xy=1221.75,195 +AudioMixer4 osc2TuneMixer; //xy=1222.75,131 +AudioSynthWaveformDc dcPulse; //xy=1238.75,43 +AudioSynthWaveformModulated osc1Waveform; //xy=1455.75,92 +AudioSynthWaveformModulated osc2Waveform; //xy=1456.75,129 +AudioSynthWaveformModulated osc3Waveform; //xy=1456.75,166 +AudioMixer4 oscMixer; //xy=1642.75,135 +AudioMixer4 globalMixer; //xy=1851.75,182 +AudioAmplifier ampPreFilter; //xy=2015.75,181 +AudioMixer4 filterMixer; //xy=2033.75,424 +AudioFilterStateVariable vcf; //xy=2202.75,418 +AudioMixer4 bandMixer; //xy=2373.75,413 +AudioEffectEnvelope mainEnvelope; //xy=2552.75,414 +AudioEffectBitcrusher bitCrushOutput; //xy=2788.75,411 +AudioAmplifier masterVolume; //xy=2981.75,410.75 +AudioOutputI2S i2s; //xy=3150.75,391 +//AudioOutputUSB usbOut; //xy=3153.75,429.75 AudioConnection patchCord1(dcFilterEnvelope, filterEnvelope); AudioConnection patchCord2(dcOscTune, 0, mainTuneMixer, 1); AudioConnection patchCord3(dcKeyTrack, 0, mainTuneMixer, 0); @@ -92,6 +94,9 @@ AudioConnection patchCord45(vcf, 2, bandMixer, 2); AudioConnection patchCord46(bandMixer, mainEnvelope); AudioConnection patchCord47(mainEnvelope, bitCrushOutput); AudioConnection patchCord48(mainEnvelope, 0, globalMixer, 1); -AudioConnection patchCord49(bitCrushOutput, 0, i2s, 0); -AudioConnection patchCord50(bitCrushOutput, 0, i2s, 1); +AudioConnection patchCord49(bitCrushOutput, masterVolume); +AudioConnection patchCord50(masterVolume, 0, i2s, 0); +AudioConnection patchCord51(masterVolume, 0, i2s, 1); +//AudioConnection patchCord52(masterVolume, 0, usbOut, 0); +//AudioConnection patchCord53(masterVolume, 0, usbOut, 1); // GUItool: end automatically generated code diff --git a/minimoog_teensy/defs.h b/minimoog_teensy/defs.h index 9d2c419..5abf9cb 100644 --- a/minimoog_teensy/defs.h +++ b/minimoog_teensy/defs.h @@ -160,7 +160,7 @@ // #define CC_FOOT_CTRL CC4 #define CC_PORTAMENTO_TIME CC5 // #define CC_DATA_ENTRY_MSB CC6 -// #define CC_CHANNEL_VOL CC7 +#define CC_CHANNEL_VOL CC7 // #define CC_BALANCE CC8 #define CC_OSC_TUNE CC9 // #define CC_PAN CC10 @@ -192,7 +192,7 @@ // #define CC_FOOT_CTRL_LSB CC36 #define CC_PORTAMENTO_TIME_LSB CC37 // #define CC_DATA_ENTRY_MSB_LSB CC38 -// #define CC_CHANNEL_VOL_LSB CC39 +#define CC_CHANNEL_VOL_LSB CC39 // #define CC_BALANCE_LSB CC40 #define CC_OSC_TUNE_LSB CC41 // #define CC_PAN_LSB CC42 diff --git a/minimoog_teensy/function settings.txt b/minimoog_teensy/function settings.txt index 9a95583..7b24cef 100644 --- a/minimoog_teensy/function settings.txt +++ b/minimoog_teensy/function settings.txt @@ -1,24 +1,38 @@ Keyboard mode - first - last - lower - upper + note : in any case, when there are several notes pressed, releasing one will trigger another, according to priority mode. + first The first key pressed has priority. It must be released for another to trigger note + last Last key pressed triggers new note. + lower The lower key on the keyboard has priority + upper The upper key has priority Bitcrush + bit crusher : reduce resolution of the samples before output 4 - 16 Midi in channel + the channel the synth reacts to when connected to USB MIDI 1 - 16 Midi out channel + the channel the synths sends on 1 - 16 Retrigger + when a key is pressed and there was already one (or several), retrigger the envelope or no 0 / 1 Detune + Add a small amount of detune to each note, to simulate a resistor ladder vintage keyboard off soft medium hard - reset \ No newline at end of file + reset + +filter mode + The filter band can be changed steplessly from low pass to high pass. + This gives the choice of how it behave at mid course + Band pass The lower half of the control mixes low pass with band pass. High pass cut. + The upper half mixes band pass with high pass. Low pass cut. + Band stop The low and high pass are mixed continuously, band pass cut, resulting in a band stop + on middle position. diff --git a/minimoog_teensy/minimoog_teensy.ino b/minimoog_teensy/minimoog_teensy.ino index f5c32b1..ade76fa 100644 --- a/minimoog_teensy/minimoog_teensy.ino +++ b/minimoog_teensy/minimoog_teensy.ino @@ -66,6 +66,7 @@ const uint8_t NUM_KEYS = 30; const uint8_t MAX_OCTAVE = 10; const uint8_t FILTER_MAX_OCTAVE = 5; + const float NOTE_MIDI_0 = 8.1757989156434; const float NOTE_RATIO = 1.0594630943593; @@ -85,12 +86,13 @@ 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; - +/* +// Moved to Mega 1 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; @@ -100,6 +102,7 @@ const uint16_t EE_MIDI_IN_CH_ADD = 2; const uint16_t EE_MIDI_OUT_CH_ADD = 3; const uint16_t EE_TRIGGER_ADD = 4; const uint16_t EE_DETUNE_ADD = 5; +const uint16_t EE_FILTER_MODE = 6; const uint16_t EE_DETUNE_TABLE_ADD = 20; // variables @@ -125,6 +128,8 @@ bool decay = 0; float filterDecay = 0; float egDecay = 0; +int16_t filterBandValue = 0; + // Waveforms uint8_t waveforms[6] = {WAVEFORM_SINE, WAVEFORM_TRIANGLE, WAVEFORM_SAWTOOTH, WAVEFORM_SAWTOOTH_REVERSE, WAVEFORM_SQUARE, WAVEFORM_PULSE}; @@ -147,6 +152,7 @@ enum function_t{ FUNCTION_RETRIGGER, FUNCTION_DETUNE, FUNCTION_BITCRUSH, + FUNCTION_FILTER_MODE, FUNCTION_MIDI_IN_CHANNEL, FUNCTION_MIDI_OUT_CHANNEL, }; @@ -173,6 +179,13 @@ enum detune_t{ detune_t detune = DETUNE_OFF; float detuneCoeff[4] = {0, 0.1, 0.3, 0.5}; +enum filterMode_t{ + FILTER_BAND_PASS = 0, + FILTER_BAND_STOP, +}; + +filterMode_t filterMode = FILTER_BAND_PASS; + uint8_t bitCrushLevel = 16; struct midiSettings : public midi::DefaultSettings{ @@ -181,7 +194,7 @@ struct midiSettings : public midi::DefaultSettings{ }; // USB midi for sending and receiving to other device or computer. -// MIDI_CREATE_DEFAULT_INSTANCE(); +MIDI_CREATE_DEFAULT_INSTANCE(); // The ones we use on synth for internal communication between Mega and Teensy MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial1, midi1, midiSettings); MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial4, midi2, midiSettings); @@ -219,6 +232,7 @@ void setup() { EEPROM.get(EE_MIDI_OUT_CH_ADD, midiOutChannel); EEPROM.get(EE_TRIGGER_ADD, noteRetrigger); EEPROM.get(EE_DETUNE_ADD, detune); + EEPROM.get(EE_FILTER_MODE, filterMode); uint16_t address = EE_DETUNE_TABLE_ADD; for(uint16_t i = 0; i < 128; ++i){ @@ -226,11 +240,10 @@ void setup() { address += 4; } // TODO : check how to receive and transmit on different channels. -// MIDI.begin(midiInChannel); -// MIDI.turnThruOff(); -// MIDI.setHandleNoteOn(handleNoteOn); -// MIDI.setHandleNoteOff(handleNoteOff); -// MIDI.setHandlePitchBend(handlePitchBend); + usbMIDI.setHandleNoteOn(handleNoteOn); + usbMIDI.setHandleNoteOff(handleNoteOff); +// usbMIDI.setHandlePitchBend(handlePitchBend); + usbMIDI.begin(); AudioMemory(200); @@ -255,6 +268,7 @@ void setup() { ampPreFilter.gain(1.0); ampModEg.gain(0.1); ampOsc3Mod.gain(1); + masterVolume.gain(1.0); osc1Waveform.frequencyModulation(MAX_OCTAVE); osc2Waveform.frequencyModulation(MAX_OCTAVE); @@ -337,7 +351,7 @@ void setup() { delay(1000); digitalWrite(13, 0); - delay(100); + delay(200); // Blink. For debug. And letting a bit more time to Mega 1 to start. for(uint8_t i = 0; i < 5; ++i){ @@ -356,17 +370,17 @@ void setup() { void loop() { midi1.read(); midi2.read(); + usbMIDI.read(midiInChannel); } void noteOn(uint8_t note, uint8_t velocity, bool trigger = 1){ -// MIDI.sendNoteOn(note, velocity, 1); /* Serial.print("playing :"); Serial.println(note); */ nowPlaying = note; float fineTune = detuneTable[note] * detuneCoeff[detune]; - float duration = (float)glideEn * (float)glide * 3.75; + float duration = 1.0 + (float)glideEn * (float)glide * 3.75; float level = ((float)note + 12 * transpose) * HALFTONE_TO_DC; level += fineTune; float filterLevel = (((float)note - FILTER_BASE_NOTE) + (12 * transpose)) * FILTER_HALFTONE_TO_DC; @@ -383,8 +397,6 @@ void noteOn(uint8_t note, uint8_t velocity, bool trigger = 1){ } void noteOff(){ -// MIDI.sendNoteOff(nowPlaying, 0, 1); - AudioNoInterrupts(); filterEnvelope.noteOff(); mainEnvelope.noteOff(); @@ -474,6 +486,7 @@ void handleInternalNoteOn(uint8_t channel, uint8_t note, uint8_t velocity){ handleKeyboardFunction(note, 1); return; } + usbMIDI.sendNoteOn(note + MIDI_OFFSET + 12 * transpose, velocity, midiOutChannel); handleNoteOn(channel, note + MIDI_OFFSET, velocity); } @@ -554,6 +567,7 @@ void handleInternalNoteOff(uint8_t channel, uint8_t note, uint8_t velocity){ // handleKeyboardFunction(note, 0); return; } + usbMIDI.sendNoteOff(note + MIDI_OFFSET + 12 * transpose, 0, midiOutChannel); handleNoteOff(channel, note + MIDI_OFFSET, velocity); } @@ -636,7 +650,7 @@ void handleNoteOff(uint8_t channel, uint8_t note, uint8_t velocity){ void handlePitchBend(uint8_t channel, int16_t bend){ // dcPitchBend.amplitude(((float)bend - PITCH_BEND_NEUTRAL) / PITCH_BEND_COURSE); // Pitch bend goes from -168 to 134. - dcPitchBend.amplitude(((float)bend) / 8190); +// dcPitchBend.amplitude(((float)bend) / 8190); // neutral at -11 from up, -24 from down. :/ // MIDI.sendPitchBend(bend - PITCH_BEND_NEUTRAL, 0); /* @@ -691,6 +705,9 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){ case CC_PORTAMENTO_TIME: // CC_5 break; + case CC_CHANNEL_VOL: + // CC_7 + break; case CC_OSC_TUNE: // CC_9 break; @@ -773,6 +790,10 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){ // CC_37 glide = longValue; break; + case CC_CHANNEL_VOL_LSB: + // CC_39 + masterVolume.gain((float)longValue / RESO); + break; case CC_OSC_TUNE_LSB: // CC_41 dcOscTune.amplitude(HALFTONE_TO_DC * 2 * ((float)longValue - HALF_RESO) / RESO); @@ -807,15 +828,22 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){ break; case CC_FILTER_BAND_LSB: // CC_51 + filterBandValue = longValue; AudioNoInterrupts(); - if(longValue < HALF_RESO){ - bandMixer.gain(0, ((float)HALF_RESO - (float)longValue) / HALF_RESO); - bandMixer.gain(1, (float)longValue / HALF_RESO); - bandMixer.gain(2, 0.0); - } else { - bandMixer.gain(0, 0.0); - bandMixer.gain(1, ((float)RESO - (float)longValue) / HALF_RESO); - bandMixer.gain(2, ((float)longValue - HALF_RESO) / HALF_RESO); + if(filterMode == FILTER_BAND_PASS){ + if(longValue < HALF_RESO){ + bandMixer.gain(0, ((float)HALF_RESO - (float)longValue) / HALF_RESO); + bandMixer.gain(1, (float)longValue / HALF_RESO); + bandMixer.gain(2, 0.0); + } else { + bandMixer.gain(0, 0.0); + bandMixer.gain(1, ((float)RESO - (float)longValue) / HALF_RESO); + bandMixer.gain(2, ((float)longValue - HALF_RESO) / HALF_RESO); + } + } else if(filterMode == FILTER_BAND_STOP){ + bandMixer.gain(0, (float)(RESO - longValue) / RESO); + bandMixer.gain(1, 0.0); + bandMixer.gain(2, (float)longValue / RESO); } AudioInterrupts(); break; @@ -833,7 +861,7 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){ break; case CC_FILTER_ATTACK_LSB: // CC_55 - filterEnvelope.attack((float)longValue * 5.0); + filterEnvelope.attack(1 + (float)longValue * 5.0); break; case CC_FILTER_DECAY_LSB: // CC_56 @@ -845,11 +873,11 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){ break; case CC_FILTER_RELEASE_LSB: // CC_58 - filterEnvelope.release((float)longValue * 5.0); + filterEnvelope.release(1 + (float)longValue * 5.0); break; case CC_EG_ATTACK_LSB: // CC_59 - mainEnvelope.attack((float)longValue * 5.0); + mainEnvelope.attack(1 + (float)longValue * 5.0); break; case CC_EG_DECAY_LSB: // CC_60 @@ -861,7 +889,7 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){ break; case CC_EG_RELEASE_LSB: // CC_62 - mainEnvelope.release((float)longValue * 5.0); + mainEnvelope.release(1 + (float)longValue * 5.0); break; case CC_LFO_RATE_LSB: // CC_63 @@ -1047,15 +1075,15 @@ void handleControlChange(uint8_t channel, uint8_t command, uint8_t value){ } } -void handleKeyboardFunction(uint8_t note, bool active){ +void handleKeyboardFunction(uint8_t key, bool active){ // /* Serial.print("key pressed : "); - Serial.println(note); + Serial.println(key); */ // Change function - switch(note){ + switch(key){ case 0: // lower DO currentFunction = FUNCTION_KEYBOARD_MODE; @@ -1078,61 +1106,84 @@ void handleKeyboardFunction(uint8_t note, bool active){ break; case 7: // lower SOL - currentFunction = FUNCTION_MIDI_IN_CHANNEL; -// Serial.println("midi in channel"); + currentFunction = FUNCTION_FILTER_MODE; break; case 9: // lower LA - currentFunction = FUNCTION_MIDI_OUT_CHANNEL; -// Serial.println("midi out channel"); + currentFunction = FUNCTION_MIDI_IN_CHANNEL; +// Serial.println("midi in channel"); break; case 11: - // lower Si + // lower SI + currentFunction = FUNCTION_MIDI_OUT_CHANNEL; +// Serial.println("midi out channel"); break; default: - if(note < 12) return; - note -= 12; + if(key < 12) return; + key -= 12; break; } switch(currentFunction){ case FUNCTION_KEYBOARD_MODE: - if(note > KEY_UPPER) return; - keyMode = (keyMode_t)note; + if(key > KEY_UPPER) return; + keyMode = (keyMode_t)key; EEPROM.put(EE_KEYBOARD_MODE_ADD, keyMode); break; case FUNCTION_RETRIGGER: - if(note > 1) return; - noteRetrigger = note; + if(key > 1) return; + noteRetrigger = key; EEPROM.put(EE_TRIGGER_ADD, noteRetrigger); break; case FUNCTION_DETUNE: - if(note > DETUNE_RESET) return; - if(note == DETUNE_RESET){ + if(key > DETUNE_RESET) return; + if(key == DETUNE_RESET){ // run a new detuning table resetDetuneTable(); } else { - detune = (detune_t)note; + detune = (detune_t)key; EEPROM.put(EE_DETUNE_ADD, detune); } break; case FUNCTION_BITCRUSH: - if(note > 12) return; - note += 4; - bitCrushOutput.bits(note); - EEPROM.put(EE_BITCRUSH_ADD, note); - break; + if(key > 12) return; + key += 4; + bitCrushOutput.bits(key); + EEPROM.put(EE_BITCRUSH_ADD, key); + break; + case FUNCTION_FILTER_MODE: + if(key > 1) return; + filterMode = (filterMode_t)key; + EEPROM.put(EE_FILTER_MODE, filterMode); + AudioNoInterrupts(); + if(filterMode == FILTER_BAND_PASS){ + if(filterBandValue < HALF_RESO){ + bandMixer.gain(0, ((float)HALF_RESO - (float)filterBandValue) / HALF_RESO); + bandMixer.gain(1, (float)filterBandValue / HALF_RESO); + bandMixer.gain(2, 0.0); + } else { + bandMixer.gain(0, 0.0); + bandMixer.gain(1, ((float)RESO - (float)filterBandValue) / HALF_RESO); + bandMixer.gain(2, ((float)filterBandValue - HALF_RESO) / HALF_RESO); + } + } else if(filterMode == FILTER_BAND_STOP){ + bandMixer.gain(0, (float)(RESO - filterBandValue) / RESO); + bandMixer.gain(1, 0.0); + bandMixer.gain(2, (float)filterBandValue / RESO); + } + AudioInterrupts(); + break; case FUNCTION_MIDI_IN_CHANNEL: // change (usb) midi in channel - if(note > 16)return; - midiInChannel = note; + if(key > 16)return; + midiInChannel = key + 1; //MIDI.begin(midiInChannel); EEPROM.put(EE_MIDI_IN_CH_ADD, midiInChannel); break; case FUNCTION_MIDI_OUT_CHANNEL: // change (usb) midi out channel - if(note > 16)return; - midiOutChannel = note; + if(key > 16)return; + midiOutChannel = key + 1; //MIDI.begin(midiInChannel); EEPROM.put(EE_MIDI_OUT_CH_ADD, midiOutChannel); break;