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.

175 lines
4.4KB

  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 MiddleWare *middleware;
  20. ostream &operator<<(ostream &out, const MidiEvent &ev)
  21. {
  22. switch(ev.type) {
  23. case M_NOTE:
  24. out << "MidiNote: note(" << ev.num << ")\n"
  25. << " channel(" << ev.channel << ")\n"
  26. << " velocity(" << ev.value << ")";
  27. break;
  28. case M_CONTROLLER:
  29. out << "MidiCtl: controller(" << ev.num << ")\n"
  30. << " channel(" << ev.channel << ")\n"
  31. << " value(" << ev.value << ")";
  32. break;
  33. case M_PGMCHANGE:
  34. out << "PgmChange: program(" << ev.num << ")\n"
  35. << " channel(" << ev.channel << ")";
  36. break;
  37. }
  38. return out;
  39. }
  40. MidiEvent::MidiEvent()
  41. :channel(0), type(0), num(0), value(0), time(0)
  42. {}
  43. InMgr &InMgr::getInstance()
  44. {
  45. static InMgr instance;
  46. return instance;
  47. }
  48. InMgr::InMgr()
  49. :queue(100), master(NULL)
  50. {
  51. current = NULL;
  52. work.init(PTHREAD_PROCESS_PRIVATE, 0);
  53. }
  54. InMgr::~InMgr()
  55. {
  56. //lets stop the consumer thread
  57. }
  58. void InMgr::putEvent(MidiEvent ev)
  59. {
  60. if(queue.push(ev)) //check for error
  61. cerr << "ERROR: Midi Ringbuffer is FULL" << endl;
  62. else
  63. work.post();
  64. }
  65. void InMgr::flush(unsigned frameStart, unsigned frameStop)
  66. {
  67. MidiEvent ev;
  68. while(!work.trywait()) {
  69. queue.peak(ev);
  70. if(ev.time < (int)frameStart || ev.time > (int)frameStop) {
  71. //Back out of transaction
  72. work.post();
  73. //printf("%d vs [%d..%d]\n",ev.time, frameStart, frameStop);
  74. break;
  75. }
  76. queue.pop(ev);
  77. //cout << ev << endl;
  78. switch(ev.type) {
  79. case M_NOTE:
  80. if(ev.value)
  81. master->noteOn(ev.channel, ev.num, ev.value);
  82. else
  83. master->noteOff(ev.channel, ev.num);
  84. break;
  85. case M_CONTROLLER:
  86. if(ev.num == C_bankselectmsb) { // Change current bank
  87. middleware->spawnMaster()->bToU->write("/forward", "");
  88. middleware->spawnMaster()->bToU->write("/bank/msb", "i", ev.value);
  89. middleware->spawnMaster()->bToU->write("/bank/bank_select", "i", ev.value);
  90. } else if(ev.num == C_bankselectlsb) {// Change current bank (LSB)
  91. middleware->spawnMaster()->bToU->write("/forward", "");
  92. middleware->spawnMaster()->bToU->write("/bank/lsb", "i", ev.value);
  93. } else
  94. master->setController(ev.channel, ev.num, ev.value);
  95. break;
  96. case M_PGMCHANGE:
  97. for(int i=0; i < NUM_MIDI_PARTS; ++i) {
  98. //set the program of the parts assigned to the midi channel
  99. if(master->part[i]->Prcvchn == ev.channel) {
  100. middleware->pendingSetProgram(i, ev.num);
  101. }
  102. }
  103. break;
  104. case M_PRESSURE:
  105. master->polyphonicAftertouch(ev.channel, ev.num, ev.value);
  106. break;
  107. }
  108. }
  109. }
  110. bool InMgr::empty(void) const
  111. {
  112. int semvalue = work.getvalue();
  113. return semvalue <= 0;
  114. }
  115. bool InMgr::setSource(string name)
  116. {
  117. MidiIn *src = getIn(name);
  118. if(!src)
  119. return false;
  120. if(current)
  121. current->setMidiEn(false);
  122. current = src;
  123. current->setMidiEn(true);
  124. bool success = current->getMidiEn();
  125. //Keep system in a valid state (aka with a running driver)
  126. if(!success)
  127. (current = getIn("NULL"))->setMidiEn(true);
  128. return success;
  129. }
  130. string InMgr::getSource() const
  131. {
  132. if(current)
  133. return current->name;
  134. else
  135. return "ERROR";
  136. }
  137. MidiIn *InMgr::getIn(string name)
  138. {
  139. EngineMgr &eng = EngineMgr::getInstance(NULL);
  140. return dynamic_cast<MidiIn *>(eng.getEng(name));
  141. }
  142. void InMgr::setMaster(Master *master_)
  143. {
  144. master = master_;
  145. }