PageRenderTime 46ms CodeModel.GetById 16ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/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>
 22using namespace std;
 23
 24#include <QDataStream>
 25#include <QFile>
 26#include <QSettings>
 27#include <QString>
 28
 29#include "midi_data.h"
 30				 
 31// Platform-dependent sleep routines.
 32#if defined(__WINDOWS_MM__)
 33 #include <windows.h>
 34 #define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds ) 
 35#else // Unix variants
 36 #include <unistd.h>
 37 #define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
 38#endif
 39				 
 40midi_data::midi_data() {
 41	verboseMode = false;
 42	createOurMIDIports();
 43	last_patch_loaded = -1;
 44	connectedInPort = -1; 
 45	connectedOutPort = -1;
 46}
 47
 48
 49midi_data::~midi_data() {
 50	
 51	delete midiIn;
 52	delete midiOut;
 53}
 54
 55void midi_data::createOurMIDIports() {
 56	
 57	midiIn = 0;
 58	midiOut = 0;
 59	
 60	try {
 61		midiIn = new RtMidiIn();
 62	}
 63	catch ( RtError &error ) {
 64		error.printMessage();
 65		exit( EXIT_FAILURE );
 66	}
 67	
 68	// Do(n't) ignore sysex, timing, or active sensing messages.
 69	midiIn->ignoreTypes( false, true, true ); // FIXME - should just be line 330?
 70	
 71	
 72	try {
 73		midiOut = new RtMidiOut();
 74	}
 75	catch ( RtError &error ) {
 76		error.printMessage();
 77		exit( EXIT_FAILURE );
 78	}
 79
 80}
 81
 82void midi_data::sendPanic() {
 83
 84	for (int mc = 0; mc < 16; mc++) {
 85		
 86		//snd_seq_ev_set_controller (&ev, mc, MIDI_CTL_ALL_NOTES_OFF,0);
 87
 88	}
 89}
 90
 91/**
 92 * Requests a single patch from the EWI and waits for one to be returned.
 93 * @param p 
 94 * @return 
 95 */
 96bool midi_data::requestPatch ( unsigned char p) {
 97
 98	std::vector<unsigned char> message;
 99
100    if (p >= EWI_NUM_PATCHES) {
101      cerr << "Illegal request for patch - aborting\n";
102      exit(1);
103    }
104    
105	//char sysex_fetch_patch[] = { 0xf0, 0x47, 0x64, 0x00, 0x40, 0x00, 0xf7 }; // 6th byte is patch #
106	message.push_back( MIDI_SYSEX_HEADER );
107    message.push_back( MIDI_SYSEX_AKAI_ID );
108    message.push_back( MIDI_SYSEX_AKAI_EWI4K );
109	message.push_back( MIDI_SYSEX_CHANNEL );
110    message.push_back( MIDI_PRESET_DUMP_REQ );
111	message.push_back( p );		// 6th byte is patch #
112	message.push_back( MIDI_SYSEX_TRAILER );
113    
114	try {
115		midiOut->sendMessage( &message );
116	}
117	catch ( RtError &error ) {
118		error.printMessage();
119	}
120	
121	mymutex.lock();  // wait for a SysEx to be returned (MIDIListener looks after that)
122	if (!sysexDone.wait( &mymutex, MIDI_TIMEOUT_MS )) {
123		// we timed out
124		cout << "Timeout waiting for response from EWI\n";	
125		mymutex.unlock();
126		return false;
127	}
128	mymutex.unlock();
129
130	// it seems the EWI can get out of sync - so retry if we didn't ge the patch back we asked for
131	if (last_patch_loaded != (int) p) requestPatch( p );
132	
133	return true;
134}
135
136/**
137 * Requests the QuickPCs from the EWI and waits for them to be returned
138 * @param 
139 * @return
140 */
141bool midi_data::requestQuickPCs () {
142
143  std::vector<unsigned char> message;
144    
145  //char sysex_fetch_patch[] = { 0xf0, 0x47, 0x64, 0x00, 0x40, 0x00, 0xf7 }; // 6th byte is patch #
146  message.push_back( MIDI_SYSEX_HEADER );
147  message.push_back( MIDI_SYSEX_AKAI_ID );
148  message.push_back( MIDI_SYSEX_AKAI_EWI4K );
149  message.push_back( MIDI_SYSEX_ALLCHANNELS );
150  message.push_back( MIDI_QUICKPC_DUMP_REQ );
151  message.push_back( 0x00 );     // 6th byte is patch #
152  message.push_back( MIDI_SYSEX_TRAILER );
153    
154  try {
155    midiOut->sendMessage( &message );
156  }
157  catch ( RtError &error ) {
158    error.printMessage();
159  }
160    
161  mymutex.lock();  // wait for a SysEx to be returned
162  if (!sysexDone.wait( &mymutex, MIDI_TIMEOUT_MS )) {
163        // we timed out
164    cout << "Timeout waiting for response from EWI\n";
165    mymutex.unlock();
166    return false;
167  }
168  mymutex.unlock();
169
170  return true;
171}
172
173/**
174 * Sends the QuickPCs to the EWI
175 * @param
176 * @return
177 */
178bool midi_data::sendQuickPCs () {
179
180  std::vector<unsigned char> message;
181    
182  //char sysex_fetch_patch[] = { 0xf0, 0x47, 0x64, 0x00, 0x40, 0x00, 0xf7 }; // 6th byte is patch #
183  message.push_back( MIDI_SYSEX_HEADER );
184  message.push_back( MIDI_SYSEX_AKAI_ID );
185  message.push_back( MIDI_SYSEX_AKAI_EWI4K );
186  message.push_back( MIDI_SYSEX_ALLCHANNELS );
187  message.push_back( MIDI_QUICKPC_DUMP );
188  message.push_back( 0x00 );     // 6th byte is patch #
189  for (int i = 0; i < EWI_NUM_QUICKPCS; i++) {
190    message.push_back(quickPCs[i]);
191  }   
192  message.push_back( MIDI_SYSEX_TRAILER );
193    
194  try {
195    midiOut->sendMessage( &message );
196  }
197  catch ( RtError &error ) {
198    error.printMessage();
199  }
200
201  SLEEP( 250 );
202  
203  return true;
204}
205
206void midi_data::sendLiveControl (int lsb, int msb, int cvalue) {
207  sendCC (MIDI_CC_NRPN_LSB, lsb);
208  sendCC (MIDI_CC_NRPN_MSB, msb);
209  sendCC (MIDI_CC_DATA_ENTRY, cvalue);
210  sendCC (MIDI_CC_NRPN_LSB, 127);
211  sendCC (MIDI_CC_NRPN_MSB, 127);
212}
213
214void midi_data::sendCC (int cc, int val, int ch) {
215	
216	std::vector<unsigned char> message;
217
218	message.push_back( 176+ch );
219	message.push_back( cc );
220	message.push_back( val );
221	
222	try {
223		midiOut->sendMessage( &message );
224	}
225	catch ( RtError &error ) {
226		error.printMessage();
227	}
228}
229
230
231/**
232 * @param sysex
233 * @param len 
234 */
235void midi_data::sendSysEx (char *sysex, int len) {
236	
237	vector<unsigned char> message;
238	
239	for (int i = 0; i<len; i++) {
240		// int h = sysex[i];
241		message.push_back( sysex[i] );
242		// cout <<dec<< i << " : "; cout << hex << h << endl;
243	}
244	
245	try {
246		midiOut->sendMessage( &message );
247	}
248	catch ( RtError &error ) {
249		error.printMessage();
250	}
251	
252	SLEEP( 250 );
253}
254
255void midi_data::sendSysExFile( QString fileName ) {
256	
257	//  N.B. It seems RtMidi assumes only 1 sysex per message.  We should check and break up files
258	//       containing multiple sysexes here... FIXME - maybe fixed in RtMidi 1.0.9?
259	int nbytes;
260	char sysex[MAX_SYSEX_LENGTH];
261	QFile sysex_file( fileName );
262	sysex_file.open( QIODevice::ReadOnly );
263	QDataStream sysex_data( &sysex_file );
264	
265	nbytes = sysex_data.readRawData( &sysex[0], MAX_SYSEX_LENGTH );
266	
267	sendSysEx( &sysex[0], nbytes );
268	
269}
270
271void midi_data::sendPatch (patch_t p, unsigned char mode) {
272	
273	p.parameters.mode = mode;
274
275	sendSysEx( &p.whole_patch[0], EWI_PATCH_LENGTH );
276	
277	if (mode == EWI_EDIT) {
278		// if we're going to edit we need to send it again as patch 0 with the 
279		// edit flag set...
280		p.parameters.patch_num = 0x00;
281		sendSysEx( &p.whole_patch[0], EWI_PATCH_LENGTH );
282	}
283}
284
285void midi_data::scanPorts() {
286	
287	QString port_name;
288
289	inPortList.clear();
290	inPortPorts.clear();
291	outPortList.clear();
292	outPortPorts.clear();
293	
294	// Check inputs.
295	unsigned int nPorts = midiIn->getPortCount();
296	std::cout << "\nThere are " << nPorts << " MIDI input sources available.\n";
297	std::string portName;
298	for ( unsigned int i=0; i<nPorts; i++ ) {
299		try {
300			portName = midiIn->getPortName(i);
301		}
302		catch ( RtError &error ) {
303			error.printMessage();
304			//goto cleanup;
305		}
306		//std::cout << "  Input Port #" << i+1 << ": " << portName << '\n';
307		inPortPorts.append( i );
308		inPortList.append( QString::number( i ) + " : " + QString::fromStdString( portName ) );
309	}
310	
311	// Check outputs.
312	nPorts = midiOut->getPortCount();
313	std::cout << "\nThere are " << nPorts << " MIDI output ports available.\n";
314	for ( unsigned int i=0; i<nPorts; i++ ) {
315		try {
316			portName = midiOut->getPortName(i);
317		}
318		catch (RtError &error) {
319			error.printMessage();
320			//goto cleanup;
321		}
322		//std::cout << "  Output Port #" << i+1 << ": " << portName << '\n';
323		outPortPorts.append( i );
324		outPortList.append( QString::number( i ) + " : " + QString::fromStdString( portName ) );
325	}
326
327}
328
329void midi_data::connectOutput( int o_port ) {
330	
331	if (connectedOutPort != -1 ) disconnectOutput();
332	try {
333		midiOut->openPort( o_port );
334	}
335	catch (RtError &error) {
336		error.printMessage();
337			//goto cleanup;
338	}
339	connectedOutPort = o_port;
340	if (verboseMode) cout << "Connected to MIDI output: " << o_port << endl;
341	QSettings settings( "EWItool", "EWItool" );
342	settings.setValue( "MIDI/OutPort", o_port );
343}
344
345void midi_data::connectInput( int i_port ) {
346	
347	if (connectedInPort != -1) disconnectInput();
348	try {
349		midiIn->openPort( i_port );
350	}
351	catch (RtError &error) {
352		error.printMessage();
353			//goto cleanup;
354	}
355
356    // don't ignore SysExes, do ignore timing and active sense messages   
357    midiIn->ignoreTypes( false, true, true );
358    
359	connectedInPort = i_port;
360	if (verboseMode) cout << "Connected to MIDI input: " << i_port << endl;
361	QSettings settings( "EWItool", "EWItool" );
362	settings.setValue( "MIDI/InPort", i_port );
363	last_patch_loaded = -1;
364}
365
366void midi_data::disconnectInput() {
367	
368	midiIn->closePort();
369	
370	connectedInPort = -1;
371}
372
373void midi_data::disconnectOutput() {
374	
375	midiOut->closePort();
376	
377	connectedOutPort = -1;
378}
379
380
381
382