PageRenderTime 57ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/Csound5.13.0/frontends/csladspa/csladspa.cpp

#
C++ | 499 lines | 385 code | 51 blank | 63 comment | 58 complexity | 425179c318ffb00fdb3ed2a6fd9a4bcb MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, BSD-3-Clause, LGPL-2.0
  1. /*
  2. Copyright (C) 2007 Rory Walsh, Victor Lazzarini
  3. csLADSPA is free software; you can redistribute it
  4. and/or modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. csLADSPA is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with Csound; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  14. 02111-1307 USA
  15. */
  16. #include <dirent.h>
  17. #include <string>
  18. #include <sstream>
  19. #include <cstdlib>
  20. #include <fstream>
  21. #include <iostream>
  22. #include "csound.hpp"
  23. #include "ladspa.h"
  24. using namespace std;
  25. #ifdef WIN32
  26. #define PUBLIC __declspec(dllexport)
  27. #elif defined(__GNUC__)
  28. #define PUBLIC __attribute__ ( (visibility("default")) )
  29. #else
  30. #define PUBLIC
  31. #endif
  32. #define MAXLINESIZE 4098
  33. #define MAXPORTS 64
  34. //to remove leading and trailing spaces
  35. string trim(string s)
  36. {
  37. //trim spaces at start
  38. s.erase( 0, s.find_first_not_of( " \t\n" ) );
  39. //trim spaces at end
  40. s.erase( s.find_last_not_of( " \t\n" ) + 1);
  41. return s;
  42. }
  43. struct AuxData {
  44. string *portnames;
  45. int ksmps;
  46. };
  47. // Csound plugin class
  48. // holds the Csound instancec
  49. // and audio/control port pointers
  50. struct CsoundPlugin {
  51. LADSPA_Data *ctl[MAXPORTS];
  52. LADSPA_Data **inp;
  53. LADSPA_Data **outp;
  54. string *ctlchn;
  55. int ctlports;
  56. Csound* csound;
  57. int result;
  58. MYFLT *spout, *spin;
  59. int chans;
  60. int frames;
  61. CsoundPlugin(const char *csd, int chns, int ports, AuxData* paux,
  62. unsigned long rate);
  63. void Process(unsigned long cnt);
  64. };
  65. // constructor
  66. CsoundPlugin::CsoundPlugin(const char *csd,
  67. int chns, int ports, AuxData *paux,
  68. unsigned long rate){
  69. char** cmdl;
  70. string sr_override, kr_override;
  71. char *sr, *kr;
  72. int ksmps = paux->ksmps;
  73. ctlchn = paux->portnames;
  74. ctlports = ports;
  75. chans = chns;
  76. frames = ksmps;
  77. inp = new LADSPA_Data*[chans];
  78. outp = new LADSPA_Data*[chans];
  79. // csound parameters
  80. cmdl = new char*[5];
  81. cmdl[0] = (char*)"csound";
  82. cmdl[1] = (char *)csd;
  83. cmdl[2] = (char*)"-n";
  84. // sampling-rate override
  85. sr = new char[32];
  86. sprintf(sr,"%d", (int)rate);
  87. sr_override.append("--sample-rate= ");
  88. sr_override.append(sr);
  89. cmdl[3] = (char *) sr_override.c_str();
  90. // ksmps override
  91. kr = new char[32];
  92. sprintf(kr,"%f",(float)rate/ksmps);
  93. kr_override.append("-k ");
  94. kr_override.append(kr);
  95. cmdl[4] = (char *) kr_override.c_str();
  96. csound = new Csound;
  97. csound->PreCompile();
  98. result = csound->Compile(5,cmdl);
  99. spout = csound->GetSpout();
  100. spin = csound->GetSpin();
  101. delete[] cmdl;
  102. delete[] sr;
  103. delete[] kr;
  104. }
  105. // Processing function
  106. void CsoundPlugin::Process(unsigned long cnt){
  107. int pos, i, j, ksmps = csound->GetKsmps(),n = cnt;
  108. MYFLT scale = csound->Get0dBFS();
  109. for(i=0;i<ctlports;i++)
  110. csound->SetChannel(ctlchn[i].c_str(),
  111. *(ctl[i]));
  112. if(!result){
  113. for(i=0; i < n; i++, frames++){
  114. if(frames == ksmps){
  115. result = csound->PerformKsmps();
  116. frames = 0;
  117. }
  118. for(j=0; j < chans; j++)
  119. if(!result){
  120. pos = frames*chans;
  121. spin[j+pos] = inp[j][i]*scale;
  122. outp[j][i] = (LADSPA_Data) (spout[j+pos]/scale);
  123. } else outp[j][i] = 0;
  124. }
  125. }
  126. }
  127. // Plugin instantiation
  128. static LADSPA_Handle createplugin(const LADSPA_Descriptor *pdesc,
  129. unsigned long rate)
  130. {
  131. CsoundPlugin* p;
  132. int i, aports=0;
  133. cerr << "instantiating plugin: " << pdesc->Label << "\n";
  134. for(i=0; i < (int)pdesc->PortCount; i++)
  135. if(pdesc->PortDescriptors[i] & LADSPA_PORT_AUDIO) aports++;
  136. #ifdef DEBUG
  137. cerr << "instantiating plugin: " << pdesc->Label << "\n";
  138. #endif
  139. p = new CsoundPlugin(pdesc->Label, aports/2, pdesc->PortCount-aports,
  140. (AuxData *)pdesc->ImplementationData,rate);
  141. #ifdef DEBUG
  142. if(!p->result)
  143. cerr << "plugin instantiated: " << pdesc->Label << "\n";
  144. else
  145. cerr << "plugin not instantiated \n";
  146. #endif
  147. return p;
  148. }
  149. // Plugin cleanup
  150. static void destroyplugin(LADSPA_Handle inst)
  151. {
  152. CsoundPlugin* p = (CsoundPlugin*)inst;
  153. delete p->csound;
  154. delete[] p->inp;
  155. delete[] p->outp;
  156. delete p;
  157. }
  158. // Port connections
  159. static void connect(LADSPA_Handle inst, unsigned long port, LADSPA_Data* pdata)
  160. {
  161. CsoundPlugin *p = (CsoundPlugin *) inst;
  162. unsigned int chans = p->chans;
  163. if(port < chans) p->inp[port] = pdata;
  164. else if(port < chans*2) p->outp[port-chans] = pdata;
  165. else p->ctl[port-chans*2] = pdata;
  166. }
  167. // Processing entry point
  168. static void runplugin(LADSPA_Handle inst, unsigned long cnt)
  169. {
  170. ((CsoundPlugin *)inst)->Process(cnt);
  171. }
  172. // initialise a descriptor for a given CSD file
  173. static LADSPA_Descriptor *init_descriptor(char *csdname)
  174. {
  175. char *str, *tmp;
  176. string csddata, temp;
  177. int portcnt=2, chans=1,i;
  178. bool plugin_found=false;
  179. string::size_type indx,indx2,equals=0;
  180. fstream csdfile(csdname);
  181. char **PortNames = new char*[MAXPORTS];
  182. AuxData *paux = new AuxData;
  183. float upper, lower;
  184. string *ctlchn = new string[MAXPORTS];
  185. LADSPA_PortDescriptor *PortDescriptors = new LADSPA_PortDescriptor[MAXPORTS];
  186. LADSPA_PortRangeHint *PortRangeHints = new LADSPA_PortRangeHint[MAXPORTS];
  187. LADSPA_Descriptor *desc = new LADSPA_Descriptor;
  188. // if descriptor was created
  189. // and csdfile was open properly
  190. if (desc && csdfile.is_open())
  191. {
  192. tmp = new char[strlen(csdname)+1];
  193. str = new char[MAXLINESIZE+1];
  194. strcpy(tmp, csdname);
  195. desc->Label = (const char*) tmp;
  196. paux->ksmps = 10;
  197. // check channels
  198. while(!csdfile.eof()){
  199. csdfile.getline(str,MAXLINESIZE);
  200. csddata = str;
  201. #ifdef DEBUG
  202. cerr << csddata << "\n";
  203. #endif
  204. // find nchnls header statement
  205. if(csddata.find("nchnls")!=string::npos)
  206. {
  207. indx = csddata.find('=');
  208. temp = csddata.substr(indx+1,100);
  209. chans = (int) atoi((char *) temp.c_str());
  210. portcnt = chans*2;
  211. break;
  212. }
  213. // if we reached the end of header block
  214. else if(csddata.find("instr")!=string::npos) break;
  215. }
  216. csdfile.seekg(0);
  217. // check ksmps, similar to above
  218. while(!csdfile.eof()){
  219. csdfile.getline(str,MAXLINESIZE);
  220. csddata = str;
  221. #ifdef DEBUG
  222. cerr << csddata << "\n";
  223. #endif
  224. if(csddata.find("ksmps")!=string::npos){
  225. indx = csddata.find('=');
  226. temp = csddata.substr(indx+1,100);
  227. paux->ksmps = (int) atoi((char *) temp.c_str());
  228. break;
  229. }
  230. else if(csddata.find("instr")!=string::npos) break;
  231. }
  232. csdfile.seekg(0);
  233. while(!csdfile.eof())
  234. {
  235. csdfile.getline(str,MAXLINESIZE);
  236. csddata = str;
  237. // check for csLADSPA section
  238. if(csddata.find("<csLADSPA>")!=string::npos){
  239. cerr << "cSLADSPA plugin found: \n";
  240. plugin_found = true;
  241. }
  242. // now if we found a plugin header section
  243. // we proceed to read it
  244. if (plugin_found) {
  245. cerr << csddata << "\n";
  246. if(csddata.find("Name")!=string::npos){
  247. equals = csddata.find('=');
  248. temp = csddata.substr(equals+1);
  249. temp = trim(temp);
  250. tmp = new char[temp.length()+1];
  251. strcpy(tmp, (const char*)temp.c_str());
  252. desc->Name = (const char*) tmp;
  253. }
  254. else if(csddata.find("Maker")!=string::npos){
  255. equals = csddata.find('=');
  256. temp = csddata.substr(equals+1) + (sizeof(MYFLT) == 4 ?
  257. " (csLADSPA: Lazzarini, Walsh)" :
  258. " (csLADSPA64: Lazzarini, Walsh)") ;
  259. temp = trim(temp);
  260. tmp = new char[temp.length()+1];
  261. strcpy(tmp, (const char*)temp.c_str());
  262. desc->Maker = (const char*) tmp;
  263. }
  264. else if(csddata.find("UniqueID")!=string::npos){
  265. equals = csddata.find('=');
  266. temp = csddata.substr(equals+1);
  267. temp = trim(temp);
  268. desc->UniqueID = atoi(temp.c_str());
  269. }
  270. else if(csddata.find("Copyright")!=string::npos){
  271. equals = csddata.find('=');
  272. temp = csddata.substr(equals+1, 100);
  273. temp = trim(temp);
  274. tmp = new char[temp.length()+1];
  275. strcpy(tmp, (const char*)temp.c_str());
  276. desc->Copyright = (const char*) tmp;
  277. }
  278. else if(csddata.find("ControlPort")!=string::npos)
  279. {
  280. equals = csddata.find('=');
  281. if(portcnt < MAXPORTS) {
  282. PortDescriptors[portcnt] =
  283. LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
  284. temp = csddata;
  285. indx = temp.find('|');
  286. string temp2 = trim(temp.substr(equals+1,indx-(equals+1)));
  287. PortNames[portcnt] = new char[temp2.length()+1];
  288. strcpy(PortNames[portcnt], (const char*)temp2.c_str());
  289. temp2 = trim(temp.substr(indx+1));
  290. ctlchn[portcnt-chans*2] = temp2;//temp.substr(indx+1);
  291. csdfile.getline(str,500);
  292. csddata = str;
  293. temp = csddata.substr(6, 200);
  294. indx = temp.find('|');
  295. indx2 = temp.find('&');
  296. // if &log is found in the range spec, then we have a
  297. // LOGARITHMIC response
  298. if(indx2<200 &&
  299. !strcmp(temp.substr(indx2+1,indx2+3).c_str(), "log")){
  300. PortRangeHints[portcnt].HintDescriptor =
  301. (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE
  302. | LADSPA_HINT_LOGARITHMIC | LADSPA_HINT_DEFAULT_MIDDLE);
  303. lower = atof((char*)temp.substr(0, indx).c_str());
  304. upper = atof((char*)temp.substr(indx+1, indx2).c_str());
  305. }
  306. else {
  307. PortRangeHints[portcnt].HintDescriptor =
  308. (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE );
  309. lower = atoi((char*)temp.substr(0, indx).c_str());
  310. upper = atoi((char*)temp.substr(indx+1, 200).c_str());
  311. }
  312. PortRangeHints[portcnt].LowerBound =
  313. lower < upper ? lower : upper;
  314. PortRangeHints[portcnt].UpperBound =
  315. upper > lower ? upper : lower;
  316. portcnt++;
  317. indx2 = 0;
  318. }
  319. }
  320. else if(csddata.find("</csLADSPA>")!=string::npos) break;
  321. }
  322. }
  323. csdfile.close();
  324. // now if a csLADSPA section was found
  325. // we proceed to create the plugin descriptor
  326. if(plugin_found) {
  327. desc->PortCount = portcnt;
  328. for(i=0;i<chans;i++){
  329. PortDescriptors[i] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
  330. PortDescriptors[i+chans] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
  331. PortRangeHints[i].HintDescriptor = 0;
  332. PortRangeHints[i+chans].HintDescriptor = 0;
  333. PortNames[i] = new char[32];
  334. sprintf(PortNames[i], "csladspa-audio-in%d", i);
  335. PortNames[i+chans] = new char[32];
  336. sprintf(PortNames[i+chans], "csladspa-audio-out%d", i);
  337. }
  338. desc->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
  339. desc->PortDescriptors = (const LADSPA_PortDescriptor *) PortDescriptors;
  340. desc->PortNames = (const char **)PortNames;
  341. desc->PortRangeHints = (const LADSPA_PortRangeHint *) PortRangeHints;
  342. desc->instantiate = createplugin;
  343. desc->connect_port = connect;
  344. desc->activate = NULL;
  345. desc->run = runplugin;
  346. desc->run_adding = NULL;
  347. desc->set_run_adding_gain = NULL;
  348. desc->deactivate = NULL;
  349. desc->cleanup = destroyplugin;
  350. // add the channel names to the descriptor
  351. paux->portnames = ctlchn;
  352. desc->ImplementationData = (void *) paux;
  353. delete[] str;
  354. cerr << "PLUGIN LOADED\n";
  355. return desc;
  356. }
  357. }
  358. // otherwise we just delete the empty descriptors
  359. // and return NULL
  360. delete desc;
  361. delete[] PortDescriptors;
  362. delete[] PortRangeHints;
  363. cerr << "PLUGIN NOT LOADED: probably missing csLADSPA section\n";
  364. return NULL;
  365. }
  366. // count CSDs in the current directory
  367. unsigned int CountCSD(char **csdnames)
  368. {
  369. DIR *dip = NULL;
  370. struct dirent *dit;
  371. string temp, name, path;
  372. char *ladspa_path;
  373. int i = 0;
  374. unsigned int indx = 0;
  375. #ifndef MACOSX
  376. ladspa_path = getenv("LADSPA_PATH");
  377. #else
  378. ladspa_path = "/Library/Audio/Plug-Ins/LADSPA";
  379. #endif
  380. // if no LADSPA_PATH attempt to open
  381. // current directory
  382. if(ladspa_path == NULL) dip = opendir(".");
  383. else {
  384. path = ladspa_path;
  385. #ifdef WIN32
  386. indx = path.find(";");
  387. #else
  388. indx = path.find(":");
  389. #endif
  390. if(indx!=string::npos){
  391. dip = opendir(path.substr(0,indx).c_str());
  392. strcpy(ladspa_path, path.substr(0,indx).c_str());
  393. }
  394. else dip = opendir(ladspa_path);
  395. }
  396. if (dip == NULL){
  397. return 0;
  398. }
  399. while ((dit = readdir(dip))!=NULL)
  400. {
  401. temp = dit->d_name;
  402. indx = temp.find(".csd", 0);
  403. string validExt = trim(temp.substr(indx+1));
  404. if(!validExt.compare("csd"))
  405. {
  406. if(ladspa_path != NULL) {
  407. name = ladspa_path;
  408. name.append("/");
  409. name.append(temp);
  410. }
  411. else name = temp;
  412. csdnames[i] = new char[name.length()+1];
  413. strcpy(csdnames[i], (char*)name.c_str());
  414. i++;
  415. }
  416. }
  417. return i;
  418. }
  419. // plugin lib entry point
  420. PUBLIC
  421. const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index)
  422. {
  423. // count CSD files to build the plugin lib
  424. // and fill in the CSD names list
  425. LADSPA_Descriptor *descriptor = NULL;
  426. char **csdnames = new char*[100];
  427. unsigned int csds;
  428. csds = CountCSD(csdnames);
  429. // if the requested index is in the range of CSD numbers
  430. if(Index<csds)
  431. {
  432. cerr << "attempting to load plugin index: " << Index << "\n";
  433. // initialise the descriptor for a given CSD
  434. descriptor = init_descriptor(csdnames[Index]);
  435. }
  436. // delete the CSD list
  437. for(unsigned int i=0; i < csds; i++) delete[] csdnames[i];
  438. if(descriptor == NULL)
  439. cerr << "no more csLADSPA plugins\n";
  440. return descriptor;
  441. }