/[svn]/linuxsampler/trunk/src/hostplugins/dssi/PluginDssi.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/hostplugins/dssi/PluginDssi.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1858 - (show annotations) (download)
Sun Mar 8 09:57:19 2009 UTC (15 years, 1 month ago) by persson
File size: 12880 byte(s)
* optimized the DSSI plugin: all plugin instances now share the same
  disk streaming buffers
* added support for the "fine tune" and "pitch bend range"
  instrument-level gig parameters
* fixed minor artifacts in pitch bend handling

1 /***************************************************************************
2 * *
3 * Copyright (C) 2008 - 2009 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 <algorithm>
22 #include <cstring>
23 #include <exception>
24 #include <sstream>
25 #include <string>
26
27 #include "PluginDssi.h"
28
29 #include "../../engines/gig/EngineChannel.h"
30
31 namespace {
32
33 // *************** PluginDssi ***************
34 // *
35
36 PluginDssi::PluginDssi(unsigned long SampleRate) :
37 RefCount(0) {
38 // As there is no way in DSSI of knowing a max value of the
39 // output buffer size, we set the audio device buffer size to
40 // 128 and let RunSynth call Render in a loop if needed.
41 Init(SampleRate, 128);
42 }
43
44 PluginDssi* PluginInstance::plugin = 0;
45
46 PluginInstance::PluginInstance(unsigned long SampleRate) {
47 Out[0] = 0;
48 Out[1] = 0;
49
50 uint outputChannel = 0;
51 uint midiPort = 0;
52 if (!plugin) {
53 plugin = new PluginDssi(SampleRate);
54 }
55 plugin->RefCount++;
56
57 pChannel = plugin->global->pSampler->AddSamplerChannel();
58 pChannel->SetEngineType("gig");
59 pChannel->SetAudioOutputDevice(plugin->pAudioDevice);
60 LinuxSampler::MidiInputPort* port = plugin->pMidiDevice->CreateMidiPort();
61 port->Connect(pChannel->GetEngineChannel(), LinuxSampler::midi_chan_all);
62
63 // TODO: remove dependency on gig engine
64 LinuxSampler::gig::EngineChannel* engineChannel =
65 (LinuxSampler::gig::EngineChannel*)pChannel->GetEngineChannel();
66 // TODO: pChannelLeft and pChannelRight are meant to be
67 // protected
68 engineChannel->pChannelLeft = new LinuxSampler::AudioChannel(0, 0, 0);
69 engineChannel->pChannelRight = new LinuxSampler::AudioChannel(1, 0, 0);
70 }
71
72 PluginInstance::~PluginInstance() {
73 LinuxSampler::gig::EngineChannel* engineChannel =
74 (LinuxSampler::gig::EngineChannel*)pChannel->GetEngineChannel();
75 delete engineChannel->pChannelLeft;
76 delete engineChannel->pChannelRight;
77 LinuxSampler::MidiInputPort* port = engineChannel->pMidiInputPort;
78
79 if (--plugin->RefCount == 0) {
80 delete plugin;
81 plugin = 0;
82 } else {
83 plugin->global->pSampler->RemoveSamplerChannel(pChannel);
84 }
85
86 LinuxSampler::MidiInputDevicePlugin::DeleteMidiPort(port);
87 }
88
89 void PluginInstance::ConnectPort(unsigned long Port, LADSPA_Data* DataLocation) {
90 if (Port < 2) Out[Port] = DataLocation;
91 }
92
93 char* PluginInstance::Configure(const char* Key, const char* Value) {
94 dmsg(2, ("linuxsampler: configure Key=%s Value=%s\n", Key, Value));
95
96 if (strcmp(Key, "instrument") == 0 && strcmp(Value, "") != 0) {
97 String filename(Value);
98 String::size_type colon = filename.rfind(':');
99 int instrument = 0;
100 if (colon != String::npos) {
101 std::stringstream(String(filename, colon + 1)) >> instrument;
102 filename.erase(colon);
103 }
104 try {
105 LinuxSampler::EngineChannel* engineChannel =
106 pChannel->GetEngineChannel();
107 dmsg(2, (" before LoadInstrument\n"));
108 engineChannel->PrepareLoadInstrument(filename.c_str(),
109 instrument);
110 engineChannel->LoadInstrument();
111 dmsg(2, (" after LoadInstrument\n"));
112 }
113 catch (std::exception& e) {
114 return strdup(e.what());
115 }
116 }
117
118 return 0;
119 }
120
121 inline void PluginInstance::RunMultipleSynths(unsigned long InstanceCount,
122 LADSPA_Handle* Instances,
123 unsigned long SampleCount,
124 snd_seq_event_t** Events,
125 unsigned long* EventCounts) {
126 if (InstanceCount == 0) return;
127
128 LinuxSampler::AudioOutputDevicePlugin* audioDevice =
129 static_cast<PluginInstance*>(Instances[0])->plugin->pAudioDevice;
130
131 unsigned eventPosArr[InstanceCount];
132 for (unsigned long i = 0 ; i < InstanceCount ; i++) eventPosArr[i] = 0;
133
134 int samplePos = 0;
135 while (SampleCount) {
136 int samples = std::min(SampleCount, 128UL);
137
138 for (unsigned long i = 0 ; i < InstanceCount ; i++) {
139 PluginInstance* instance = static_cast<PluginInstance*>(Instances[i]);
140 LinuxSampler::EngineChannel* engineChannel =
141 instance->pChannel->GetEngineChannel();
142 LinuxSampler::MidiInputPort* port = engineChannel->GetMidiInputPort();
143
144 snd_seq_event_t* events = Events[i];
145 unsigned& eventPos = eventPosArr[i];
146
147 for ( ; eventPos < EventCounts[i] ; eventPos++) {
148 snd_seq_event_t* ev = &events[eventPos];
149 int time = ev->time.tick - samplePos;
150 if (time >= samples) break;
151 switch (ev->type) {
152 case SND_SEQ_EVENT_CONTROLLER:
153 port->DispatchControlChange(ev->data.control.param,
154 ev->data.control.value,
155 ev->data.control.channel, time);
156 break;
157
158 case SND_SEQ_EVENT_CHANPRESS:
159 port->DispatchControlChange(128, ev->data.control.value,
160 ev->data.control.channel, time);
161 break;
162
163 case SND_SEQ_EVENT_PITCHBEND:
164 port->DispatchPitchbend(ev->data.control.value,
165 ev->data.control.channel, time);
166 break;
167
168 case SND_SEQ_EVENT_NOTEON:
169 port->DispatchNoteOn(ev->data.note.note,
170 ev->data.note.velocity,
171 ev->data.control.channel, time);
172 break;
173
174 case SND_SEQ_EVENT_NOTEOFF:
175 port->DispatchNoteOff(ev->data.note.note,
176 ev->data.note.velocity,
177 ev->data.control.channel, time);
178 break;
179
180 case SND_SEQ_EVENT_SYSEX:
181 port->DispatchSysex(ev->data.ext.ptr, ev->data.ext.len);
182 break;
183 }
184 }
185
186 LinuxSampler::gig::EngineChannel* gigEngineChannel =
187 (LinuxSampler::gig::EngineChannel*)engineChannel;
188 gigEngineChannel->pChannelLeft->SetBuffer(instance->Out[0] + samplePos);
189 gigEngineChannel->pChannelRight->SetBuffer(instance->Out[1] + samplePos);
190 if (i) {
191 gigEngineChannel->pChannelLeft->Clear(samples);
192 gigEngineChannel->pChannelRight->Clear(samples);
193 } else {
194 // the buffer set in the audio device is cleared
195 // by Render
196 audioDevice->Channel(0)->SetBuffer(instance->Out[0] + samplePos);
197 audioDevice->Channel(1)->SetBuffer(instance->Out[1] + samplePos);
198 }
199 }
200
201 audioDevice->Render(samples);
202
203 samplePos += samples;
204 SampleCount -= samples;
205 }
206 }
207
208 void PluginInstance::Activate() {
209 dmsg(2, ("linuxsampler: activate instance=%p\n", static_cast<void*>(this)));
210 pChannel->GetEngineChannel()->GetMidiInputPort()->DispatchControlChange(123, 0, 0, 0); // all sound off
211 }
212
213
214 // *************** LADSPA callback functions ***************
215 // *
216
217 LADSPA_Handle instantiate(const LADSPA_Descriptor* Descriptor,
218 unsigned long SampleRate) {
219 return new PluginInstance(SampleRate);
220 }
221
222 void cleanup(LADSPA_Handle Instance) {
223 dmsg(2, ("linuxsampler: cleanup Instance=%p\n", static_cast<void*>(Instance)));
224 delete static_cast<PluginInstance*>(Instance);
225 }
226
227 void activate(LADSPA_Handle Instance) {
228 static_cast<PluginInstance*>(Instance)->Activate();
229 }
230
231 void connect_port(LADSPA_Handle Instance, unsigned long Port,
232 LADSPA_Data* DataLocation) {
233 static_cast<PluginInstance*>(Instance)->ConnectPort(Port, DataLocation);
234 }
235
236 void run(LADSPA_Handle Instance, unsigned long SampleCount) {
237 return;
238 }
239
240
241 // *************** DSSI callback functions ***************
242 // *
243
244 void run_multiple_synths(unsigned long InstanceCount,
245 LADSPA_Handle* Instances,
246 unsigned long SampleCount,
247 snd_seq_event_t** Events,
248 unsigned long* EventCounts) {
249 PluginInstance::RunMultipleSynths(InstanceCount, Instances,
250 SampleCount, Events,
251 EventCounts);
252 }
253
254 char* configure(LADSPA_Handle Instance, const char* Key, const char* Value) {
255 return static_cast<PluginInstance*>(Instance)->Configure(Key, Value);
256 }
257
258
259 // *************** PluginInfo ***************
260 // *
261
262 PluginInfo PluginInfo::Instance;
263
264 PluginInfo::PluginInfo() {
265 Ladspa.UniqueID = 3781; // (received from ladspa.org)
266 Ladspa.Label = "LinuxSampler";
267 Ladspa.Properties = 0;
268 Ladspa.Name = "LinuxSampler";
269 Ladspa.Maker = "linuxsampler.org";
270 Ladspa.Copyright = "(C) 2003,2004 Benno Senoner and Christian Schoenebeck, "
271 "2005-2009 Christian Schoenebeck";
272 Ladspa.PortCount = 2;
273 Ladspa.ImplementationData = 0;
274 Ladspa.PortDescriptors = PortDescriptors;
275 Ladspa.PortRangeHints = PortRangeHints;
276 Ladspa.PortNames = PortNames;
277
278 PortDescriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
279 PortNames[0] = "Output Left";
280 PortRangeHints[0].HintDescriptor = 0;
281 PortDescriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
282 PortNames[1] = "Output Right";
283 PortRangeHints[1].HintDescriptor = 0;
284
285 Ladspa.activate = activate;
286 Ladspa.cleanup = cleanup;
287 Ladspa.connect_port = connect_port;
288 Ladspa.deactivate = 0;
289 Ladspa.instantiate = instantiate;
290 Ladspa.run = run;
291 Ladspa.run_adding = 0;
292 Ladspa.set_run_adding_gain = 0;
293
294 Dssi.DSSI_API_Version = 1;
295 Dssi.LADSPA_Plugin = &Ladspa;
296 Dssi.configure = configure;
297 Dssi.get_program = 0;
298 Dssi.get_midi_controller_for_port = 0;
299 Dssi.select_program = 0;
300 Dssi.run_synth = 0;
301 Dssi.run_synth_adding = 0;
302 Dssi.run_multiple_synths = run_multiple_synths;
303 Dssi.run_multiple_synths_adding = 0;
304 }
305 }
306
307
308 extern "C" {
309 const LADSPA_Descriptor* ladspa_descriptor(unsigned long Index) {
310 dmsg(2, ("linuxsampler: ladspa_descriptor\n"));
311 return Index == 0 ? PluginInfo::LadspaDescriptor() : 0;
312 }
313
314 const DSSI_Descriptor *dssi_descriptor(unsigned long Index) {
315 dmsg(2, ("linuxsampler: dssi_descriptor\n"));
316 return Index == 0 ? PluginInfo::DssiDescriptor() : 0;
317 }
318 }

  ViewVC Help
Powered by ViewVC