35 |
#include <iostream> |
#include <iostream> |
36 |
#include <sigc++/bind.h> |
#include <sigc++/bind.h> |
37 |
#include <glibmm/main.h> |
#include <glibmm/main.h> |
38 |
|
#include <set> |
39 |
|
|
40 |
REGISTER_INSTRUMENT_EDITOR(LinuxSamplerPlugin) |
REGISTER_INSTRUMENT_EDITOR(LinuxSamplerPlugin) |
41 |
|
|
42 |
|
struct LSPluginPrivate { |
43 |
|
std::set<gig::Region*> debounceRegionChange; |
44 |
|
bool debounceRegionChangedScheduled; |
45 |
|
|
46 |
|
LSPluginPrivate() { |
47 |
|
debounceRegionChangedScheduled = false; |
48 |
|
} |
49 |
|
}; |
50 |
|
|
51 |
LinuxSamplerPlugin::LinuxSamplerPlugin() { |
LinuxSamplerPlugin::LinuxSamplerPlugin() { |
52 |
pApp = new GigEdit; |
pApp = new GigEdit; |
53 |
|
priv = new LSPluginPrivate; |
54 |
} |
} |
55 |
|
|
56 |
LinuxSamplerPlugin::~LinuxSamplerPlugin() { |
LinuxSamplerPlugin::~LinuxSamplerPlugin() { |
57 |
if (pApp) delete static_cast<GigEdit*>(pApp); |
if (pApp) delete static_cast<GigEdit*>(pApp); |
58 |
|
if (priv) delete priv; |
59 |
} |
} |
60 |
|
|
61 |
int LinuxSamplerPlugin::Main(void* pInstrument, String sTypeName, String sTypeVersion, void* /*pUserData*/) { |
int LinuxSamplerPlugin::Main(void* pInstrument, String sTypeName, String sTypeVersion, void* /*pUserData*/) { |
107 |
) |
) |
108 |
); |
); |
109 |
app->signal_dimreg_to_be_changed().connect( |
app->signal_dimreg_to_be_changed().connect( |
110 |
sigc::bind( |
// not connected directly anymore ... |
111 |
|
/*sigc::bind( |
112 |
sigc::mem_fun( |
sigc::mem_fun( |
113 |
*this, &LinuxSamplerPlugin::NotifyDataStructureToBeChanged |
*this, &LinuxSamplerPlugin::NotifyDataStructureToBeChanged |
114 |
), |
), |
115 |
"gig::DimensionRegion" |
"gig::DimensionRegion" |
116 |
) |
)*/ |
117 |
|
// ... because we are doing some event debouncing here : |
118 |
|
sigc::mem_fun(*this, &LinuxSamplerPlugin::__onDimRegionToBeChanged) |
119 |
); |
); |
120 |
app->signal_dimreg_changed().connect( |
app->signal_dimreg_changed().connect( |
121 |
sigc::bind( |
// not connected directly anymore ... |
122 |
|
/*sigc::bind( |
123 |
sigc::mem_fun( |
sigc::mem_fun( |
124 |
*this, &LinuxSamplerPlugin::NotifyDataStructureChanged |
*this, &LinuxSamplerPlugin::NotifyDataStructureChanged |
125 |
), |
), |
126 |
"gig::DimensionRegion" |
"gig::DimensionRegion" |
127 |
) |
)*/ |
128 |
|
// ... because we are doing some event debouncing here : |
129 |
|
sigc::mem_fun(*this, &LinuxSamplerPlugin::__onDimRegionChanged) |
130 |
); |
); |
131 |
app->signal_sample_changed().connect( |
app->signal_sample_changed().connect( |
132 |
sigc::bind( |
sigc::bind( |
181 |
return app->run(pGigInstr); |
return app->run(pGigInstr); |
182 |
} |
} |
183 |
|
|
184 |
|
void LinuxSamplerPlugin::__onDimRegionToBeChanged(gig::DimensionRegion* pDimRgn) { |
185 |
|
// instead of sending this signal per dimregion ... |
186 |
|
//NotifyDataStructureToBeChanged(pDimRgn, "gig::DimensionRegion"); |
187 |
|
|
188 |
|
// ... we are rather debouncing those dimregion to be changed events, and |
189 |
|
// instead only send a region to be changed event, which is much faster when |
190 |
|
// changing a very large amount of dimregions. |
191 |
|
if (!pDimRgn) return; |
192 |
|
gig::Region* pRegion = (gig::Region*) pDimRgn->GetParent(); |
193 |
|
const bool bIdle = priv->debounceRegionChange.empty(); |
194 |
|
bool bRegionLocked = priv->debounceRegionChange.count(pRegion); |
195 |
|
if (!bRegionLocked) { |
196 |
|
if (bIdle) |
197 |
|
printf("DimRgn change event debounce BEGIN (%p)\n", pRegion); |
198 |
|
priv->debounceRegionChange.insert(pRegion); |
199 |
|
NotifyDataStructureToBeChanged(pRegion, "gig::Region"); |
200 |
|
} |
201 |
|
} |
202 |
|
|
203 |
|
void LinuxSamplerPlugin::__onDimRegionChanged(gig::DimensionRegion* pDimRgn) { |
204 |
|
// like above, not sending this ... |
205 |
|
//NotifyDataStructureChanged(pDimRgn, "gig::DimensionRegion"); |
206 |
|
|
207 |
|
// ... but rather aggressively debounce those dim region changed events and |
208 |
|
// sending a debounced region changed event instead. |
209 |
|
if (!pDimRgn) return; |
210 |
|
if (!priv->debounceRegionChangedScheduled) { |
211 |
|
priv->debounceRegionChangedScheduled = true; |
212 |
|
Glib::signal_idle().connect_once( |
213 |
|
sigc::mem_fun(*this, &LinuxSamplerPlugin::__onDimRegionChangedDebounced), |
214 |
|
Glib::PRIORITY_HIGH_IDLE |
215 |
|
); |
216 |
|
} |
217 |
|
} |
218 |
|
|
219 |
|
void LinuxSamplerPlugin::__onDimRegionChangedDebounced() { |
220 |
|
// Note that we are really aggressively unlocking the region here: we are |
221 |
|
// not even bothering whether the amount "changed" events match with the |
222 |
|
// previously sent amount of "to be changed" events, because this handler |
223 |
|
// here is only called when the app's event loop is already idle for a |
224 |
|
// while, which is not the case if the app is still changing instrument |
225 |
|
// parameters (except if the app is i.e. currently showing an error dialog |
226 |
|
// to the user). |
227 |
|
priv->debounceRegionChangedScheduled = false; |
228 |
|
for (std::set<gig::Region*>::const_iterator it = priv->debounceRegionChange.begin(); |
229 |
|
it != priv->debounceRegionChange.end(); ++it) |
230 |
|
{ |
231 |
|
gig::Region* pRegion = *it; |
232 |
|
NotifyDataStructureChanged(pRegion, "gig::Region"); |
233 |
|
} |
234 |
|
priv->debounceRegionChange.clear(); |
235 |
|
printf("DimRgn change event debounce END\n"); |
236 |
|
} |
237 |
|
|
238 |
bool LinuxSamplerPlugin::__onPollPeriod() { |
bool LinuxSamplerPlugin::__onPollPeriod() { |
239 |
#if HAVE_LINUXSAMPLER_VIRTUAL_MIDI_DEVICE |
#if HAVE_LINUXSAMPLER_VIRTUAL_MIDI_DEVICE |
240 |
GigEdit* app = static_cast<GigEdit*>(pApp); |
GigEdit* app = static_cast<GigEdit*>(pApp); |