/[svn]/linuxsampler/trunk/src/drivers/Plugin.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/drivers/Plugin.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3766 - (hide annotations) (download)
Mon Apr 6 12:41:49 2020 UTC (4 years, 1 month ago) by schoenebeck
File size: 16262 byte(s)
Fixed deadlocks (e.g. when restarting engines).

* Individual thread implementations (e.g. disk thread, etc.):
  Disable thread cancellation on critical sections, e.g. when holding
  mutex locks, to prevent deadlocks if thread is stopped and/or
  restarted.

* Added TestCancel() calls to thread implementations if missing.

* No need to wrap Thread::TestCancel() calls into
  CONFIG_PTHREAD_TESTCANCEL macro conditions (since TestCancel() is
  already a stub on systems which don't have pthread_testcancel()
  available).

* If compiled for debugging: give each thread a human readable name
  to simplify debugging of multi-threading issues.

* DiskThreadBase: TestCancel() and pthread_testcancel() calls are
  per-se redundant, so only call TestCancel().

* Added missing override keywords to silent compiler warnings.

* Bumped version (2.1.1.svn54).

1 persson 1777 /***************************************************************************
2     * *
3 persson 2165 * Copyright (C) 2008 - 2011 Andreas Persson *
4 persson 1777 * *
5     * This program is free software; you can redistribute it and/or modify *
6     * it under the terms of the GNU General Public License as published by *
7     * the Free Software Foundation; either version 2 of the License, or *
8     * (at your option) any later version. *
9     * *
10     * This program is distributed in the hope that it will be useful, *
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13     * GNU General Public License for more details. *
14     * *
15     * You should have received a copy of the GNU General Public License *
16     * along with this program; if not, write to the Free Software *
17     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
18     * MA 02110-1301 USA *
19     ***************************************************************************/
20    
21 persson 1922 #include <limits>
22 persson 1777 #include <sstream>
23    
24     #include "Plugin.h"
25     #include "audio/AudioOutputDeviceFactory.h"
26     #include "midi/MidiInputDeviceFactory.h"
27    
28     namespace LinuxSampler {
29    
30     // *************** PluginGlobal ***************
31     // *
32    
33     PluginGlobal::PluginGlobal() :
34     RefCount(0) {
35     // we need to remove the ASIO driver, otherwise the lscp info
36     // methods will lock up the audio device
37 persson 1889 AudioOutputDeviceFactory::Unregister("ASIO");
38 persson 1777
39     REGISTER_AUDIO_OUTPUT_DRIVER(AudioOutputDevicePlugin);
40     REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDevicePlugin, ParameterActive);
41     REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDevicePlugin, ParameterSampleRate);
42 iliev 1907 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDevicePlugin, ParameterChannelsPlugin);
43 persson 1777 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDevicePlugin, ParameterFragmentSize);
44    
45     REGISTER_MIDI_INPUT_DRIVER(MidiInputDevicePlugin);
46     REGISTER_MIDI_INPUT_DRIVER_PARAMETER(MidiInputDevicePlugin, ParameterActive);
47 iliev 1907 REGISTER_MIDI_INPUT_DRIVER_PARAMETER(MidiInputDevicePlugin, ParameterPortsPlugin);
48 persson 1777
49     pSampler = new Sampler;
50    
51 iliev 1994 #if defined(__APPLE__)
52     // AU plugin sometimes hangs if bound to loopback
53     pLSCPServer = new LSCPServer(pSampler, htonl(INADDR_ANY), htons(LSCP_PORT));
54     #else
55 persson 1777 // using LOOPBACK instead of ANY to prevent windows firewall
56     // warnings
57 iliev 1994 pLSCPServer = new LSCPServer(pSampler, htonl(INADDR_LOOPBACK), htons(LSCP_PORT));
58     #endif
59    
60 persson 1777 pLSCPServer->StartThread();
61     pLSCPServer->WaitUntilInitialized();
62    
63     pEventThread = new EventThread(pSampler);
64     pEventThread->StartThread();
65     }
66    
67    
68     PluginGlobal::~PluginGlobal() {
69     pEventThread->StopThread();
70     pLSCPServer->StopThread();
71 iliev 1835 pLSCPServer->RemoveListeners();
72 persson 1777
73     delete pEventThread;
74     delete pSampler;
75     delete pLSCPServer;
76     }
77    
78    
79     // *************** EventThread ***************
80     // *
81    
82    
83     EventThread::EventThread(Sampler* pSampler) :
84     Thread(false, false, 0, 0),
85     pSampler(pSampler) {
86     }
87    
88     int EventThread::Main() {
89 schoenebeck 3766
90     #if DEBUG
91     Thread::setNameOfCaller("HostPlugin");
92     #endif
93    
94 persson 1777 for (;;) {
95 persson 2185 TestCancel();
96 persson 1777 sleep(1);
97 schoenebeck 3766
98     // prevent thread from being cancelled
99     // (e.g. to prevent deadlocks while holding mutex lock(s))
100     pushCancelable(false);
101    
102 persson 1777 pSampler->fireStatistics();
103 schoenebeck 3766
104     // now allow thread being cancelled again
105     // (since all mutexes are now unlocked)
106     popCancelable();
107 persson 1777 }
108 persson 1895 return 0;
109 persson 1777 }
110    
111    
112     // *************** Plugin ***************
113     // *
114    
115     PluginGlobal* Plugin::global = 0;
116    
117 iliev 1835 Plugin::Plugin(bool bDoPreInit) :
118 persson 1777 pAudioDevice(0),
119     pMidiDevice(0) {
120 iliev 1835 bPreInitDone = false;
121     if (bDoPreInit) PreInit();
122     }
123    
124     void Plugin::PreInit() {
125     if (bPreInitDone) return;
126    
127     bPreInitDone = true;
128 persson 1777 if (!global) {
129     global = new PluginGlobal;
130     }
131     global->RefCount++;
132     }
133    
134 iliev 1835 void Plugin::Init(int SampleRate, int FragmentSize, int Channels) {
135 persson 1895 if (pAudioDevice && SampleRate == pAudioDevice->SampleRate() &&
136     FragmentSize == pAudioDevice->MaxSamplesPerCycle()) {
137     return; // nothing has changed
138     }
139    
140     String oldState;
141     if (pAudioDevice) {
142     oldState = GetState();
143     RemoveChannels();
144 schoenebeck 1934 AudioOutputDeviceFactory::DestroyPrivate(pAudioDevice);
145 persson 1895 }
146 persson 1777 std::map<String, String> params;
147     params["SAMPLERATE"] = ToString(SampleRate);
148     params["FRAGMENTSIZE"] = ToString(FragmentSize);
149 iliev 1835 if (Channels > 0) params["CHANNELS"] = ToString(Channels);
150 persson 1777 pAudioDevice = dynamic_cast<AudioOutputDevicePlugin*>(
151 schoenebeck 1934 AudioOutputDeviceFactory::CreatePrivate(
152     AudioOutputDevicePlugin::Name(), params
153     )
154     );
155 persson 1777
156 persson 1895 if (!pMidiDevice) {
157     pMidiDevice = dynamic_cast<MidiInputDevicePlugin*>(
158 schoenebeck 1934 MidiInputDeviceFactory::CreatePrivate(
159     MidiInputDevicePlugin::Name(), std::map<String,String>(),
160     global->pSampler
161     )
162     );
163 persson 1895 }
164    
165     if (!oldState.empty()) {
166     SetState(oldState);
167     }
168 persson 1777 }
169    
170     Plugin::~Plugin() {
171     RemoveChannels();
172 schoenebeck 1934 if (pAudioDevice) AudioOutputDeviceFactory::DestroyPrivate(pAudioDevice);
173     if (pMidiDevice) MidiInputDeviceFactory::DestroyPrivate(pMidiDevice);
174 iliev 1835 if (bPreInitDone) {
175     if (--global->RefCount == 0) {
176     delete global;
177     global = 0;
178     }
179 persson 1777 }
180     }
181    
182     void Plugin::InitState() {
183     SamplerChannel* channel = global->pSampler->AddSamplerChannel();
184     channel->SetEngineType("gig");
185     channel->SetAudioOutputDevice(pAudioDevice);
186     channel->SetMidiInputDevice(pMidiDevice);
187     channel->SetMidiInputChannel(midi_chan_1);
188     }
189    
190 persson 1922 /*
191 capela 2174 These methods can be overloaded by different plugin types to map
192     file names to/from file names to be used in the state text, making
193     it possible for state to be self-contained and/or movable.
194     */
195    
196     String Plugin::PathToState(const String& string) {
197     return string;
198     }
199    
200     String Plugin::PathFromState(const String& string) {
201     return string;
202     }
203    
204     /*
205 persson 1922 The sampler state is stored in a text base format, designed to
206     be easy to parse with the istream >> operator. Values are
207     separated by spaces or newlines. All string values that may
208     contain spaces end with a newline.
209 persson 1777
210 persson 1922 The first line contains the global volume.
211    
212     The rest of the lines have an integer first representing the
213     type of information on the line, except for the two lines that
214     describe each sampler channel. The first of these two starts
215     with an integer from 0 to 16 (the midi channel for the sampler
216     channel).
217    
218     Note that we should try to keep the parsing of this format both
219     backwards and forwards compatible between versions. The parser
220     ignores lines with unknown type integers and accepts that new
221     types are missing.
222     */
223    
224     enum {
225     FXSEND = 17,
226     MIDIMAP,
227     MIDIMAPPING,
228     DEFAULTMIDIMAP
229     };
230    
231 persson 1777 String Plugin::GetState() {
232     std::stringstream s;
233    
234     s << GLOBAL_VOLUME << '\n';
235 persson 1922
236     std::vector<int> maps = MidiInstrumentMapper::Maps();
237     for (int i = 0 ; i < maps.size() ; i++) {
238     s << MIDIMAP << ' ' <<
239     maps[i] << ' ' <<
240     MidiInstrumentMapper::MapName(maps[i]) << '\n';
241    
242     std::map<midi_prog_index_t, MidiInstrumentMapper::entry_t> mappings = MidiInstrumentMapper::Entries(maps[i]);
243     for (std::map<midi_prog_index_t, MidiInstrumentMapper::entry_t>::iterator iter = mappings.begin() ;
244     iter != mappings.end(); iter++) {
245     s << MIDIMAPPING << ' ' <<
246     ((int(iter->first.midi_bank_msb) << 7) |
247     int(iter->first.midi_bank_lsb)) << ' ' <<
248     int(iter->first.midi_prog) << ' ' <<
249     iter->second.EngineName << ' ' <<
250 capela 2174 PathToState(iter->second.InstrumentFile) << '\n' <<
251 persson 1922 MIDIMAPPING << ' ' <<
252     iter->second.InstrumentIndex << ' ' <<
253     iter->second.Volume << ' ' <<
254     iter->second.LoadMode << ' ' <<
255     iter->second.Name << '\n';
256     }
257     }
258     if (maps.size()) {
259     s << DEFAULTMIDIMAP << ' ' <<
260     MidiInstrumentMapper::GetDefaultMap() << '\n';
261     }
262    
263 persson 1777 std::map<uint, SamplerChannel*> channels = global->pSampler->GetSamplerChannels();
264     for (std::map<uint, SamplerChannel*>::iterator iter = channels.begin() ;
265     iter != channels.end() ; iter++) {
266     SamplerChannel* channel = iter->second;
267     if (channel->GetAudioOutputDevice() == pAudioDevice) {
268     EngineChannel* engine_channel = channel->GetEngineChannel();
269     String filename = engine_channel->InstrumentFileName();
270     s << channel->GetMidiInputChannel() << ' ' <<
271     engine_channel->Volume() << ' ' <<
272 capela 2174 PathToState(filename) << '\n' <<
273 persson 1777 engine_channel->InstrumentIndex() << ' ' <<
274     engine_channel->GetSolo() << ' ' <<
275 persson 1922 (engine_channel->GetMute() == 1) << ' ' <<
276     engine_channel->OutputChannel(0) << ' ' <<
277     engine_channel->OutputChannel(1) << ' ' <<
278     (engine_channel->UsesNoMidiInstrumentMap() ? -2 :
279     (engine_channel->UsesDefaultMidiInstrumentMap() ? -1 :
280 persson 2165 engine_channel->GetMidiInstrumentMap())) << ' ' <<
281     engine_channel->EngineName() << '\n';
282 persson 1922
283     for (int i = 0 ; i < engine_channel->GetFxSendCount() ; i++) {
284     FxSend* fxsend = engine_channel->GetFxSend(i);
285     s << FXSEND << ' ' <<
286     fxsend->Level() << ' ' <<
287     int(fxsend->MidiController()) << ' ' <<
288     fxsend->DestinationChannel(0) << ' ' <<
289     fxsend->DestinationChannel(1) << ' ' <<
290     fxsend->Name() << '\n';
291     }
292 persson 1777 }
293     }
294     return s.str();
295     }
296    
297     void Plugin::RemoveChannels() {
298 iliev 1835 if(global == NULL) return;
299    
300 persson 1777 std::map<uint, SamplerChannel*> channels = global->pSampler->GetSamplerChannels();
301 iliev 1835
302 persson 1777 for (std::map<uint, SamplerChannel*>::iterator iter = channels.begin() ;
303     iter != channels.end() ; iter++) {
304     if (iter->second->GetAudioOutputDevice() == pAudioDevice) {
305     global->pSampler->RemoveSamplerChannel(iter->second);
306     }
307     }
308     }
309    
310     bool Plugin::SetState(String State) {
311     RemoveChannels();
312 persson 1922 MidiInstrumentMapper::RemoveAllMaps();
313 persson 1777
314     std::stringstream s(State);
315     s >> GLOBAL_VOLUME;
316    
317 persson 1922 EngineChannel* engine_channel;
318     int midiMapId;
319     std::map<int, int> oldToNewId;
320     int type;
321     while (s >> type) {
322 persson 1777
323 persson 1922 if (type <= 16) { // sampler channel
324     int midiChannel = type;
325     float volume;
326     s >> volume;
327     s.ignore();
328     String filename;
329     std::getline(s, filename);
330     int index;
331     bool solo;
332     bool mute;
333     s >> index >> solo >> mute;
334 persson 1777
335 persson 2165 int left = -1;
336     int right;
337     int oldMapId;
338     String engineType = "gig";
339     if (s.get() == ' ') {
340     s >> left >> right >> oldMapId;
341     if (s.get() == ' ') {
342     s >> engineType;
343     // skip rest of line
344     s.ignore(std::numeric_limits<int>::max(), '\n');
345     }
346     }
347 persson 1922 SamplerChannel* channel = global->pSampler->AddSamplerChannel();
348 persson 2165 channel->SetEngineType(engineType);
349 persson 1922 channel->SetAudioOutputDevice(pAudioDevice);
350     channel->SetMidiInputDevice(pMidiDevice);
351     channel->SetMidiInputChannel(midi_chan_t(midiChannel));
352    
353     engine_channel = channel->GetEngineChannel();
354     engine_channel->Volume(volume);
355 persson 2165
356     if (left != -1) {
357 persson 1922 engine_channel->SetOutputChannel(0, left);
358     engine_channel->SetOutputChannel(1, right);
359    
360     if (oldMapId == -1) {
361     engine_channel->SetMidiInstrumentMapToDefault();
362     } else if (oldMapId >= 0) {
363     engine_channel->SetMidiInstrumentMap(oldToNewId[oldMapId]);
364     }
365     }
366     if (!filename.empty() && index != -1) {
367     InstrumentManager::instrument_id_t id;
368 capela 2174 id.FileName = PathFromState(filename);
369 persson 1922 id.Index = index;
370     InstrumentManager::LoadInstrumentInBackground(id, engine_channel);
371     }
372     if (solo) engine_channel->SetSolo(solo);
373     if (mute) engine_channel->SetMute(1);
374    
375     } else if (type == FXSEND) {
376     float level;
377     int controller;
378     int fxleft;
379     int fxright;
380     String name;
381    
382     s >> level >> controller >> fxleft >> fxright;
383     s.ignore();
384     std::getline(s, name);
385     FxSend* send = engine_channel->AddFxSend(controller, name);
386     send->SetLevel(level);
387     send->SetDestinationChannel(0, fxleft);
388     send->SetDestinationChannel(1, fxright);
389    
390     } else if (type == MIDIMAP) {
391     int oldId;
392     s >> oldId;
393     String name;
394     s.ignore();
395     std::getline(s, name);
396     midiMapId = MidiInstrumentMapper::AddMap(name);
397     oldToNewId[oldId] = midiMapId;
398    
399     } else if (type == MIDIMAPPING) {
400     int bank;
401     int prog;
402     String engine;
403     String file;
404     int index;
405     float volume;
406     int loadmode;
407     String name;
408    
409     s >> bank >> prog >> engine;
410     s.ignore();
411     std::getline(s, file);
412     s >> type >> index >> volume >> loadmode;
413     s.ignore();
414     std::getline(s, name);
415    
416     global->pLSCPServer->AddOrReplaceMIDIInstrumentMapping(
417     midiMapId, bank, prog, engine, file, index, volume,
418     MidiInstrumentMapper::mode_t(loadmode), name, false);
419    
420     } else if (type == DEFAULTMIDIMAP) {
421     int oldId;
422     s >> oldId;
423     MidiInstrumentMapper::SetDefaultMap(oldToNewId[oldId]);
424    
425     } else { // unknown type
426     // try to be forward-compatible and just skip the line
427     s.ignore(std::numeric_limits<int>::max(), '\n');
428 persson 1777 }
429     }
430    
431     return true;
432     }
433 iliev 1992
434     void Plugin::DestroyDevice(AudioOutputDevicePlugin* pDevice) {
435     AudioOutputDeviceFactory::DestroyPrivate(pDevice);
436     }
437    
438     void Plugin::DestroyDevice(MidiInputDevicePlugin* pDevice) {
439     MidiInputDeviceFactory::DestroyPrivate(pDevice);
440     }
441 persson 1777 }

  ViewVC Help
Powered by ViewVC