Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

712 lines
25KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. DSSIaudiooutput.cpp - Audio functions for DSSI
  4. Copyright (C) 2002 Nasca Octavian Paul
  5. Author: Nasca Octavian Paul
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of version 2 of the GNU General Public License
  8. as published by the Free Software Foundation.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License (version 2 or later) for more details.
  13. You should have received a copy of the GNU General Public License (version 2)
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. /*
  18. * Inital working DSSI output code contributed by Stephen G. Parry
  19. */
  20. //this file contains code used from trivial_synth.c from
  21. //the DSSI (published by Steve Harris under public domain) as a template.
  22. #include "DSSIaudiooutput.h"
  23. #include "../Misc/Config.h"
  24. #include "../Misc/Bank.h"
  25. #include "../Misc/Util.h"
  26. #include <string.h>
  27. #include <limits.h>
  28. using std::string;
  29. using std::vector;
  30. //Dummy variables and functions for linking purposes
  31. const char *instance_name = 0;
  32. class WavFile;
  33. namespace Nio {
  34. bool start(void){return 1;};
  35. void stop(void){};
  36. void waveNew(WavFile *){}
  37. void waveStart(void){}
  38. void waveStop(void){}
  39. void waveEnd(void){}
  40. }
  41. //
  42. // Static stubs for LADSPA member functions
  43. //
  44. // LADSPA is essentially a C handle based API; This plug-in implementation is
  45. // a C++ OO one so we need stub functions to map from C API calls to C++ object
  46. // method calls.
  47. void DSSIaudiooutput::stub_connectPort(LADSPA_Handle instance,
  48. unsigned long port,
  49. LADSPA_Data *data)
  50. {
  51. getInstance(instance)->connectPort(port, data);
  52. }
  53. void DSSIaudiooutput::stub_activate(LADSPA_Handle instance)
  54. {
  55. getInstance(instance)->activate();
  56. }
  57. void DSSIaudiooutput::stub_run(LADSPA_Handle instance,
  58. unsigned long sample_count)
  59. {
  60. getInstance(instance)->run(sample_count);
  61. }
  62. void DSSIaudiooutput::stub_deactivate(LADSPA_Handle instance)
  63. {
  64. getInstance(instance)->deactivate();
  65. }
  66. void DSSIaudiooutput::stub_cleanup(LADSPA_Handle instance)
  67. {
  68. DSSIaudiooutput *plugin_instance = getInstance(instance);
  69. plugin_instance->cleanup();
  70. delete plugin_instance;
  71. }
  72. const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
  73. {
  74. return DSSIaudiooutput::getLadspaDescriptor(index);
  75. }
  76. //
  77. // Static stubs for DSSI member functions
  78. //
  79. // DSSI is essentially a C handle based API; This plug-in implementation is
  80. // a C++ OO one so we need stub functions to map from C API calls to C++ object
  81. // method calls.
  82. const DSSI_Program_Descriptor *DSSIaudiooutput::stub_getProgram(
  83. LADSPA_Handle instance,
  84. unsigned long index)
  85. {
  86. return getInstance(instance)->getProgram(index);
  87. }
  88. void DSSIaudiooutput::stub_selectProgram(LADSPA_Handle instance,
  89. unsigned long bank,
  90. unsigned long program)
  91. {
  92. getInstance(instance)->selectProgram(bank, program);
  93. }
  94. int DSSIaudiooutput::stub_getMidiControllerForPort(LADSPA_Handle instance,
  95. unsigned long port)
  96. {
  97. return getInstance(instance)->getMidiControllerForPort(port);
  98. }
  99. void DSSIaudiooutput::stub_runSynth(LADSPA_Handle instance,
  100. unsigned long sample_count,
  101. snd_seq_event_t *events,
  102. unsigned long event_count)
  103. {
  104. getInstance(instance)->runSynth(sample_count, events, event_count);
  105. }
  106. const DSSI_Descriptor *dssi_descriptor(unsigned long index)
  107. {
  108. return DSSIaudiooutput::getDssiDescriptor(index);
  109. }
  110. //
  111. // LADSPA member functions
  112. //
  113. /**
  114. * Instantiates a plug-in.
  115. *
  116. * This LADSPA member function instantiates a plug-in.
  117. * Note that instance initialisation should generally occur in
  118. * activate() rather than here.
  119. *
  120. * Zyn Implementation
  121. * ------------------
  122. * This implementation creates a C++ class object and hides its pointer
  123. * in the handle by type casting.
  124. *
  125. * @param descriptor [in] the descriptor for this plug-in
  126. * @param s_rate [in] the sample rate
  127. * @return the plug-in instance handle if successful else NULL
  128. */
  129. LADSPA_Handle DSSIaudiooutput::instantiate(const LADSPA_Descriptor *descriptor,
  130. unsigned long s_rate)
  131. {
  132. if(descriptor->UniqueID == dssiDescriptor->LADSPA_Plugin->UniqueID)
  133. return (LADSPA_Handle)(new DSSIaudiooutput(s_rate));
  134. else
  135. return NULL;
  136. }
  137. /**
  138. * Connects a port on an instantiated plug-in.
  139. *
  140. * This LADSPA member function connects a port on an instantiated plug-in to a
  141. * memory location at which a block of data for the port will be read/written.
  142. * The data location is expected to be an array of LADSPA_Data for audio ports
  143. * or a single LADSPA_Data value for control ports. Memory issues will be
  144. * managed by the host. The plug-in must read/write the data at these locations
  145. * every time run() or run_adding() is called and the data present at the time
  146. * of this connection call should not be considered meaningful.
  147. *
  148. * Zyn Implementation
  149. * ------------------
  150. * The buffer pointers are stored as member variables
  151. *
  152. * @param port [in] the port to be connected
  153. * @param data [in] the data buffer to write to / read from
  154. */
  155. void DSSIaudiooutput::connectPort(unsigned long port, LADSPA_Data *data)
  156. {
  157. switch(port) {
  158. case 0:
  159. outl = data;
  160. break;
  161. case 1:
  162. outr = data;
  163. break;
  164. }
  165. }
  166. /**
  167. * Initialises a plug-in instance and activates it for use.
  168. *
  169. * This LADSPA member function initialises a plug-in instance and activates it
  170. * for use. This is separated from instantiate() to aid real-time support and
  171. * so that hosts can reinitialise a plug-in instance by calling deactivate() and
  172. * then activate(). In this case the plug-in instance must reset all state
  173. * information dependent on the history of the plug-in instance except for any
  174. * data locations provided by connect_port() and any gain set by
  175. * set_run_adding_gain().
  176. *
  177. * Zyn Implementation
  178. * ------------------
  179. * Currently this does nothing; Care must be taken as to code placed here as
  180. * too much code here seems to cause time-out problems in jack-dssi-host.
  181. */
  182. void DSSIaudiooutput::activate()
  183. {}
  184. /**
  185. * Runs an instance of a plug-in for a block.
  186. *
  187. * This LADSPA member function runs an instance of a plug-in for a block.
  188. * Note that if an activate() function exists then it must be called before
  189. * run() or run_adding(). If deactivate() is called for a plug-in instance then
  190. * the plug-in instance may not be reused until activate() has been called again.
  191. *
  192. * Zyn Implementation
  193. * ------------------
  194. * This is a LADSPA function that does not process any MIDI events; it is hence
  195. * implemented by simply calling runSynth() with an empty event list.
  196. *
  197. * @param sample_count [in] the block size (in samples) for which the plug-in instance may run
  198. */
  199. void DSSIaudiooutput::run(unsigned long sample_count)
  200. {
  201. runSynth(sample_count, NULL, (unsigned long)0);
  202. }
  203. /**
  204. * Counterpart to activate().
  205. *
  206. * This LADSPA member function is the counterpart to activate() (see above).
  207. * Deactivation is not similar to pausing as the plug-in instance will be
  208. * reinitialised when activate() is called to reuse it.
  209. *
  210. * Zyn Implementation
  211. * ------------------
  212. * Currently this function does nothing.
  213. */
  214. void DSSIaudiooutput::deactivate()
  215. {}
  216. /**
  217. * Deletes a plug-in instance that is no longer required.
  218. *
  219. * LADSPA member function; once an instance of a plug-in has been finished with
  220. * it can be deleted using this function. The instance handle ceases to be
  221. * valid after this call.
  222. *
  223. * If activate() was called for a plug-in instance then a corresponding call to
  224. * deactivate() must be made before cleanup() is called.
  225. *
  226. * Zyn Implementation
  227. * ------------------
  228. * Currently cleanup is deferred to the destructor that is invoked after cleanup()
  229. */
  230. void DSSIaudiooutput::cleanup()
  231. {}
  232. /**
  233. * Initial entry point for the LADSPA plug-in library.
  234. *
  235. * This LADSPA function is the initial entry point for the plug-in library.
  236. * The LADSPA host looks for this entry point in each shared library object it
  237. * finds and then calls the function to enumerate the plug-ins within the
  238. * library.
  239. *
  240. * Zyn Implementation
  241. * ------------------
  242. * As the Zyn plug-in is a DSSI plug-in, the LADSPA descriptor is embedded inside
  243. * the DSSI descriptor, which is created by DSSIaudiooutput::initDssiDescriptor()
  244. * statically when the library is loaded. This function then merely returns a pointer
  245. * to that embedded descriptor.
  246. *
  247. * @param index [in] the index number of the plug-in within the library.
  248. * @return if index is in range, a pointer to the plug-in descriptor is returned, else NULL
  249. */
  250. const LADSPA_Descriptor *DSSIaudiooutput::getLadspaDescriptor(
  251. unsigned long index)
  252. {
  253. if((index > 0) || (dssiDescriptor == NULL))
  254. return NULL;
  255. else
  256. return dssiDescriptor->LADSPA_Plugin;
  257. }
  258. //
  259. // DSSI member functions
  260. //
  261. /**
  262. * Provides a description of a program available on this synth.
  263. *
  264. * This DSSI member function pointer provides a description of a program (named
  265. * preset sound) available on this synth.
  266. *
  267. * Zyn Implementation
  268. * ------------------
  269. * The instruments in all Zyn's bank directories, as shown by the `instrument
  270. * -> show instrument bank` command, are enumerated to the host by this
  271. * function, allowing access to all those instruments.
  272. * The first time an instrument is requested, the bank it is in and any
  273. * unmapped ones preceding that are mapped; all the instruments names and
  274. * filenames from those banks are stored in the programMap member variable for
  275. * later use. This is done on demand in this way, rather than up front in one
  276. * go because loading all the instrument names in one go can lead to timeouts
  277. * and zombies.
  278. *
  279. * @param index [in] index into the plug-in's list of
  280. * programs, not a program number as represented by the Program
  281. * field of the DSSI_Program_Descriptor. (This distinction is
  282. * needed to support synths that use non-contiguous program or
  283. * bank numbers.)
  284. * @return a DSSI_Program_Descriptor pointer that is
  285. * guaranteed to be valid only until the next call to get_program,
  286. * deactivate, or configure, on the same plug-in instance, or NULL if index is out of range.
  287. */
  288. const DSSI_Program_Descriptor *DSSIaudiooutput::getProgram(unsigned long index)
  289. {
  290. static DSSI_Program_Descriptor retVal;
  291. /* Make sure we have the list of banks loaded */
  292. initBanks();
  293. /* Make sure that the bank containing the instrument has been mapped */
  294. while(index >= programMap.size() && mapNextBank())
  295. /* DO NOTHING MORE */;
  296. if(index >= programMap.size())
  297. /* No more instruments */
  298. return NULL;
  299. else {
  300. /* OK, return the instrument */
  301. retVal.Name = programMap[index].name.c_str();
  302. retVal.Program = programMap[index].program;
  303. retVal.Bank = programMap[index].bank;
  304. return &retVal;
  305. }
  306. }
  307. /**
  308. * Selects a new program for this synth.
  309. *
  310. * This DSSI member function selects a new program for this synth. The program
  311. * change will take effect immediately at the start of the next run_synth()
  312. * call. An invalid bank / instrument combination is ignored.
  313. *
  314. * Zyn Implementation
  315. * ------------------
  316. * the banks and instruments are as shown in the `instrument -> show instrument
  317. * bank` command in Zyn. The bank no is a 1-based index into the list of banks
  318. * Zyn loads and shows in the drop down and the program number is the
  319. * instrument within that bank.
  320. *
  321. * @param bank [in] the bank number to select
  322. * @param program [in] the program number within the bank to select
  323. */
  324. void DSSIaudiooutput::selectProgram(unsigned long bank, unsigned long program)
  325. {
  326. initBanks();
  327. // cerr << "selectProgram(" << (bank & 0x7F) << ':' << ((bank >> 7) & 0x7F) << "," << program << ")" << '\n';
  328. if((bank < master->bank.banks.size()) && (program < BANK_SIZE)) {
  329. const std::string bankdir = master->bank.banks[bank].dir;
  330. if(!bankdir.empty()) {
  331. pthread_mutex_lock(&master->mutex);
  332. /* We have to turn off the CheckPADsynth functionality, else
  333. * the program change takes way too long and we get timeouts
  334. * and hence zombies (!) */
  335. int save = config.cfg.CheckPADsynth;
  336. config.cfg.CheckPADsynth = 0;
  337. /* Load the bank... */
  338. master->bank.loadbank(bankdir);
  339. /* restore the CheckPADsynth flag */
  340. config.cfg.CheckPADsynth = save;
  341. /* Now load the instrument... */
  342. master->bank.loadfromslot((unsigned int)program, master->part[0]);
  343. pthread_mutex_unlock(&master->mutex);
  344. }
  345. }
  346. }
  347. /**
  348. * Returns the MIDI controller number or NRPN for a input control port
  349. *
  350. * This DSSI member function returns the MIDI controller number or NRPN that
  351. * should be mapped to the given input control port. If the given port should
  352. * not have any MIDI controller mapped to it, the function will return DSSI_NONE.
  353. * The behaviour of this function is undefined if the given port
  354. * number does not correspond to an input control port.
  355. *
  356. * Zyn Implementation
  357. * ------------------
  358. * Currently Zyn does not define any controller ports, but may do in the future.
  359. *
  360. * @param port [in] the input controller port
  361. * @return the CC and NRPN values shifted and ORed together.
  362. */
  363. int DSSIaudiooutput::getMidiControllerForPort(unsigned long port)
  364. {
  365. return DSSI_NONE;
  366. }
  367. /**
  368. * Runs the synth for a block.
  369. *
  370. * This DSSI member function runs the synth for a block. This is identical in
  371. * function to the LADSPA run() function, except that it also supplies events
  372. * to the synth.
  373. *
  374. * Zyn Implementation
  375. * ------------------
  376. * Zyn implements synthesis in Master::GetAudioOutSamples; runSynth calls this
  377. * function in chunks delimited by the sample_count and the frame indexes in
  378. * the events block, calling the appropriate NoteOn, NoteOff and SetController
  379. * members of Master to process the events supplied between each chunk.
  380. *
  381. * @param sample_count [in] the block size (in samples) for which the synth
  382. * instance may run.
  383. * @param events [in] The Events pointer points to a block of ALSA
  384. * sequencer events, used to communicate MIDI and related events to the synth.
  385. * Each event must be timestamped relative to the start of the block,
  386. * (mis)using the ALSA "tick time" field as a frame count. The host is
  387. * responsible for ensuring that events with differing timestamps are already
  388. * ordered by time. Must not include NOTE (only NOTE_ON / NOTE_OFF), LSB or MSB
  389. * events.
  390. * @param event_count [in] the number of entries in the `events` block
  391. */
  392. void DSSIaudiooutput::runSynth(unsigned long sample_count,
  393. snd_seq_event_t *events,
  394. unsigned long event_count)
  395. {
  396. unsigned long from_frame = 0;
  397. unsigned long event_index = 0;
  398. unsigned long next_event_frame = 0;
  399. unsigned long to_frame = 0;
  400. pthread_mutex_lock(&master->mutex);
  401. do {
  402. /* Find the time of the next event, if any */
  403. if((events == NULL) || (event_index >= event_count))
  404. next_event_frame = ULONG_MAX;
  405. else
  406. next_event_frame = events[event_index].time.tick;
  407. /* find the end of the sub-sample to be processed this time round... */
  408. /* if the next event falls within the desired sample interval... */
  409. if((next_event_frame < sample_count) && (next_event_frame >= to_frame))
  410. /* set the end to be at that event */
  411. to_frame = next_event_frame;
  412. else
  413. /* ...else go for the whole remaining sample */
  414. to_frame = sample_count;
  415. if(from_frame < to_frame) {
  416. // call master to fill from `from_frame` to `to_frame`:
  417. master->GetAudioOutSamples(to_frame - from_frame,
  418. (int)sampleRate,
  419. &(outl[from_frame]),
  420. &(outr[from_frame]));
  421. // next sub-sample please...
  422. from_frame = to_frame;
  423. }
  424. // Now process any event(s) at the current timing point
  425. while(events != NULL && event_index < event_count
  426. && events[event_index].time.tick == to_frame) {
  427. if(events[event_index].type == SND_SEQ_EVENT_NOTEON)
  428. master->noteOn(events[event_index].data.note.channel,
  429. events[event_index].data.note.note,
  430. events[event_index].data.note.velocity);
  431. else
  432. if(events[event_index].type == SND_SEQ_EVENT_NOTEOFF)
  433. master->noteOff(events[event_index].data.note.channel,
  434. events[event_index].data.note.note);
  435. else
  436. if(events[event_index].type == SND_SEQ_EVENT_CONTROLLER)
  437. master->setController(events[event_index].data.control.channel,
  438. events[event_index].data.control.param,
  439. events[event_index].data.control.value);
  440. else {}
  441. event_index++;
  442. }
  443. // Keep going until we have the desired total length of sample...
  444. } while(to_frame < sample_count);
  445. pthread_mutex_unlock(&master->mutex);
  446. }
  447. /**
  448. * Initial entry point for the DSSI plug-in library.
  449. *
  450. * This DSSI function is the initial entry point for the plug-in library.
  451. * The DSSI host looks for this entry point in each shared library object it
  452. * finds and then calls the function to enumerate the plug-ins within the
  453. * library.
  454. *
  455. * Zyn Implementation
  456. * ------------------
  457. * The descriptor is created statically by DSSIaudiooutput::initDssiDescriptor()
  458. * when the plug-in library is loaded. This function merely returns a pointer to
  459. * that descriptor.
  460. *
  461. * @param index [in] the index number of the plug-in within the library.
  462. * @return if index is in range, a pointer to the plug-in descriptor is returned, else NULL
  463. */
  464. const DSSI_Descriptor *DSSIaudiooutput::getDssiDescriptor(unsigned long index)
  465. {
  466. if((index > 0) || (dssiDescriptor == NULL))
  467. return NULL;
  468. else
  469. return dssiDescriptor;
  470. }
  471. //
  472. // Internal member functions
  473. //
  474. // Initialise the DSSI descriptor, statically:
  475. DSSI_Descriptor *DSSIaudiooutput::dssiDescriptor =
  476. DSSIaudiooutput::initDssiDescriptor();
  477. /**
  478. * Initializes the DSSI (and LADSPA) descriptor, returning it is an object.
  479. */
  480. DSSI_Descriptor *DSSIaudiooutput::initDssiDescriptor()
  481. {
  482. DSSI_Descriptor *newDssiDescriptor = new DSSI_Descriptor;
  483. LADSPA_PortDescriptor *newPortDescriptors;
  484. const char **newPortNames;
  485. LADSPA_PortRangeHint *newPortRangeHints;
  486. if(newDssiDescriptor) {
  487. LADSPA_Descriptor *newLadspaDescriptor = new LADSPA_Descriptor;
  488. if(newLadspaDescriptor) {
  489. newLadspaDescriptor->UniqueID = 100;
  490. newLadspaDescriptor->Label = "ZASF";
  491. newLadspaDescriptor->Properties = 0;
  492. newLadspaDescriptor->Name = "ZynAddSubFX";
  493. newLadspaDescriptor->Maker =
  494. "Nasca Octavian Paul <zynaddsubfx@yahoo.com>";
  495. newLadspaDescriptor->Copyright = "GNU General Public License v.2";
  496. newLadspaDescriptor->PortCount = 2;
  497. newPortNames = new const char *[newLadspaDescriptor->PortCount];
  498. newPortNames[0] = "Output L";
  499. newPortNames[1] = "Output R";
  500. newLadspaDescriptor->PortNames = newPortNames;
  501. newPortDescriptors =
  502. new LADSPA_PortDescriptor[newLadspaDescriptor->PortCount];
  503. newPortDescriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
  504. newPortDescriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
  505. newLadspaDescriptor->PortDescriptors = newPortDescriptors;
  506. newPortRangeHints =
  507. new LADSPA_PortRangeHint[newLadspaDescriptor->PortCount];
  508. newPortRangeHints[0].HintDescriptor = 0;
  509. newPortRangeHints[1].HintDescriptor = 0;
  510. newLadspaDescriptor->PortRangeHints = newPortRangeHints;
  511. newLadspaDescriptor->activate = stub_activate;
  512. newLadspaDescriptor->cleanup = stub_cleanup;
  513. newLadspaDescriptor->connect_port = stub_connectPort;
  514. newLadspaDescriptor->deactivate = stub_deactivate;
  515. newLadspaDescriptor->instantiate = instantiate;
  516. newLadspaDescriptor->run = stub_run;
  517. newLadspaDescriptor->run_adding = NULL;
  518. newLadspaDescriptor->set_run_adding_gain = NULL;
  519. }
  520. newDssiDescriptor->LADSPA_Plugin = newLadspaDescriptor;
  521. newDssiDescriptor->DSSI_API_Version = 1;
  522. newDssiDescriptor->configure = NULL;
  523. newDssiDescriptor->get_program = stub_getProgram;
  524. newDssiDescriptor->get_midi_controller_for_port =
  525. stub_getMidiControllerForPort;
  526. newDssiDescriptor->select_program = stub_selectProgram;
  527. newDssiDescriptor->run_synth = stub_runSynth;
  528. newDssiDescriptor->run_synth_adding = NULL;
  529. newDssiDescriptor->run_multiple_synths = NULL;
  530. newDssiDescriptor->run_multiple_synths_adding = NULL;
  531. }
  532. dssiDescriptor = newDssiDescriptor;
  533. return dssiDescriptor;
  534. }
  535. /**
  536. * Converts a LADSPA / DSSI handle into a DSSIaudiooutput instance.
  537. *
  538. * @param instance [in]
  539. * @return the instance
  540. */
  541. DSSIaudiooutput *DSSIaudiooutput::getInstance(LADSPA_Handle instance)
  542. {
  543. return (DSSIaudiooutput *)(instance);
  544. }
  545. SYNTH_T *synth;
  546. /**
  547. * The private sole constructor for the DSSIaudiooutput class.
  548. *
  549. * Only ever called via instantiate().
  550. * @param sampleRate [in] the sample rate to be used by the synth.
  551. * @return
  552. */
  553. DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate)
  554. {
  555. synth = new SYNTH_T;
  556. synth->samplerate = sampleRate;
  557. this->sampleRate = sampleRate;
  558. this->banksInited = false;
  559. config.init();
  560. sprng(time(NULL));
  561. denormalkillbuf = new float [synth->buffersize];
  562. for(int i = 0; i < synth->buffersize; i++)
  563. denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
  564. synth->alias();
  565. this->master = new Master();
  566. }
  567. /**
  568. * The destructor for the DSSIaudiooutput class
  569. * @return
  570. */
  571. DSSIaudiooutput::~DSSIaudiooutput()
  572. {}
  573. /**
  574. * Ensures the list of bank (directories) has been initialised.
  575. */
  576. void DSSIaudiooutput::initBanks(void)
  577. {
  578. if(!banksInited) {
  579. pthread_mutex_lock(&master->mutex);
  580. master->bank.rescanforbanks();
  581. banksInited = true;
  582. pthread_mutex_unlock(&master->mutex);
  583. }
  584. }
  585. /**
  586. * constructor for the internally used ProgramDescriptor class
  587. *
  588. * @param _bank [in] bank number
  589. * @param _program [in] program number
  590. * @param _name [in] instrument / sample name
  591. * @return
  592. */
  593. DSSIaudiooutput::ProgramDescriptor::ProgramDescriptor(unsigned long _bank,
  594. unsigned long _program,
  595. char *_name)
  596. :bank(_bank), program(_program), name(_name)
  597. {}
  598. /**
  599. * The map of programs available; held as a single shared statically allocated object.
  600. */
  601. vector<DSSIaudiooutput::ProgramDescriptor> DSSIaudiooutput::programMap =
  602. vector<DSSIaudiooutput::ProgramDescriptor>();
  603. /**
  604. * Index controlling the map of banks
  605. */
  606. long DSSIaudiooutput::bankNoToMap = 1;
  607. /**
  608. * Queries and maps the next available bank of instruments.
  609. *
  610. * If the program index requested to getProgram() lies beyond the banks mapped to date,
  611. * this member function is called to map the next one.
  612. * @return true if a new bank has been found and mapped, else false.
  613. */
  614. bool DSSIaudiooutput::mapNextBank()
  615. {
  616. pthread_mutex_lock(&master->mutex);
  617. Bank &bank = master->bank;
  618. bool retval;
  619. if((bankNoToMap >= (int)bank.banks.size())
  620. || bank.banks[bankNoToMap].dir.empty())
  621. retval = false;
  622. else {
  623. bank.loadbank(bank.banks[bankNoToMap].dir);
  624. for(unsigned long instrument = 0; instrument < BANK_SIZE;
  625. ++instrument) {
  626. string insName = bank.getname(instrument);
  627. if(!insName.empty() && (insName[0] != '\0') && (insName[0] != ' '))
  628. programMap.push_back(ProgramDescriptor(bankNoToMap, instrument,
  629. const_cast<char *>(
  630. insName.c_str())));
  631. }
  632. bankNoToMap++;
  633. retval = true;
  634. }
  635. pthread_mutex_unlock(&master->mutex);
  636. return retval;
  637. }