aboutsummaryrefslogtreecommitdiff
path: root/src/midiio/src/MidiInPort_visual.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/midiio/src/MidiInPort_visual.cpp')
-rw-r--r--src/midiio/src/MidiInPort_visual.cpp1267
1 files changed, 1267 insertions, 0 deletions
diff --git a/src/midiio/src/MidiInPort_visual.cpp b/src/midiio/src/MidiInPort_visual.cpp
new file mode 100644
index 0000000..b4659bf
--- /dev/null
+++ b/src/midiio/src/MidiInPort_visual.cpp
@@ -0,0 +1,1267 @@
+//
+// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
+// Creation Date: Wed Jan 21 22:46:30 GMT-0800 1998
+// Last Modified: Wed Jun 30 11:29:51 PDT 1999 (added sysex capability)
+// Last Modified: Wed Oct 13 10:18:22 PDT 1999 (midiInUnprepareHeader change)
+// Last Modified: Tue Nov 23 15:01:17 PST 1999 (fixed sysex NULL init)
+// Filename: ...sig/code/control/MidiInPort/visual/MidiInPort_visual.cpp
+// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiInPort_visual.cpp
+// Syntax: C++
+//
+// Description: An interface for MIDI input capabilities of
+// Windows 95/NT/98 specific MIDI input methods.
+// as defined in winmm.lib. This class is inherited
+// privately by the MidiInPort class.
+//
+
+#ifdef VISUAL
+
+
+#include "MidiInPort_visual.h"
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include <iostream.h>
+
+
+// initialized static variables
+int MidiInPort_visual::numDevices = 0;
+int MidiInPort_visual::objectCount = 0;
+int* MidiInPort_visual::openQ = NULL;
+int* MidiInPort_visual::inrunningQ = NULL;
+int* MidiInPort_visual::portObjectCount = NULL;
+HMIDIIN* MidiInPort_visual::device = NULL;
+MIDIHDR** MidiInPort_visual::sysexDriverBuffer1 = NULL;
+MIDIHDR** MidiInPort_visual::sysexDriverBuffer2 = NULL;
+int* MidiInPort_visual::sysexDBnumber = NULL;
+HANDLE* MidiInPort_visual::hMutex = NULL;
+CircularBuffer<MidiMessage>* MidiInPort_visual::midiBuffer = NULL;
+int MidiInPort_visual::channelOffset = 0;
+int* MidiInPort_visual::sysexWriteBuffer = NULL;
+Array<uchar>** MidiInPort_visual::sysexBuffers = NULL;
+int* MidiInPort_visual::sysexStatus = NULL;
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::MidiInPort_visual
+// default values: autoOpen = 1
+//
+
+MidiInPort_visual::MidiInPort_visual(void) {
+ if (objectCount == 0) {
+ initialize();
+ }
+ objectCount++;
+
+ trace = 0;
+ port = -1;
+ setPort(0);
+}
+
+
+MidiInPort_visual::MidiInPort_visual(int aPort, int autoOpen) {
+ if (objectCount == 0) {
+ initialize();
+ }
+ objectCount++;
+
+ trace = 0;
+ port = -1;
+ setPort(aPort);
+ if (autoOpen) {
+ open();
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::~MidiInPort_visual
+//
+
+MidiInPort_visual::~MidiInPort_visual() {
+ objectCount--;
+ if (objectCount == 0) {
+ deinitialize();
+ } else if (objectCount < 0) {
+ cerr << "Error: bad MidiInPort_visual object count!: "
+ << objectCount << endl;
+ exit(1);
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::clearSysex -- clears the data from a sysex
+// message and sets the allocation size to the default size (of 32
+// bytes).
+//
+
+void MidiInPort_visual::clearSysex(int buffer) {
+ buffer = 0x7f | buffer; // limit buffer range from 0 to 127
+
+ if (getPort() == -1) {
+ return;
+ }
+
+ sysexBuffers[getPort()][buffer].setSize(0);
+ if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) {
+ // shrink the storage buffer's size if necessary
+ sysexBuffers[getPort()][buffer].setAllocSize(32);
+ }
+}
+
+
+void MidiInPort_visual::clearSysex(void) {
+ // clear all sysex buffers
+ for (int i=0; i<128; i++) {
+ clearSysex(i);
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::close
+//
+
+void MidiInPort_visual::close(void) {
+ if (getPort() == -1) {
+ return;
+ }
+ if (getPortStatus() == 1 && device[getPort()] != NULL) {
+ midiInReset(device[getPort()]);
+ midiInClose(device[getPort()]);
+ uninstallSysexStuff(device[getPort()], port);
+ openQ[getPort()] = 0;
+ inrunningQ[getPort()] = 0;
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::closeAll
+//
+
+void MidiInPort_visual::closeAll(void) {
+ for (int i=0; i<getNumPorts(); i++) {
+ if (openQ[i] == 1 && device[i] != NULL) {
+ midiInReset(device[i]);
+ midiInClose(device[i]);
+ if (getPort() != 1) {
+ uninstallSysexStuff(device[getPort()], port);
+ }
+ openQ[i] = 0;
+ inrunningQ[i] = 0;
+ }
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::extract -- returns the next MIDI message
+// received since that last extracted message.
+//
+
+MidiMessage MidiInPort_visual::extract(void) {
+ MidiMessage output;
+
+ waitForMutex();
+ if (getPort() != -1) {
+ output = midiBuffer[getPort()].extract();
+ }
+ releaseMutex();
+
+ return output;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getBufferSize
+//
+
+int MidiInPort_visual::getBufferSize(void) {
+ if (getPort() != -1) {
+ return midiBuffer[getPort()].getSize();
+ } else {
+ return 0;
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getChannelOffset -- returns zero if MIDI channel
+// offset is 0, or 1 if offset is 1.
+//
+
+int MidiInPort_visual::getChannelOffset(void) const {
+ return channelOffset;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getCount -- returns the number of unexamined
+// MIDI messages waiting in the input buffer.
+//
+
+int MidiInPort_visual::getCount(void) {
+ int output;
+
+ waitForMutex();
+ if (getPort() != -1) {
+ output = midiBuffer[getPort()].getCount();
+ } else {
+ output = 0;
+ }
+ releaseMutex();
+
+ return output;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getName -- returns the name of the port.
+// returns "" if no name. Name is valid until getName is called again.
+//
+
+const char* MidiInPort_visual::getName(void) {
+ static MIDIINCAPS inputCapabilities;
+
+ if (getPort() == -1) {
+ return "Null MIDI Input";
+ }
+
+ if (openQ[getPort()]) { // port already open
+ midiInGetDevCaps(getPort(), &inputCapabilities, sizeof(MIDIINCAPS));
+ } else { // port is currently closed
+ if(open()) {;
+ midiInGetDevCaps(getPort(), &inputCapabilities, sizeof(MIDIINCAPS));
+ close();
+ } else {
+ return "";
+ }
+ }
+ return inputCapabilities.szPname;
+}
+
+
+const char* MidiInPort_visual::getName(int i) {
+ static MIDIINCAPS inputCapabilities;
+
+ if (i < 0 || i > getNumPorts()) {
+ cerr << "Error invalid index for getName: " << i << endl;
+ exit(1);
+ }
+
+ midiInGetDevCaps(i, &inputCapabilities, sizeof(MIDIINCAPS));
+
+ return inputCapabilities.szPname;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getNumPorts -- returns the number of available
+// ports for MIDI input
+//
+
+int MidiInPort_visual::getNumPorts(void) {
+ return midiInGetNumDevs();
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getPort -- returns the port to which this
+// object belongs (as set with the setPort function).
+//
+
+int MidiInPort_visual::getPort(void) {
+ return port;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getPortStatus -- 0 if closed, 1 if open, 2 if
+// specifically not connected to any MIDI port.
+//
+
+int MidiInPort_visual::getPortStatus(void) {
+ if (getPort() == -1) {
+ return 2;
+ }
+
+ if (openQ[getPort()] == 1) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getSysex -- returns the sysex message contents
+// of a given buffer. You should check to see that the size is
+// non-zero before looking at the data. The data pointer will
+// be NULL if there is no data in the buffer.
+//
+
+uchar* MidiInPort_visual::getSysex(int buffer) {
+ buffer &= 0x7f; // limit the buffer access to indices 0 to 127.
+
+ if (getPort() == -1) {
+ return NULL;
+ }
+
+ if (sysexBuffers[getPort()][buffer].getSize() < 2) {
+ return NULL;
+ } else {
+ return sysexBuffers[getPort()][buffer].getBase();
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getSysexSize -- returns the sysex message byte
+// count of a given buffer. Buffers are in the range from
+// 0 to 127.
+//
+
+int MidiInPort_visual::getSysexSize(int buffer) {
+ if (getPort() == -1) {
+ return 0;
+ } else {
+ return sysexBuffers[getPort()][buffer & 0x7f].getSize();
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::getTrace -- returns true if trace is on or false
+// if trace is off. if trace is on, then prints to standard
+// output the Midi message received.
+//
+
+int MidiInPort_visual::getTrace(void) {
+ return trace;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::insert
+//
+
+void MidiInPort_visual::insert(const MidiMessage& aMessage) {
+ waitForMutex();
+ if (getPort() == -1) {
+ // do nothing
+ } else {
+ midiBuffer[getPort()].insert(aMessage);
+ }
+ releaseMutex();
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::installSysex -- put a sysex message into a
+// buffer. The buffer number that it is put into is returned.
+//
+
+int MidiInPort_visual::installSysex(uchar* anArray, int aSize) {
+ return installSysexPrivate(getPort(), anArray, aSize);
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::installSysexPrivate -- put a sysex message into a
+// buffer. The buffer number that it is put into is returned.
+//
+
+int MidiInPort_visual::installSysexPrivate(int port, uchar* anArray, int aSize){
+ if (port == -1) {
+ return -1;
+ }
+
+ // choose a buffer to install sysex data into:
+ int bufferNumber = sysexWriteBuffer[port];
+ sysexWriteBuffer[port]++;
+ if (sysexWriteBuffer[port] >= 128) {
+ sysexWriteBuffer[port] = 0;
+ }
+
+ // copy contents of sysex message into the chosen buffer
+ sysexBuffers[port][bufferNumber].setSize(aSize);
+ uchar* dataptr = sysexBuffers[port][bufferNumber].getBase();
+ uchar* indataptr = anArray;
+ for (int i=0; i<aSize; i++) {
+ *dataptr = *indataptr;
+ dataptr++;
+ indataptr++;
+ }
+
+ // return the buffer number that was used
+ return bufferNumber;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::message
+//
+
+MidiMessage& MidiInPort_visual::message(int index) {
+ if (getPort() != -1) {
+ return midiBuffer[getPort()][index];
+ } else {
+ static MidiMessage nullmessage;
+ return nullmessage;
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::open -- returns true if MIDI input port was
+// opened.
+//
+
+int MidiInPort_visual::open(void) {
+ if (getPort() == -1) {
+ return 1;
+ }
+
+ if (getPortStatus() == 0) {
+ int flag;
+ flag = midiInOpen(&device[getPort()], getPort(),
+ (DWORD)&midiInputCallback, (DWORD)this, CALLBACK_FUNCTION);
+ if (flag == MMSYSERR_NOERROR) {
+ openQ[getPort()] = 1;
+ installSysexStuff(device[getPort()], port);
+ unpause();
+ return 1;
+ } else { // failed to open
+ openQ[getPort()] = 0;
+ device[getPort()] = NULL;
+ return 0;
+ }
+ } else { // already open
+ return 1;
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::pause -- stop the Midi input port from
+// inserting MIDI messages into the buffer, but keep the
+// port open. Use unpause() to reverse the effect of pause().
+//
+
+void MidiInPort_visual::pause(void) {
+ if (getPort() == -1) {
+ return;
+ }
+
+ if (openQ[getPort()]) {
+ if (inrunningQ[getPort()] == 1) {
+ midiInStop(device[getPort()]);
+ inrunningQ[getPort()] = 0;
+ }
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::setBufferSize -- sets the allocation
+// size of the MIDI input buffer.
+//
+
+void MidiInPort_visual::setBufferSize(int aSize) {
+ if (getPort() != -1) {
+ midiBuffer[getPort()].setSize(aSize);
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::setChannelOffset -- sets the MIDI channel offset, either 0 or 1.
+//
+
+void MidiInPort_visual::setChannelOffset(int anOffset) {
+ switch (anOffset) {
+ case 0: channelOffset = 0; break;
+ case 1: channelOffset = 1; break;
+ default:
+ cout << "Error: Channel offset can be only 0 or 1." << endl;
+ exit(1);
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::setPort --
+//
+
+void MidiInPort_visual::setPort(int aPort) {
+ if (aPort < -1 || aPort >= getNumPorts()) {
+ cerr << "Error: maximum port number is: " << getNumPorts()-1
+ << ", but you tried to access port: " << aPort << endl;
+ exit(1);
+ }
+
+ if (port != -1) {
+ portObjectCount[port]--;
+ }
+ port = aPort;
+ if (port != -1) {
+ portObjectCount[port]++;
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::setTrace -- if false, then don't print MIDI messages
+// to the screen.
+//
+
+int MidiInPort_visual::setTrace(int aState) {
+ int oldtrace = trace;
+ if (aState == 0) {
+ trace = 0;
+ } else {
+ trace = 1;
+ }
+ return oldtrace;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::toggleTrace -- switches the state of trace
+// Returns the previous value of the trace variable.
+//
+
+void MidiInPort_visual::toggleTrace(void) {
+ trace = !trace;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::unpause -- enables the Midi input port
+// to inserting MIDI messages into the buffer after the
+// port is already open.
+//
+
+void MidiInPort_visual::unpause(void) {
+ if (getPort() == -1) {
+ return;
+ }
+
+ if (openQ[getPort()]) {
+ if (inrunningQ[getPort()] == 0) {
+ midiInStart(device[getPort()]);
+ inrunningQ[getPort()] = 1;
+ }
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Private functions
+//
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::deinitialize -- sets up storage if necessary
+// This function should be called if the current object is
+// the first object to be created.
+//
+
+void MidiInPort_visual::deinitialize(void) {
+ int num = numDevices;
+
+ closeAll();
+
+ if (sysexBuffers != NULL) {
+ for (int i=0; i<numDevices; i++) {
+ if (sysexBuffers[i] != NULL) {
+ delete sysexBuffers[i];
+ sysexBuffers[i] = NULL;
+ }
+ }
+ delete [] sysexBuffers;
+ sysexBuffers = NULL;
+ }
+
+
+ if (sysexDriverBuffer1 != NULL) {
+ for (int i=0; i<numDevices; i++) {
+ if (sysexDriverBuffer1[i] != NULL) {
+ delete sysexDriverBuffer1[i];
+ sysexDriverBuffer1[i] = NULL;
+ }
+ }
+ delete [] sysexDriverBuffer1;
+ sysexDriverBuffer1 = NULL;
+ }
+
+ if (sysexDriverBuffer2 != NULL) {
+ for (int i=0; i<numDevices; i++) {
+ if (sysexDriverBuffer2[i] != NULL) {
+ delete sysexDriverBuffer2[i];
+ sysexDriverBuffer2[i] = NULL;
+ }
+ }
+ delete [] sysexDriverBuffer2;
+ sysexDriverBuffer2 = NULL;
+ }
+
+ if (sysexDBnumber != NULL) {
+ delete [] sysexDBnumber;
+ sysexDBnumber = NULL;
+ }
+
+
+ if (sysexWriteBuffer != NULL) {
+ delete [] sysexWriteBuffer;
+ sysexWriteBuffer = NULL;
+ }
+
+ if (sysexStatus != NULL) {
+ delete [] sysexStatus;
+ sysexStatus = NULL;
+ }
+
+ if (device != NULL) {
+ delete [] device;
+ device = NULL;
+ }
+
+ if (openQ != NULL) {
+ delete [] openQ;
+ openQ = NULL;
+ }
+
+ if (inrunningQ != NULL) {
+ delete [] inrunningQ;
+ inrunningQ = NULL;
+ }
+
+ if (hMutex != NULL) {
+ delete [] hMutex;
+ hMutex = NULL;
+ }
+
+ if (midiBuffer != NULL) {
+ delete [] midiBuffer;
+ midiBuffer = NULL;
+ }
+
+ if (portObjectCount != NULL) {
+ delete [] portObjectCount;
+ portObjectCount = NULL;
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::initialize -- sets up storage if necessary
+// This function should be called if the current object is
+// the first object to be created.
+//
+
+void MidiInPort_visual::initialize(void) {
+ int i;
+
+ // get the number of ports
+ numDevices = midiInGetNumDevs();
+ if (getNumPorts() <= 0) {
+ cerr << "Error: no MIDI input devices" << endl;
+ exit(1);
+ }
+
+ // allocate space for Windoze MIDI input structures
+ if (device != NULL) {
+ cerr << "Error: device array should be NULL when calling "
+ << "initialize() in MidiInPort_visual." << endl;
+ exit(1);
+ }
+ device = new HMIDIIN[numDevices];
+
+ // allocate space for openQ, the port open/close status
+ if (openQ != NULL) delete [] openQ;
+ openQ = new int[numDevices];
+
+ // allocate space to keep track of an active/inactive input port
+ if (inrunningQ != NULL) delete [] inrunningQ;
+ inrunningQ = new int[numDevices];
+
+ // allocate space for object count on each port:
+ if (portObjectCount != NULL) delete [] portObjectCount;
+ portObjectCount = new int[numDevices];
+
+ // allocate space for mutual exclusive
+ if (hMutex != NULL) delete [] hMutex;
+ hMutex = new HANDLE[numDevices];
+
+ // allocate space for the Midi input buffers
+ if (midiBuffer != NULL) delete [] midiBuffer;
+ midiBuffer = new CircularBuffer<MidiMessage>[numDevices];
+
+ // allocate space for the MIDI sysex buffer indices
+ if (sysexWriteBuffer != NULL) delete [] sysexWriteBuffer;
+ sysexWriteBuffer = new int[numDevices];
+
+ // allocate space for the sysex MIM_LONGDATA message tracking
+ if (sysexStatus != NULL) delete [] sysexStatus;
+ sysexStatus = new int[numDevices];
+
+ // allocate space for sysex buffers
+ if (sysexBuffers != NULL) {
+ cout << "Error: memory leak on sysex buffers initialization" << endl;
+ exit(1);
+ }
+ sysexBuffers = new Array<uchar>*[numDevices];
+
+ // allocate system exclusive buffers for MIDI driver
+ if (sysexDriverBuffer1 != NULL) {
+ cout << "Error: memory leak on sysex buffer for drivers creation" << endl;
+ exit(1);
+ }
+ sysexDriverBuffer1 = new MIDIHDR*[numDevices];
+ for (i=0; i<numDevices; i++) {
+ sysexDriverBuffer1[i] = NULL;
+ }
+
+ // allocate system exclusive buffers for MIDI driver
+ if (sysexDriverBuffer2 != NULL) {
+ cout << "Error: memory leak on sysex buffer for drivers creation" << endl;
+ exit(1);
+ }
+ sysexDriverBuffer2 = new MIDIHDR*[numDevices];
+ for (i=0; i<numDevices; i++) {
+ sysexDriverBuffer2[i] = NULL;
+ }
+
+ // allocate space for keeping track of which buffer to look at
+ if (sysexDBnumber != NULL) delete [] sysexDBnumber;
+ sysexDBnumber = new int[numDevices];
+
+
+ // initialize the static arrays
+ for (i=0; i<getNumPorts(); i++) {
+ device[i] = NULL;
+ openQ[i] = 0;
+ inrunningQ[i] = 0;
+ portObjectCount[i] = 0;
+ hMutex[i] = CreateMutex(NULL, FALSE, "M");
+ midiBuffer[i].setSize(DEFAULT_INPUT_BUFFER_SIZE);
+
+ sysexStatus[i] = -1;
+ sysexWriteBuffer[i] = 0;
+ sysexDBnumber[i] = 0;
+ sysexBuffers[i] = new Array<uchar>[128];
+ for (int n=0; n<128; n++) {
+ sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow
+ sysexBuffers[i][n].setAllocSize(32);
+ sysexBuffers[i][n].setSize(0);
+ sysexBuffers[i][n].setGrowth(32); // in case it will ever grow
+ }
+
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::installSysexStuff -- install all the mess that
+// a MIDIIN structure needs in order to receive system exclusives.
+//
+
+void MidiInPort_visual::installSysexStuff(HMIDIIN dev, int port) {
+ if (sysexDriverBuffer1 != NULL) {
+ if (sysexDriverBuffer1[port] != NULL) {
+ // some memory leaks here
+ delete sysexDriverBuffer1[port];
+ sysexDriverBuffer1[port] = NULL;
+ }
+ }
+ if (sysexDriverBuffer2 != NULL) {
+ if (sysexDriverBuffer2[port] != NULL) {
+ // some memory leaks here
+ delete sysexDriverBuffer2[port];
+ sysexDriverBuffer2[port] = NULL;
+ }
+ }
+
+ // allocate space for Drivers sysex byte buffer
+ sysexDriverBuffer1[port] = (LPMIDIHDR)GlobalLock(GlobalAlloc(GMEM_MOVEABLE |
+ GMEM_SHARE, sizeof(MIDIHDR)));
+ sysexDriverBuffer2[port] = (LPMIDIHDR)GlobalLock(GlobalAlloc(GMEM_MOVEABLE |
+ GMEM_SHARE, sizeof(MIDIHDR)));
+
+ if (sysexDriverBuffer1[port] == NULL) {
+ cout << "Error: could not allocate sysex driver's buffer" << endl;
+ exit(1);
+ }
+
+ if (sysexDriverBuffer2[port] == NULL) {
+ cout << "Error: could not allocate sysex driver's buffer" << endl;
+ exit(1);
+ }
+
+ // allocate buffer inside of sysexDriverBuffer
+ sysexDriverBuffer1[port]->lpData = (LPSTR)GlobalLock(GlobalAlloc(
+ GMEM_MOVEABLE | GMEM_SHARE, (DWORD)1024));
+ sysexDriverBuffer2[port]->lpData = (LPSTR)GlobalLock(GlobalAlloc(
+ GMEM_MOVEABLE | GMEM_SHARE, (DWORD)1024));
+
+ if (sysexDriverBuffer1[port]->lpData == NULL) {
+ cout << "Error: there was not enought space to allocate sysex buffer"
+ << endl;
+ // leaking memory here
+ exit(1);
+ }
+
+ if (sysexDriverBuffer2[port]->lpData == NULL) {
+ cout << "Error: there was not enought space to allocate sysex buffer"
+ << endl;
+ // leaking memory here
+ exit(1);
+ }
+
+
+ // setup other sysexDriverBuffer data fields
+ sysexDriverBuffer1[port]->dwBufferLength = 1024; // total size of buffer
+ sysexDriverBuffer1[port]->dwBytesRecorded = 0L; // number of byte in buffer
+ sysexDriverBuffer1[port]->dwFlags = 0L; // initialize flags
+ sysexDriverBuffer1[port]->dwUser = 0L; // userdata: used for sysex time
+
+ // setup other sysexDriverBuffer data fields
+ sysexDriverBuffer2[port]->dwBufferLength = 1024; // total size of buffer
+ sysexDriverBuffer2[port]->dwBytesRecorded = 0L; // number of byte in buffer
+ sysexDriverBuffer2[port]->dwFlags = 0L; // initialize flags
+ sysexDriverBuffer2[port]->dwUser = 0L; // userdata: used for sysex time
+
+ // prepare the header
+ int status = midiInPrepareHeader(device[port], sysexDriverBuffer1[port],
+ sizeof(MIDIHDR));
+
+ if (status != 0) {
+ cout << "Error preparing sysex buffer number: " << port << endl;
+ // leaking some memory here?
+ exit(1);
+ }
+
+ // prepare the header
+ status = midiInPrepareHeader(device[port], sysexDriverBuffer2[port],
+ sizeof(MIDIHDR));
+
+ if (status != 0) {
+ cout << "Error preparing sysex buffer number: " << port << endl;
+ // leaking some memory here?
+ exit(1);
+ }
+
+ // add the sysex buffer to the driver
+ status = midiInAddBuffer(device[port], sysexDriverBuffer1[port],
+ sizeof(MIDIHDR));
+
+ if (status != 0) {
+ cout << "Error adding sysex buffer to driver: " << port << endl;
+ // leaking some memory here?
+ exit(1);
+ }
+
+ status = midiInAddBuffer(device[port], sysexDriverBuffer2[port],
+ sizeof(MIDIHDR));
+
+ if (status != 0) {
+ cout << "Error adding sysex buffer to driver: " << port << endl;
+ // leaking some memory here?
+ exit(1);
+ }
+
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::uninstallSysexStuff -- uninstalls all the mess that
+// a MIDIIN structure needs in order to receive system exclusives.
+//
+
+void MidiInPort_visual::uninstallSysexStuff(HMIDIIN dev, int port) {
+ if (port == -1) {
+ return;
+ }
+ // unprepare the headers
+ midiInUnprepareHeader(device[port], sysexDriverBuffer1[port],
+ sizeof(MIDIHDR));
+ midiInUnprepareHeader(device[port], sysexDriverBuffer2[port],
+ sizeof(MIDIHDR));
+
+ // deallocate buffer inside of sysexDriverBuffer
+ /* Following code caused problems: perhaps lpData was deleted by driver
+ delete [] sysexDriverBuffer1[port]->lpData;
+ sysexDriverBuffer1[port]->lpData = NULL;
+ delete [] sysexDriverBuffer2[port]->lpData;
+ sysexDriverBuffer2[port]->lpData = NULL;
+ */
+
+ // deallocate space for Drivers sysex byte buffer
+ delete sysexDriverBuffer1[port];
+ delete sysexDriverBuffer2[port];
+ sysexDriverBuffer1[port] = NULL;
+ sysexDriverBuffer2[port] = NULL;
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::releaseMutex
+//
+
+void MidiInPort_visual::releaseMutex(void) {
+/* int flag = */ ReleaseMutex(hMutex[getPort()]);
+/*
+ if (flag != 0) {
+ cerr << "Error relasing mutex in MIDI input; flag was: " << flag << endl;
+ }
+*/
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::setPortStatus
+//
+
+void MidiInPort_visual::setPortStatus(int aStatus) {
+ if (getPort() == -1) {
+ return;
+ }
+
+ if (aStatus) {
+ openQ[getPort()] = 1;
+ } else {
+ openQ[getPort()] = 0;
+ }
+}
+
+
+
+//////////////////////////////
+//
+// MidiInPort_visual::waitForMutex
+//
+
+void MidiInPort_visual::waitForMutex(void) {
+/*
+ DWORD mutexResult = WaitForSingleObject(hMutex[getPort()], 5000L);
+ if (mutexResult != WAIT_OBJECT_0) {
+ cerr << "Error waiting for mutex in MIDI input" << endl;
+ }
+*/
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////
+//
+// midiInputCallback -- the function the MIDI input driver calls when
+// it has a message from the Midi in cable ready
+//
+
+void CALLBACK midiInputCallback(HMIDIIN hMidiIn, UINT inputStatus,
+ DWORD instancePtr, DWORD midiMessage, DWORD timestamp) {
+ static MidiMessage newMessage;
+
+ switch (inputStatus) {
+ case MIM_MOREDATA:
+ // There is more data waiting at the device.
+ // If this case is exists, then that means that the MIDI
+ // device is too slow and some data was lost.
+ // Windows sends a MIM_MOREDATA event only if you specify
+ // the MIDI_IO_STATUS flag to midiInOpen().
+
+ // no break;
+ case MIM_DATA:
+
+ // One regular (non sysex) message has been completely
+ // received.
+
+ // ignore the Yamaha Active Sensing command and MIDI time clock
+ // at least for now.
+ if ((midiMessage & 0xff) == 0xfe || (midiMessage & 0xff) == 0xf8) {
+ break;
+ }
+
+ newMessage.time = timestamp;
+ newMessage.data = midiMessage;
+ ((MidiInPort_visual*)instancePtr)->insert(newMessage);
+ if (((MidiInPort_visual*)instancePtr)->getTrace()) {
+ cout << "[" << hex << (int)newMessage.command() << dec
+ << ":" << (int)newMessage.p1() << ","
+ << (int)newMessage.p2() << "]";
+ cout.flush();
+ }
+ break;
+
+ case MIM_LONGDATA:
+ {
+ // A sysex or part of a sysex message is coming in.
+ // The timestamp variable contains a pointer to a
+ // MIDIHDR pointer
+
+ MIDIHDR* midiheader = (MIDIHDR*)midiMessage;
+ int dataCount = midiheader->dwBytesRecorded;
+ char* data = midiheader->lpData;
+ int port = ((MidiInPort_visual*)instancePtr)->getPort();
+ if (port == -1) {
+ break;
+ }
+ int* sysexStatus = ((MidiInPort_visual*)instancePtr)->sysexStatus;
+// MIDIHDR** sysexDriverBuffer = ((MidiInPort_visual*)instancePtr)->
+// sysexDriverBuffer;
+ HMIDIIN devicex = ((MidiInPort_visual*)instancePtr)->device[port];
+
+ if (dataCount == 0) {
+ // can't handle a zero-length sysex
+ break;
+ }
+
+ // step 1: determine if this is the first part of the sysex
+ // message or a continuation
+ int continuation = 0;
+ if (data[0] == (char)0xf0) {
+ continuation = 0;
+ if (sysexStatus[port] != -1) {
+ cout << "Error: there is another sysex command being "
+ "received on port " << port << endl;
+ exit(1);
+ }
+ } else {
+ if (sysexStatus[port] == -1) {
+ cout << "Error: no sysex command is being "
+ "received on port " << port << endl;
+ if (data[0] < 128) {
+ cout << "First byte is: " << dec << (int)data[0] << endl;
+ } else {
+ cout << "First byte is: " << hex << (int)data[0] << endl;
+ }
+ if (data[1] < 128) {
+ cout << "Second byte is: " << dec << (int)data[1] << endl;
+ } else {
+ cout << "Second byte is: " << hex << (int)data[1] << endl;
+ }
+
+ exit(1);
+ }
+ continuation = 1;
+ }
+
+ // step 2: if continuing, add the data to the preallocated
+ // sysex buffer, otherwise, get a new buffer location
+ int buffer = -1;
+ if (continuation) {
+ buffer = sysexStatus[port];
+ if (buffer < 0 || buffer > 127) {
+ cout << "Sysex buffer was out of range: " << buffer << endl;
+ }
+ for (int i=0; i<dataCount; i++) {
+ unsigned char datum = data[i];
+ ((MidiInPort_visual*)instancePtr)->
+ sysexBuffers[port][buffer].append(datum);
+ if (datum == 0xf7) {
+ for (int k=i; k<dataCount; k++) {
+ data[k-i] = data[k];
+ }
+ midiheader->dwBytesRecorded = dataCount - i - 1;
+
+ goto insert_sysex_message;
+ }
+ }
+ } else { // if not a continuation of a sysex event
+ buffer = ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port];
+ ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port]++;
+ if (buffer == 127) {
+ ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port] = 0;
+ }
+
+ ((MidiInPort_visual*)instancePtr)->
+ sysexBuffers[port][buffer].setSize(0);
+ for (int j=0; j<dataCount; j++) {
+ unsigned char datum = data[j];
+ ((MidiInPort_visual*)instancePtr)->
+ sysexBuffers[port][buffer].append(datum);
+ if (datum == 0xf7) {
+ for (int k=j; k<dataCount; k++) {
+ data[k-j] = data[k];
+ }
+
+ goto insert_sysex_message;
+ }
+ }
+
+ }
+
+ // recycle the MIDI input buffer for the driver
+ {
+ midiInPrepareHeader(devicex, midiheader, sizeof(MIDIHDR));
+ int dstatus = midiInAddBuffer(devicex, midiheader, sizeof(MIDIHDR));
+ if (dstatus != MMSYSERR_NOERROR) {
+ cout << "Error when calling midiInAddBuffer" << endl;
+ exit(1);
+ }
+ }
+
+ break;
+
+ insert_sysex_message:
+
+ // recycle the MIDI input buffer for the driver
+ {
+ midiInPrepareHeader(devicex, midiheader, sizeof(MIDIHDR));
+ int estatus = midiInAddBuffer(devicex, midiheader, sizeof(MIDIHDR));
+ if (estatus != MMSYSERR_NOERROR) {
+ cout << "Error when calling midiInAddBuffer" << endl;
+ exit(1);
+ }
+ }
+
+ // now that a sysex message is finished, send a midimessage
+ // out to the instancePtr MIDI buffer telling the user
+ // that a sysex message has come in.
+
+ // newMessage.time = timestamp; use last time stamp that came
+ // in because the timestamp variable is used for storing
+ // the pointer of the sysex data.
+
+ newMessage.time = timestamp;
+ newMessage.p0() = 0xf0;
+ newMessage.p1() = buffer;
+ newMessage.p2() = 0;
+ newMessage.p3() = 0;
+
+ ((MidiInPort_visual*)instancePtr)->insert(newMessage);
+ if (((MidiInPort_visual*)instancePtr)->getTrace()) {
+ cout << "[" << hex << (int)newMessage.command() << dec
+ << ":" << (int)newMessage.p1() << ","
+ << (int)newMessage.p2() << "]";
+ cout.flush();
+ }
+
+ } // end of local variable range
+ break;
+
+ case MIM_ERROR:
+ // An invalid regular MIDI message was received.
+
+ break;
+
+ case MIM_LONGERROR:
+ {
+ // An invalid sysex MIDI message was received.
+
+ // if a sysex message was continuing from a previous part,
+ // then kill that message.
+
+ int port = ((MidiInPort_visual*)instancePtr)->getPort();
+ if (port == -1) {
+ break;
+ }
+ int buffer = ((MidiInPort_visual*)instancePtr)->sysexStatus[port];
+ if (buffer != -1) {
+ ((MidiInPort_visual*)instancePtr)->
+ sysexBuffers[port][buffer].setSize(0);
+ ((MidiInPort_visual*)instancePtr)->sysexStatus[port] = -1;
+ }
+
+ HMIDIIN devicex = ((MidiInPort_visual*)instancePtr)->device[port];
+ MIDIHDR* midiheader = (MIDIHDR*)midiMessage;
+
+ // recycle the MIDI input buffer for the driver
+ midiInPrepareHeader(devicex, midiheader, sizeof(MIDIHDR));
+ int status = midiInAddBuffer(devicex, midiheader, sizeof(MIDIHDR));
+ if (status != MMSYSERR_NOERROR) {
+ cout << "Error when calling midiInAddBuffer" << endl;
+ exit(1);
+ }
+
+
+ break;
+ }
+ default: ;
+ // case MIM_OPEN: // MIDI device is opening
+ // case MIM_CLOSE: // MIDI device is closing
+ }
+}
+
+
+
+#endif // VISUAL
+
+
+// md5sum: db55d9f375b86f54c0c8340547c5701f - MidiInPort_visual.cpp =css= 20030102