f@0
|
1 //
|
f@0
|
2 // AccessiblePeakMeter.h
|
f@0
|
3 //
|
f@0
|
4 // Author: Fiore Martin
|
f@0
|
5 // Started from IPlugMultiTargets example in WDL-OL, by Oli Larkin - https://github.com/olilarkin/wdl-ol
|
f@0
|
6 //
|
f@0
|
7 // Licensed under the Cockos WDL License, see README.txt
|
f@0
|
8 //
|
f@0
|
9
|
f@0
|
10 #ifndef __ACCESSIBLEPEAKMETER__
|
f@0
|
11 #define __ACCESSIBLEPEAKMETER__
|
f@0
|
12
|
f@0
|
13 #include "IPlug_include_in_plug_hdr.h"
|
f@0
|
14 #include "stk/include/SineWave.h"
|
f@0
|
15 #include "stk/include/Envelope.h"
|
f@0
|
16 #include "stk/include/ADSR.h"
|
f@0
|
17 #include "stk/include/RtAudio.h"
|
f@0
|
18 #include "stk/include/RtWvOut.h"
|
f@0
|
19
|
f@0
|
20 #include <thread>
|
f@0
|
21 #include <mutex>
|
f@0
|
22
|
f@0
|
23
|
f@0
|
24 const int DAC_BUFFER_SIZE = 64;
|
f@0
|
25 const int SONIFICATION_TYPE_CLIPPING = 1;
|
f@0
|
26 const int SONIFICATION_TYPE_CONTINUOUS = 0;
|
f@0
|
27 const double BEEP_TIME = 0.2;
|
f@0
|
28 const int MAX_CHANNELS = 2;
|
f@0
|
29
|
f@0
|
30 /*
|
f@0
|
31 This is a slightly hacked version of the AccessiblePeakMeter. The sonification is sent to
|
f@0
|
32 the defualt audio card rather than to the plugin output. The input audio signal is still
|
f@0
|
33 routed to the plugin out put with nomodification besides the amplitude, modified according
|
f@0
|
34 to the dry parameter.
|
f@0
|
35
|
f@0
|
36 When Reset() is called for the first time on the plugin, a new thread is spawned.
|
f@0
|
37 The VST plugin then continuously shares information about the input audio with the thread.
|
f@0
|
38 The thread continously polls this information and plays the sonification on the default audio interface.
|
f@0
|
39
|
f@0
|
40 DacRoutine() : is the function execute by the new thread
|
f@0
|
41 DacSynced : is the struct with all shared variables between the new thread and the VST plugin
|
f@0
|
42 Sonification: is the structure with all the sonification stuff. In this version it is only
|
f@0
|
43 accessed by the new thread.
|
f@0
|
44
|
f@0
|
45 DacThread struct does RAAI on the resource "thread"
|
f@0
|
46
|
f@0
|
47 */
|
f@0
|
48
|
f@0
|
49
|
f@0
|
50
|
f@0
|
51 /* DacRouting is the function executed by the thread that plays the sonification to the dac */
|
f@0
|
52 void DacRoutine();
|
f@0
|
53
|
f@0
|
54 /* the sonification struct contains all the variables for sonification.
|
f@0
|
55 It is accessed exclusively by the sonification thread */
|
f@0
|
56 struct Sonification {
|
f@0
|
57 stk::SineWave ugen[MAX_CHANNELS];
|
f@0
|
58
|
f@0
|
59 /* resets all the ugens. Type and ugen freq are not affected by reset
|
f@0
|
60 as well as sample rate, when srate is less than 0 */
|
f@0
|
61 void reset(double srate = -1.0){
|
f@0
|
62 for (int i = 0; i < MAX_CHANNELS; i++){
|
f@0
|
63 ugen[i].reset();
|
f@0
|
64
|
f@0
|
65 /* continous sonification */
|
f@0
|
66 continous.isOn[i] = true;
|
f@0
|
67 stk::Envelope & coe = continous.envelope[i];
|
f@0
|
68 coe.setValue(1.0); // setValue also sets the target
|
f@0
|
69 coe.setTime(0.2);
|
f@0
|
70
|
f@0
|
71 /* clipping sonification */
|
f@0
|
72 clipping.maxDiff[i] = 0.0;
|
f@0
|
73 stk::ADSR & cle = clipping.envelope[i];
|
f@0
|
74 cle.setValue(0.0);
|
f@0
|
75 cle.setReleaseTime(BEEP_TIME);
|
f@0
|
76 cle.setAttackTime(0.01);
|
f@0
|
77 cle.setSustainLevel(1);
|
f@0
|
78
|
f@0
|
79 /*
|
f@0
|
80 the sample is fixed to 44100 when the handle to the soundcard is created
|
f@0
|
81 the sonification is independent from changes in the daw sample rate anyway
|
f@0
|
82 if (srate > 0.0){
|
f@0
|
83 ugen[i].setSampleRate(srate);
|
f@0
|
84 coe.setSampleRate(srate);
|
f@0
|
85 cle.setSampleRate(srate);
|
f@0
|
86 }
|
f@0
|
87 */
|
f@0
|
88 }
|
f@0
|
89 }
|
f@0
|
90
|
f@0
|
91 struct Continous {
|
f@0
|
92 stk::Envelope envelope[MAX_CHANNELS];
|
f@0
|
93 bool isOn[MAX_CHANNELS];
|
f@0
|
94 } continous;
|
f@0
|
95
|
f@0
|
96 struct Clipping {
|
f@0
|
97 double maxDiff[MAX_CHANNELS];
|
f@0
|
98 stk::ADSR envelope[MAX_CHANNELS];
|
f@0
|
99 } clipping;
|
f@0
|
100
|
f@0
|
101 Sonification() {
|
f@0
|
102 reset();
|
f@0
|
103 }
|
f@0
|
104 } sSonification;
|
f@0
|
105
|
f@0
|
106 /* this structure is used to pass information back and forth between
|
f@0
|
107 the puginthread and the sonification thread, with direct access to the sound card */
|
f@0
|
108 struct DacSynced {
|
f@0
|
109 bool die;
|
f@0
|
110 double wet;
|
f@0
|
111 double sonifFreq[MAX_CHANNELS];
|
f@0
|
112 int type;
|
f@0
|
113 double maxClippingDiff[MAX_CHANNELS];
|
f@0
|
114 int sonificationType;
|
f@0
|
115 DacSynced()
|
f@0
|
116 : die(false),
|
f@0
|
117 wet(0.5),
|
f@0
|
118 sonificationType( SONIFICATION_TYPE_CLIPPING )
|
f@0
|
119 {
|
f@0
|
120 for (int i = 0; i < MAX_CHANNELS; i++){
|
f@0
|
121 sonifFreq[i] = 0.0;
|
f@0
|
122 maxClippingDiff[i] = 0.0;
|
f@0
|
123 }
|
f@0
|
124 }
|
f@0
|
125 } sDacSynced;
|
f@0
|
126
|
f@0
|
127
|
f@0
|
128
|
f@0
|
129 /* mutex to sync the vst plugin thread with the thread
|
f@0
|
130 that writes directly into the soundcard (DacThread)
|
f@0
|
131 */
|
f@0
|
132 std::mutex sDacMutex;
|
f@0
|
133
|
f@0
|
134
|
f@0
|
135 /*sPrevSonificationType keeps track of the sonification type. Useful for DacThread
|
f@0
|
136 to assess whether the sonification has changed from the last loop cycle */
|
f@0
|
137 int sPrevSonificationType = SONIFICATION_TYPE_CLIPPING;
|
f@0
|
138
|
f@0
|
139 struct DacThread {
|
f@0
|
140 std::thread t;
|
f@0
|
141 bool started = false;
|
f@0
|
142
|
f@0
|
143 /* when this struct goes out of scope (user *
|
f@0
|
144 * exits daw) The thread is stopped and joined. */
|
f@0
|
145 ~DacThread(){
|
f@0
|
146 sDacMutex.lock();
|
f@0
|
147 sDacSynced.die = true;
|
f@0
|
148 sDacMutex.unlock();
|
f@0
|
149
|
f@0
|
150 if (t.joinable())
|
f@0
|
151 t.join();
|
f@0
|
152 }
|
f@0
|
153
|
f@0
|
154 } sDacThread;
|
f@0
|
155
|
f@0
|
156 class AccessiblePeakMeter : public IPlug
|
f@0
|
157 {
|
f@0
|
158 public:
|
f@0
|
159
|
f@0
|
160 AccessiblePeakMeter(IPlugInstanceInfo instanceInfo);
|
f@0
|
161 ~AccessiblePeakMeter();
|
f@0
|
162
|
f@0
|
163 void Reset();
|
f@0
|
164 void OnParamChange(int paramIdx);
|
f@0
|
165
|
f@0
|
166 void ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames);
|
f@0
|
167 bool HostRequestingAboutBox();
|
f@0
|
168
|
f@0
|
169 static const double DRY_DEFAULT;
|
f@0
|
170 static const double WET_DEFAULT;
|
f@0
|
171 static const int SONIFICATION_TYPE_DEFAULT;
|
f@0
|
172 static const double METERDECAY_DEFAULT;
|
f@0
|
173 static const double THRESHOLD_DEFAULT;
|
f@0
|
174 static const double BEEP_TIME;
|
f@0
|
175 static const double DB_RANGE;
|
f@0
|
176 static const double SONIFICATION_RANGE;
|
f@0
|
177 static const int NO_BEEP;
|
f@0
|
178 static const int NUM_PRESETS = 2;
|
f@0
|
179 static const double MIN_SONIFICATION_FREQ;
|
f@0
|
180 static const int NUM_KNOB_FRAMES;
|
f@0
|
181 static const double CLIPPING_CEILING_SNAP;
|
f@0
|
182
|
f@0
|
183 private:
|
f@0
|
184 /* parameters on the GUI */
|
f@0
|
185 double mDry;
|
f@0
|
186 double mWet;
|
f@0
|
187 double mMeterDecayRate;
|
f@0
|
188 double mThreshold;
|
f@0
|
189
|
f@0
|
190 double mSampleRate;
|
f@0
|
191
|
f@0
|
192 double mPrevPeak[MAX_CHANNELS];
|
f@0
|
193 int mMeterIdx[MAX_CHANNELS];
|
f@0
|
194
|
f@0
|
195 int mSonificationType;
|
f@0
|
196
|
f@0
|
197 void addContinuousSonification(double** inputs, double** outputs, int nFrames);
|
f@0
|
198 void addClippingSonification(double** inputs, double** outputs, int nFrames);
|
f@0
|
199 };
|
f@0
|
200
|
f@0
|
201 #endif //__ACCESSIBLEPEAKMETER__
|