CLAM-Development  1.4.0
LadspaNetworkExporter.cxx
Go to the documentation of this file.
2 #include "ControlSource.hxx"
3 #include "ControlSink.hxx"
4 #include "AudioBufferSource.hxx"
5 #include "AudioBufferSink.hxx"
6 #include "NetworkPlayer.hxx"
7 
8 namespace CLAM
9 {
10 
11 class LadspaNetworkPlayer : public NetworkPlayer
12 {
13  template<class T>
14  class LADSPAInfo
15  {
16  public:
17  std::string name;
18  T* processing;
19  LADSPA_Data *dataBuffer;
20  unsigned port;
21  };
22 
23 private:
24  typedef std::vector< LADSPAInfo<ControlSource> > LADSPAInControlList;
25  typedef std::vector< LADSPAInfo<ControlSink> > LADSPAOutControlList;
26  typedef std::vector<LADSPA_Data * > Buffers;
27 
28  Network _network;
29  Buffers _sourceBuffers;
30  Buffers _sinkBuffers;
31  Buffers _inControlBuffers;
32  Buffers _outControlBuffers;
33  LADSPAInControlList mInControlList;
34  LADSPAOutControlList mOutControlList;
35  unsigned long mClamBufferSize;
36  unsigned long mExternBufferSize;
37 public:
38  virtual bool IsWorking() { return true; }
39  virtual std::string NonWorkingReason() { return ""; }
40  virtual void Start() {}
41  virtual void Stop() {}
42 // virtual void Pause() {}
43  virtual bool IsRealTime() const { return true; }
44 // virtual unsigned BackendBufferSize();
45 // virtual unsigned BackendSampleRate();
46 public:
47  LadspaNetworkPlayer(const std::string & label, const std::string & networkXmlContent);
48  ~LadspaNetworkPlayer();
49 
50  void Activate();
51  void Deactivate();
52 
53  void LocateConnections();
54  void UpdatePortFrameAndHopSize();
55  void FillPortInfo( LADSPA_PortDescriptor* descriptors, char** names, LADSPA_PortRangeHint* rangehints );
56  void ConnectTo(unsigned long port, LADSPA_Data * data);
57 
58  void Run( unsigned long nsamples );
59  void EstablishLadspaBuffersToAudioSources(const unsigned long nframes);
60  void EstablishLadspaBuffersToAudioSinks(const unsigned long nframes);
61  void ProcessInControlValues();
62  void ProcessOutControlValues();
63  static LADSPA_Descriptor * CreateLADSPADescriptor(
64  const std::string & networkXmlContent,
65  unsigned id,
66  const std::string & label,
67  const std::string & name,
68  const std::string & maker,
69  const std::string & copyright
70  );
71 };
72 
73 }
74 
75 // Ladspa Callbacks
76 extern "C"
77 {
78  // Construct a new plugin instance.
79  static LADSPA_Handle Instantiate(const LADSPA_Descriptor * descriptor, unsigned long sampleRate)
80  {
81 // std::cerr << "Network2Ladspa: instantiate" << std::endl;
82  return new CLAM::LadspaNetworkPlayer(descriptor->Label, (const char*)descriptor->ImplementationData);
83  }
84  // Destruct plugin instance
85  static void CleanUp(LADSPA_Handle handle)
86  {
87 // std::cerr << "Network2Ladspa: cleanup " << handle << std::endl;
88  delete (CLAM::LadspaNetworkPlayer*) handle;
89  }
90 
91  // Run the plugin
92  static void Run(LADSPA_Handle handle, unsigned long sampleCount)
93  {
94  CLAM::LadspaNetworkPlayer *p = (CLAM::LadspaNetworkPlayer*) handle;
95  p->Run( sampleCount );
96  }
97  // Activate Plugin
98  static void Activate(LADSPA_Handle handle)
99  {
100 // std::cerr << "Network2Ladspa: activate " << handle << std::endl;
101  CLAM::LadspaNetworkPlayer *p = (CLAM::LadspaNetworkPlayer*) handle;
102  p->Activate();
103  }
104 
105  static void Deactivate(LADSPA_Handle handle)
106  {
107 // std::cerr << "Network2Ladspa: deactivate " << handle << std::endl;
108  CLAM::LadspaNetworkPlayer *p = (CLAM::LadspaNetworkPlayer*) handle;
109  p->Deactivate();
110  }
111 
112  // Connect a port to a data location.
113  static void ConnectTo(LADSPA_Handle handle, unsigned long port, LADSPA_Data * dataLocation)
114  {
115 // std::cerr << "Network2Ladspa: connect " << port << std::endl;
116  CLAM::LadspaNetworkPlayer *p = (CLAM::LadspaNetworkPlayer*) handle;
117  p->ConnectTo( port, dataLocation );
118  }
119 }
120 
121 namespace CLAM
122 {
123 
124 
125 LadspaNetworkPlayer::LadspaNetworkPlayer(const std::string & name, const std::string & networkXmlContent)
126 {
127  mClamBufferSize=512;
128  mExternBufferSize=mClamBufferSize;
129 
130  std::istringstream xmlfile(networkXmlContent);
131  try
132  {
133  XmlStorage::Restore( _network, xmlfile );
134  }
135  catch ( XmlStorageErr err)
136  {
137  std::cerr << "CLAM LADSPA: Error while loading CLAM network based plugin '" << name << "'." <<std::endl;
138  std::cerr << err.what() << std::endl;
139  std::cerr << "Plugin not loaded." << std::endl;
140  return;
141  }
142  if (_network.HasMisconfiguredProcessings())
143  {
144  std::cerr << "CLAM LADSPA: Error while configuring CLAM network based plugin '" << name << "'." <<std::endl;
145  std::cerr << _network.GetConfigurationErrors() << std::endl;
146  std::cerr << "Plugin not loaded." << std::endl;
147  return;
148  }
149  if (_network.HasUnconnectedInPorts())
150  {
151  std::cerr << "CLAM LADSPA: Error loading CLAM network based plugin '" << name << "'." <<std::endl;
152  std::cerr << "Plugin not loaded because internal network inports were unconnected." <<std::endl;
153  std::cerr << _network.GetUnconnectedInPorts() << std::flush;
154  return;
155  }
156 
157  // TOFIX: Should be a full link for the network to obtain parameters
158  // but the network adquires the ownership of the player and, in this case,
159  // the player owns the network.
160  SetNetworkBackLink(_network);
161  LocateConnections();
162 }
163 
164 LadspaNetworkPlayer::~LadspaNetworkPlayer()
165 {
166 }
167 
169 {
170 
171  CLAM_WARNING(_network.SupportsVariableAudioSize(), "Network don't support variable audio size");
172  _network.Start();
173 }
174 
176 {
177  _network.Stop();
178 }
179 
180 void LadspaNetworkPlayer::LocateConnections()
181 {
182  CacheSourcesAndSinks();
183 
184  CLAM_ASSERT( mInControlList.empty(), "LadspaNetworkPlayer::LocateConnections() : there are already registered controls");
185  CLAM_ASSERT( mOutControlList.empty(), "LadspaNetworkPlayer::LocateConnections() : there are already registered controls");
186 
187  Network::ControlSources controlSources = _network.getOrderedControlSources();
188  Network::ControlSinks controlSinks = _network.getOrderedControlSinks();
189 
190  _sourceBuffers.resize(GetNSources());
191  _sinkBuffers.resize(GetNSinks());
192 
193  for (Network::ControlSources::const_iterator it=controlSources.begin(); it!=controlSources.end(); it++)
194  {
195  LADSPAInfo<ControlSource> info;
196  info.name = _network.GetNetworkId(*it).c_str();
197  info.processing=*it;
198  mInControlList.push_back(info);
199  }
200  _inControlBuffers.resize(mInControlList.size());
201 
202  for (Network::ControlSinks::const_iterator it=controlSinks.begin(); it!=controlSinks.end(); it++)
203  {
204  LADSPAInfo<ControlSink> info;
205  info.name = _network.GetNetworkId( *it ).c_str();
206  info.processing =*it;
207  mOutControlList.push_back(info);
208  }
209  _outControlBuffers.resize(mOutControlList.size());
210 
211  UpdatePortFrameAndHopSize();
212 }
213 
214 void LadspaNetworkPlayer::UpdatePortFrameAndHopSize()
215 {
216  //AudioSources and AudioBufferSource
217  for (unsigned i=0; i<GetNSources(); i++)
218  {
219  SetSourceFrameSize(i, mExternBufferSize);
220  }
221  for (unsigned i=0; i<GetNSinks(); i++)
222  {
223  SetSinkFrameSize(i, mExternBufferSize);
224  }
225 }
226 
227 void LadspaNetworkPlayer::FillPortInfo( LADSPA_PortDescriptor* descriptors, char** names, LADSPA_PortRangeHint* rangehints )
228 {
229  int currentport=0;
230 
231  //Manage InPorts (AudioSource and AudioBufferSources)
232  for (unsigned i=0; i<GetNSources(); i++)
233  {
234  descriptors[currentport] = (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO);
235  names[currentport] = LadspaLibrary::dupstr( SourceName(i).c_str() );
236  rangehints[currentport].HintDescriptor = 0;
237  currentport++;
238  }
239 
240  //Manage OutPorts (AudioSink and AudioSinksBuffer)
241  for (unsigned i=0; i<GetNSinks(); i++)
242  {
243  descriptors[currentport] = (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO);
244  names[currentport] = LadspaLibrary::dupstr( SinkName(i).c_str() );
245  rangehints[currentport].HintDescriptor = 0;
246  currentport++;
247  }
248 
249  //Manage InControls (ExternInControls)
250  for (LADSPAInControlList::iterator it=mInControlList.begin(); it!=mInControlList.end(); it++)
251  {
252  descriptors[currentport] = (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL);
253  names[currentport] = LadspaLibrary::dupstr( it->name.c_str() );
254 
255  //Obté processingConfig, i defineix cada param
256  ControlSourceConfig conf = dynamic_cast<const ControlSourceConfig&>(it->processing->GetConfig() );
257 
258  rangehints[currentport].LowerBound=(LADSPA_Data)conf.GetMinValue();
259  rangehints[currentport].UpperBound=(LADSPA_Data)conf.GetMaxValue();
260 
261  unsigned defaultHintValue=LADSPA_HINT_DEFAULT_MIDDLE;
262  // specific cases when the default value is equal to some of defined LADSPA hints (ugly!):
263  if (conf.GetDefaultValue() == conf.GetMinValue() ) defaultHintValue=LADSPA_HINT_DEFAULT_MINIMUM;
264  else if (conf.GetDefaultValue() == conf.GetMaxValue() ) defaultHintValue=LADSPA_HINT_DEFAULT_MAXIMUM;
265  else if (conf.GetDefaultValue() == 0) defaultHintValue = LADSPA_HINT_DEFAULT_0;
266  else if (conf.GetDefaultValue() == 1) defaultHintValue = LADSPA_HINT_DEFAULT_1;
267  else if (conf.GetDefaultValue() == 100) defaultHintValue = LADSPA_HINT_DEFAULT_100;
268  else if (conf.GetDefaultValue() == 440) defaultHintValue = LADSPA_HINT_DEFAULT_440;
269 
270  rangehints[currentport].HintDescriptor = (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | defaultHintValue);
271  currentport++;
272  }
273 
274  //Manage OutControls (ExternOutControls)
275  // (Please note that not all the LADSPA hosts make use of these kind of ports)
276  for (LADSPAOutControlList::iterator it=mOutControlList.begin(); it!=mOutControlList.end(); it++)
277  {
278  descriptors[currentport] = (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL);
279  names[currentport] = LadspaLibrary::dupstr( it->name.c_str() );
280  rangehints[currentport].LowerBound=(LADSPA_Data)0;
281  rangehints[currentport].UpperBound=(LADSPA_Data)1000;
282  rangehints[currentport].HintDescriptor = (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE);
283  currentport++;
284  }
285 }
286 
287 void LadspaNetworkPlayer::Run( unsigned long nsamples )
288 {
289  //Check current buffer size of ports, to make sure everything fits!
290  // if it isn't so, upgrade Frame and Hop sizes (vital)
291  if (nsamples!=mExternBufferSize)
292  {
293  mExternBufferSize=nsamples;
294  if (nsamples==0)
295  return; // Seems that in Ardour2.8 it does never runs plugins with 0 samples
296  UpdatePortFrameAndHopSize();
297  }
298 
299  ProcessInControlValues();
300 
301  EstablishLadspaBuffersToAudioSources(nsamples);
302  EstablishLadspaBuffersToAudioSinks(nsamples);
303  //Do() as much as it is needed
304 // for (int stepcount=0; stepcount < (int(mExternBufferSize)/int(mClamBufferSize)); stepcount++)
305  {
306  _network.Do();
307 // if (stepcount>0) std::cout << "ieeps!" << std::flush;
308  }
309 
310  ProcessOutControlValues();
311 }
312 
313 void LadspaNetworkPlayer::ProcessInControlValues()
314 {
315  for (LADSPAInControlList::iterator it=mInControlList.begin(); it!=mInControlList.end(); it++)
316  it->processing->Do( (float) *(it->dataBuffer) );
317 }
318 
319 void LadspaNetworkPlayer::ProcessOutControlValues()
320 {
321  for (LADSPAOutControlList::iterator it=mOutControlList.begin(); it!=mOutControlList.end(); it++)
322  *(it->dataBuffer)=it->processing->GetControlValue();
323 }
324 
325 void LadspaNetworkPlayer::EstablishLadspaBuffersToAudioSources(const unsigned long nframes)
326 {
327  for (unsigned i=0; i<GetNSources(); i++)
328  SetSourceBuffer(i, _sourceBuffers[i], nframes);
329 }
330 
331 void LadspaNetworkPlayer::EstablishLadspaBuffersToAudioSinks(const unsigned long nframes)
332 {
333  for (unsigned i=0; i<GetNSinks(); i++)
334  SetSinkBuffer(i, _sinkBuffers[i], nframes);
335 }
336 
337 void LadspaNetworkPlayer::ConnectTo(unsigned long port, LADSPA_Data * data)
338 {
339 
340  unsigned nSources = GetNSources();
341  unsigned nSinks = GetNSinks();
342  unsigned nInControls = mInControlList.size();
343  unsigned nOutControls = mInControlList.size();
344 
345  if ( port < nSources ) //Input port
346  {
347  _sourceBuffers[port]=data;
348  return;
349  }
350  port-=nSources;
351  if (port < nSinks) //Output port
352  {
353  _sinkBuffers[port]=data;
354  return;
355  }
356  port-=nSinks;
357  if ( port < nInControls) //Input control
358  {
359  mInControlList.at( port ).dataBuffer=data;
360  return;
361  }
362  port-=nInControls;
363  if (port < nOutControls)
364  {
365  mOutControlList.at( port ).dataBuffer=data;
366  return;
367  }
368 }
369 
370 
371 
372 LADSPA_Descriptor * LadspaNetworkPlayer::CreateLADSPADescriptor(
373  const std::string & networkXmlContent,
374  unsigned id,
375  const std::string & label,
376  const std::string & name,
377  const std::string & maker,
378  const std::string & copyright
379  )
380 {
381  CLAM::LadspaNetworkPlayer plugin(label, networkXmlContent);
382 
383  unsigned numports = plugin.GetNSources() + plugin.GetNSinks() +
384  plugin.mInControlList.size() + plugin.mOutControlList.size();
385 
386  if (numports == 0) return 0;
387 
388  LADSPA_Descriptor * descriptor = new LADSPA_Descriptor;
389 
390  descriptor->UniqueID = id;
391  descriptor->Label = LadspaLibrary::dupstr(label.c_str());
392  descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; // LADSPA_PROPERTY_REALTIME;
393  descriptor->Name = LadspaLibrary::dupstr(name.c_str());
394  descriptor->Maker = LadspaLibrary::dupstr(maker.c_str());
395  descriptor->Copyright = LadspaLibrary::dupstr(copyright.c_str());
396  descriptor->ImplementationData = LadspaLibrary::dupstr(networkXmlContent.c_str());
397  descriptor->PortCount = numports;
398 
399  LADSPA_PortDescriptor * piPortDescriptors = new LADSPA_PortDescriptor[ numports ];
400  descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)piPortDescriptors;
401 
402  char ** pcPortNames = new char*[ numports ];
403 
404  descriptor->PortNames = (const char **)pcPortNames;
405 
406  LADSPA_PortRangeHint * psPortRangeHints = new LADSPA_PortRangeHint[ numports ];
407  descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)psPortRangeHints;
408 
409  plugin.FillPortInfo( piPortDescriptors, pcPortNames, psPortRangeHints);
410 
411  descriptor->instantiate = ::Instantiate;
412  descriptor->connect_port = ::ConnectTo;
413  descriptor->activate = ::Activate;
414  descriptor->run = ::Run;
415  descriptor->deactivate = ::Deactivate;
416  descriptor->cleanup = ::CleanUp;
417 
418  return descriptor;
419 }
420 
422  LadspaLibrary & library, const std::string & networkXmlContent,
423  unsigned id,
424  const std::string & label,
425  const std::string & name,
426  const std::string & maker,
427  const std::string & copyright
428  )
429 {
430  LADSPA_Descriptor * descriptor = LadspaNetworkPlayer::CreateLADSPADescriptor(
431  networkXmlContent, id, label, name,
432  maker, copyright);
433  if (not descriptor) return;
434  library.AddPluginType(descriptor);
435 }
436 
437 } //end namespace CLAM
438