// // Programmer: Craig Stuart Sapp // Creation Date: Sun Dec 28 15:18:46 GMT-0800 1997 // Last Modified: Mon Jan 12 15:42:44 GMT-0800 1998 // Last Modified: Tue Jun 29 13:10:30 PDT 1999 (verified sysex sending) // Last Modified: Tue Jun 4 22:10:16 PDT 2002 (getNumPorts fix for static use) // Filename: ...sig/code/control/MidiOutPort/visual/MidiOutPort_visual.cpp // Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiOutPort_visual.cpp // Syntax: C++ // // Description: Operating-System specific interface for // basic MIDI output capabilities in Windows 95/NT/98 // using winmm.lib. Privately inherited by the // MidiOutPort class. // #ifdef VISUAL #include "MidiOutPort_visual.h" #ifndef OLDCPP #include using namespace std; #else #include #endif typedef unsigned long ulong; typedef unsigned char uchar; // initialized static variables int MidiOutPort_visual::numDevices = 0; int MidiOutPort_visual::objectCount = 0; int* MidiOutPort_visual::openQ = NULL; int* MidiOutPort_visual::portObjectCount = NULL; HMIDIOUT* MidiOutPort_visual::device = NULL; int MidiOutPort_visual::channelOffset = 0; ////////////////////////////// // // MidiOutPort_visual::MidiOutPort_visual // default values: autoOpen = 1 // MidiOutPort_visual::MidiOutPort_visual(void) { if (objectCount == 0) { initialize(); } objectCount++; port = -1; setPort(0); } MidiOutPort_visual::MidiOutPort_visual(int aPort, int autoOpen) { if (objectCount == 0) { initialize(); } objectCount++; port = -1; setPort(aPort); if (autoOpen) { open(); } } ////////////////////////////// // // MidiOutPort_visual::~MidiOutPort_visual // MidiOutPort_visual::~MidiOutPort_visual() { objectCount--; if (objectCount == 0) { deinitialize(); } else if (objectCount < 0) { cerr << "Error: bad MidiOutPort object count!: " << objectCount << endl; exit(1); } } ////////////////////////////// // // MidiOutPort_visual::close // void MidiOutPort_visual::close(void) { if (getPort() == -1) { return; } if (getPortStatus() == 1 && device[getPort()] != NULL) { // The following function, midiOutClose, is not what I like. // It will send note offs to any note which it thinks is // on when the port is closed. Uncomment the line if // you want this feature. // midiOutReset(device[getPort()]); midiOutClose(device[getPort()]); setPortStatus(0); } } ////////////////////////////// // // MidiOutPort_visual::closeAll // void MidiOutPort_visual::closeAll(void) { for (int i=0; i 64000 || size < 1) { cerr << "Warning: cannot write a MIDI stream larger than 64kB" << endl; return 0; } MIDIHDR midiheader; // structure for sending an array of MIDI bytes midiheader.lpData = (char *)array; midiheader.dwBufferLength = size; // midiheader.dwBytesRecorded = size; // example program doesn't set midiheader.dwFlags = 0; // flags must be set to 0 if (getPort() == -1) { return -1; } int status = midiOutPrepareHeader(device[getPort()], &midiheader, sizeof(MIDIHDR)); if (status != MMSYSERR_NOERROR) { return 0; } status = midiOutLongMsg(device[getPort()], &midiheader, sizeof(MIDIHDR)); if (status != MMSYSERR_NOERROR) { return 0; } while (MIDIERR_STILLPLAYING == midiOutUnprepareHeader(device[getPort()], &midiheader, sizeof(MIDIHDR))) { Sleep(1); // sleep for 1 millisecond } return 1; } ////////////////////////////// // // MidiOutPort_visual::open -- returns true if MIDI output port was // opened. // int MidiOutPort_visual::open(void) { if (getPort() == -1) { return 2; } if (getPortStatus() == 0) { int flag; flag = midiOutOpen(&device[getPort()], getPort(), 0, 0, CALLBACK_NULL); if (flag == MMSYSERR_NOERROR) { openQ[getPort()] = 1; return 1; } else { // faied to open openQ[getPort()] = 0; device[getPort()] = NULL; return 0; } } else { // already open return 1; } } ////////////////////////////// // // MidiOutPort_visual::setChannelOffset -- sets the MIDI channel offset, // either 0 or 1. // void MidiOutPort_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); } } ////////////////////////////// // // MidiOutPort_visual::setPort // void MidiOutPort_visual::setPort(int aPort) { if (aPort < 0 || 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; portObjectCount[port]++; } ////////////////////////////// // // MidiOutPort_visual::setTrace -- if false, then won't print // Midi messages to standard output. // int MidiOutPort_visual::setTrace(int aState) { int oldtrace = trace; if (aState == 0) { trace = 0; } else { trace = 1; } return oldtrace; } ////////////////////////////// // // MidiOutPort_visual::sysex -- send a system exclusive message. // The first byte of the message must be a 0xf0 byte. // int MidiOutPort_visual::sysex(uchar* array, int size) { if (size == 0 || array[0] != 0xf0) { cout << "Error: invalid system exclusive message," " first byte must be 0xf0" << endl; exit(1); } return rawsend(array, size); } ////////////////////////////// // // MidiOutPort_visual::toggleTrace // void MidiOutPort_visual::toggleTrace(void) { trace = !trace; } /////////////////////////////////////////////////////////////////////////// // // Private functions // ////////////////////////////// // // MidiOutPort_visual::deinitialize -- sets up storage if necessary // This function should be called if the current object is // the first object to be created. // void MidiOutPort_visual::deinitialize(void) { closeAll(); if (device != NULL) delete [] device; device = NULL; if (openQ != NULL) delete [] openQ; openQ = NULL; if (portObjectCount != NULL) delete [] portObjectCount; portObjectCount = NULL; } ////////////////////////////// // // MidiOutPort_visual::initialize -- sets up storage if necessary // This function should be called if the current object is // the first object to be created. // void MidiOutPort_visual::initialize(void) { // get the number of ports numDevices = midiOutGetNumDevs(); if (getNumPorts() <= 0) { cerr << "Error: no MIDI output devices" << endl; exit(1); } // allocate space for Windoze MIDI output structures if (device != NULL) { cerr << "Error: device array should be NULL when calling " << "initialize() in MidiOutPort." << endl; exit(1); } device = new HMIDIOUT[numDevices]; // allocate space for openQ, the port open/close status if (openQ != NULL) delete [] openQ; openQ = new int[numDevices]; // allocate space for object count on each port: if (portObjectCount != NULL) delete [] portObjectCount; portObjectCount = new int[numDevices]; // initialize the static arrays for (int i=0; i