Collection of tools useful for audio production
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.

699 lines
24KB

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