diff --git a/Readme.md b/Readme.md index 1cf31d87..4a577540 100644 --- a/Readme.md +++ b/Readme.md @@ -1,182 +1,122 @@ -# CSI - Control Surface Integrator +# CSI Code Specifically Modified for the Icon V1-M Surface +## The Major Changes + +**Four new classes. (control_surface_midi_widgets.h)** + +``` + class V1MDisplay_Midi_FeedbackProcessor : public Midi_FeedbackProcessor + + class V1MTrackColors_Midi_FeedbackProcessor : public Midi_FeedbackProcessor + + class V1MDisplay_Midi_FeedbackProcessor : public Midi_FeedbackProcessor -Welcome to the primary code repository for the **CSI (Control Surface Integrator)** project! - -CSI is a powerful and flexible system for integrating a wide range of hardware control surfaces with [REAPER](https://www.reaper.fm/), providing advanced mapping, feedback, and workflow customization capabilities. Whether you're using a basic MIDI controller or a complex multi-surface studio setup including MIDI and OSC devices, CSI enables deep control over your DAW environment. - -CSI is a fully open-source project. Anyone is welcome to explore, contribute to, or fork the codebase to create customized builds that meet their specific needs. - ---- - -## Resources and Documentation - -- ๐Ÿ“š **[CSI Wiki - User Guide and Troubleshooting](https://github.com/FunkybotsEvilTwin/CSIUserGuide/wiki)** - The official CSI User Guide with setup instructions, feature documentation, and troubleshooting tips. - -- ๐Ÿ“ฆ **[CSI Install Repository](https://github.com/FunkybotsEvilTwin/CSI_Install)** - Contains required installation files, surface definitions, and support scripts needed to run CSI. - -- ๐Ÿงช **[CSI Experimental Repository](https://github.com/FunkybotsEvilTwin/CSI_Install)** - A place to explore experimental and beta versions of CSI. - ---- - -## Issue Reporting - -If you encounter a bug or problem with CSI, we recommend first reporting it in the **main CSI thread** on the [REAPER Forum](https://forum.cockos.com/showthread.php?t=183143). -This allows for community discussion and quick troubleshooting. - -If community discussions and quick troubleshooting fail to resolve the issue, feel free to open an Issue here on GitHub to help track and resolve the problem. - -When submitting an Issue, please provide: -- A clear description of the problem -- Steps to reproduce -- Expected results -- Actual results -- Surface(s) involved -- CSI version -- Operating system and REAPER version - ---- - -## Contributing Code - -**Code contributions are welcome and encouraged!** - -We kindly ask that contributors follow these guidelines, as well as review the CSI Code Style Guide and Authoring Tips in the next section, to help keep the project organized and moving forward smoothly: - -- **Introduce yourself!** - Feel free to reach out to the team before beginning work โ€” either by posting in the **main CSI thread** on the [REAPER Forum](https://forum.cockos.com/showthread.php?t=183143) or by sending a private message to `funkybot` on the forum. - Contacting us helps avoid conflicts with project goals or other contributors who may already be working on related tasks. - -- **Align with project goals.** - Before making major changes, please check in to make sure your ideas fit with the long-term direction of the project. - -- **Issues list.** - If you see an open Issue you would like to tackle, please post a quick comment calling "dibs" before you start working. - This helps avoid duplicate efforts where multiple contributors work on the same thing. - -- **Keep Pull Requests (PRs) focused and small.** - PRs should ideally cover a **single feature or fix**. - This makes reviewing and testing changes much easier. - -- **Include clear explanations.** - When submitting a PR, please describe: - - The purpose of the change - - Why the change is necessary - - How the change is used (especially if it relates to a specific surface) - - Any relevant zone or syntax information - -- **Do not remove project files** without prior discussion. - Project files (such as Visual Studio solutions, WDL components, etc.) are important for cross-platform builds and ongoing development. Please avoid deleting or replacing these files in a PR unless the change has been discussed and agreed upon by the team. - -- **PR review process.** - Regular CSI contributors will review and approve pull requests to ensure consistency, compatibility, and project integrity. - ---- - -## CSI Code Style Guide and Authoring Tips + class V1MVUMeter_Midi_FeedbackProcessor : public Midi_FeedbackProcessor + (This handles both master and channel strip VUMeters since there is only one difference in the code. + channel strip VU = 0xD0 and MasterVU = 0xD1) +``` -### 1. Avoid Shorthand -Use full, descriptive names instead of abbreviations. This makes code self-documenting and easier to read. +**Widgets linked to the new classes (control_surface_integrator.cpp)** -**Bad:** ``` - #elif CONDITION - // ... - #endif + else if (widgetType == "FB_V1MMasterVUMeter" && size == 2) + { + int displayType = NULL; + int code = 0xD1; //Master + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, code, displayType, atoi(tokenLines[i][1].c_str()))); + } + else if ((widgetType == "FB_V1MVUMeter" || widgetType == "FB_V1MXVUMeter") && size == 2) //Kev Smart + { + int displayType = (widgetType == "FB_V1MVUMeter") ? 0x14 : 0x15; + int code = 0xD0; //Channel Strip + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, code, displayType, atoi(tokenLines[i][1].c_str()))); + SetHasMCUMeters(displayType); + } - int oldTracksSize = (int)t; -``` + else if (widgetType == "FB_V1MTrackColors") + { + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget)); + AddTrackColorFeedbackProcessor(widget->GetFeedbackProcessors().back().get()); + } -**Good:** + else if ((widgetType == "FB_V1MDisplay1Upper" || widgetType == "FB_V1MDisplay1Lower" || widgetType == "FB_V1MDisplay2Upper" || widgetType == "FB_V1MDisplay2Lower") && size == 2) //Kev Smart + { + if (widgetType == "FB_V1MDisplay1Upper") + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, 1, 0x14, 0x12, atoi(tokenLines[i][1].c_str()), 0x00, 0x66)); + else if (widgetType == "FB_V1MDisplay1Lower") + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, 0, 0x14, 0x12, atoi(tokenLines[i][1].c_str()), 0x00, 0x66)); + else if (widgetType == "FB_V1MDisplay2Upper") + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, 1, 0x15, 0x13, atoi(tokenLines[i][1].c_str()), 0x02, 0x4e)); + else if (widgetType == "FB_V1MDisplay2Lower") + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, 0, 0x15, 0x13, atoi(tokenLines[i][1].c_str()), 0x02, 0x4e)); + } ``` - #else - #if CONDITION - // ... - #endif - int oldTracksSize = static_cast(tracks); +**The New widgets (Surface.txt)** ``` +Widget TrackColors + FB_V1MTrackColors +WidgetEnd -### 2. Bracket Usage -Place opening braces on their own line and align closing braces vertically. Never leave an opening brace at the end of a line. This helps visually align code in various IDE's. +Widget Display1Upper1 + FB_V1MDisplay1Upper 0 +WidgetEnd +............. +Widget Display1Upper8 + FB_V1MDisplay1Upper 7 +WidgetEnd -**Bad:** -``` - class Something : public Action { - public: - const char* GetName() override { return "Something"; } - }; -``` +Widget Display1Lower1 + FB_V1MDisplay1Lower 0 +WidgetEnd +................ +Widget Display1Lower8 + FB_V1MDisplay1Lower 7 +WidgetEnd -**Good:** -``` - class Something : public Action - { - public: - const char* GetName() override - { - return "Something"; - } - }; -``` +Widget Display2Upper1 + FB_V1MDisplay2Upper 0 +WidgetEnd +............. +Widget Display2Upper8 + FB_V1MDisplay2Upper 7 +WidgetEnd -### 3. Lowercase Variables -Variable names should be lowercase and spelled out and use a trailing underscore for private members. +Widget Display2Lower1 + FB_V1MDisplay2Lower 0 +WidgetEnd +................ +Widget Display2Lower8 + FB_V1MDisplay2Lower 7 +WidgetEnd -**Bad:** -``` - if (!T) continue; -``` +Widget MasterChannelMeterLeft + FB_V1MMasterVUMeter 0 +WidgetEnd -**Good:** -``` - if (!track) continue; -``` - - **Bad:** -``` - bool IsInitialized_ = false; -``` +Widget MasterChannelMeterRight + FB_V1MMasterVUMeter 1 +WidgetEnd -**Good:** -``` - bool isInitialized_ = false; +Widget VUMeter1 + FB_V1MVUMeter 0 +WidgetEnd +............. +Widget VUMeter8 + FB_V1MVUMeter 7 +WidgetEnd ``` -### 4. Spacing and Comparisons -Use consistent spacing around operators and align related expressions to improve readability. -**Not Recommended:** -``` - if (tracks_[i] !=track||colors_[i] !=GetTrackColor(track)) -``` -**Preferred:** Adds a few extra spaces to make comparisons a little easier to spot. -``` - if (tracks_[i] != track || colors_[i] != GetTrackColor(track)) -``` -### 5. Avoid Timers -CSI's Run method is called approximately every 30 ms. Do not introduce timers. Keep all logic within Run. -### 6. Embrace Object-Oriented Design Principles -CSI is built around object-oriented design. Before implementing a solution, review how existing classes interact to ensure your changes integrate seamlessly. -### 7. Keep Code Self-Contained -When adding things like new actions or feedback processors, encapsulate logic within the class. If you find yourself scattering helper functions across files, reconsider your design or stop and ask for guidance. ---- -## Forks and Custom Versions -Because CSI is open source, anyone is free to clone this repository and create their own builds incorporating any changes, large or small. -If you have ideas that significantly diverge from the current project goals, you're welcome to maintain your own fork! ---- +``` + -## Thank You! -We appreciate your contributions and interest in helping CSI continue to grow and improve. Your support makes this project possible! diff --git a/Windows/reaper_csurf_integrator/reaper_csurf_integrator/reaper_csurf_integrator.vcxproj b/Windows/reaper_csurf_integrator/reaper_csurf_integrator/reaper_csurf_integrator.vcxproj index f1f97ad8..116d67be 100644 --- a/Windows/reaper_csurf_integrator/reaper_csurf_integrator/reaper_csurf_integrator.vcxproj +++ b/Windows/reaper_csurf_integrator/reaper_csurf_integrator/reaper_csurf_integrator.vcxproj @@ -22,7 +22,7 @@ 15.0 {07525C13-3611-4726-ADB4-2EA085EDCDC6} reaper_csurf_integrator - 10.0.22621.0 + 10.0 reaper_csurf_integrator @@ -84,7 +84,8 @@ Disabled true _WINDLL;%(PreprocessorDefinitions) _CRT_SECURE_NO_WARNINGS - stdcpp17 + stdcpp17 + diff --git a/reaper_csurf_integrator/control_surface_Reaper_actions.h b/reaper_csurf_integrator/control_surface_Reaper_actions.h index 2b06c12b..ff775107 100755 --- a/reaper_csurf_integrator/control_surface_Reaper_actions.h +++ b/reaper_csurf_integrator/control_surface_Reaper_actions.h @@ -3355,7 +3355,13 @@ class TrackToggleFolderSpill : public Action if (value == ActionContext::BUTTON_RELEASE_MESSAGE_VALUE) return; if (MediaTrack *track = context->GetTrack()) - context->GetPage()->ToggleFolderSpill(track); + { + Page* page = context->GetPage(); + page->ToggleFolderSpill(track); + + if (GetMediaTrackInfo_Value(track, "I_FOLDERDEPTH") == 1) + DAW::UpdateView("ToggleSpill", true, track); + } } }; diff --git a/reaper_csurf_integrator/control_surface_integrator.cpp b/reaper_csurf_integrator/control_surface_integrator.cpp index d18ebb8a..0afa306d 100644 --- a/reaper_csurf_integrator/control_surface_integrator.cpp +++ b/reaper_csurf_integrator/control_surface_integrator.cpp @@ -719,6 +719,39 @@ void Midi_ControlSurface::ProcessMidiWidget(int &lineNumber, ifstream &surfaceTe AddTrackColorFeedbackProcessor(widget->GetFeedbackProcessors().back().get()); } + + //V1M Start + else if (widgetType == "FB_V1MMasterVUMeter" && size == 2) + { + int displayType = NULL; + int code = 0xD1; //Master + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, code, displayType, atoi(tokenLines[i][1].c_str()))); + } + else if ((widgetType == "FB_V1MVUMeter" || widgetType == "FB_V1MXVUMeter") && size == 2) //Kev Smart + { + int displayType = (widgetType == "FB_V1MVUMeter") ? 0x14 : 0x15; + int code = 0xD0; //Channel Strip + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, code, displayType, atoi(tokenLines[i][1].c_str()))); + SetHasMCUMeters(displayType); + } + else if (widgetType == "FB_V1MTrackColors") + { + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget)); + AddTrackColorFeedbackProcessor(widget->GetFeedbackProcessors().back().get()); + } + else if ((widgetType == "FB_V1MDisplay1Upper" || widgetType == "FB_V1MDisplay1Lower" || widgetType == "FB_V1MDisplay2Upper" || widgetType == "FB_V1MDisplay2Lower") && size == 2) //Kev Smart + { + if (widgetType == "FB_V1MDisplay1Upper") + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, 1, 0x14, 0x12, atoi(tokenLines[i][1].c_str()), 0x00, 0x66)); + else if (widgetType == "FB_V1MDisplay1Lower") + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, 0, 0x14, 0x12, atoi(tokenLines[i][1].c_str()), 0x00, 0x66)); + else if (widgetType == "FB_V1MDisplay2Upper") + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, 1, 0x15, 0x13, atoi(tokenLines[i][1].c_str()), 0x02, 0x4e)); + else if (widgetType == "FB_V1MDisplay2Lower") + widget->GetFeedbackProcessors().push_back(make_unique(csi_, this, widget, 0, 0x15, 0x13, atoi(tokenLines[i][1].c_str()), 0x02, 0x4e)); + } + //V1M End + else if ((widgetType == "FB_C4DisplayUpper" || widgetType == "FB_C4DisplayLower") && size == 3) { if (widgetType == "FB_C4DisplayUpper") @@ -1031,6 +1064,8 @@ void CSurfIntegrator::InitActionsDictionary() actions_.insert(make_pair("LeaveSubZone", make_unique())); actions_.insert(make_pair("SetXTouchDisplayColors", make_unique())); actions_.insert(make_pair("RestoreXTouchDisplayColors", make_unique())); + actions_.insert(make_pair("OverrideTrackColors", make_unique())); + actions_.insert(make_pair("RestoreTrackColors", make_unique())); actions_.insert(make_pair("GoFXSlot", make_unique())); actions_.insert(make_pair("ShowFXSlot", make_unique())); actions_.insert(make_pair("HideFXSlot", make_unique())); @@ -2241,6 +2276,20 @@ void Zone::RestoreXTouchDisplayColors() widget->RestoreXTouchDisplayColors(); } +void Zone::OverrideTrackColors(const char* colors) +{ + for (auto& widget : widgets_) + widget->OverrideTrackColors(colors, name_); +} + +void Zone::RestoreTrackColors() +{ + for (auto& widget : widgets_) + widget->RestoreTrackColors(); +} + + + void Zone::DoAction(Widget *widget, bool &isUsed, double value) { if (! isActive_ || isUsed) @@ -2306,7 +2355,7 @@ void Zone::DoRelativeAction(Widget *widget, bool &isUsed, int accelerationIndex, { isUsed = true; - for (auto &actionContext : GetActionContexts(widget)) + for (auto &actionContext : GetActionContexts(widget)) actionContext->DoRelativeAction(accelerationIndex, delta); } else @@ -2462,6 +2511,19 @@ void Widget::RestoreXTouchDisplayColors() feedbackProcessor->RestoreXTouchDisplayColors(); } +void Widget::OverrideTrackColors(const char* colors, string const zone_name) +{ + for (auto& feedbackProcessor : feedbackProcessors_) + feedbackProcessor->OverrideTrackColors(colors, zone_name); +} + +void Widget::RestoreTrackColors() +{ + for (auto& feedbackProcessor : feedbackProcessors_) + feedbackProcessor->RestoreTrackColors(); +} + + void Widget::ForceClear() { for (auto &feedbackProcessor : feedbackProcessors_) @@ -3493,18 +3555,18 @@ void ControlSurface::UpdateTrackColors() rgba_color ControlSurface::GetTrackColorForChannel(int channel) { - rgba_color white; - white.r = 255; - white.g = 255; - white.b = 255; + rgba_color black; + black.r = 0; + black.g = 0; + black.b = 0; if (channel < 0 || channel >= numChannels_) - return white; + return black; if (MediaTrack *track = page_->GetNavigatorForChannel(channel + channelOffset_)->GetTrack()) return DAW::GetTrackColor(track); else - return white; + return black; } void ControlSurface::RequestUpdate() diff --git a/reaper_csurf_integrator/control_surface_integrator.h b/reaper_csurf_integrator/control_surface_integrator.h index 064066e7..aaa0eb92 100644 --- a/reaper_csurf_integrator/control_surface_integrator.h +++ b/reaper_csurf_integrator/control_surface_integrator.h @@ -794,6 +794,9 @@ class Zone int GetSlotIndex(); void SetXTouchDisplayColors(const char *colors); void RestoreXTouchDisplayColors(); + void OverrideTrackColors(const char* colors); + void RestoreTrackColors(); + void UpdateCurrentActionContextModifiers(); const vector> &GetActionContexts(Widget *widget); @@ -920,9 +923,11 @@ class FeedbackProcessor virtual void ForceUpdateTrackColors() {} virtual void RunDeferredActions() {} virtual void ForceClear() {} - + virtual void SetXTouchDisplayColors(const char *colors) {} virtual void RestoreXTouchDisplayColors() {} + virtual void OverrideTrackColors(const char* colors, string const zone_name) {} + virtual void RestoreTrackColors() {} virtual void SetColorValue(const rgba_color &color) {} @@ -1053,6 +1058,10 @@ class Widget void UpdateColorValue(const rgba_color &color); void SetXTouchDisplayColors(const char *colors); void RestoreXTouchDisplayColors(); + void OverrideTrackColors(const char* colors, string const zone_name); + void RestoreTrackColors(); + + void ForceClear(); void SetHasDoublePressActions() { hasDoublePressActions_ = true; }; @@ -1625,6 +1634,8 @@ class ZoneManager ClearFXMapping(); ResetOffsets(); + DAW::SetHomeView(); + for (auto &goZone : goZones_) goZone->Deactivate(); @@ -3957,7 +3968,7 @@ class Page const char *GetCurrentInputMonitorMode(MediaTrack *track) { return trackNavigationManager_->GetCurrentInputMonitorMode(track); } const vector &GetSelectedTracks() { return trackNavigationManager_->GetSelectedTracks(); } - + /* int repeats = 0; diff --git a/reaper_csurf_integrator/control_surface_integrator_Reaper.h b/reaper_csurf_integrator/control_surface_integrator_Reaper.h index f1ffa930..0e23685c 100755 --- a/reaper_csurf_integrator/control_surface_integrator_Reaper.h +++ b/reaper_csurf_integrator/control_surface_integrator_Reaper.h @@ -14,6 +14,8 @@ #include #include +#include "handy_functions.h" //for LogToConsole() + using namespace std; extern HWND g_hwnd; @@ -27,23 +29,23 @@ struct rgba_color int g; int b; int a; - + bool operator == (const rgba_color &other) const { return r == other.r && g == other.g && b == other.b && a == other.a ; } - + bool operator != (const rgba_color &other) const { return r != other.r || g != other.g || b != other.b || a != other.a; } - + const char *rgba_to_string(char *buf) const // buf must be at least 10 bytes { - snprintf(buf,10,"#%02x%02x%02x%02x",r,g,b,a); - return buf; + snprintf(buf,10,"#%02x%02x%02x%02x",r,g,b,a); + return buf; } - + rgba_color() { r = 0; @@ -57,11 +59,11 @@ static bool GetColorValue(const char *hexColor, rgba_color &colorValue) { if (strlen(hexColor) == 7) { - return sscanf(hexColor, "#%2x%2x%2x", &colorValue.r, &colorValue.g, &colorValue.b) == 3; + return sscanf(hexColor, "#%2x%2x%2x", &colorValue.r, &colorValue.g, &colorValue.b) == 3; } if (strlen(hexColor) == 9) { - return sscanf(hexColor, "#%2x%2x%2x%2x", &colorValue.r, &colorValue.g, &colorValue.b, &colorValue.a) == 4; + return sscanf(hexColor, "#%2x%2x%2x%2x", &colorValue.r, &colorValue.g, &colorValue.b, &colorValue.a) == 4; } return false; } @@ -77,7 +79,7 @@ struct MIDI_event_ex_t : MIDI_event_t midi_message[2] = 0x00; midi_message[3] = 0x00; }; - + MIDI_event_ex_t(const unsigned char first, const unsigned char second, const unsigned char third) { size = 3; @@ -86,86 +88,113 @@ struct MIDI_event_ex_t : MIDI_event_t midi_message[2] = third; midi_message[3] = 0x00; }; - + bool IsEqualTo(const MIDI_event_ex_t *other) const { if (this->size != other->size) return false; - + for (int i = 0; i < size; ++i) if (this->midi_message[i] != other->midi_message[i]) return false; - + return true; } }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class DAW -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// { +private: + enum Modes { e_all = 0, e_folder, e_tracks, e_spill }; //static Modes items; // this is legal + + inline static bool spillMode_ = false; + inline static int startSpill_ = 1; + + struct Params + { + bool showfolders; + bool showchild; + int start; + int end; + int folderheight; + int childheight; + }; + public: + + DAW() + { + } + static void SendCommandMessage(WPARAM wparam) { ::SendMessage(g_hwnd, WM_COMMAND, wparam, 0); } - + + static void SendCommandMessage(const char* cmd) + { + int commandId = NamedCommandLookup(cmd); + SendCommandMessage(commandId); + } + static MediaTrack *GetSelectedTrack(int seltrackidx) { return ::GetSelectedTrack(NULL, seltrackidx); } - + static bool ValidateTrackPtr(MediaTrack *track) { return ::ValidatePtr(track, "MediaTrack*"); } - + static bool CanUndo() { if (::Undo_CanUndo2(NULL)) - return true; + return true; else return false; } - + static bool CanRedo() { if (::Undo_CanRedo2(NULL)) - return true; + return true; else return false; } - + static void Undo() { if (CanUndo()) ::Undo_DoUndo2(NULL); } - + static void Redo() { if (CanRedo()) ::Undo_DoRedo2(NULL); } - + static MediaTrack *GetTrack(int trackidx) { trackidx--; - + if (trackidx < 0) trackidx = 0; - + return ::GetTrack(NULL, trackidx) ; } - + static rgba_color GetTrackColor(MediaTrack *track) { rgba_color color; - + if (ValidateTrackPtr(track)) ::ColorFromNative(::GetTrackColor(track), &color.r, &color.g, &color.b); - + if (color.r == 0 && color.g == 0 && color.b == 0) { color.r = 64; color.g = 64; color.b = 64; } - + return color; } - + static unsigned int GetTrackGroupMembership(MediaTrack *track, const char *groupname) { if (ValidateTrackPtr(track)) @@ -173,7 +202,7 @@ class DAW else return 0; } - + static unsigned int GetTrackGroupMembershipHigh(MediaTrack *track, const char *groupname) { if (ValidateTrackPtr(track)) @@ -181,7 +210,7 @@ class DAW else return 0; } - + static const char* GetCommandName(int cmdID) { const char* actionName = ::kbd_getTextFromCmd(cmdID, ::SectionFromUniqueID(1)); @@ -190,6 +219,127 @@ class DAW else return "NOT FOUND!"; } + + //====================== My DAW Sync Functions ============================== + static void SetHomeView() //control_surface_integrator.h class ZoneManager->GoHome() + { + SendCommandMessage("_SWSTL_SHOWALLTCP"); + SendCommandMessage("_d5b9a4565d3e7340b1b1a17142c42dab"); //Custom: HOME + SendCommandMessage("_ed94f234ca542041b239da13df07fcca"); //Custom : SetHeights + //TOADD Global automation override: All automation in trim/read mode + } + + static void UpdateTracks(Params p) //WIP + { + int show; + int folderdepth; + int numTracks = GetNumTracks(); + + int height; + bool start = false; + + for (int i = 1; i <= numTracks; ++i) + { + if (MediaTrack* track = CSurf_TrackFromID(i, true)) + { + if (IsTrackVisible(track, true)) + { + show = 0; //start as hide on each pass in the loop + + folderdepth = (int)GetMediaTrackInfo_Value(track, "I_FOLDERDEPTH"); + + if (p.start == i) start = true; + + if (folderdepth == 1) + { + height = p.folderheight; + if (start && p.showfolders) + show = 1; + } + else + { + height = p.childheight; + if (start && p.showchild) + show = 1; + } + + GetSetMediaTrackInfo(track, "I_HEIGHTOVERRIDE", &height); + //GetSetMediaTrackInfo(track, "I_AUTOMODE", &automode); + GetSetMediaTrackInfo(track, "B_SHOWINTCP", &show); + + if (folderdepth == p.end) start = false; //end of spill + } + } + } + TrackList_AdjustWindows(true); //replaced SendCommandMessage("_SWS_SAVEVIEW"); and SendCommandMessage("_SWS_RESTOREVIEW"); + } + + static void Folder_Spill_View(MediaTrack* track) + { + Params p; + if (spillMode_ == false) //folder + { + p = { true, false, 1, 2, 80, 80 }; + UpdateTracks(p); + } + else //spill + { + if(track != NULL) + startSpill_ = (int)GetMediaTrackInfo_Value(track, "IP_TRACKNUMBER"); + p = { true, true, startSpill_, -1, 22, 80 }; + UpdateTracks(p); + } + } + + static void UpdateView(const char* name, bool status, MediaTrack* track) //CALLED: control_surface_manager_actions.h class GoZone->Do() DAW::UpdateView(name); + { + Params p; + if (!strcmp(name, "Folder") && status == true) + { + Folder_Spill_View(NULL); + } + else if (!strcmp(name, "SelectedTracks") && status == true) + { + p = { true, true, 1, 2, 80, 600}; // params[0] = { 80, 600, 1 }; //add new param show selected tracks + UpdateTracks(p); + SendCommandMessage("_SWSTL_SHOWTCPEX"); //SWS: Show selected track(s) in TCP, hide others + SendCommandMessage(40888); //Envelope: Show all active envelopes for tracks + SendCommandMessage(40421); //Item : Select all items in track + SendCommandMessage(40847); //Item: Open item inline editors + } + else if (!strcmp(name, "ToggleSpill") && status == true) + { + spillMode_ = !spillMode_; + Folder_Spill_View(track); + } + else + { + p = {true, true, 1, 2, 22, 80}; + UpdateTracks(p); + SendCommandMessage(41887); //Item: Close item inline editors + SendCommandMessage(41150); //Envelope : Hide all envelopes for all tracks + SendCommandMessage(41887); //Item: Close item inline editors + } + } + + static void ShowInfo() //FOR DEBUGGING + { + int numTracks = GetNumTracks(); + for (int i = 1; i <= numTracks; ++i) + { + if (MediaTrack* track = CSurf_TrackFromID(i, true)) + if (IsTrackVisible(track, true)) + { + char buf[MEDBUF]; + + GetTrackName(track, buf, sizeof(buf)); + int h = (int)GetMediaTrackInfo_Value(track, "I_TCPH"); + int d = (int)GetMediaTrackInfo_Value(track, "I_FOLDERDEPTH"); + + LogToConsole(512, "[KEV] Name:%s Height:%d Depth:%d\n", buf, h, d); + } + } + } }; #endif /* control_surface_integrator_Reaper_h */ diff --git a/reaper_csurf_integrator/control_surface_manager_actions.h b/reaper_csurf_integrator/control_surface_manager_actions.h index a63268bb..fd5c2799 100644 --- a/reaper_csurf_integrator/control_surface_manager_actions.h +++ b/reaper_csurf_integrator/control_surface_manager_actions.h @@ -129,19 +129,51 @@ class SetXTouchDisplayColors : public Action ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class RestoreXTouchDisplayColors : public Action -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// { public: virtual const char *GetName() override { return "RestoreXTouchDisplayColors"; } - + void Do(ActionContext *context, double value) override { if (value == ActionContext::BUTTON_RELEASE_MESSAGE_VALUE) return; - + context->GetZone()->RestoreXTouchDisplayColors(); } }; + +class OverrideTrackColors : public Action + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{ +public: + virtual const char* GetName() override { return "OverrideTrackColors"; } + + void Do(ActionContext* context, double value) override + { + if (value == ActionContext::BUTTON_RELEASE_MESSAGE_VALUE) return; + + context->GetZone()->OverrideTrackColors(context->GetStringParam()); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class RestoreTrackColors : public Action + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{ +public: + virtual const char* GetName() override { return "RestoreTrackColors"; } + + void Do(ActionContext* context, double value) override + { + if (value == ActionContext::BUTTON_RELEASE_MESSAGE_VALUE) return; + + context->GetZone()->RestoreTrackColors(); + } +}; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class SaveProject : public Action ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -736,6 +768,10 @@ class GoZone : public Action context->GetPage()->GoZone(name); else context->GetSurface()->GetZoneManager()->DeclareGoZone(name); + + bool isActive = context->GetSurface()->GetZoneManager()->GetIsGoZoneActive(context->GetStringParam()); + DAW::UpdateView(name, isActive, NULL); + } }; diff --git a/reaper_csurf_integrator/control_surface_midi_widgets.h b/reaper_csurf_integrator/control_surface_midi_widgets.h index 59ec2197..b6e73d23 100755 --- a/reaper_csurf_integrator/control_surface_midi_widgets.h +++ b/reaper_csurf_integrator/control_surface_midi_widgets.h @@ -2564,6 +2564,300 @@ class iCON_V1MDisplay_Midi_FeedbackProcessor : public Midi_FeedbackProcessor } }; +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class V1MVUMeter_Midi_FeedbackProcessor : public Midi_FeedbackProcessor // Linked to widget "FB_V1MVUMeter" Kev Smart +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{ +protected: + int displayType_; //would be needed if an extender is being used. Set to NULL for master VU + int channelNumber_; //this is either for channel strip 0-7 or for master 0-1 (L-R) + int table[62]; + int newledValue_; + int oldledValue_; + int code_; //will be d0 for channle strip or D1 for master + +public: + virtual ~V1MVUMeter_Midi_FeedbackProcessor() {} + V1MVUMeter_Midi_FeedbackProcessor(CSurfIntegrator* const csi, Midi_ControlSurface* surface, Widget* widget, int code, int displayType, int channelNumber) : + Midi_FeedbackProcessor(csi, surface, widget), code_(code), displayType_(displayType), channelNumber_(channelNumber) + { + int newledValue_ = 0x00; int oldledValue_ = 0x00; + int v = 0x0E; + for (int i = 0; i < 62; i++) + { + if (i > 0) v = 0x0B; + if (i > 3) v = 0x0A; + if (i > 6) v = 0x09; + if (i > 9) v = 0x08; + if (i > 12) v = 0x07; + if (i > 18) v = 0x06; + if (i > 24) v = 0x05; + if (i > 30) v = 0x04; + if (i > 36) v = 0x03; + if (i > 42) v = 0x02; + if (i > 48) v = 0x01; + if (i > 60) v = 0x00; + table[i] = v; + } + } + + virtual const char* GetName() override { return "V1MVUMeter_Midi_FeedbackProcessor"; } + + virtual void ForceClear() override + { + const PropertyList properties; + ForceValue(properties, 0.0); + } + + int UpdateLEDValue(const PropertyList& properties, double v) + { + double db; + if (code_ == 0xd0) //channel + { + db = SLIDER2DB(v * 1000.0) + 0.1; //add 0.1 so that it fits with prev scaling i.e. >= -60.1 + } + else if (code_ == 0xd1) //master + { + db = SLIDER2DB(v * 1000.0) + 1.1; //add 1.1 for the master track + } + + if (db > 0) db = 0; + if (db < -60) db = -61; + + int index = (int)(ceil(abs(db))); + newledValue_ = table[index]; + + if (newledValue_ || newledValue_ != oldledValue_) + { + oldledValue_ = newledValue_; + return true; + } + return false; + } + + virtual void SetValue(const PropertyList& properties, double value) override + { + if (UpdateLEDValue(properties, value)) + SendMidiMessage(code_, (channelNumber_ << 4) | newledValue_, 0); + } + + virtual void ForceValue(const PropertyList& properties, double value) override + { + UpdateLEDValue(properties, value); + ForceMidiMessage(code_, (channelNumber_ << 4) | newledValue_, 0); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class V1MTrackColors_Midi_FeedbackProcessor : public Midi_FeedbackProcessor + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{ +private: + bool preventUpdateTrackColors_; + struct rgb : rgba_color + { + rgb(int x, int y, int z) { r = x; g = y; b = z; } // parameterized constructor + }; + + map rgba_Arr_; + vector TrackColors_; + + struct SysexHeader + { + MIDI_event_ex_t evt; + char data[28]; //allocate extra data for this Sysex + 1 + } SysExMessage_; + int header_size_; + +public: + virtual ~V1MTrackColors_Midi_FeedbackProcessor() {} + + V1MTrackColors_Midi_FeedbackProcessor(CSurfIntegrator* const csi, Midi_ControlSurface* surface, Widget* widget) : + Midi_FeedbackProcessor(csi, surface, widget) + { + //g_debugLevel = DEBUG_LEVEL_DEBUG; + + preventUpdateTrackColors_ = false; + + rgba_Arr_.insert(make_pair("Black", rgb(0x00, 0x00, 0x00))); + rgba_Arr_.insert(make_pair("Red", rgb(0x7F, 0x00, 0x00))); + rgba_Arr_.insert(make_pair("Green", rgb(0x00, 0x7F, 0x00))); + rgba_Arr_.insert(make_pair("Blue", rgb(0x00, 0x00, 0x7F))); + rgba_Arr_.insert(make_pair("Yellow", rgb(0x7F, 0x7F, 0x00))); + rgba_Arr_.insert(make_pair("Magenta", rgb(0x7F, 0x00, 0x7F))); + rgba_Arr_.insert(make_pair("Cyan", rgb(0x00, 0x7F, 0x7F))); + rgba_Arr_.insert(make_pair("White", rgb(0x7F, 0x7F, 0x7F))); + + SysExMessage_.evt.frame_offset = 0; + SysExMessage_.evt.size = 0; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0xF0; // Start SysEx + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0x00; // Start of header + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0x02; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0x4E; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0x16; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0x14; // End of header + header_size_ = SysExMessage_.evt.size; + } + + virtual const char* GetName() override { return "V1MTrackColors_Midi_FeedbackProcessor"; } + + virtual void OverrideTrackColors(const char* colors, string const zone_name) override + { + if (preventUpdateTrackColors_ == true) return; + + preventUpdateTrackColors_ = true; + + + //search "TrackFXMenu", "SelectedTrackFXMenu", "MasterTrackFXMenu" + + MediaTrack* selectedTrack = GetSelectedTrack(NULL, 0); // DAW::GetSelectedTrack(0); + for (int i = 0; i < TrackFX_GetCount(selectedTrack); ++i) + { + } + + TrackColors_.clear(); + rgb color = rgba_Arr_.find(colors)->second; //this color is applied to all 8 tracks + + for (int i = 0; i < surface_->GetNumChannels(); ++i) + { + TrackColors_.push_back(color); + } + SetTrackColors(); + } + + virtual void RestoreTrackColors() override + { + if (preventUpdateTrackColors_ == false) return; + + preventUpdateTrackColors_ = false; + ForceUpdateTrackColors(); + } + + virtual void ForceClear() override //only called when shutting down? + { + rgb color(0x00, 0x00, 0x00); + TrackColors_.clear(); + for (int i = 0; i < surface_->GetNumChannels(); ++i) + { + TrackColors_.push_back(color); + } + SetTrackColors(); + } + + virtual void ForceUpdateTrackColors() override //all 8 tracks colors are configured at once + { + if (preventUpdateTrackColors_) + return; + + TrackColors_.clear(); + for (int i = 0; i < surface_->GetNumChannels(); ++i) + { + rgba_color color = surface_->GetTrackColorForChannel(i); + color.r = (color.r >> 1) & 0x7F; //adjustTo7bit(color.r); + color.g = (color.g >> 1) & 0x7F; //adjustTo7bit(color.g); + color.b = (color.b >> 1) & 0x7F; //adjustTo7bit(color.b); + color.b = static_cast(color.b * (0.70f + (0.30f * color.g / 127.0f))) & 0x7F; // Apply the blue correction for better color representation b = b * (0.70 + (0.30 * (g / 128))) + TrackColors_.push_back(color); + } + SetTrackColors(); + } + + void SetTrackColors() //all 8 track colors are configured at once + { + SysExMessage_.evt.size = header_size_; + for (auto& color : TrackColors_) + { + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = color.r; // Add RGB values to SysEx message header + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = color.g; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = color.b; + } + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0xF7; // End SysEx + + SendMidiSysExMessage(&SysExMessage_.evt); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class V1MDisplay_Midi_FeedbackProcessor : public Midi_FeedbackProcessor // Linked to widgets "FB_V1MDisplay1Upper" "FB_V1MDisplay1Lower" "FB_V1MDisplay2Upper" "FB_V1MDisplay2Lower"" Kev Smart + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{ +private: + int sysExByte1_; + int sysExByte2_; + int offset_; + int displayType_; + int displayRow_; + int channel_; + string lastStringSent_; + + struct SysexHeader + { + MIDI_event_ex_t evt; + char data[12]; //allocate extra data for this Sysex + 1 + } SysExMessage_; + int header_size_; + + +public: + virtual ~V1MDisplay_Midi_FeedbackProcessor() {} + + V1MDisplay_Midi_FeedbackProcessor(CSurfIntegrator* const csi, Midi_ControlSurface* surface, Widget* widget, int displayUpperLower, int displayType, int displayRow, int channel, int sysExByte1, int sysExByte2) : + Midi_FeedbackProcessor(csi, surface, widget), + offset_(displayUpperLower * 56), + displayType_(displayType), + displayRow_(displayRow), + channel_(channel), + sysExByte1_(sysExByte1), + sysExByte2_(sysExByte2) + { + SysExMessage_.evt.frame_offset = 0; + SysExMessage_.evt.size = 0; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0xF0; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0x00; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = sysExByte1_; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = sysExByte2_; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = displayType_; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = displayRow_; + header_size_ = SysExMessage_.evt.size; + } + + virtual const char* GetName() override { return "V1MDisplay_Midi_FeedbackProcessor"; } + + virtual void ForceClear() override + { + const PropertyList properties; + ForceValue(properties, ""); + } + + virtual void SetValue(const PropertyList& properties, const char* const& inputText) override + { + if (strcmp(inputText, lastStringSent_.c_str())) // changes since last send + ForceValue(properties, inputText); + } + + virtual void ForceValue(const PropertyList& properties, const char* const& inputText) override + { + lastStringSent_ = inputText; + + char tmp[MEDBUF]; + const char* text = GetWidget()->GetSurface()->GetRestrictedLengthText(inputText, tmp, sizeof(tmp)); + + if (!strcmp(text, "-150.00")) text = "-Inf"; + + SysExMessage_.evt.size = header_size_; + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = channel_ * 7 + offset_; + + int cnt = 0; + while (cnt++ < 7) + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = *text ? *text++ : ' '; + + SysExMessage_.evt.midi_message[SysExMessage_.evt.size++] = 0xF7; + + SendMidiSysExMessage(&SysExMessage_.evt); + } +}; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class FPDisplay_Midi_FeedbackProcessor : public Midi_FeedbackProcessor /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////