PageRenderTime 43ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/midi_data.cpp

http://ewitool.googlecode.com/
C++ | 382 lines | 240 code | 80 blank | 62 comment | 18 complexity | 2bca88ddee194e5e959dd84fec06ec5d MD5 | raw file
  1. /***************************************************************************
  2. * Copyright (C) 2008 by Steve Merrony *
  3. * *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 3 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  19. ***************************************************************************/
  20. #include <cstdlib>
  21. #include <iostream>
  22. using namespace std;
  23. #include <QDataStream>
  24. #include <QFile>
  25. #include <QSettings>
  26. #include <QString>
  27. #include "midi_data.h"
  28. // Platform-dependent sleep routines.
  29. #if defined(__WINDOWS_MM__)
  30. #include <windows.h>
  31. #define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds )
  32. #else // Unix variants
  33. #include <unistd.h>
  34. #define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
  35. #endif
  36. midi_data::midi_data() {
  37. verboseMode = false;
  38. createOurMIDIports();
  39. last_patch_loaded = -1;
  40. connectedInPort = -1;
  41. connectedOutPort = -1;
  42. }
  43. midi_data::~midi_data() {
  44. delete midiIn;
  45. delete midiOut;
  46. }
  47. void midi_data::createOurMIDIports() {
  48. midiIn = 0;
  49. midiOut = 0;
  50. try {
  51. midiIn = new RtMidiIn();
  52. }
  53. catch ( RtError &error ) {
  54. error.printMessage();
  55. exit( EXIT_FAILURE );
  56. }
  57. // Do(n't) ignore sysex, timing, or active sensing messages.
  58. midiIn->ignoreTypes( false, true, true ); // FIXME - should just be line 330?
  59. try {
  60. midiOut = new RtMidiOut();
  61. }
  62. catch ( RtError &error ) {
  63. error.printMessage();
  64. exit( EXIT_FAILURE );
  65. }
  66. }
  67. void midi_data::sendPanic() {
  68. for (int mc = 0; mc < 16; mc++) {
  69. //snd_seq_ev_set_controller (&ev, mc, MIDI_CTL_ALL_NOTES_OFF,0);
  70. }
  71. }
  72. /**
  73. * Requests a single patch from the EWI and waits for one to be returned.
  74. * @param p
  75. * @return
  76. */
  77. bool midi_data::requestPatch ( unsigned char p) {
  78. std::vector<unsigned char> message;
  79. if (p >= EWI_NUM_PATCHES) {
  80. cerr << "Illegal request for patch - aborting\n";
  81. exit(1);
  82. }
  83. //char sysex_fetch_patch[] = { 0xf0, 0x47, 0x64, 0x00, 0x40, 0x00, 0xf7 }; // 6th byte is patch #
  84. message.push_back( MIDI_SYSEX_HEADER );
  85. message.push_back( MIDI_SYSEX_AKAI_ID );
  86. message.push_back( MIDI_SYSEX_AKAI_EWI4K );
  87. message.push_back( MIDI_SYSEX_CHANNEL );
  88. message.push_back( MIDI_PRESET_DUMP_REQ );
  89. message.push_back( p ); // 6th byte is patch #
  90. message.push_back( MIDI_SYSEX_TRAILER );
  91. try {
  92. midiOut->sendMessage( &message );
  93. }
  94. catch ( RtError &error ) {
  95. error.printMessage();
  96. }
  97. mymutex.lock(); // wait for a SysEx to be returned (MIDIListener looks after that)
  98. if (!sysexDone.wait( &mymutex, MIDI_TIMEOUT_MS )) {
  99. // we timed out
  100. cout << "Timeout waiting for response from EWI\n";
  101. mymutex.unlock();
  102. return false;
  103. }
  104. mymutex.unlock();
  105. // it seems the EWI can get out of sync - so retry if we didn't ge the patch back we asked for
  106. if (last_patch_loaded != (int) p) requestPatch( p );
  107. return true;
  108. }
  109. /**
  110. * Requests the QuickPCs from the EWI and waits for them to be returned
  111. * @param
  112. * @return
  113. */
  114. bool midi_data::requestQuickPCs () {
  115. std::vector<unsigned char> message;
  116. //char sysex_fetch_patch[] = { 0xf0, 0x47, 0x64, 0x00, 0x40, 0x00, 0xf7 }; // 6th byte is patch #
  117. message.push_back( MIDI_SYSEX_HEADER );
  118. message.push_back( MIDI_SYSEX_AKAI_ID );
  119. message.push_back( MIDI_SYSEX_AKAI_EWI4K );
  120. message.push_back( MIDI_SYSEX_ALLCHANNELS );
  121. message.push_back( MIDI_QUICKPC_DUMP_REQ );
  122. message.push_back( 0x00 ); // 6th byte is patch #
  123. message.push_back( MIDI_SYSEX_TRAILER );
  124. try {
  125. midiOut->sendMessage( &message );
  126. }
  127. catch ( RtError &error ) {
  128. error.printMessage();
  129. }
  130. mymutex.lock(); // wait for a SysEx to be returned
  131. if (!sysexDone.wait( &mymutex, MIDI_TIMEOUT_MS )) {
  132. // we timed out
  133. cout << "Timeout waiting for response from EWI\n";
  134. mymutex.unlock();
  135. return false;
  136. }
  137. mymutex.unlock();
  138. return true;
  139. }
  140. /**
  141. * Sends the QuickPCs to the EWI
  142. * @param
  143. * @return
  144. */
  145. bool midi_data::sendQuickPCs () {
  146. std::vector<unsigned char> message;
  147. //char sysex_fetch_patch[] = { 0xf0, 0x47, 0x64, 0x00, 0x40, 0x00, 0xf7 }; // 6th byte is patch #
  148. message.push_back( MIDI_SYSEX_HEADER );
  149. message.push_back( MIDI_SYSEX_AKAI_ID );
  150. message.push_back( MIDI_SYSEX_AKAI_EWI4K );
  151. message.push_back( MIDI_SYSEX_ALLCHANNELS );
  152. message.push_back( MIDI_QUICKPC_DUMP );
  153. message.push_back( 0x00 ); // 6th byte is patch #
  154. for (int i = 0; i < EWI_NUM_QUICKPCS; i++) {
  155. message.push_back(quickPCs[i]);
  156. }
  157. message.push_back( MIDI_SYSEX_TRAILER );
  158. try {
  159. midiOut->sendMessage( &message );
  160. }
  161. catch ( RtError &error ) {
  162. error.printMessage();
  163. }
  164. SLEEP( 250 );
  165. return true;
  166. }
  167. void midi_data::sendLiveControl (int lsb, int msb, int cvalue) {
  168. sendCC (MIDI_CC_NRPN_LSB, lsb);
  169. sendCC (MIDI_CC_NRPN_MSB, msb);
  170. sendCC (MIDI_CC_DATA_ENTRY, cvalue);
  171. sendCC (MIDI_CC_NRPN_LSB, 127);
  172. sendCC (MIDI_CC_NRPN_MSB, 127);
  173. }
  174. void midi_data::sendCC (int cc, int val, int ch) {
  175. std::vector<unsigned char> message;
  176. message.push_back( 176+ch );
  177. message.push_back( cc );
  178. message.push_back( val );
  179. try {
  180. midiOut->sendMessage( &message );
  181. }
  182. catch ( RtError &error ) {
  183. error.printMessage();
  184. }
  185. }
  186. /**
  187. * @param sysex
  188. * @param len
  189. */
  190. void midi_data::sendSysEx (char *sysex, int len) {
  191. vector<unsigned char> message;
  192. for (int i = 0; i<len; i++) {
  193. // int h = sysex[i];
  194. message.push_back( sysex[i] );
  195. // cout <<dec<< i << " : "; cout << hex << h << endl;
  196. }
  197. try {
  198. midiOut->sendMessage( &message );
  199. }
  200. catch ( RtError &error ) {
  201. error.printMessage();
  202. }
  203. SLEEP( 250 );
  204. }
  205. void midi_data::sendSysExFile( QString fileName ) {
  206. // N.B. It seems RtMidi assumes only 1 sysex per message. We should check and break up files
  207. // containing multiple sysexes here... FIXME - maybe fixed in RtMidi 1.0.9?
  208. int nbytes;
  209. char sysex[MAX_SYSEX_LENGTH];
  210. QFile sysex_file( fileName );
  211. sysex_file.open( QIODevice::ReadOnly );
  212. QDataStream sysex_data( &sysex_file );
  213. nbytes = sysex_data.readRawData( &sysex[0], MAX_SYSEX_LENGTH );
  214. sendSysEx( &sysex[0], nbytes );
  215. }
  216. void midi_data::sendPatch (patch_t p, unsigned char mode) {
  217. p.parameters.mode = mode;
  218. sendSysEx( &p.whole_patch[0], EWI_PATCH_LENGTH );
  219. if (mode == EWI_EDIT) {
  220. // if we're going to edit we need to send it again as patch 0 with the
  221. // edit flag set...
  222. p.parameters.patch_num = 0x00;
  223. sendSysEx( &p.whole_patch[0], EWI_PATCH_LENGTH );
  224. }
  225. }
  226. void midi_data::scanPorts() {
  227. QString port_name;
  228. inPortList.clear();
  229. inPortPorts.clear();
  230. outPortList.clear();
  231. outPortPorts.clear();
  232. // Check inputs.
  233. unsigned int nPorts = midiIn->getPortCount();
  234. std::cout << "\nThere are " << nPorts << " MIDI input sources available.\n";
  235. std::string portName;
  236. for ( unsigned int i=0; i<nPorts; i++ ) {
  237. try {
  238. portName = midiIn->getPortName(i);
  239. }
  240. catch ( RtError &error ) {
  241. error.printMessage();
  242. //goto cleanup;
  243. }
  244. //std::cout << " Input Port #" << i+1 << ": " << portName << '\n';
  245. inPortPorts.append( i );
  246. inPortList.append( QString::number( i ) + " : " + QString::fromStdString( portName ) );
  247. }
  248. // Check outputs.
  249. nPorts = midiOut->getPortCount();
  250. std::cout << "\nThere are " << nPorts << " MIDI output ports available.\n";
  251. for ( unsigned int i=0; i<nPorts; i++ ) {
  252. try {
  253. portName = midiOut->getPortName(i);
  254. }
  255. catch (RtError &error) {
  256. error.printMessage();
  257. //goto cleanup;
  258. }
  259. //std::cout << " Output Port #" << i+1 << ": " << portName << '\n';
  260. outPortPorts.append( i );
  261. outPortList.append( QString::number( i ) + " : " + QString::fromStdString( portName ) );
  262. }
  263. }
  264. void midi_data::connectOutput( int o_port ) {
  265. if (connectedOutPort != -1 ) disconnectOutput();
  266. try {
  267. midiOut->openPort( o_port );
  268. }
  269. catch (RtError &error) {
  270. error.printMessage();
  271. //goto cleanup;
  272. }
  273. connectedOutPort = o_port;
  274. if (verboseMode) cout << "Connected to MIDI output: " << o_port << endl;
  275. QSettings settings( "EWItool", "EWItool" );
  276. settings.setValue( "MIDI/OutPort", o_port );
  277. }
  278. void midi_data::connectInput( int i_port ) {
  279. if (connectedInPort != -1) disconnectInput();
  280. try {
  281. midiIn->openPort( i_port );
  282. }
  283. catch (RtError &error) {
  284. error.printMessage();
  285. //goto cleanup;
  286. }
  287. // don't ignore SysExes, do ignore timing and active sense messages
  288. midiIn->ignoreTypes( false, true, true );
  289. connectedInPort = i_port;
  290. if (verboseMode) cout << "Connected to MIDI input: " << i_port << endl;
  291. QSettings settings( "EWItool", "EWItool" );
  292. settings.setValue( "MIDI/InPort", i_port );
  293. last_patch_loaded = -1;
  294. }
  295. void midi_data::disconnectInput() {
  296. midiIn->closePort();
  297. connectedInPort = -1;
  298. }
  299. void midi_data::disconnectOutput() {
  300. midiOut->closePort();
  301. connectedOutPort = -1;
  302. }