From ae7d5a7f959cb906ee9205d050c2833fd1eddea4 Mon Sep 17 00:00:00 2001 From: Jason Justian Date: Wed, 22 Aug 2018 22:20:49 -0400 Subject: [PATCH] ADSR: Improve resolution, Capt MIDI: Add beat clock in --- .gitignore | 1 - software/APP_Boilerplate.ino.txt | 2 +- software/o_c_REV/APP_HEMISPHERE.ino | 2 +- software/o_c_REV/APP_MIDI.ino | 79 ++++++++++++++----- software/o_c_REV/APP_SCALEEDITOR.ino | 2 +- software/o_c_REV/APP_THEDARKESTTIMELINE.ino | 2 +- software/o_c_REV/HEM_ADEG.ino | 2 +- software/o_c_REV/HEM_ADSREG.ino | 16 ++-- .../{SystemExclusiveHandler.h => HSMIDI.h} | 12 +-- 9 files changed, 80 insertions(+), 38 deletions(-) rename software/o_c_REV/{SystemExclusiveHandler.h => HSMIDI.h} (98%) diff --git a/.gitignore b/.gitignore index d78672704..91576e3b9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ Release .cproject .gitignore.swp .settings/ -*.ino sloeber.ino.cpp .gitignore bin diff --git a/software/APP_Boilerplate.ino.txt b/software/APP_Boilerplate.ino.txt index 826473879..5fa518a5a 100644 --- a/software/APP_Boilerplate.ino.txt +++ b/software/APP_Boilerplate.ino.txt @@ -19,7 +19,7 @@ // SOFTWARE. #include "HSApplication.h" -#include "SystemExclusiveHandler.h" +#include "HSMIDI.h" class ClassName : public HSApplication, public SystemExclusiveHandler { public: diff --git a/software/o_c_REV/APP_HEMISPHERE.ino b/software/o_c_REV/APP_HEMISPHERE.ino index e914cc3d6..c9eea8f3b 100644 --- a/software/o_c_REV/APP_HEMISPHERE.ino +++ b/software/o_c_REV/APP_HEMISPHERE.ino @@ -27,7 +27,7 @@ namespace menu = OC::menu; #include "hemisphere_config.h" #include "HemisphereApplet.h" -#include "SystemExclusiveHandler.h" +#include "HSMIDI.h" #define DECLARE_APPLET(id, categories, class_name) \ { id, categories, class_name ## _Start, class_name ## _Controller, class_name ## _View, class_name ## _Screensaver, \ diff --git a/software/o_c_REV/APP_MIDI.ino b/software/o_c_REV/APP_MIDI.ino index 75d304972..40a3a49c8 100644 --- a/software/o_c_REV/APP_MIDI.ino +++ b/software/o_c_REV/APP_MIDI.ino @@ -23,7 +23,7 @@ // See https://www.pjrc.com/teensy/td_midi.html #include "HSApplication.h" -#include "SystemExclusiveHandler.h" +#include "HSMIDI.h" const uint16_t MIDI_INDICATOR_COUNTDOWN = 2000; const int MIDI_PARAMETER_COUNT = 40; @@ -31,18 +31,23 @@ const int MIDI_CURRENT_SETUP = MIDI_PARAMETER_COUNT * 4; const int MIDI_SETTING_LAST = MIDI_CURRENT_SETUP + 1; const int MIDI_LOG_MAX_SIZE = 101; -const char* const midi_in_functions[13] = { - "--", "Note", "Gate", "Trig", "Veloc", "Mod", "Aft", "Bend", "Expr", "Pan", "Hold", "Brth", "yAxis" +// Icons that are used next to the menu items +const uint8_t MIDI_midi_icon[8] = {0x3c, 0x42, 0x91, 0x45, 0x45, 0x91, 0x42, 0x3c}; +const uint8_t MIDI_note_icon[8] = {0xc0, 0xe0, 0xe0, 0xe0, 0x7f, 0x02, 0x14, 0x08}; +const uint8_t MIDI_clock_icon[8] = {0x9c, 0xa2, 0xc1, 0xcf, 0xc9, 0xa2, 0x9c, 0x00}; + +const char* const midi_in_functions[17] = { + "--", "Note", "Gate", "Trig", "Veloc", "Mod", "Aft", "Bend", "Expr", "Pan", "Hold", "Brth", "yAxis", "Qtr", "8th", "16th", "24ppq" }; const char* const midi_out_functions[12] = { "--", "Note", "Leg.", "Veloc", "Mod", "Aft", "Bend", "Expr", "Pan", "Hold", "Brth", "yAxis" }; #define MIDI_SETUP_PARAMETER_LIST \ -{ 0, 0, 12, "MIDI > A", midi_in_functions, settings::STORAGE_TYPE_U8 },\ -{ 0, 0, 12, "MIDI > B", midi_in_functions, settings::STORAGE_TYPE_U8 },\ -{ 0, 0, 12, "MIDI > C", midi_in_functions, settings::STORAGE_TYPE_U8 },\ -{ 0, 0, 12, "MIDI > D", midi_in_functions, settings::STORAGE_TYPE_U8 },\ +{ 0, 0, 16, "MIDI > A", midi_in_functions, settings::STORAGE_TYPE_U8 },\ +{ 0, 0, 16, "MIDI > B", midi_in_functions, settings::STORAGE_TYPE_U8 },\ +{ 0, 0, 16, "MIDI > C", midi_in_functions, settings::STORAGE_TYPE_U8 },\ +{ 0, 0, 16, "MIDI > D", midi_in_functions, settings::STORAGE_TYPE_U8 },\ { 0, 0, 11, "1 > MIDI", midi_out_functions, settings::STORAGE_TYPE_U8 },\ { 0, 0, 11, "2 > MIDI", midi_out_functions, settings::STORAGE_TYPE_U8 },\ { 0, 0, 11, "3 > MIDI", midi_out_functions, settings::STORAGE_TYPE_U8 },\ @@ -93,7 +98,11 @@ enum MIDI_IN_FUNCTION { MIDI_IN_PAN, MIDI_IN_HOLD, MIDI_IN_BREATH, - MIDI_IN_Y_AXIS + MIDI_IN_Y_AXIS, + MIDI_IN_CLOCK_4TH, + MIDI_IN_CLOCK_8TH, + MIDI_IN_CLOCK_16TH, + MIDI_IN_CLOCK_24PPQN, }; enum MIDI_OUT_FUNCTION { @@ -111,13 +120,13 @@ enum MIDI_OUT_FUNCTION { MIDI_OUT_Y_AXIS, }; -const char* const midi_messages[6] = { - "Note", "Off", "CC#", "Aft", "Bend", "SysEx" +const char* const midi_messages[7] = { + "Note", "Off", "CC#", "Aft", "Bend", "SysEx", "Clock" }; struct CaptainMIDILog { bool midi_in; // 0 = out, 1 = in char io; // 1, 2, 3, 4, A, B, C, D - uint8_t message; // 0 = Note On, 1 = Note Off, 2 = CC, 3 = Aftertouch, 4 = Bend, 5 = SysEx + uint8_t message; // 0 = Note On, 1 = Note Off, 2 = CC, 3 = Aftertouch, 4 = Bend, 5 = SysEx, 6 = Clock uint8_t channel; // MIDI channel int16_t data1; int16_t data2; @@ -164,6 +173,12 @@ struct CaptainMIDILog { if (data2 > 0) graphics.print("+"); graphics.print(data2); // Aftertouch or bend value } + + if (message == 6) { + graphics.print(data1); + graphics.print("/"); + graphics.print(data2); + } } } }; @@ -269,6 +284,7 @@ public: indicator_out[ch] = 0; Out(ch, 0); } + clock_count = 0; } void Panic() { @@ -378,6 +394,7 @@ private: // MIDI In int note_in[4]; // Up to four notes at a time are kept track of with MIDI In uint16_t indicator_in[4]; // A MIDI indicator will display next to MIDI In assignment + uint8_t clock_count; // MIDI clock counter (24ppqn) // MIDI Out bool gated[4]; // Current gated status of each input @@ -388,10 +405,6 @@ private: uint16_t indicator_out[4]; // A MIDI indicator will display next to MIDI Out assignment void DrawSetupScreens() { - // Icons that are used next to the menu items - const uint8_t midi_icon[8] = {0x3c, 0x42, 0x91, 0x45, 0x45, 0x91, 0x42, 0x3c}; - const uint8_t note_icon[8] = {0xc0, 0xe0, 0xe0, 0xe0, 0x7f, 0x02, 0x14, 0x08}; - // Create the header, showing the current Setup and Screen name gfxHeader("Setup "); graphics.print(get_setup_number() + 1); @@ -419,13 +432,21 @@ private: graphics.setPrintPos(70, list_item.y + 2); graphics.print(midi_note_numbers[note_in[p]]); } - } else graphics.drawBitmap8(70, list_item.y + 2, 8, midi_icon); + } else graphics.drawBitmap8(70, list_item.y + 2, 8, MIDI_midi_icon); } // Indicate if the assignment is a note type if (get_in_channel(p) > 0 && get_in_assign(p) == MIDI_IN_NOTE) - graphics.drawBitmap8(56, list_item.y + 1, 8, note_icon); + graphics.drawBitmap8(56, list_item.y + 1, 8, MIDI_note_icon); else if (screen > 1) suppress = 1; + + // Indicate if the assignment is a clock + if (get_in_assign(p) >= MIDI_IN_CLOCK_4TH) { + uint8_t o_x = (clock_count < 12) ? 2 : 0; + graphics.drawBitmap8(80 + o_x, list_item.y + 1, 8, MIDI_clock_icon); + if (screen > 0) suppress = 1; + } + } else { // It's a MIDI Out assignment p -= 4; if (indicator_out[p] > 0 || note_out[p] > -1) { @@ -434,12 +455,12 @@ private: graphics.setPrintPos(70, list_item.y + 2); graphics.print(midi_note_numbers[note_out[p]]); } - } else graphics.drawBitmap8(70, list_item.y + 2, 8, midi_icon); + } else graphics.drawBitmap8(70, list_item.y + 2, 8, MIDI_midi_icon); } // Indicate if the assignment is a note type if (get_out_channel(p) > 0 && (get_out_assign(p) == MIDI_OUT_NOTE || get_out_assign(p) == MIDI_OUT_LEGATO)) - graphics.drawBitmap8(56, list_item.y + 1, 8, note_icon); + graphics.drawBitmap8(56, list_item.y + 1, 8, MIDI_note_icon); else if (screen > 1) suppress = 1; } @@ -618,6 +639,12 @@ private: // Handle system exclusive dump for Setup data if (message == MIDI_MSG_SYSEX) OnReceiveSysEx(); + // Listen for incoming clock + if (message == MIDI_MSG_REALTIME && data1 == 0) { + if (++clock_count >= 24) clock_count = 0; + } + + bool note_captured = 0; // A note or gate should only be captured by bool gate_captured = 0; // one assignment, to allow polyphony in the interface @@ -716,11 +743,25 @@ private: indicator = 1; } + if (in_fn >= MIDI_IN_CLOCK_4TH) { + // Clock is unlogged because there can be a lot of it + uint8_t mod = get_clock_mod(in_fn); + if (clock_count % mod == 0) ClockOut(ch); + } + if (indicator) indicator_in[ch] = MIDI_INDICATOR_COUNTDOWN; } } } + uint8_t get_clock_mod(int fn) { + uint8_t mod = 1; + if (fn == MIDI_IN_CLOCK_4TH) mod = 24; + if (fn == MIDI_IN_CLOCK_8TH) mod = 12; + if (fn == MIDI_IN_CLOCK_16TH) mod = 6; + return mod; + } + int get_in_assign(int ch) { int setup_offset = get_setup_number() * MIDI_PARAMETER_COUNT; return values_[ch + setup_offset]; diff --git a/software/o_c_REV/APP_SCALEEDITOR.ino b/software/o_c_REV/APP_SCALEEDITOR.ino index 3b62912ba..df0a3b198 100644 --- a/software/o_c_REV/APP_SCALEEDITOR.ino +++ b/software/o_c_REV/APP_SCALEEDITOR.ino @@ -22,7 +22,7 @@ #include "braids_quantizer_scales.h" #include "OC_scales.h" #include "HSApplication.h" -#include "SystemExclusiveHandler.h" +#include "HSMIDI.h" #include "SegmentDisplay.h" class ScaleEditor : public HSApplication, public SystemExclusiveHandler { diff --git a/software/o_c_REV/APP_THEDARKESTTIMELINE.ino b/software/o_c_REV/APP_THEDARKESTTIMELINE.ino index 491c3c6ee..6438f9d57 100644 --- a/software/o_c_REV/APP_THEDARKESTTIMELINE.ino +++ b/software/o_c_REV/APP_THEDARKESTTIMELINE.ino @@ -28,7 +28,7 @@ #include "braids_quantizer_scales.h" #include "OC_scales.h" #include "HSApplication.h" -#include "SystemExclusiveHandler.h" +#include "HSMIDI.h" const bool DT_CV_TIMELINE = 0; const bool DT_PROBABILITY_TIMELINE = 1; diff --git a/software/o_c_REV/HEM_ADEG.ino b/software/o_c_REV/HEM_ADEG.ino index 458b92ec8..90e3d30c1 100644 --- a/software/o_c_REV/HEM_ADEG.ino +++ b/software/o_c_REV/HEM_ADEG.ino @@ -19,7 +19,7 @@ // SOFTWARE. #define HEM_ADEG_MAX_VALUE 255 -#define HEM_ADEG_MAX_TICKS 32000 +#define HEM_ADEG_MAX_TICKS 33333 class ADEG : public HemisphereApplet { public: diff --git a/software/o_c_REV/HEM_ADSREG.ino b/software/o_c_REV/HEM_ADSREG.ino index d23fdb92e..b1ed8fa13 100644 --- a/software/o_c_REV/HEM_ADSREG.ino +++ b/software/o_c_REV/HEM_ADSREG.ino @@ -23,13 +23,13 @@ #define HEM_EG_SUSTAIN 2 #define HEM_EG_RELEASE 3 #define HEM_EG_NO_STAGE -1 -#define HEM_EG_MAX_VALUE 200 +#define HEM_EG_MAX_VALUE 255 #define HEM_SUSTAIN_CONST 35 #define HEM_EG_DISPLAY_HEIGHT 30 // About four seconds -#define HEM_EG_MAX_TICKS_AD 66667 +#define HEM_EG_MAX_TICKS_AD 33333 // About eight seconds #define HEM_EG_MAX_TICKS_R 133333 @@ -145,10 +145,10 @@ protected: private: int edit_stage; - int attack; // Attack rate from 1-200 where 1 is fast - int decay; // Decay rate from 1-200 where 1 is fast - int sustain; // Sustain level from 1-200 where 1 is low - int release; // Release rate from 1-200 where 1 is fast + int attack; // Attack rate from 1-255 where 1 is fast + int decay; // Decay rate from 1-255 where 1 is fast + int sustain; // Sustain level from 1-255 where 1 is low + int release; // Release rate from 1-255 where 1 is fast int attack_mod; // Modification to attack from CV1 int release_mod; // Modification to release from CV2 @@ -245,10 +245,10 @@ private: } void ReleaseAmplitude(int ch) { - int effective_release = constrain(release + release_mod, 1, HEM_EG_MAX_VALUE); + int effective_release = constrain(release + release_mod, 1, HEM_EG_MAX_VALUE) - 1; int total_stage_ticks = Proportion(effective_release, HEM_EG_MAX_VALUE, HEM_EG_MAX_TICKS_R); int ticks_remaining = total_stage_ticks - stage_ticks[ch]; - if (effective_release == 1) ticks_remaining = 0; + if (effective_release == 0) ticks_remaining = 0; if (ticks_remaining <= 0 || amplitude[ch] <= 0) { // End of release; turn off envelope stage[ch] = HEM_EG_NO_STAGE; stage_ticks[ch] = 0; diff --git a/software/o_c_REV/SystemExclusiveHandler.h b/software/o_c_REV/HSMIDI.h similarity index 98% rename from software/o_c_REV/SystemExclusiveHandler.h rename to software/o_c_REV/HSMIDI.h index ae9de83ef..704095e24 100644 --- a/software/o_c_REV/SystemExclusiveHandler.h +++ b/software/o_c_REV/HSMIDI.h @@ -27,16 +27,18 @@ // * MIDI note/CV quantizer functions ////////////////////////////////////////////////////////////////////////// -#ifndef SYSEX_HANDLER_H_ -#define SYSEX_HANDLER_H_ +#ifndef HSMIDI_H +#define HSMIDI_H // Teensyduino USB MIDI Library message numbers +// See https://www.pjrc.com/teensy/td_midi.html const uint8_t MIDI_MSG_NOTE_ON = 1; const uint8_t MIDI_MSG_NOTE_OFF = 0; const uint8_t MIDI_MSG_MIDI_CC = 3; const uint8_t MIDI_MSG_AFTERTOUCH = 5; const uint8_t MIDI_MSG_PITCHBEND = 6; const uint8_t MIDI_MSG_SYSEX = 7; +const uint8_t MIDI_MSG_REALTIME = 8; const char* const midi_note_numbers[128] = { "C-1","C#-1","D-1","D#-1","E-1","F-1","F#-1","G-1","G#-1","A-1","A#-1","B-1", @@ -53,8 +55,8 @@ const char* const midi_note_numbers[128] = { }; const char* const midi_channels[17] = { - "Off", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", - " 9", " 10", " 11", " 12", " 13", " 14", " 15", " 16" + "Off", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", + " 9", "10", "11", "12", "13", "14", "15", "16" }; @@ -315,4 +317,4 @@ class MIDIQuantizer { } }; -#endif /* SYSEX_HANDLER_H_ */ +#endif /* HSMIDI_H */