/[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 2185 - (show annotations) (download)
Sun Jun 19 09:09:38 2011 UTC (12 years, 10 months ago) by persson
File size: 15885 byte(s)
* fixed compilation with gcc 4.6.1
* another "make dist" fix, for LV2 plugin
* made --enable-pthread-testcancel default on Mac OS X
* Mac OS X: fixed hanging threads

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 for (;;) {
90 TestCancel();
91 sleep(1);
92 pSampler->fireStatistics();
93 }
94 return 0;
95 }
96
97
98 // *************** Plugin ***************
99 // *
100
101 PluginGlobal* Plugin::global = 0;
102
103 Plugin::Plugin(bool bDoPreInit) :
104 pAudioDevice(0),
105 pMidiDevice(0) {
106 bPreInitDone = false;
107 if (bDoPreInit) PreInit();
108 }
109
110 void Plugin::PreInit() {
111 if (bPreInitDone) return;
112
113 bPreInitDone = true;
114 if (!global) {
115 global = new PluginGlobal;
116 }
117 global->RefCount++;
118 }
119
120 void Plugin::Init(int SampleRate, int FragmentSize, int Channels) {
121 if (pAudioDevice && SampleRate == pAudioDevice->SampleRate() &&
122 FragmentSize == pAudioDevice->MaxSamplesPerCycle()) {
123 return; // nothing has changed
124 }
125
126 String oldState;
127 if (pAudioDevice) {
128 oldState = GetState();
129 RemoveChannels();
130 AudioOutputDeviceFactory::DestroyPrivate(pAudioDevice);
131 }
132 std::map<String, String> params;
133 params["SAMPLERATE"] = ToString(SampleRate);
134 params["FRAGMENTSIZE"] = ToString(FragmentSize);
135 if (Channels > 0) params["CHANNELS"] = ToString(Channels);
136 pAudioDevice = dynamic_cast<AudioOutputDevicePlugin*>(
137 AudioOutputDeviceFactory::CreatePrivate(
138 AudioOutputDevicePlugin::Name(), params
139 )
140 );
141
142 if (!pMidiDevice) {
143 pMidiDevice = dynamic_cast<MidiInputDevicePlugin*>(
144 MidiInputDeviceFactory::CreatePrivate(
145 MidiInputDevicePlugin::Name(), std::map<String,String>(),
146 global->pSampler
147 )
148 );
149 }
150
151 if (!oldState.empty()) {
152 SetState(oldState);
153 }
154 }
155
156 Plugin::~Plugin() {
157 RemoveChannels();
158 if (pAudioDevice) AudioOutputDeviceFactory::DestroyPrivate(pAudioDevice);
159 if (pMidiDevice) MidiInputDeviceFactory::DestroyPrivate(pMidiDevice);
160 if (bPreInitDone) {
161 if (--global->RefCount == 0) {
162 delete global;
163 global = 0;
164 }
165 }
166 }
167
168 void Plugin::InitState() {
169 SamplerChannel* channel = global->pSampler->AddSamplerChannel();
170 channel->SetEngineType("gig");
171 channel->SetAudioOutputDevice(pAudioDevice);
172 channel->SetMidiInputDevice(pMidiDevice);
173 channel->SetMidiInputChannel(midi_chan_1);
174 }
175
176 /*
177 These methods can be overloaded by different plugin types to map
178 file names to/from file names to be used in the state text, making
179 it possible for state to be self-contained and/or movable.
180 */
181
182 String Plugin::PathToState(const String& string) {
183 return string;
184 }
185
186 String Plugin::PathFromState(const String& string) {
187 return string;
188 }
189
190 /*
191 The sampler state is stored in a text base format, designed to
192 be easy to parse with the istream >> operator. Values are
193 separated by spaces or newlines. All string values that may
194 contain spaces end with a newline.
195
196 The first line contains the global volume.
197
198 The rest of the lines have an integer first representing the
199 type of information on the line, except for the two lines that
200 describe each sampler channel. The first of these two starts
201 with an integer from 0 to 16 (the midi channel for the sampler
202 channel).
203
204 Note that we should try to keep the parsing of this format both
205 backwards and forwards compatible between versions. The parser
206 ignores lines with unknown type integers and accepts that new
207 types are missing.
208 */
209
210 enum {
211 FXSEND = 17,
212 MIDIMAP,
213 MIDIMAPPING,
214 DEFAULTMIDIMAP
215 };
216
217 String Plugin::GetState() {
218 std::stringstream s;
219
220 s << GLOBAL_VOLUME << '\n';
221
222 std::vector<int> maps = MidiInstrumentMapper::Maps();
223 for (int i = 0 ; i < maps.size() ; i++) {
224 s << MIDIMAP << ' ' <<
225 maps[i] << ' ' <<
226 MidiInstrumentMapper::MapName(maps[i]) << '\n';
227
228 std::map<midi_prog_index_t, MidiInstrumentMapper::entry_t> mappings = MidiInstrumentMapper::Entries(maps[i]);
229 for (std::map<midi_prog_index_t, MidiInstrumentMapper::entry_t>::iterator iter = mappings.begin() ;
230 iter != mappings.end(); iter++) {
231 s << MIDIMAPPING << ' ' <<
232 ((int(iter->first.midi_bank_msb) << 7) |
233 int(iter->first.midi_bank_lsb)) << ' ' <<
234 int(iter->first.midi_prog) << ' ' <<
235 iter->second.EngineName << ' ' <<
236 PathToState(iter->second.InstrumentFile) << '\n' <<
237 MIDIMAPPING << ' ' <<
238 iter->second.InstrumentIndex << ' ' <<
239 iter->second.Volume << ' ' <<
240 iter->second.LoadMode << ' ' <<
241 iter->second.Name << '\n';
242 }
243 }
244 if (maps.size()) {
245 s << DEFAULTMIDIMAP << ' ' <<
246 MidiInstrumentMapper::GetDefaultMap() << '\n';
247 }
248
249 std::map<uint, SamplerChannel*> channels = global->pSampler->GetSamplerChannels();
250 for (std::map<uint, SamplerChannel*>::iterator iter = channels.begin() ;
251 iter != channels.end() ; iter++) {
252 SamplerChannel* channel = iter->second;
253 if (channel->GetAudioOutputDevice() == pAudioDevice) {
254 EngineChannel* engine_channel = channel->GetEngineChannel();
255 String filename = engine_channel->InstrumentFileName();
256 s << channel->GetMidiInputChannel() << ' ' <<
257 engine_channel->Volume() << ' ' <<
258 PathToState(filename) << '\n' <<
259 engine_channel->InstrumentIndex() << ' ' <<
260 engine_channel->GetSolo() << ' ' <<
261 (engine_channel->GetMute() == 1) << ' ' <<
262 engine_channel->OutputChannel(0) << ' ' <<
263 engine_channel->OutputChannel(1) << ' ' <<
264 (engine_channel->UsesNoMidiInstrumentMap() ? -2 :
265 (engine_channel->UsesDefaultMidiInstrumentMap() ? -1 :
266 engine_channel->GetMidiInstrumentMap())) << ' ' <<
267 engine_channel->EngineName() << '\n';
268
269 for (int i = 0 ; i < engine_channel->GetFxSendCount() ; i++) {
270 FxSend* fxsend = engine_channel->GetFxSend(i);
271 s << FXSEND << ' ' <<
272 fxsend->Level() << ' ' <<
273 int(fxsend->MidiController()) << ' ' <<
274 fxsend->DestinationChannel(0) << ' ' <<
275 fxsend->DestinationChannel(1) << ' ' <<
276 fxsend->Name() << '\n';
277 }
278 }
279 }
280 return s.str();
281 }
282
283 void Plugin::RemoveChannels() {
284 if(global == NULL) return;
285
286 std::map<uint, SamplerChannel*> channels = global->pSampler->GetSamplerChannels();
287
288 for (std::map<uint, SamplerChannel*>::iterator iter = channels.begin() ;
289 iter != channels.end() ; iter++) {
290 if (iter->second->GetAudioOutputDevice() == pAudioDevice) {
291 global->pSampler->RemoveSamplerChannel(iter->second);
292 }
293 }
294 }
295
296 bool Plugin::SetState(String State) {
297 RemoveChannels();
298 MidiInstrumentMapper::RemoveAllMaps();
299
300 std::stringstream s(State);
301 s >> GLOBAL_VOLUME;
302
303 EngineChannel* engine_channel;
304 int midiMapId;
305 std::map<int, int> oldToNewId;
306 int type;
307 while (s >> type) {
308
309 if (type <= 16) { // sampler channel
310 int midiChannel = type;
311 float volume;
312 s >> volume;
313 s.ignore();
314 String filename;
315 std::getline(s, filename);
316 int index;
317 bool solo;
318 bool mute;
319 s >> index >> solo >> mute;
320
321 int left = -1;
322 int right;
323 int oldMapId;
324 String engineType = "gig";
325 if (s.get() == ' ') {
326 s >> left >> right >> oldMapId;
327 if (s.get() == ' ') {
328 s >> engineType;
329 // skip rest of line
330 s.ignore(std::numeric_limits<int>::max(), '\n');
331 }
332 }
333 SamplerChannel* channel = global->pSampler->AddSamplerChannel();
334 channel->SetEngineType(engineType);
335 channel->SetAudioOutputDevice(pAudioDevice);
336 channel->SetMidiInputDevice(pMidiDevice);
337 channel->SetMidiInputChannel(midi_chan_t(midiChannel));
338
339 engine_channel = channel->GetEngineChannel();
340 engine_channel->Volume(volume);
341
342 if (left != -1) {
343 engine_channel->SetOutputChannel(0, left);
344 engine_channel->SetOutputChannel(1, right);
345
346 if (oldMapId == -1) {
347 engine_channel->SetMidiInstrumentMapToDefault();
348 } else if (oldMapId >= 0) {
349 engine_channel->SetMidiInstrumentMap(oldToNewId[oldMapId]);
350 }
351 }
352 if (!filename.empty() && index != -1) {
353 InstrumentManager::instrument_id_t id;
354 id.FileName = PathFromState(filename);
355 id.Index = index;
356 InstrumentManager::LoadInstrumentInBackground(id, engine_channel);
357 }
358 if (solo) engine_channel->SetSolo(solo);
359 if (mute) engine_channel->SetMute(1);
360
361 } else if (type == FXSEND) {
362 float level;
363 int controller;
364 int fxleft;
365 int fxright;
366 String name;
367
368 s >> level >> controller >> fxleft >> fxright;
369 s.ignore();
370 std::getline(s, name);
371 FxSend* send = engine_channel->AddFxSend(controller, name);
372 send->SetLevel(level);
373 send->SetDestinationChannel(0, fxleft);
374 send->SetDestinationChannel(1, fxright);
375
376 } else if (type == MIDIMAP) {
377 int oldId;
378 s >> oldId;
379 String name;
380 s.ignore();
381 std::getline(s, name);
382 midiMapId = MidiInstrumentMapper::AddMap(name);
383 oldToNewId[oldId] = midiMapId;
384
385 } else if (type == MIDIMAPPING) {
386 int bank;
387 int prog;
388 String engine;
389 String file;
390 int index;
391 float volume;
392 int loadmode;
393 String name;
394
395 s >> bank >> prog >> engine;
396 s.ignore();
397 std::getline(s, file);
398 s >> type >> index >> volume >> loadmode;
399 s.ignore();
400 std::getline(s, name);
401
402 global->pLSCPServer->AddOrReplaceMIDIInstrumentMapping(
403 midiMapId, bank, prog, engine, file, index, volume,
404 MidiInstrumentMapper::mode_t(loadmode), name, false);
405
406 } else if (type == DEFAULTMIDIMAP) {
407 int oldId;
408 s >> oldId;
409 MidiInstrumentMapper::SetDefaultMap(oldToNewId[oldId]);
410
411 } else { // unknown type
412 // try to be forward-compatible and just skip the line
413 s.ignore(std::numeric_limits<int>::max(), '\n');
414 }
415 }
416
417 return true;
418 }
419
420 void Plugin::DestroyDevice(AudioOutputDevicePlugin* pDevice) {
421 AudioOutputDeviceFactory::DestroyPrivate(pDevice);
422 }
423
424 void Plugin::DestroyDevice(MidiInputDevicePlugin* pDevice) {
425 MidiInputDeviceFactory::DestroyPrivate(pDevice);
426 }
427 }

  ViewVC Help
Powered by ViewVC