Launchpad.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include "Launchpad.h"
  2. #include "RtMidi.h"
  3. #include "MidiMessage.h"
  4. #include <string>
  5. LaunchpadColor::LaunchpadColor()
  6. : red(0), green(0)
  7. {
  8. }
  9. LaunchpadColor::LaunchpadColor(unsigned char r, unsigned char g)
  10. : red(r), green(g)
  11. {
  12. }
  13. bool LaunchpadColor::operator==(const LaunchpadColor& color) const
  14. {
  15. return red == color.red && green == color.green;
  16. }
  17. bool LaunchpadColor::operator!=(const LaunchpadColor& color) const
  18. {
  19. return !operator==(color);
  20. }
  21. Launchpad::Launchpad()
  22. : midiin(), midiout(), keyPressedCallback(0), keyReleasedCallback(0)
  23. {
  24. // define callback before opening port to keep the message queue empty.
  25. midiin.setCallback(midiMessageCallback, (void*) this);
  26. for(unsigned int i=0; i<midiout.getPortCount(); i++)
  27. {
  28. if(midiout.getPortName(i).find("Launchpad") != std::string::npos)
  29. {
  30. midiout.openPort(i);
  31. break;
  32. }
  33. }
  34. if(!midiout.isPortOpen())
  35. {
  36. throw RtMidiError(
  37. "no launchpad for midi output found",
  38. RtMidiError::NO_DEVICES_FOUND
  39. );
  40. }
  41. for(unsigned int i=0; i<midiin.getPortCount(); i++)
  42. {
  43. if(midiin.getPortName(i).find("Launchpad") != std::string::npos)
  44. {
  45. midiin.openPort(i);
  46. break;
  47. }
  48. }
  49. if(!midiin.isPortOpen())
  50. {
  51. throw RtMidiError(
  52. "no launchpad for midi input found",
  53. RtMidiError::NO_DEVICES_FOUND
  54. );
  55. }
  56. }
  57. void Launchpad::midiMessageCallback(double timeStamp, MidiMessage &message, void *userData)
  58. {
  59. Launchpad *launchpad = (Launchpad*) userData;
  60. // use runtime type information to check for the message type.
  61. // this requires the specified class to have a virtual member.
  62. NoteMessage *noteMessage = dynamic_cast<NoteMessage*>(&message);
  63. if(noteMessage)
  64. {
  65. unsigned char x = noteMessage->pitch % 16;
  66. unsigned char y = 7 - noteMessage->pitch / 16;
  67. if(dynamic_cast<NoteOnMessage*>(noteMessage))
  68. {
  69. launchpad->keyPressed(x, y);
  70. }
  71. else
  72. {
  73. launchpad->keyReleased(x, y);
  74. }
  75. }
  76. else
  77. {
  78. ControlChangeMessage *controlChangeMessage = dynamic_cast<ControlChangeMessage*>(&message);
  79. if(controlChangeMessage)
  80. {
  81. unsigned char x = controlChangeMessage->control - 104;
  82. unsigned char y = 8;
  83. if(controlChangeMessage->value == 127)
  84. {
  85. launchpad->keyPressed(x, y);
  86. }
  87. else
  88. {
  89. launchpad->keyReleased(x, y);
  90. }
  91. }
  92. }
  93. }
  94. bool Launchpad::issetColor(unsigned char x, unsigned char y) const
  95. {
  96. return colorSet[x][y];
  97. }
  98. const LaunchpadColor& Launchpad::getColor(unsigned char x, unsigned char y) const
  99. {
  100. return colors[x][y];
  101. }
  102. void Launchpad::setColor(unsigned char x, unsigned char y, const LaunchpadColor& color)
  103. {
  104. if(x >= width || y >= height || (x == 8 && y == 8))
  105. {
  106. throw RtMidiError(
  107. "specified launchpad position is out of range",
  108. RtMidiError::INVALID_PARAMETER
  109. );
  110. }
  111. if(color.red > 3 || color.green > 3)
  112. {
  113. throw RtMidiError(
  114. "specified launchpad color is out of range",
  115. RtMidiError::INVALID_PARAMETER
  116. );
  117. }
  118. unsigned char velocity = (color.green << 4) + color.red;
  119. if(y == 8)
  120. {
  121. midiout.sendMessage(ControlChangeMessage(
  122. 0,
  123. 104 + x,
  124. velocity
  125. ));
  126. }
  127. else
  128. {
  129. midiout.sendMessage(NoteOnMessage(
  130. 0,
  131. ((7 - y) << 4) + x,
  132. velocity
  133. ));
  134. }
  135. colors[x][y] = color;
  136. colorSet[x][y] = true;
  137. }
  138. void Launchpad::setColorAll(const LaunchpadColor& color)
  139. {
  140. for(unsigned char x = 0; x < width; x++)
  141. {
  142. for(unsigned char y = 0; y < height; y++)
  143. {
  144. if(x != 8 || y != 8)
  145. {
  146. setColor(x, y, color);
  147. }
  148. }
  149. }
  150. }
  151. void Launchpad::keyPressed(unsigned char x, unsigned char y)
  152. {
  153. if(keyPressedCallback)
  154. {
  155. keyPressedCallback(x, y, keyEventCallbackData);
  156. }
  157. }
  158. void Launchpad::keyReleased(unsigned char x, unsigned char y)
  159. {
  160. if(keyReleasedCallback)
  161. {
  162. keyReleasedCallback(x, y, keyEventCallbackData);
  163. }
  164. }
  165. void LaunchpadScreen::keyPressed(unsigned char x, unsigned char y)
  166. {
  167. }
  168. void LaunchpadScreen::keyReleased(unsigned char x, unsigned char y)
  169. {
  170. }
  171. void LaunchpadScreen::setColor(unsigned char x, unsigned char y, const LaunchpadColor& color)
  172. {
  173. if(active && (!launchpad->issetColor(x, y) || launchpad->getColor(x, y) != color)) {
  174. launchpad->setColor(x, y, color);
  175. }
  176. colors[x][y] = color;
  177. }
  178. void LaunchpadScreen::setColorAll(const LaunchpadColor& color)
  179. {
  180. for(unsigned char x = 0; x < Launchpad::width; x++) {
  181. for(unsigned char y = 0; y < Launchpad::height; y++) {
  182. if(x != 8 || y != 8)
  183. {
  184. setColor(x, y, color);
  185. }
  186. }
  187. }
  188. }
  189. void LaunchpadScreen::sync()
  190. {
  191. for(unsigned char x = 0; x < Launchpad::width; x++) {
  192. for(unsigned char y = 0; y < Launchpad::height; y++) {
  193. if((x != 8 || y != 8)
  194. && (!launchpad->issetColor(x, y) || launchpad->getColor(x, y) != colors[x][y])) {
  195. launchpad->setColor(x, y, colors[x][y]);
  196. }
  197. }
  198. }
  199. }
  200. LaunchpadScreen::LaunchpadScreen()
  201. : launchpad(0), active(false)
  202. {
  203. }
  204. void LaunchpadScreen::enable()
  205. {
  206. if(!launchpad) {
  207. throw RtMidiError(
  208. "no launchpad set",
  209. RtMidiError::INVALID_USE
  210. );
  211. }
  212. launchpad->keyEventCallbackData = (void*)this;
  213. launchpad->keyPressedCallback = keyPressedCallback;
  214. launchpad->keyReleasedCallback = keyReleasedCallback;
  215. sync();
  216. active = true;
  217. }
  218. void LaunchpadScreen::disable()
  219. {
  220. launchpad->keyPressedCallback = 0;
  221. launchpad->keyReleasedCallback = 0;
  222. launchpad->keyEventCallbackData = 0;
  223. active = false;
  224. }
  225. bool LaunchpadScreen::enabled() const
  226. {
  227. return active;
  228. }
  229. void LaunchpadScreen::setLaunchpad(Launchpad& l)
  230. {
  231. if(enabled()) {
  232. disable();
  233. launchpad = &l;
  234. enable();
  235. } else {
  236. launchpad = &l;
  237. }
  238. }
  239. void LaunchpadScreen::keyPressedCallback(unsigned char x, unsigned char y, void* screen)
  240. {
  241. ((LaunchpadScreen*)screen)->keyPressed(x, y);
  242. }
  243. void LaunchpadScreen::keyReleasedCallback(unsigned char x, unsigned char y, void* screen)
  244. {
  245. ((LaunchpadScreen*)screen)->keyReleased(x, y);
  246. }