1 /*
2  * MIDI CCRecorder plugin based on DISTRHO Plugin Framework (DPF)
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Copyright (C) 2019 Christopher Arndt <info@chrisarndt.de>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to
10  * deal in the Software without restriction, including without limitation the
11  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12  * sell copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24  * IN THE SOFTWARE.
25  */
26 
27 #ifndef PLUGIN_MIDICCRECORDER_H
28 #define PLUGIN_MIDICCRECORDER_H
29 
30 #include "DistrhoPlugin.hpp"
31 
32 START_NAMESPACE_DISTRHO
33 
34 #ifndef MAP
35 #define MAP(v, imin, imax, omin, omax) (((v) - (imin)) * ((omax) - (omin)) / ((imax) - (imin)) + (omin))
36 #endif
37 
38 #ifndef MIN
39 #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
40 #endif
41 
42 #ifndef MAX
43 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
44 #endif
45 
46 #ifndef CLAMP
47 #define CLAMP(v, min, max) (MIN((max), MAX((min), (v))))
48 #endif
49 
50 #define MIDI_CONTROL_CHANGE 0xB0
51 #define MIDI_PROGRAM_CHANGE 0xC0
52 #define NUM_CHANNELS 16
53 #define NUM_CONTROLLERS 128
54 
55 // -----------------------------------------------------------------------
56 
57 class PluginMIDICCRecorder : public Plugin {
58 public:
59     enum Parameters {
60         paramRecordEnable = 0,
61         paramTrigClear,
62         paramTrigSend,
63         paramTrigTransport,
64         paramTrigPCChannel,
65         paramTrigPC,
66         paramSendChannel,
67         paramSendInterval,
68         paramCount
69     };
70 
71     PluginMIDICCRecorder();
72 
73 protected:
74     // -------------------------------------------------------------------
75     // Information
76 
getLabel() const77     const char* getLabel() const noexcept override {
78         return "MIDICCRecorder";
79     }
80 
getDescription() const81     const char* getDescription() const override {
82         return "Store received Control Change messages and replay them when triggered";
83     }
84 
getMaker() const85     const char* getMaker() const noexcept override {
86         return "chrisarndt.de";
87     }
88 
getHomePage() const89     const char* getHomePage() const override {
90         return "https://chrisarndt.de/plugins/midiccrecorder";
91     }
92 
getLicense() const93     const char* getLicense() const noexcept override {
94         return "https://spdx.org/licenses/MIT";
95     }
96 
getVersion() const97     uint32_t getVersion() const noexcept override {
98         return d_version(0, 3, 0);
99     }
100 
101     // Go to:
102     //
103     // http://service.steinberg.de/databases/plugin.nsf/plugIn
104     //
105     // Get a proper plugin UID and fill it in here!
getUniqueId() const106     int64_t getUniqueId() const noexcept override {
107         return d_cconst('M', 'C', 'c', 'r');
108     }
109 
110     // -------------------------------------------------------------------
111     // Init
112 
113     void initParameter(uint32_t index, Parameter& parameter) override;
114     void initProgramName(uint32_t index, String& programName) override;
115     void initState(uint32_t index, String& stateKey, String& defaultStateValue) override;
116 
117     // -------------------------------------------------------------------
118     // Internal data
119 
120     float getParameterValue(uint32_t index) const override;
121     void setParameterValue(uint32_t index, float value) override;
122     void loadProgram(uint32_t index) override;
123     String getState(const char* key) const override;
124     void setState(const char* key, const char* value) override;
125     void clearState();
126 
127     // -------------------------------------------------------------------
128     // Optional
129 
130     // Optional callback to inform the plugin about a sample rate change.
131     void sampleRateChanged(double newSampleRate) override;
132 
133     // -------------------------------------------------------------------
134     // Process
135 
136     void activate() override;
137     void startSend();
138     void run(const float**, float**, uint32_t,
139              const MidiEvent* midiEvents, uint32_t midiEventCount) override;
140 
141     // -------------------------------------------------------------------
142 
143 private:
144     float fParams[paramCount];
145     double fSampleRate;
146     uint8_t stateCC[NUM_CHANNELS][NUM_CONTROLLERS];
147     uint8_t curChan, curCC, sendChannel;
148     bool playing, sendInProgress;
149 
150     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginMIDICCRecorder)
151 };
152 
153 struct Preset {
154     const char* name;
155     float params[PluginMIDICCRecorder::paramCount];
156 };
157 
158 Preset factoryPresets[] = {
159     {
160         "Default",
161         {0, 0, 0, 0, 17, 0, 0, 1.0}
162     },
163 };
164 
165 constexpr uint presetCount = sizeof(factoryPresets) / sizeof(Preset);
166 constexpr uint stateCount = NUM_CHANNELS;
167 
168 // -----------------------------------------------------------------------
169 
170 END_NAMESPACE_DISTRHO
171 
172 #endif  // #ifndef PLUGIN_MIDICCRECORDER_H
173