/[svn]/gigedit/trunk/src/plugin/linuxsamplerplugin.cpp
ViewVC logotype

Diff of /gigedit/trunk/src/plugin/linuxsamplerplugin.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1654 by schoenebeck, Wed Jan 30 02:20:48 2008 UTC revision 3177 by schoenebeck, Thu May 11 20:59:46 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2007, 2008 Andreas Persson   * Copyright (C) 2007 - 2017 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 19  Line 19 
19    
20  #include "linuxsamplerplugin.h"  #include "linuxsamplerplugin.h"
21    
22  #include <linuxsampler/plugins/InstrumentEditorFactory.h>  #ifdef LIBLINUXSAMPLER_HEADER_FILE
23    # include LIBLINUXSAMPLER_HEADER_FILE(plugins/InstrumentEditorFactory.h)
24    # include LIBLINUXSAMPLER_HEADER_FILE(engines/Engine.h)
25    # include LIBLINUXSAMPLER_HEADER_FILE(engines/EngineChannel.h)
26    #else
27    # include <linuxsampler/plugins/InstrumentEditorFactory.h>
28    # include <linuxsampler/engines/Engine.h>
29    # include <linuxsampler/engines/EngineChannel.h>
30    #endif
31    
32    #include "../gigedit/gigedit.h"
33    #include "../gigedit/global.h"
34    
35  #include <iostream>  #include <iostream>
36  #include <sigc++/bind.h>  #include <sigc++/bind.h>
37    #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 (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*/) {
62        return Main(pInstrument, sTypeName, sTypeVersion);
63  }  }
64    
65  int LinuxSamplerPlugin::Main(void* pInstrument, String sTypeName, String sTypeVersion) {  int LinuxSamplerPlugin::Main(void* pInstrument, String sTypeName, String sTypeVersion) {
66      std::cout << "Entered Gigedit Main() loop :)\n" << std::flush;      std::cout << "Entered Gigedit Main() loop :)\n" << std::flush;
67      gig::Instrument* pGigInstr = static_cast<gig::Instrument*>(pInstrument);      gig::Instrument* pGigInstr = static_cast<gig::Instrument*>(pInstrument);
68      GigEdit* app = (GigEdit*) pApp;      GigEdit* app = static_cast<GigEdit*>(pApp);
69    
70      // connect notification signals      // connect notification signals
71      app->signal_file_structure_to_be_changed().connect(      app->signal_file_structure_to_be_changed().connect(
# Line 79  int LinuxSamplerPlugin::Main(void* pInst Line 107  int LinuxSamplerPlugin::Main(void* pInst
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(
132            sigc::bind(
133                sigc::mem_fun(
134                    *this, &LinuxSamplerPlugin::NotifyDataStructureChanged
135                ),
136                "gig::Sample"
137          )          )
138      );      );
139      app->signal_sample_ref_changed().connect(      app->signal_sample_ref_changed().connect(
140          sigc::mem_fun(*this, &LinuxSamplerPlugin::NotifySampleReferenceChanged)          sigc::mem_fun(*this, &LinuxSamplerPlugin::NotifySampleReferenceChanged)
141      );      );
142    
143      app->add_timeout_job(this);      app->signal_keyboard_key_hit().connect(
144            sigc::mem_fun(*this, &LinuxSamplerPlugin::__onVirtualKeyboardKeyHit)
145        );
146        app->signal_keyboard_key_released().connect(
147            sigc::mem_fun(*this, &LinuxSamplerPlugin::__onVirtualKeyboardKeyReleased)
148        );
149        app->signal_switch_sampler_instrument().connect(
150            sigc::mem_fun(*this, &LinuxSamplerPlugin::__requestSamplerToSwitchInstrument)
151        );
152        app->signal_script_to_be_changed.connect(
153            sigc::bind(
154                sigc::mem_fun(
155                    *this, &LinuxSamplerPlugin::NotifyDataStructureToBeChanged
156                ),
157                "gig::Script"
158            )
159        );
160        app->signal_script_changed.connect(
161            sigc::bind(
162                sigc::mem_fun(
163                    *this, &LinuxSamplerPlugin::NotifyDataStructureChanged
164                ),
165                "gig::Script"
166            )
167        );
168    
169        // register a timeout job to gigedit's main loop, so we can poll the
170        // the sampler periodically for MIDI events (I HOPE it works on all
171        // archs, because gigedit is actually running in another thread than
172        // the one that is calling this timeout handler register code)
173        const Glib::RefPtr<Glib::TimeoutSource> timeout_source =
174            Glib::TimeoutSource::create(100); // poll every 100ms
175        timeout_source->connect(
176            sigc::mem_fun(this, &LinuxSamplerPlugin::__onPollPeriod)
177        );
178        timeout_source->attach(Glib::MainContext::get_default());
179    
180      // run gigedit application      // run gigedit application
181      return app->run(pGigInstr);      return app->run(pGigInstr);
182  }  }
183    
184  bool LinuxSamplerPlugin::runGigEditJob() {  void LinuxSamplerPlugin::__onDimRegionToBeChanged(gig::DimensionRegion* pDimRgn) {
185      GigEdit* app = (GigEdit*) pApp;      // 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() {
239        #if HAVE_LINUXSAMPLER_VIRTUAL_MIDI_DEVICE
240        GigEdit* app = static_cast<GigEdit*>(pApp);
241      if (!NotesChanged()) return true;      if (!NotesChanged()) return true;
242      for (int iKey = 0; iKey < 128; iKey++)      for (int iKey = 0; iKey < 128; iKey++)
243          if (NoteChanged(iKey))          if (NoteChanged(iKey))
244              NoteIsActive(iKey) ? // we don't care about velocity yet              NoteIsActive(iKey) ?
245                  app->on_note_on_event(iKey, 127) :                  app->on_note_on_event(iKey, NoteOnVelocity(iKey)) :
246                  app->on_note_off_event(iKey, 127);                  app->on_note_off_event(iKey, NoteOffVelocity(iKey));
247      return true;      return true;
248        #else
249        return false;
250        #endif
251  }  }
252    
253  void LinuxSamplerPlugin::__onSamplesToBeRemoved(std::list<gig::Sample*> lSamples) {  void LinuxSamplerPlugin::__onSamplesToBeRemoved(std::list<gig::Sample*> lSamples) {
# Line 120  void LinuxSamplerPlugin::__onSamplesToBe Line 255  void LinuxSamplerPlugin::__onSamplesToBe
255      std::set<void*> samples;      std::set<void*> samples;
256      for (      for (
257          std::list<gig::Sample*>::iterator iter = lSamples.begin();          std::list<gig::Sample*>::iterator iter = lSamples.begin();
258          iter != lSamples.end(); iter++          iter != lSamples.end(); ++iter
259      ) samples.insert((void*)*iter);      ) samples.insert((void*)*iter);
260      // finally send notification to sampler      // finally send notification to sampler
261      NotifySamplesToBeRemoved(samples);      NotifySamplesToBeRemoved(samples);
262  }  }
263    
264    void LinuxSamplerPlugin::__onVirtualKeyboardKeyHit(int Key, int Velocity) {
265        #if HAVE_LINUXSAMPLER_VIRTUAL_MIDI_DEVICE
266        SendNoteOnToSampler(Key, Velocity);
267        #endif
268    }
269    
270    void LinuxSamplerPlugin::__onVirtualKeyboardKeyReleased(int Key, int Velocity) {
271        #if HAVE_LINUXSAMPLER_VIRTUAL_MIDI_DEVICE
272        SendNoteOffToSampler(Key, Velocity);
273        #endif
274    }
275    
276    void LinuxSamplerPlugin::__requestSamplerToSwitchInstrument(gig::Instrument* pInstrument) {
277        if (!pInstrument) return;
278    
279        LinuxSampler::EngineChannel* pEngineChannel = GetEngineChannel();
280        if (!pEngineChannel) return;
281    
282        LinuxSampler::Engine* pEngine = pEngineChannel->GetEngine();
283        if (!pEngine) return;
284    
285        LinuxSampler::InstrumentManager* pInstrumentManager = pEngine->GetInstrumentManager();
286        if (!pInstrumentManager) return;
287    
288        gig::File* pFile = (gig::File*) pInstrument->GetParent();
289    
290        // resolve instrument's index number in its gig file
291        int index = -1;
292        for (int i = 0; pFile->GetInstrument(i); ++i) {
293            if (pFile->GetInstrument(i) == pInstrument) {
294                index = i;
295                break;
296            }
297        }
298        if (index < 0) return;
299    
300        LinuxSampler::InstrumentManager::instrument_id_t id;
301        id.FileName = pFile->GetFileName();
302        id.Index    = index;
303        pInstrumentManager->LoadInstrumentInBackground(id, pEngineChannel);
304    }
305    
306  bool LinuxSamplerPlugin::IsTypeSupported(String sTypeName, String sTypeVersion) {  bool LinuxSamplerPlugin::IsTypeSupported(String sTypeName, String sTypeVersion) {
307      return sTypeName == gig::libraryName() &&      return sTypeName == gig::libraryName() &&
308             sTypeVersion == gig::libraryVersion();             sTypeVersion == gig::libraryVersion();

Legend:
Removed from v.1654  
changed lines
  Added in v.3177

  ViewVC Help
Powered by ViewVC