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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3766 - (show annotations) (download)
Mon Apr 6 12:41:49 2020 UTC (4 years 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 /***************************************************************************
2 * *
3 * Copyright (C) 2008 - 2011 Andreas Persson *
4 * *
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 #include <limits>
22 #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 AudioOutputDeviceFactory::Unregister("ASIO");
38
39 REGISTER_AUDIO_OUTPUT_DRIVER(AudioOutputDevicePlugin);
40 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDevicePlugin, ParameterActive);
41 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDevicePlugin, ParameterSampleRate);
42 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDevicePlugin, ParameterChannelsPlugin);
43 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDevicePlugin, ParameterFragmentSize);
44
45 REGISTER_MIDI_INPUT_DRIVER(MidiInputDevicePlugin);
46 REGISTER_MIDI_INPUT_DRIVER_PARAMETER(MidiInputDevicePlugin, ParameterActive);
47 REGISTER_MIDI_INPUT_DRIVER_PARAMETER(MidiInputDevicePlugin, ParameterPortsPlugin);
48
49 pSampler = new Sampler;
50
51 #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 // using LOOPBACK instead of ANY to prevent windows firewall
56 // warnings
57 pLSCPServer = new LSCPServer(pSampler, htonl(INADDR_LOOPBACK), htons(LSCP_PORT));
58 #endif
59
60 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 pLSCPServer->RemoveListeners();
72
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
90 #if DEBUG
91 Thread::setNameOfCaller("HostPlugin");
92 #endif
93
94 for (;;) {
95 TestCancel();
96 sleep(1);
97
98 // prevent thread from being cancelled
99 // (e.g. to prevent deadlocks while holding mutex lock(s))
100 pushCancelable(false);
101
102 pSampler->fireStatistics();
103
104 // now allow thread being cancelled again
105 // (since all mutexes are now unlocked)
106 popCancelable();
107 }
108 return 0;
109 }
110
111
112 // *************** Plugin ***************
113 // *
114
115 PluginGlobal* Plugin::global = 0;
116
117 Plugin::Plugin(bool bDoPreInit) :
118 pAudioDevice(0),
119 pMidiDevice(0) {
120 bPreInitDone = false;
121 if (bDoPreInit) PreInit();
122 }
123
124 void Plugin::PreInit() {
125 if (bPreInitDone) return;
126
127 bPreInitDone = true;
128 if (!global) {
129 global = new PluginGlobal;
130 }
131 global->RefCount++;
132 }
133
134 void Plugin::Init(int SampleRate, int FragmentSize, int Channels) {
135 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 AudioOutputDeviceFactory::DestroyPrivate(pAudioDevice);
145 }
146 std::map<String, String> params;
147 params["SAMPLERATE"] = ToString(SampleRate);
148 params["FRAGMENTSIZE"] = ToString(FragmentSize);
149 if (Channels > 0) params["CHANNELS"] = ToString(Channels);
150 pAudioDevice = dynamic_cast<AudioOutputDevicePlugin*>(
151 AudioOutputDeviceFactory::CreatePrivate(
152 AudioOutputDevicePlugin::Name(), params
153 )
154 );
155
156 if (!pMidiDevice) {
157 pMidiDevice = dynamic_cast<MidiInputDevicePlugin*>(
158 MidiInputDeviceFactory::CreatePrivate(
159 MidiInputDevicePlugin::Name(), std::map<String,String>(),
160 global->pSampler
161 )
162 );
163 }
164
165 if (!oldState.empty()) {
166 SetState(oldState);
167 }
168 }
169
170 Plugin::~Plugin() {
171 RemoveChannels();
172 if (pAudioDevice) AudioOutputDeviceFactory::DestroyPrivate(pAudioDevice);
173 if (pMidiDevice) MidiInputDeviceFactory::DestroyPrivate(pMidiDevice);
174 if (bPreInitDone) {
175 if (--global->RefCount == 0) {
176 delete global;
177 global = 0;
178 }
179 }
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 /*
191 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 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
210 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 String Plugin::GetState() {
232 std::stringstream s;
233
234 s << GLOBAL_VOLUME << '\n';
235
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 PathToState(iter->second.InstrumentFile) << '\n' <<
251 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 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 PathToState(filename) << '\n' <<
273 engine_channel->InstrumentIndex() << ' ' <<
274 engine_channel->GetSolo() << ' ' <<
275 (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 engine_channel->GetMidiInstrumentMap())) << ' ' <<
281 engine_channel->EngineName() << '\n';
282
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 }
293 }
294 return s.str();
295 }
296
297 void Plugin::RemoveChannels() {
298 if(global == NULL) return;
299
300 std::map<uint, SamplerChannel*> channels = global->pSampler->GetSamplerChannels();
301
302 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 MidiInstrumentMapper::RemoveAllMaps();
313
314 std::stringstream s(State);
315 s >> GLOBAL_VOLUME;
316
317 EngineChannel* engine_channel;
318 int midiMapId;
319 std::map<int, int> oldToNewId;
320 int type;
321 while (s >> type) {
322
323 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
335 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 SamplerChannel* channel = global->pSampler->AddSamplerChannel();
348 channel->SetEngineType(engineType);
349 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
356 if (left != -1) {
357 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 id.FileName = PathFromState(filename);
369 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 }
429 }
430
431 return true;
432 }
433
434 void Plugin::DestroyDevice(AudioOutputDevicePlugin* pDevice) {
435 AudioOutputDeviceFactory::DestroyPrivate(pDevice);
436 }
437
438 void Plugin::DestroyDevice(MidiInputDevicePlugin* pDevice) {
439 MidiInputDeviceFactory::DestroyPrivate(pDevice);
440 }
441 }

  ViewVC Help
Powered by ViewVC