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.

178 lines
4.5KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. InMgr.cpp - MIDI Input Manager
  4. Copyright (C) 2016 Mark McCurry
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. */
  10. #include "InMgr.h"
  11. #include "MidiIn.h"
  12. #include "EngineMgr.h"
  13. #include "../Misc/Master.h"
  14. #include "../Misc/Part.h"
  15. #include "../Misc/MiddleWare.h"
  16. #include <rtosc/thread-link.h>
  17. #include <iostream>
  18. using namespace std;
  19. extern zyncarla::MiddleWare *middleware;
  20. namespace zyncarla {
  21. ostream &operator<<(ostream &out, const MidiEvent &ev)
  22. {
  23. switch(ev.type) {
  24. case M_NOTE:
  25. out << "MidiNote: note(" << ev.num << ")\n"
  26. << " channel(" << ev.channel << ")\n"
  27. << " velocity(" << ev.value << ")";
  28. break;
  29. case M_CONTROLLER:
  30. out << "MidiCtl: controller(" << ev.num << ")\n"
  31. << " channel(" << ev.channel << ")\n"
  32. << " value(" << ev.value << ")";
  33. break;
  34. case M_PGMCHANGE:
  35. out << "PgmChange: program(" << ev.num << ")\n"
  36. << " channel(" << ev.channel << ")";
  37. break;
  38. }
  39. return out;
  40. }
  41. MidiEvent::MidiEvent()
  42. :channel(0), type(0), num(0), value(0), time(0)
  43. {}
  44. InMgr &InMgr::getInstance()
  45. {
  46. static InMgr instance;
  47. return instance;
  48. }
  49. InMgr::InMgr()
  50. :queue(100), master(NULL)
  51. {
  52. current = NULL;
  53. work.init(PTHREAD_PROCESS_PRIVATE, 0);
  54. }
  55. InMgr::~InMgr()
  56. {
  57. //lets stop the consumer thread
  58. }
  59. void InMgr::putEvent(MidiEvent ev)
  60. {
  61. if(queue.push(ev)) //check for error
  62. cerr << "ERROR: Midi Ringbuffer is FULL" << endl;
  63. else
  64. work.post();
  65. }
  66. void InMgr::flush(unsigned frameStart, unsigned frameStop)
  67. {
  68. MidiEvent ev;
  69. while(!work.trywait()) {
  70. queue.peak(ev);
  71. if(ev.time < (int)frameStart || ev.time > (int)frameStop) {
  72. //Back out of transaction
  73. work.post();
  74. //printf("%d vs [%d..%d]\n",ev.time, frameStart, frameStop);
  75. break;
  76. }
  77. queue.pop(ev);
  78. //cout << ev << endl;
  79. switch(ev.type) {
  80. case M_NOTE:
  81. if(ev.value)
  82. master->noteOn(ev.channel, ev.num, ev.value);
  83. else
  84. master->noteOff(ev.channel, ev.num);
  85. break;
  86. case M_CONTROLLER:
  87. if(ev.num == C_bankselectmsb) { // Change current bank
  88. middleware->spawnMaster()->bToU->write("/forward", "");
  89. middleware->spawnMaster()->bToU->write("/bank/msb", "i", ev.value);
  90. middleware->spawnMaster()->bToU->write("/bank/bank_select", "i", ev.value);
  91. } else if(ev.num == C_bankselectlsb) {// Change current bank (LSB)
  92. middleware->spawnMaster()->bToU->write("/forward", "");
  93. middleware->spawnMaster()->bToU->write("/bank/lsb", "i", ev.value);
  94. } else
  95. master->setController(ev.channel, ev.num, ev.value);
  96. break;
  97. case M_PGMCHANGE:
  98. for(int i=0; i < NUM_MIDI_PARTS; ++i) {
  99. //set the program of the parts assigned to the midi channel
  100. if(master->part[i]->Prcvchn == ev.channel) {
  101. middleware->pendingSetProgram(i, ev.num);
  102. }
  103. }
  104. break;
  105. case M_PRESSURE:
  106. master->polyphonicAftertouch(ev.channel, ev.num, ev.value);
  107. break;
  108. }
  109. }
  110. }
  111. bool InMgr::empty(void) const
  112. {
  113. int semvalue = work.getvalue();
  114. return semvalue <= 0;
  115. }
  116. bool InMgr::setSource(string name)
  117. {
  118. MidiIn *src = getIn(name);
  119. if(!src)
  120. return false;
  121. if(current)
  122. current->setMidiEn(false);
  123. current = src;
  124. current->setMidiEn(true);
  125. bool success = current->getMidiEn();
  126. //Keep system in a valid state (aka with a running driver)
  127. if(!success)
  128. (current = getIn("NULL"))->setMidiEn(true);
  129. return success;
  130. }
  131. string InMgr::getSource() const
  132. {
  133. if(current)
  134. return current->name;
  135. else
  136. return "ERROR";
  137. }
  138. MidiIn *InMgr::getIn(string name)
  139. {
  140. EngineMgr &eng = EngineMgr::getInstance(NULL);
  141. return dynamic_cast<MidiIn *>(eng.getEng(name));
  142. }
  143. void InMgr::setMaster(Master *master_)
  144. {
  145. master = master_;
  146. }
  147. }