| @@ -37,7 +37,7 @@ namespace Jack { | |||
| BUFFER_FULL, | |||
| BUFFER_TOO_SMALL, | |||
| EVENT_EARLY, | |||
| ERROR, | |||
| EN_ERROR, | |||
| OK | |||
| }; | |||
| @@ -54,7 +54,7 @@ namespace Jack { | |||
| * if the write queue isn't able to accept the event right now, | |||
| * `BUFFER_TOO_SMALL` if this write queue will never be able to accept | |||
| * the event because the event is too large, `EVENT_EARLY` if this | |||
| * queue cannot schedule events ahead of time, and `ERROR` if an error | |||
| * queue cannot schedule events ahead of time, and `EN_ERROR` if an error | |||
| * occurs that cannot be specified by another return code. | |||
| */ | |||
| @@ -151,8 +151,16 @@ namespace Jack | |||
| //allocate midi ports lists | |||
| fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels]; | |||
| fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels]; | |||
| assert ( fMidiCapturePortList ); | |||
| assert ( fMidiPlaybackPortList ); | |||
| assert(fMidiCapturePortList); | |||
| assert(fMidiPlaybackPortList); | |||
| for (uint midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) { | |||
| fMidiCapturePortList[midi_port_index] = NULL; | |||
| } | |||
| for (uint midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) { | |||
| fMidiPlaybackPortList[midi_port_index] = NULL; | |||
| } | |||
| //register jack ports | |||
| if ( AllocPorts() != 0 ) | |||
| @@ -362,20 +370,32 @@ namespace Jack | |||
| { | |||
| jack_log ( "JackNetDriver::FreePorts" ); | |||
| int audio_port_index; | |||
| uint midi_port_index; | |||
| for ( audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++ ) | |||
| if (fCapturePortList[audio_port_index] > 0) | |||
| fGraphManager->ReleasePort ( fClientControl.fRefNum, fCapturePortList[audio_port_index] ); | |||
| for ( audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++ ) | |||
| if (fPlaybackPortList[audio_port_index] > 0) | |||
| fGraphManager->ReleasePort ( fClientControl.fRefNum, fPlaybackPortList[audio_port_index] ); | |||
| for ( midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++ ) | |||
| if (fMidiCapturePortList[midi_port_index] > 0) | |||
| fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiCapturePortList[midi_port_index] ); | |||
| for ( midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++ ) | |||
| if (fMidiPlaybackPortList[midi_port_index] > 0) | |||
| fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index] ); | |||
| for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) { | |||
| if (fCapturePortList[audio_port_index] > 0) { | |||
| fGraphManager->ReleasePort ( fClientControl.fRefNum, fCapturePortList[audio_port_index]); | |||
| } | |||
| } | |||
| for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) { | |||
| if (fPlaybackPortList[audio_port_index] > 0) { | |||
| fGraphManager->ReleasePort ( fClientControl.fRefNum, fPlaybackPortList[audio_port_index]); | |||
| } | |||
| } | |||
| for (uint midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) { | |||
| if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) { | |||
| fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]); | |||
| } | |||
| } | |||
| for (uint midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) { | |||
| if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) { | |||
| fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]); | |||
| } | |||
| } | |||
| // Clear MIDI channels | |||
| fParams.fSendMidiChannels = 0; | |||
| fParams.fReturnMidiChannels = 0; | |||
| return 0; | |||
| } | |||
| @@ -14,7 +14,7 @@ extern "C" | |||
| { | |||
| #endif | |||
| #define MAX_SERVERS 8 /* maximum concurrent servers */ | |||
| #define MAX_SERVERS 64 /* maximum concurrent servers */ | |||
| #define MAX_SHM_ID 256 /* generally about 16 per server */ | |||
| #define JACK_SERVER_NAME_SIZE 256 /* maximum length of server name */ | |||
| #define JACK_SHM_MAGIC 0x4a41434b /* shm magic number: "JACK" */ | |||
| @@ -30,7 +30,7 @@ JackALSARawMidiSendQueue::EnqueueEvent(jack_nframes_t time, size_t size, | |||
| } | |||
| jack_error("JackALSARawMidiSendQueue::EnqueueEvent - snd_rawmidi_write: " | |||
| "%s", snd_strerror(result)); | |||
| return ERROR; | |||
| return EN_ERROR; | |||
| } | |||
| bool | |||
| @@ -108,42 +108,6 @@ | |||
| /* Begin PBXBuildFile section */ | |||
| 4B0A28ED0D520852002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; }; | |||
| 4B0A29260D52108E002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; }; | |||
| 4B193933133F311400547810 /* JackMidiAsyncQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */; }; | |||
| 4B193934133F311400547810 /* JackMidiAsyncQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193932133F311400547810 /* JackMidiAsyncQueue.h */; }; | |||
| 4B193935133F311400547810 /* JackMidiAsyncQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */; }; | |||
| 4B193936133F311400547810 /* JackMidiAsyncQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193932133F311400547810 /* JackMidiAsyncQueue.h */; }; | |||
| 4B19393D133F313000547810 /* JackMidiAsyncWaitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */; }; | |||
| 4B19393E133F313000547810 /* JackMidiAsyncWaitQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */; }; | |||
| 4B19393F133F313000547810 /* JackMidiAsyncWaitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */; }; | |||
| 4B193940133F313000547810 /* JackMidiAsyncWaitQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */; }; | |||
| 4B193947133F315300547810 /* JackMidiReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193945133F315200547810 /* JackMidiReadQueue.cpp */; }; | |||
| 4B193948133F315300547810 /* JackMidiReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193946133F315200547810 /* JackMidiReadQueue.h */; }; | |||
| 4B193949133F315300547810 /* JackMidiReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193945133F315200547810 /* JackMidiReadQueue.cpp */; }; | |||
| 4B19394A133F315300547810 /* JackMidiReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193946133F315200547810 /* JackMidiReadQueue.h */; }; | |||
| 4B19395F133F317300547810 /* JackMidiBufferReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */; }; | |||
| 4B193960133F317300547810 /* JackMidiBufferReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */; }; | |||
| 4B193961133F317300547810 /* JackMidiBufferReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */; }; | |||
| 4B193962133F317300547810 /* JackMidiBufferReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */; }; | |||
| 4B19396A133F319000547810 /* JackMidiBufferWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */; }; | |||
| 4B19396B133F319000547810 /* JackMidiBufferWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */; }; | |||
| 4B19396C133F319000547810 /* JackMidiBufferWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */; }; | |||
| 4B19396D133F319000547810 /* JackMidiBufferWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */; }; | |||
| 4B19397B133F31CB00547810 /* JackMidiReceiveQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */; }; | |||
| 4B19397C133F31CB00547810 /* JackMidiReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */; }; | |||
| 4B19397D133F31CB00547810 /* JackMidiSendQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */; }; | |||
| 4B19397E133F31CB00547810 /* JackMidiSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193976133F31CB00547810 /* JackMidiSendQueue.h */; }; | |||
| 4B19397F133F31CB00547810 /* JackMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193977133F31CB00547810 /* JackMidiUtil.cpp */; }; | |||
| 4B193980133F31CB00547810 /* JackMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193978133F31CB00547810 /* JackMidiUtil.h */; }; | |||
| 4B193981133F31CB00547810 /* JackMidiWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */; }; | |||
| 4B193982133F31CB00547810 /* JackMidiWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */; }; | |||
| 4B193983133F31CB00547810 /* JackMidiReceiveQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */; }; | |||
| 4B193984133F31CB00547810 /* JackMidiReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */; }; | |||
| 4B193985133F31CB00547810 /* JackMidiSendQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */; }; | |||
| 4B193986133F31CB00547810 /* JackMidiSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193976133F31CB00547810 /* JackMidiSendQueue.h */; }; | |||
| 4B193987133F31CB00547810 /* JackMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193977133F31CB00547810 /* JackMidiUtil.cpp */; }; | |||
| 4B193988133F31CB00547810 /* JackMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193978133F31CB00547810 /* JackMidiUtil.h */; }; | |||
| 4B193989133F31CB00547810 /* JackMidiWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */; }; | |||
| 4B19398A133F31CB00547810 /* JackMidiWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */; }; | |||
| 4B193991133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; }; | |||
| 4B193992133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; }; | |||
| 4B193993133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; }; | |||
| @@ -671,6 +635,42 @@ | |||
| 4B94334A10A5E666002A187F /* systemdeps.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B94334910A5E666002A187F /* systemdeps.h */; settings = {ATTRIBUTES = (Public, ); }; }; | |||
| 4B94334B10A5E666002A187F /* systemdeps.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B94334910A5E666002A187F /* systemdeps.h */; settings = {ATTRIBUTES = (Public, ); }; }; | |||
| 4B95BCAE0D913073000F7695 /* control.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B95BCAD0D913073000F7695 /* control.h */; settings = {ATTRIBUTES = (Public, ); }; }; | |||
| 4B97B6381344B3C100794F57 /* JackMidiAsyncQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */; }; | |||
| 4B97B6391344B3C300794F57 /* JackMidiAsyncQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193932133F311400547810 /* JackMidiAsyncQueue.h */; }; | |||
| 4B97B63A1344B3C700794F57 /* JackMidiAsyncWaitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */; }; | |||
| 4B97B63D1344B3EC00794F57 /* JackMidiAsyncWaitQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */; }; | |||
| 4B97B63E1344B3F100794F57 /* JackMidiBufferReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */; }; | |||
| 4B97B6411344B40C00794F57 /* JackMidiBufferReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */; }; | |||
| 4B97B6531344B41E00794F57 /* JackMidiBufferWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */; }; | |||
| 4B97B6541344B42400794F57 /* JackMidiBufferWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */; }; | |||
| 4B97B6561344B43600794F57 /* JackMidiReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193946133F315200547810 /* JackMidiReadQueue.h */; }; | |||
| 4B97B6571344B43A00794F57 /* JackMidiReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193945133F315200547810 /* JackMidiReadQueue.cpp */; }; | |||
| 4B97B6581344B43F00794F57 /* JackMidiReceiveQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */; }; | |||
| 4B97B6591344B44800794F57 /* JackMidiReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */; }; | |||
| 4B97B65A1344B44F00794F57 /* JackMidiSendQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */; }; | |||
| 4B97B65B1344B45600794F57 /* JackMidiSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193976133F31CB00547810 /* JackMidiSendQueue.h */; }; | |||
| 4B97B65C1344B45D00794F57 /* JackMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193977133F31CB00547810 /* JackMidiUtil.cpp */; }; | |||
| 4B97B65D1344B46400794F57 /* JackMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193978133F31CB00547810 /* JackMidiUtil.h */; }; | |||
| 4B97B65E1344B46B00794F57 /* JackMidiWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */; }; | |||
| 4B97B65F1344B47100794F57 /* JackMidiWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */; }; | |||
| 4B97B6601344B48F00794F57 /* JackMidiAsyncQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */; }; | |||
| 4B97B6611344B49500794F57 /* JackMidiAsyncQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193932133F311400547810 /* JackMidiAsyncQueue.h */; }; | |||
| 4B97B6621344B49C00794F57 /* JackMidiAsyncWaitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */; }; | |||
| 4B97B6631344B4A800794F57 /* JackMidiAsyncWaitQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */; }; | |||
| 4B97B6641344B4AE00794F57 /* JackMidiBufferReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */; }; | |||
| 4B97B6651344B4B500794F57 /* JackMidiBufferReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */; }; | |||
| 4B97B6671344B4C700794F57 /* JackMidiBufferWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */; }; | |||
| 4B97B6691344B4CE00794F57 /* JackMidiBufferWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */; }; | |||
| 4B97B66E1344B4D500794F57 /* JackMidiReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193945133F315200547810 /* JackMidiReadQueue.cpp */; }; | |||
| 4B97B66F1344B4DC00794F57 /* JackMidiReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193946133F315200547810 /* JackMidiReadQueue.h */; }; | |||
| 4B97B6701344B4E300794F57 /* JackMidiReceiveQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */; }; | |||
| 4B97B6711344B4EA00794F57 /* JackMidiReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */; }; | |||
| 4B97B6721344B4F000794F57 /* JackMidiSendQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */; }; | |||
| 4B97B6781344B50800794F57 /* JackMidiSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193976133F31CB00547810 /* JackMidiSendQueue.h */; }; | |||
| 4B97B6791344B50F00794F57 /* JackMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193977133F31CB00547810 /* JackMidiUtil.cpp */; }; | |||
| 4B97B67A1344B51600794F57 /* JackMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193978133F31CB00547810 /* JackMidiUtil.h */; }; | |||
| 4B97B67B1344B51D00794F57 /* JackMidiWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */; }; | |||
| 4B97B67C1344B52800794F57 /* JackMidiWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */; }; | |||
| 4B9A25B50DBF8330006E9FBC /* JackError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9A25B30DBF8330006E9FBC /* JackError.cpp */; }; | |||
| 4B9A25B60DBF8330006E9FBC /* JackError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9A25B30DBF8330006E9FBC /* JackError.cpp */; }; | |||
| 4B9A26010DBF8584006E9FBC /* jslist.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B9A26000DBF8584006E9FBC /* jslist.h */; settings = {ATTRIBUTES = (Public, ); }; }; | |||
| @@ -3454,6 +3454,15 @@ | |||
| 4B8A38C4117B814000664E07 /* JackSocketServerNotifyChannel.h in Headers */, | |||
| 4B5160AA13215ED900BB7DCB /* systemdeps.h in Headers */, | |||
| 4B193995133F321500547810 /* JackFilters.h in Headers */, | |||
| 4B97B6611344B49500794F57 /* JackMidiAsyncQueue.h in Headers */, | |||
| 4B97B6631344B4A800794F57 /* JackMidiAsyncWaitQueue.h in Headers */, | |||
| 4B97B6651344B4B500794F57 /* JackMidiBufferReadQueue.h in Headers */, | |||
| 4B97B6671344B4C700794F57 /* JackMidiBufferWriteQueue.h in Headers */, | |||
| 4B97B66F1344B4DC00794F57 /* JackMidiReadQueue.h in Headers */, | |||
| 4B97B6711344B4EA00794F57 /* JackMidiReceiveQueue.h in Headers */, | |||
| 4B97B6781344B50800794F57 /* JackMidiSendQueue.h in Headers */, | |||
| 4B97B67A1344B51600794F57 /* JackMidiUtil.h in Headers */, | |||
| 4B97B67C1344B52800794F57 /* JackMidiWriteQueue.h in Headers */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -3917,6 +3926,15 @@ | |||
| 4B2209E712F6BC0300E5DC26 /* JackSocket.h in Headers */, | |||
| 4B2209EA12F6BC1600E5DC26 /* JackSocketNotifyChannel.h in Headers */, | |||
| 4B193992133F321500547810 /* JackFilters.h in Headers */, | |||
| 4B97B6391344B3C300794F57 /* JackMidiAsyncQueue.h in Headers */, | |||
| 4B97B63D1344B3EC00794F57 /* JackMidiAsyncWaitQueue.h in Headers */, | |||
| 4B97B6411344B40C00794F57 /* JackMidiBufferReadQueue.h in Headers */, | |||
| 4B97B6541344B42400794F57 /* JackMidiBufferWriteQueue.h in Headers */, | |||
| 4B97B6561344B43600794F57 /* JackMidiReadQueue.h in Headers */, | |||
| 4B97B6591344B44800794F57 /* JackMidiReceiveQueue.h in Headers */, | |||
| 4B97B65B1344B45600794F57 /* JackMidiSendQueue.h in Headers */, | |||
| 4B97B65D1344B46400794F57 /* JackMidiUtil.h in Headers */, | |||
| 4B97B65F1344B47100794F57 /* JackMidiWriteQueue.h in Headers */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -4152,15 +4170,6 @@ | |||
| 4B370A3F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */, | |||
| 4B370A41133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */, | |||
| 4B370A43133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h in Headers */, | |||
| 4B193936133F311400547810 /* JackMidiAsyncQueue.h in Headers */, | |||
| 4B193940133F313000547810 /* JackMidiAsyncWaitQueue.h in Headers */, | |||
| 4B19394A133F315300547810 /* JackMidiReadQueue.h in Headers */, | |||
| 4B193962133F317300547810 /* JackMidiBufferReadQueue.h in Headers */, | |||
| 4B19396D133F319000547810 /* JackMidiBufferWriteQueue.h in Headers */, | |||
| 4B193984133F31CB00547810 /* JackMidiReceiveQueue.h in Headers */, | |||
| 4B193986133F31CB00547810 /* JackMidiSendQueue.h in Headers */, | |||
| 4B193988133F31CB00547810 /* JackMidiUtil.h in Headers */, | |||
| 4B19398A133F31CB00547810 /* JackMidiWriteQueue.h in Headers */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -4229,15 +4238,6 @@ | |||
| 4B370A2F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */, | |||
| 4B370A31133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */, | |||
| 4B370A33133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h in Headers */, | |||
| 4B193934133F311400547810 /* JackMidiAsyncQueue.h in Headers */, | |||
| 4B19393E133F313000547810 /* JackMidiAsyncWaitQueue.h in Headers */, | |||
| 4B193948133F315300547810 /* JackMidiReadQueue.h in Headers */, | |||
| 4B193960133F317300547810 /* JackMidiBufferReadQueue.h in Headers */, | |||
| 4B19396B133F319000547810 /* JackMidiBufferWriteQueue.h in Headers */, | |||
| 4B19397C133F31CB00547810 /* JackMidiReceiveQueue.h in Headers */, | |||
| 4B19397E133F31CB00547810 /* JackMidiSendQueue.h in Headers */, | |||
| 4B193980133F31CB00547810 /* JackMidiUtil.h in Headers */, | |||
| 4B193982133F31CB00547810 /* JackMidiWriteQueue.h in Headers */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -6885,6 +6885,15 @@ | |||
| 4B8A38AE117B811100664E07 /* JackSocketNotifyChannel.cpp in Sources */, | |||
| 4B8A38B1117B812D00664E07 /* JackSocketServerChannel.cpp in Sources */, | |||
| 4B8A38B2117B813400664E07 /* JackSocketServerNotifyChannel.cpp in Sources */, | |||
| 4B97B6601344B48F00794F57 /* JackMidiAsyncQueue.cpp in Sources */, | |||
| 4B97B6621344B49C00794F57 /* JackMidiAsyncWaitQueue.cpp in Sources */, | |||
| 4B97B6641344B4AE00794F57 /* JackMidiBufferReadQueue.cpp in Sources */, | |||
| 4B97B6691344B4CE00794F57 /* JackMidiBufferWriteQueue.cpp in Sources */, | |||
| 4B97B66E1344B4D500794F57 /* JackMidiReadQueue.cpp in Sources */, | |||
| 4B97B6701344B4E300794F57 /* JackMidiReceiveQueue.cpp in Sources */, | |||
| 4B97B6721344B4F000794F57 /* JackMidiSendQueue.cpp in Sources */, | |||
| 4B97B6791344B50F00794F57 /* JackMidiUtil.cpp in Sources */, | |||
| 4B97B67B1344B51D00794F57 /* JackMidiWriteQueue.cpp in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -7337,6 +7346,15 @@ | |||
| 4B2209E312F6BBF500E5DC26 /* JackSocketServerNotifyChannel.cpp in Sources */, | |||
| 4B2209E612F6BC0200E5DC26 /* JackSocket.cpp in Sources */, | |||
| 4B2209E912F6BC1500E5DC26 /* JackSocketNotifyChannel.cpp in Sources */, | |||
| 4B97B6381344B3C100794F57 /* JackMidiAsyncQueue.cpp in Sources */, | |||
| 4B97B63A1344B3C700794F57 /* JackMidiAsyncWaitQueue.cpp in Sources */, | |||
| 4B97B63E1344B3F100794F57 /* JackMidiBufferReadQueue.cpp in Sources */, | |||
| 4B97B6531344B41E00794F57 /* JackMidiBufferWriteQueue.cpp in Sources */, | |||
| 4B97B6571344B43A00794F57 /* JackMidiReadQueue.cpp in Sources */, | |||
| 4B97B6581344B43F00794F57 /* JackMidiReceiveQueue.cpp in Sources */, | |||
| 4B97B65A1344B44F00794F57 /* JackMidiSendQueue.cpp in Sources */, | |||
| 4B97B65C1344B45D00794F57 /* JackMidiUtil.cpp in Sources */, | |||
| 4B97B65E1344B46B00794F57 /* JackMidiWriteQueue.cpp in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -7575,15 +7593,6 @@ | |||
| 4B370A3E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */, | |||
| 4B370A40133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */, | |||
| 4B370A42133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp in Sources */, | |||
| 4B193935133F311400547810 /* JackMidiAsyncQueue.cpp in Sources */, | |||
| 4B19393F133F313000547810 /* JackMidiAsyncWaitQueue.cpp in Sources */, | |||
| 4B193949133F315300547810 /* JackMidiReadQueue.cpp in Sources */, | |||
| 4B193961133F317300547810 /* JackMidiBufferReadQueue.cpp in Sources */, | |||
| 4B19396C133F319000547810 /* JackMidiBufferWriteQueue.cpp in Sources */, | |||
| 4B193983133F31CB00547810 /* JackMidiReceiveQueue.cpp in Sources */, | |||
| 4B193985133F31CB00547810 /* JackMidiSendQueue.cpp in Sources */, | |||
| 4B193987133F31CB00547810 /* JackMidiUtil.cpp in Sources */, | |||
| 4B193989133F31CB00547810 /* JackMidiWriteQueue.cpp in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -7657,15 +7666,6 @@ | |||
| 4B370A2E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */, | |||
| 4B370A30133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */, | |||
| 4B370A32133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp in Sources */, | |||
| 4B193933133F311400547810 /* JackMidiAsyncQueue.cpp in Sources */, | |||
| 4B19393D133F313000547810 /* JackMidiAsyncWaitQueue.cpp in Sources */, | |||
| 4B193947133F315300547810 /* JackMidiReadQueue.cpp in Sources */, | |||
| 4B19395F133F317300547810 /* JackMidiBufferReadQueue.cpp in Sources */, | |||
| 4B19396A133F319000547810 /* JackMidiBufferWriteQueue.cpp in Sources */, | |||
| 4B19397B133F31CB00547810 /* JackMidiReceiveQueue.cpp in Sources */, | |||
| 4B19397D133F31CB00547810 /* JackMidiSendQueue.cpp in Sources */, | |||
| 4B19397F133F31CB00547810 /* JackMidiUtil.cpp in Sources */, | |||
| 4B193981133F31CB00547810 /* JackMidiWriteQueue.cpp in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -972,14 +972,14 @@ int main (int argc, char *argv[]) | |||
| float factor = 0.5f; | |||
| old_buffer_size = jack_get_buffer_size(client1); | |||
| Log("Testing BufferSize change & Callback...\n--> Current buffer size : %i.\n", old_buffer_size); | |||
| Log("Testing BufferSize change & Callback...\n--> Current buffer size : %d.\n", old_buffer_size); | |||
| linebuf = linecount; | |||
| if (jack_set_buffer_size(client1, (jack_nframes_t)(old_buffer_size * factor)) < 0) { | |||
| printf("!!! ERROR !!! jack_set_buffer_size fails !\n"); | |||
| } | |||
| jack_sleep(1 * 1000); | |||
| cur_buffer_size = jack_get_buffer_size(client1); | |||
| if ((old_buffer_size * factor) != cur_buffer_size) { | |||
| if (abs((old_buffer_size * factor) - cur_buffer_size) > 5) { // Tolerance needed for dummy driver... | |||
| printf("!!! ERROR !!! Buffer size has not been changed !\n"); | |||
| printf("!!! Maybe jack was compiled without the '--enable-resize' flag...\n"); | |||
| } else { | |||
| @@ -106,6 +106,12 @@ | |||
| <Option compilerVar="WINDRES" /> | |||
| </Unit> | |||
| <Unit filename="winmme\JackWinMMEDriver.cpp" /> | |||
| <Unit filename="winmme\JackWinMMEDriver.h" /> | |||
| <Unit filename="winmme\JackWinMMEInputPort.cpp" /> | |||
| <Unit filename="winmme\JackWinMMEInputPort.h" /> | |||
| <Unit filename="winmme\JackWinMMEOutputPort.cpp" /> | |||
| <Unit filename="winmme\JackWinMMEOutputPort.h" /> | |||
| <Unit filename="winmme\JackWinMMEPort.cpp" /> | |||
| <Extensions> | |||
| <code_completion /> | |||
| <envvars /> | |||
| @@ -56,7 +56,7 @@ | |||
| <Project filename="multiple_metro.cbp"> | |||
| <Depends filename="libjack.cbp" /> | |||
| </Project> | |||
| <Project filename="jack_winmme.cbp" /> | |||
| <Project filename="jack_loopback.cbp" active="1" /> | |||
| <Project filename="jack_winmme.cbp" active="1" /> | |||
| <Project filename="jack_loopback.cbp" /> | |||
| </Workspace> | |||
| </CodeBlocks_workspace_file> | |||
| @@ -150,12 +150,16 @@ | |||
| <Unit filename="..\common\JackLoopbackDriver.cpp" /> | |||
| <Unit filename="..\common\JackMessageBuffer.cpp" /> | |||
| <Unit filename="..\common\JackMidiAPI.cpp" /> | |||
| <Unit filename="..\common\JackMidiAsyncQueue.cpp" /> | |||
| <Unit filename="..\common\JackMidiBufferReadQueue.cpp" /> | |||
| <Unit filename="..\common\JackMidiBufferWriteQueue.cpp" /> | |||
| <Unit filename="..\common\JackMidiDriver.cpp" /> | |||
| <Unit filename="..\common\JackMidiPort.cpp" /> | |||
| <Unit filename="..\common\JackMidiReadQueue.cpp" /> | |||
| <Unit filename="..\common\JackMidiUtil.cpp" /> | |||
| <Unit filename="..\common\JackMidiWriteQueue.cpp" /> | |||
| <Unit filename="..\common\JackNetInterface.cpp" /> | |||
| <Unit filename="..\common\JackNetTool.cpp" /> | |||
| <Unit filename="..\common\JackPhysicalMidiInput.cpp" /> | |||
| <Unit filename="..\common\JackPhysicalMidiOutput.cpp" /> | |||
| <Unit filename="..\common\JackPort.cpp" /> | |||
| <Unit filename="..\common\JackPortType.cpp" /> | |||
| <Unit filename="..\common\JackRestartThreadedDriver.cpp" /> | |||
| @@ -248,7 +248,7 @@ error: | |||
| } else { | |||
| JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails | |||
| // PortAudio specific | |||
| UpdateLatencies(); | |||
| JackAudioDriver::UpdateLatencies(); | |||
| return 0; | |||
| } | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| /* | |||
| Copyright (C) 2009 Grame | |||
| Copyright (C) 2011 Devin Anderson | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| @@ -17,401 +18,302 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #include "JackWinMMEDriver.h" | |||
| #include "JackGraphManager.h" | |||
| #include "JackEngineControl.h" | |||
| #include "JackDriverLoader.h" | |||
| #include <assert.h> | |||
| #include <iostream> | |||
| #include <sstream> | |||
| #include <string> | |||
| #include <windows.h> | |||
| #include <windowsx.h> | |||
| #include <mmsystem.h> | |||
| #include "JackWinMMEDriver.h" | |||
| namespace Jack | |||
| { | |||
| using Jack::JackWinMMEDriver; | |||
| static bool InitHeaders(MidiSlot* slot) | |||
| JackWinMMEDriver::JackWinMMEDriver(const char *name, const char *alias, | |||
| JackLockedEngine *engine, | |||
| JackSynchro *table): | |||
| JackMidiDriver(name, alias, engine, table) | |||
| { | |||
| slot->fHeader = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, sizeof(MIDIHDR) + kBuffSize); | |||
| if (!slot->fHeader) | |||
| return false; | |||
| slot->fHeader->lpData = (LPSTR)((LPBYTE)slot->fHeader + sizeof(MIDIHDR)); | |||
| slot->fHeader->dwBufferLength = kBuffSize; | |||
| slot->fHeader->dwFlags = 0; | |||
| slot->fHeader->dwUser = 0; | |||
| slot->fHeader->lpNext = 0; | |||
| slot->fHeader->dwBytesRecorded = 0; | |||
| return true; | |||
| fCaptureChannels = 0; | |||
| fPlaybackChannels = 0; | |||
| input_ports = 0; | |||
| output_ports = 0; | |||
| } | |||
| void CALLBACK JackWinMMEDriver::MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD userData, DWORD dwParam1, DWORD dwParam2) | |||
| JackWinMMEDriver::~JackWinMMEDriver() | |||
| { | |||
| jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)userData; | |||
| //jack_info("JackWinMMEDriver::MidiInProc 0\n"); | |||
| switch (wMsg) { | |||
| case MIM_OPEN: | |||
| break; | |||
| case MIM_ERROR: | |||
| case MIM_DATA: { | |||
| //jack_info("JackWinMMEDriver::MidiInProc"); | |||
| // One event | |||
| unsigned int num_packet = 1; | |||
| jack_ringbuffer_write(ringbuffer, (char*)&num_packet, sizeof(unsigned int)); | |||
| // Write event actual data | |||
| jack_ringbuffer_write(ringbuffer, (char*)&dwParam1, 3); | |||
| break; | |||
| } | |||
| case MIM_LONGERROR: | |||
| case MIM_LONGDATA: | |||
| /* | |||
| Nothing for now | |||
| */ | |||
| break; | |||
| } | |||
| Stop(); | |||
| Close(); | |||
| } | |||
| JackWinMMEDriver::JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) | |||
| : JackMidiDriver(name, alias, engine, table), | |||
| fRealCaptureChannels(0), | |||
| fRealPlaybackChannels(0), | |||
| fMidiSource(NULL), | |||
| fMidiDestination(NULL) | |||
| {} | |||
| JackWinMMEDriver::~JackWinMMEDriver() | |||
| {} | |||
| int JackWinMMEDriver::Open(bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| int outchannels, | |||
| bool monitor, | |||
| const char* capture_driver_name, | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency) | |||
| int | |||
| JackWinMMEDriver::Attach() | |||
| { | |||
| jack_log("JackWinMMEDriver::Open"); | |||
| fRealCaptureChannels = midiInGetNumDevs(); | |||
| fRealPlaybackChannels = midiOutGetNumDevs(); | |||
| // Generic JackMidiDriver Open | |||
| if (JackMidiDriver::Open(capturing, playing, fRealCaptureChannels, fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) | |||
| return -1; | |||
| fMidiDestination = new MidiSlot[fRealCaptureChannels]; | |||
| assert(fMidiDestination); | |||
| // Real input | |||
| int devindex = 0; | |||
| for (int i = 0; i < fRealCaptureChannels; i++) { | |||
| HMIDIIN handle; | |||
| fMidiDestination[devindex].fIndex = i; | |||
| MMRESULT ret = midiInOpen(&handle, fMidiDestination[devindex].fIndex, (DWORD)MidiInProc, (DWORD)fRingBuffer[devindex], CALLBACK_FUNCTION); | |||
| if (ret == MMSYSERR_NOERROR) { | |||
| fMidiDestination[devindex].fHandle = handle; | |||
| if (!InitHeaders(&fMidiDestination[devindex])) { | |||
| jack_error("memory allocation failed"); | |||
| midiInClose(handle); | |||
| continue; | |||
| } | |||
| ret = midiInPrepareHeader(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR)); | |||
| if (ret == MMSYSERR_NOERROR) { | |||
| fMidiDestination[devindex].fHeader->dwUser = 1; | |||
| ret = midiInAddBuffer(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR)); | |||
| if (ret == MMSYSERR_NOERROR) { | |||
| ret = midiInStart(handle); | |||
| if (ret != MMSYSERR_NOERROR) { | |||
| jack_error("midiInStart error"); | |||
| CloseInput(&fMidiDestination[devindex]); | |||
| continue; | |||
| } | |||
| } else { | |||
| jack_error ("midiInAddBuffer error"); | |||
| CloseInput(&fMidiDestination[devindex]); | |||
| continue; | |||
| } | |||
| } else { | |||
| jack_error("midiInPrepareHeader error"); | |||
| midiInClose(handle); | |||
| continue; | |||
| } | |||
| } else { | |||
| jack_error ("midiInOpen error"); | |||
| continue; | |||
| jack_nframes_t buffer_size = fEngineControl->fBufferSize; | |||
| jack_port_id_t index; | |||
| jack_nframes_t latency = buffer_size; | |||
| jack_latency_range_t latency_range; | |||
| const char *name; | |||
| JackPort *port; | |||
| latency_range.max = latency; | |||
| latency_range.min = latency; | |||
| jack_info("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels); | |||
| jack_info("JackWinMMEDriver::Attach - fPlaybackChannels %d", fPlaybackChannels); | |||
| // Inputs | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| JackWinMMEInputPort *input_port = input_ports[i]; | |||
| name = input_port->GetName(); | |||
| index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, | |||
| JACK_DEFAULT_MIDI_TYPE, | |||
| CaptureDriverFlags, buffer_size); | |||
| if (index == NO_PORT) { | |||
| jack_error("JackWinMMEDriver::Attach - cannot register input port " | |||
| "with name '%s'.", name); | |||
| // X: Do we need to deallocate ports? | |||
| return -1; | |||
| } | |||
| devindex += 1; | |||
| port = fGraphManager->GetPort(index); | |||
| port->SetAlias(input_port->GetAlias()); | |||
| port->SetLatencyRange(JackCaptureLatency, &latency_range); | |||
| fCapturePortList[i] = index; | |||
| } | |||
| fRealCaptureChannels = devindex; | |||
| fCaptureChannels = devindex; | |||
| fMidiSource = new MidiSlot[fRealPlaybackChannels]; | |||
| assert(fMidiSource); | |||
| // Real output | |||
| devindex = 0; | |||
| for (int i = 0; i < fRealPlaybackChannels; i++) { | |||
| MMRESULT res; | |||
| HMIDIOUT handle; | |||
| fMidiSource[devindex].fIndex = i; | |||
| UINT ret = midiOutOpen(&handle, fMidiSource[devindex].fIndex, 0L, 0L, CALLBACK_NULL); | |||
| if (ret == MMSYSERR_NOERROR) { | |||
| fMidiSource[devindex].fHandle = handle; | |||
| if (!InitHeaders(&fMidiSource[devindex])) { | |||
| jack_error("memory allocation failed"); | |||
| midiOutClose(handle); | |||
| continue; | |||
| } | |||
| res = midiOutPrepareHeader(handle, fMidiSource[devindex].fHeader, sizeof(MIDIHDR)); | |||
| if (res != MMSYSERR_NOERROR) { | |||
| jack_error("midiOutPrepareHeader error %d %d %d", i, handle, res); | |||
| continue; | |||
| } else { | |||
| fMidiSource[devindex].fHeader->dwUser = 1; | |||
| } | |||
| } else { | |||
| jack_error("midiOutOpen error"); | |||
| continue; | |||
| if (! fEngineControl->fSyncMode) { | |||
| latency += buffer_size; | |||
| latency_range.max = latency; | |||
| latency_range.min = latency; | |||
| } | |||
| // Outputs | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| JackWinMMEOutputPort *output_port = output_ports[i]; | |||
| name = output_port->GetName(); | |||
| index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, | |||
| JACK_DEFAULT_MIDI_TYPE, | |||
| PlaybackDriverFlags, buffer_size); | |||
| if (index == NO_PORT) { | |||
| jack_error("JackWinMMEDriver::Attach - cannot register output " | |||
| "port with name '%s'.", name); | |||
| // X: Do we need to deallocate ports? | |||
| return -1; | |||
| } | |||
| devindex += 1; | |||
| port = fGraphManager->GetPort(index); | |||
| port->SetAlias(output_port->GetAlias()); | |||
| port->SetLatencyRange(JackPlaybackLatency, &latency_range); | |||
| fPlaybackPortList[i] = index; | |||
| } | |||
| fRealPlaybackChannels = devindex; | |||
| fPlaybackChannels = devindex; | |||
| return 0; | |||
| } | |||
| void JackWinMMEDriver::CloseInput(MidiSlot* slot) | |||
| int | |||
| JackWinMMEDriver::Close() | |||
| { | |||
| MMRESULT res; | |||
| int retry = 0; | |||
| if (slot->fHandle == 0) | |||
| return; | |||
| HMIDIIN handle = (HMIDIIN)slot->fHandle; | |||
| slot->fHeader->dwUser = 0; | |||
| res = midiInStop(handle); | |||
| if (res != MMSYSERR_NOERROR) { | |||
| jack_error("midiInStop error"); | |||
| } | |||
| res = midiInReset(handle); | |||
| if (res != MMSYSERR_NOERROR) { | |||
| jack_error("midiInReset error"); | |||
| } | |||
| res = midiInUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR)); | |||
| if (res != MMSYSERR_NOERROR) { | |||
| jack_error("midiInUnprepareHeader error"); | |||
| int result = JackMidiDriver::Close(); | |||
| if (input_ports) { | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| delete input_ports[i]; | |||
| } | |||
| delete[] input_ports; | |||
| input_ports = 0; | |||
| } | |||
| do { | |||
| res = midiInClose(handle); | |||
| if (res != MMSYSERR_NOERROR) { | |||
| jack_error("midiInClose error"); | |||
| if (output_ports) { | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| delete output_ports[i]; | |||
| } | |||
| if (res == MIDIERR_STILLPLAYING) | |||
| midiInReset(handle); | |||
| Sleep (10); | |||
| retry++; | |||
| } while ((res == MIDIERR_STILLPLAYING) && (retry < 10)); | |||
| if (slot->fHeader) { | |||
| GlobalFreePtr(slot->fHeader); | |||
| delete[] output_ports; | |||
| output_ports = 0; | |||
| } | |||
| return result; | |||
| } | |||
| void JackWinMMEDriver::CloseOutput(MidiSlot* slot) | |||
| int | |||
| JackWinMMEDriver::Open(bool capturing, bool playing, int in_channels, | |||
| int out_channels, bool monitor, | |||
| const char* capture_driver_name, | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency) | |||
| { | |||
| MMRESULT res; | |||
| int retry = 0; | |||
| if (slot->fHandle == 0) | |||
| return; | |||
| HMIDIOUT handle = (HMIDIOUT)slot->fHandle; | |||
| res = midiOutReset(handle); | |||
| if (res != MMSYSERR_NOERROR) | |||
| jack_error("midiOutReset error"); | |||
| midiOutUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR)); | |||
| do { | |||
| res = midiOutClose(handle); | |||
| if (res != MMSYSERR_NOERROR) | |||
| jack_error("midiOutClose error"); | |||
| Sleep(10); | |||
| retry++; | |||
| } while ((res == MIDIERR_STILLPLAYING) && (retry < 10)); | |||
| if (slot->fHeader) { | |||
| GlobalFreePtr(slot->fHeader); | |||
| const char *client_name = fClientControl.fName; | |||
| int input_count = 0; | |||
| int output_count = 0; | |||
| int num_potential_inputs = midiInGetNumDevs(); | |||
| int num_potential_outputs = midiOutGetNumDevs(); | |||
| jack_info("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs); | |||
| jack_info("JackWinMMEDriver::Open - num_potential_outputs %d", num_potential_outputs); | |||
| if (num_potential_inputs) { | |||
| try { | |||
| input_ports = new JackWinMMEInputPort *[num_potential_inputs]; | |||
| } catch (std::exception e) { | |||
| jack_error("JackWinMMEDriver::Open - while creating input port " | |||
| "array: %s", e.what()); | |||
| return -1; | |||
| } | |||
| for (int i = 0; i < num_potential_inputs; i++) { | |||
| try { | |||
| input_ports[input_count] = | |||
| new JackWinMMEInputPort(fAliasName, client_name, | |||
| capture_driver_name, i); | |||
| } catch (std::exception e) { | |||
| jack_error("JackWinMMEDriver::Open - while creating input " | |||
| "port: %s", e.what()); | |||
| continue; | |||
| } | |||
| input_count++; | |||
| } | |||
| } | |||
| if (num_potential_outputs) { | |||
| try { | |||
| output_ports = new JackWinMMEOutputPort *[num_potential_outputs]; | |||
| } catch (std::exception e) { | |||
| jack_error("JackWinMMEDriver::Open - while creating output port " | |||
| "array: %s", e.what()); | |||
| goto destroy_input_ports; | |||
| } | |||
| for (int i = 0; i < num_potential_outputs; i++) { | |||
| try { | |||
| output_ports[output_count] = | |||
| new JackWinMMEOutputPort(fAliasName, client_name, | |||
| playback_driver_name, i); | |||
| } catch (std::exception e) { | |||
| jack_error("JackWinMMEDriver::Open - while creating output " | |||
| "port: %s", e.what()); | |||
| continue; | |||
| } | |||
| output_count++; | |||
| } | |||
| } | |||
| } | |||
| int JackWinMMEDriver::Close() | |||
| { | |||
| jack_log("JackWinMMEDriver::Close"); | |||
| jack_info("JackWinMMEDriver::Open - input_count %d", input_count); | |||
| jack_info("JackWinMMEDriver::Open - output_count %d", output_count); | |||
| // Generic midi driver close | |||
| int res = JackMidiDriver::Close(); | |||
| // Close input | |||
| if (fMidiDestination) { | |||
| for (int i = 0; i < fRealCaptureChannels; i++) { | |||
| CloseInput(&fMidiDestination[i]); | |||
| } | |||
| delete[] fMidiDestination; | |||
| if (! (input_count || output_count)) { | |||
| jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs " | |||
| "allocated."); | |||
| } else if (! JackMidiDriver::Open(capturing, playing, input_count, | |||
| output_count, monitor, | |||
| capture_driver_name, | |||
| playback_driver_name, capture_latency, | |||
| playback_latency)) { | |||
| return 0; | |||
| } | |||
| // Close output | |||
| if (fMidiSource) { | |||
| for (int i = 0; i < fRealPlaybackChannels; i++) { | |||
| CloseOutput(&fMidiSource[i]); | |||
| destroy_input_ports: | |||
| if (input_ports) { | |||
| for (int i = 0; i < input_count; i++) { | |||
| delete input_ports[i]; | |||
| } | |||
| delete[] fMidiSource; | |||
| delete[] input_ports; | |||
| input_ports = 0; | |||
| } | |||
| return res; | |||
| return -1; | |||
| } | |||
| int JackWinMMEDriver::Attach() | |||
| int | |||
| JackWinMMEDriver::Read() | |||
| { | |||
| JackPort* port; | |||
| jack_port_id_t port_index; | |||
| char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
| char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
| MMRESULT res; | |||
| int i; | |||
| jack_log("JackMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); | |||
| for (i = 0; i < fCaptureChannels; i++) { | |||
| MIDIINCAPS caps; | |||
| res = midiInGetDevCaps(fMidiDestination[i].fIndex, &caps, sizeof(caps)); | |||
| if (res == MMSYSERR_NOERROR) { | |||
| snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1); | |||
| } else { | |||
| snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1); | |||
| } | |||
| snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1); | |||
| if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { | |||
| jack_error("driver: cannot register port for %s", name); | |||
| return -1; | |||
| } | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetAlias(alias); | |||
| fCapturePortList[i] = port_index; | |||
| jack_log("JackMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index); | |||
| } | |||
| for (i = 0; i < fPlaybackChannels; i++) { | |||
| MIDIOUTCAPS caps; | |||
| res = midiOutGetDevCaps(fMidiSource[i].fIndex, &caps, sizeof(caps)); | |||
| if (res == MMSYSERR_NOERROR) { | |||
| snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1); | |||
| } else { | |||
| snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fPlaybackDriverName, i + 1); | |||
| } | |||
| snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1); | |||
| if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { | |||
| jack_error("driver: cannot register port for %s", name); | |||
| return -1; | |||
| } | |||
| port = fGraphManager->GetPort(port_index); | |||
| port->SetAlias(alias); | |||
| fPlaybackPortList[i] = port_index; | |||
| jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); | |||
| jack_nframes_t buffer_size = fEngineControl->fBufferSize; | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size); | |||
| } | |||
| return 0; | |||
| } | |||
| int JackWinMMEDriver::Read() | |||
| int | |||
| JackWinMMEDriver::Write() | |||
| { | |||
| size_t size; | |||
| /* | |||
| jack_nframes_t buffer_size = fEngineControl->fBufferSize; | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size); | |||
| } | |||
| */ | |||
| return 0; | |||
| } | |||
| for (int chan = 0; chan < fCaptureChannels; chan++) { | |||
| int | |||
| JackWinMMEDriver::Start() | |||
| { | |||
| jack_info("JackWinMMEDriver::Start - Starting driver."); | |||
| if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) { | |||
| JackMidiDriver::Start(); | |||
| JackMidiBuffer* midi_buffer = GetInputBuffer(chan); | |||
| int input_count = 0; | |||
| int output_count = 0; | |||
| if (jack_ringbuffer_read_space (fRingBuffer[chan]) == 0) { | |||
| // Reset buffer | |||
| midi_buffer->Reset(midi_buffer->nframes); | |||
| } else { | |||
| jack_info("JackWinMMEDriver::Start - Enabling input ports."); | |||
| while ((size = jack_ringbuffer_read_space (fRingBuffer[chan])) > 0) { | |||
| for (; input_count < fCaptureChannels; input_count++) { | |||
| if (input_ports[input_count]->Start() < 0) { | |||
| jack_error("JackWinMMEDriver::Start - Failed to enable input " | |||
| "port."); | |||
| goto stop_input_ports; | |||
| } | |||
| } | |||
| //jack_info("jack_ringbuffer_read_space %d", size); | |||
| int ev_count = 0; | |||
| jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int)); | |||
| jack_info("JackWinMMEDriver::Start - Enabling output ports."); | |||
| if (ev_count > 0) { | |||
| for (int j = 0; j < ev_count; j++) { | |||
| unsigned int event_len = 3; | |||
| // Read event actual data | |||
| jack_midi_data_t* dest = midi_buffer->ReserveEvent(0, event_len); | |||
| jack_ringbuffer_read(fRingBuffer[chan], (char*)dest, event_len); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } else { | |||
| //jack_info("Consume ring buffer"); | |||
| jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan])); | |||
| for (; output_count < fPlaybackChannels; output_count++) { | |||
| if (output_ports[output_count]->Start() < 0) { | |||
| jack_error("JackWinMMEDriver::Start - Failed to enable output " | |||
| "port."); | |||
| goto stop_output_ports; | |||
| } | |||
| } | |||
| jack_info("JackWinMMEDriver::Start - Driver started."); | |||
| return 0; | |||
| stop_output_ports: | |||
| for (int i = 0; i < output_count; i++) { | |||
| if (output_ports[i]->Stop() < 0) { | |||
| jack_error("JackWinMMEDriver::Start - Failed to disable output " | |||
| "port."); | |||
| } | |||
| } | |||
| stop_input_ports: | |||
| for (int i = 0; i < input_count; i++) { | |||
| if (input_ports[i]->Stop() < 0) { | |||
| jack_error("JackWinMMEDriver::Start - Failed to disable input " | |||
| "port."); | |||
| } | |||
| } | |||
| return -1; | |||
| } | |||
| int JackWinMMEDriver::Write() | |||
| int | |||
| JackWinMMEDriver::Stop() | |||
| { | |||
| for (int chan = 0; chan < fPlaybackChannels; chan++) { | |||
| int result = 0; | |||
| if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) { | |||
| jack_info("JackWinMMEDriver::Stop - disabling input ports."); | |||
| JackMidiBuffer* midi_buffer = GetOutputBuffer(chan); | |||
| // TODO : use timestamp | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| if (input_ports[i]->Stop() < 0) { | |||
| jack_error("JackWinMMEDriver::Stop - Failed to disable input " | |||
| "port."); | |||
| result = -1; | |||
| } | |||
| } | |||
| for (unsigned int j = 0; j < midi_buffer->event_count; j++) { | |||
| JackMidiEvent* ev = &midi_buffer->events[j]; | |||
| if (ev->size <= 3) { | |||
| jack_midi_data_t *d = ev->GetData(midi_buffer); | |||
| DWORD winev = 0; | |||
| if (ev->size > 0) winev |= d[0]; | |||
| if (ev->size > 1) winev |= (d[1] << 8); | |||
| if (ev->size > 2) winev |= (d[2] << 16); | |||
| MMRESULT res = midiOutShortMsg((HMIDIOUT)fMidiSource[chan].fHandle, winev); | |||
| if (res != MMSYSERR_NOERROR) | |||
| jack_error ("midiOutShortMsg error res %d", res); | |||
| } else { | |||
| jack_info("JackWinMMEDriver::Stop - disabling output ports."); | |||
| } | |||
| } | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| if (output_ports[i]->Stop() < 0) { | |||
| jack_error("JackWinMMEDriver::Stop - Failed to disable output " | |||
| "port."); | |||
| result = -1; | |||
| } | |||
| } | |||
| return 0; | |||
| return result; | |||
| } | |||
| } // end of namespace | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| { | |||
| @@ -1,5 +1,6 @@ | |||
| /* | |||
| Copyright (C) 2009 Grame | |||
| Copyright (C) 2011 Devin Anderson | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| @@ -21,67 +22,51 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #define __JackWinMMEDriver__ | |||
| #include "JackMidiDriver.h" | |||
| #include "JackTime.h" | |||
| #include "JackWinMMEInputPort.h" | |||
| #include "JackWinMMEOutputPort.h" | |||
| namespace Jack | |||
| { | |||
| namespace Jack { | |||
| /*! | |||
| \brief The WinMME driver. | |||
| */ | |||
| #define kBuffSize 512 | |||
| struct MidiSlot { | |||
| LPVOID fHandle; // MMSystem handler | |||
| short fIndex; // MMSystem dev index | |||
| LPMIDIHDR fHeader; // for long msg output | |||
| MidiSlot():fHandle(0),fIndex(0) | |||
| {} | |||
| class JackWinMMEDriver : public JackMidiDriver { | |||
| }; | |||
| private: | |||
| class JackWinMMEDriver : public JackMidiDriver | |||
| { | |||
| JackWinMMEInputPort **input_ports; | |||
| JackWinMMEOutputPort **output_ports; | |||
| private: | |||
| public: | |||
| int fRealCaptureChannels; | |||
| int fRealPlaybackChannels; | |||
| JackWinMMEDriver(const char* name, const char* alias, | |||
| JackLockedEngine* engine, JackSynchro* table); | |||
| MidiSlot* fMidiSource; | |||
| MidiSlot* fMidiDestination; | |||
| ~JackWinMMEDriver(); | |||
| void CloseInput(MidiSlot* slot); | |||
| void CloseOutput(MidiSlot* slot); | |||
| int | |||
| Attach(); | |||
| static void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2); | |||
| int | |||
| Close(); | |||
| public: | |||
| int | |||
| Open(bool capturing, bool playing, int num_inputs, int num_outputs, | |||
| bool monitor, const char* capture_driver_name, | |||
| const char* playback_driver_name, jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); | |||
| virtual ~JackWinMMEDriver(); | |||
| int | |||
| Read(); | |||
| int Open(bool capturing, | |||
| bool playing, | |||
| int chan_in, | |||
| int chan_out, | |||
| bool monitor, | |||
| const char* capture_driver_name, | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| int Close(); | |||
| int | |||
| Start(); | |||
| int Attach(); | |||
| int | |||
| Stop(); | |||
| int Read(); | |||
| int Write(); | |||
| int | |||
| Write(); | |||
| }; | |||
| }; | |||
| } // end of namespace | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,294 @@ | |||
| /* | |||
| Copyright (C) 2011 Devin Anderson | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #include <cassert> | |||
| #include <memory> | |||
| #include <stdexcept> | |||
| #include "JackError.h" | |||
| #include "JackMidiUtil.h" | |||
| #include "JackWinMMEInputPort.h" | |||
| #include "JackMidiWriteQueue.h" | |||
| using Jack::JackWinMMEInputPort; | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| // Static callbacks | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| void CALLBACK | |||
| JackWinMMEInputPort::HandleMidiInputEvent(HMIDIIN handle, UINT message, | |||
| DWORD port, DWORD param1, | |||
| DWORD param2) | |||
| { | |||
| ((JackWinMMEInputPort *) port)->ProcessWinMME(message, param1, param2); | |||
| } | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| // Class | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| JackWinMMEInputPort::JackWinMMEInputPort(const char *alias_name, | |||
| const char *client_name, | |||
| const char *driver_name, UINT index, | |||
| size_t max_bytes, size_t max_messages) | |||
| { | |||
| thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages); | |||
| std::auto_ptr<JackMidiAsyncQueue> thread_queue_ptr(thread_queue); | |||
| write_queue = new JackMidiBufferWriteQueue(); | |||
| std::auto_ptr<JackMidiBufferWriteQueue> write_queue_ptr(write_queue); | |||
| sysex_buffer = new jack_midi_data_t[max_bytes]; | |||
| char error_message[MAXERRORLENGTH]; | |||
| MMRESULT result = midiInOpen(&handle, index, (DWORD)HandleMidiInputEvent, | |||
| (DWORD)this, | |||
| CALLBACK_FUNCTION | MIDI_IO_STATUS); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| GetInErrorString(result, error_message); | |||
| goto delete_sysex_buffer; | |||
| } | |||
| sysex_header.dwBufferLength = max_bytes; | |||
| sysex_header.dwBytesRecorded = 0; | |||
| sysex_header.dwFlags = 0; | |||
| sysex_header.dwUser = 0; | |||
| sysex_header.lpData = (LPSTR)(((LPBYTE) &sysex_header) + sizeof(MIDIHDR)); | |||
| sysex_header.lpNext = 0; | |||
| result = midiInPrepareHeader(handle, &sysex_header, sizeof(MIDIHDR)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| GetInErrorString(result, error_message); | |||
| goto close_handle; | |||
| } | |||
| result = midiInAddBuffer(handle, &sysex_header, sizeof(MIDIHDR)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| GetInErrorString(result, error_message); | |||
| goto unprepare_header; | |||
| } | |||
| MIDIINCAPS capabilities; | |||
| char *name_tmp; | |||
| result = midiInGetDevCaps(index, &capabilities, sizeof(capabilities)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteInError("JackWinMMEInputPort [constructor]", "midiInGetDevCaps", | |||
| result); | |||
| name_tmp = (char*) driver_name; | |||
| } else { | |||
| name_tmp = capabilities.szPname; | |||
| } | |||
| snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", alias_name, name_tmp, | |||
| index + 1); | |||
| snprintf(name, sizeof(name) - 1, "%s:capture_%d", client_name, index + 1); | |||
| jack_event = 0; | |||
| started = false; | |||
| write_queue_ptr.release(); | |||
| thread_queue_ptr.release(); | |||
| return; | |||
| unprepare_header: | |||
| result = midiInUnprepareHeader(handle, &sysex_header, sizeof(MIDIHDR)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteInError("JackWinMMEInputPort [constructor]", | |||
| "midiInUnprepareHeader", result); | |||
| } | |||
| close_handle: | |||
| result = midiInClose(handle); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteInError("JackWinMMEInputPort [constructor]", "midiInClose", result); | |||
| } | |||
| delete_sysex_buffer: | |||
| delete[] sysex_buffer; | |||
| throw std::runtime_error(error_message); | |||
| } | |||
| JackWinMMEInputPort::~JackWinMMEInputPort() | |||
| { | |||
| Stop(); | |||
| MMRESULT result = midiInReset(handle); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteInError("JackWinMMEInputPort [destructor]", "midiInReset", result); | |||
| } | |||
| result = midiInUnprepareHeader(handle, &sysex_header, sizeof(MIDIHDR)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteInError("JackWinMMEInputPort [destructor]", "midiInUnprepareHeader", | |||
| result); | |||
| } | |||
| result = midiInClose(handle); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteInError("JackWinMMEInputPort [destructor]", "midiInClose", result); | |||
| } | |||
| delete[] sysex_buffer; | |||
| delete thread_queue; | |||
| delete write_queue; | |||
| } | |||
| void | |||
| JackWinMMEInputPort::EnqueueMessage(jack_nframes_t time, size_t length, | |||
| jack_midi_data_t *data) | |||
| { | |||
| switch (thread_queue->EnqueueEvent(time, length, data)) { | |||
| case JackMidiWriteQueue::BUFFER_FULL: | |||
| jack_error("JackWinMMEInputPort::EnqueueMessage - The thread queue " | |||
| "cannot currently accept a %d-byte event. Dropping event.", | |||
| length); | |||
| break; | |||
| case JackMidiWriteQueue::BUFFER_TOO_SMALL: | |||
| jack_error("JackWinMMEInputPort::EnqueueMessage - The thread queue " | |||
| "buffer is too small to enqueue a %d-byte event. Dropping " | |||
| "event.", length); | |||
| break; | |||
| default: | |||
| ; | |||
| } | |||
| } | |||
| void | |||
| JackWinMMEInputPort::ProcessJack(JackMidiBuffer *port_buffer, | |||
| jack_nframes_t frames) | |||
| { | |||
| write_queue->ResetMidiBuffer(port_buffer, frames); | |||
| if (! jack_event) { | |||
| jack_event = thread_queue->DequeueEvent(); | |||
| } | |||
| for (; jack_event; jack_event = thread_queue->DequeueEvent()) { | |||
| switch (write_queue->EnqueueEvent(jack_event)) { | |||
| case JackMidiWriteQueue::BUFFER_TOO_SMALL: | |||
| jack_error("JackWinMMEMidiInputPort::Process - The buffer write " | |||
| "queue couldn't enqueue a %d-byte event. Dropping " | |||
| "event.", jack_event->size); | |||
| // Fallthrough on purpose | |||
| case JackMidiWriteQueue::OK: | |||
| continue; | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| void | |||
| JackWinMMEInputPort::ProcessWinMME(UINT message, DWORD param1, DWORD param2) | |||
| { | |||
| set_threaded_log_function(); | |||
| jack_nframes_t current_frame = GetCurrentFrame(); | |||
| switch (message) { | |||
| case MIM_CLOSE: | |||
| jack_info("JackWinMMEInputPort::ProcessWinMME - MIDI device closed."); | |||
| break; | |||
| case MIM_MOREDATA: | |||
| jack_info("JackWinMMEInputPort::ProcessWinMME - The MIDI input device " | |||
| "driver thinks that JACK is not processing messages fast " | |||
| "enough."); | |||
| // Fallthrough on purpose. | |||
| case MIM_DATA: | |||
| jack_midi_data_t message_buffer[3]; | |||
| jack_midi_data_t status = param1 & 0xff; | |||
| int length = GetMessageLength(status); | |||
| switch (length) { | |||
| case 3: | |||
| message_buffer[2] = param1 & 0xff0000; | |||
| // Fallthrough on purpose. | |||
| case 2: | |||
| message_buffer[1] = param1 & 0xff00; | |||
| // Fallthrough on purpose. | |||
| case 1: | |||
| message_buffer[0] = status; | |||
| break; | |||
| case 0: | |||
| jack_error("JackWinMMEInputPort::ProcessWinMME - **BUG** MIDI " | |||
| "input driver sent an MIM_DATA message with a sysex " | |||
| "status byte."); | |||
| return; | |||
| case -1: | |||
| jack_error("JackWinMMEInputPort::ProcessWinMME - **BUG** MIDI " | |||
| "input driver sent an MIM_DATA message with an invalid " | |||
| "status byte."); | |||
| return; | |||
| } | |||
| EnqueueMessage(current_frame, (size_t) length, message_buffer); | |||
| break; | |||
| case MIM_LONGDATA: | |||
| LPMIDIHDR header = (LPMIDIHDR) param1; | |||
| jack_midi_data_t *data = (jack_midi_data_t *) header->lpData; | |||
| size_t length1 = header->dwBytesRecorded; | |||
| if ((data[0] != 0xf0) || (data[length1 - 1] != 0xf7)) { | |||
| jack_error("JackWinMMEInputPort::ProcessWinMME - Discarding " | |||
| "%d-byte sysex chunk.", length); | |||
| } else { | |||
| EnqueueMessage(current_frame, length1, data); | |||
| } | |||
| // Is this realtime-safe? This function isn't run in the JACK thread, | |||
| // but we still want it to perform as quickly as possible. Even if | |||
| // this isn't realtime safe, it may not be avoidable. | |||
| MMRESULT result = midiInAddBuffer(handle, &sysex_header, | |||
| sizeof(MIDIHDR)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteInError("JackWinMMEInputPort::ProcessWinMME", "midiInAddBuffer", | |||
| result); | |||
| } | |||
| break; | |||
| case MIM_LONGERROR: | |||
| jack_error("JackWinMMEInputPort::ProcessWinMME - Invalid or " | |||
| "incomplete sysex message received."); | |||
| break; | |||
| case MIM_OPEN: | |||
| jack_info("JackWinMMEInputPort::ProcessWinMME - MIDI device opened."); | |||
| } | |||
| } | |||
| bool | |||
| JackWinMMEInputPort::Start() | |||
| { | |||
| if (! started) { | |||
| MMRESULT result = midiInStart(handle); | |||
| started = result == MMSYSERR_NOERROR; | |||
| if (! started) { | |||
| WriteInError("JackWinMMEInputPort::Start", "midiInStart", result); | |||
| } | |||
| } | |||
| return started; | |||
| } | |||
| bool | |||
| JackWinMMEInputPort::Stop() | |||
| { | |||
| if (started) { | |||
| MMRESULT result = midiInStop(handle); | |||
| started = result != MMSYSERR_NOERROR; | |||
| if (started) { | |||
| WriteInError("JackWinMMEInputPort::Stop", "midiInStop", result); | |||
| } | |||
| } | |||
| return ! started; | |||
| } | |||
| void | |||
| JackWinMMEInputPort::GetInErrorString(MMRESULT error, LPTSTR text) | |||
| { | |||
| MMRESULT result = midiInGetErrorText(error, text, MAXERRORLENGTH); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| snprintf(text, MAXERRORLENGTH, "Unknown error code '%d'", error); | |||
| } | |||
| } | |||
| void | |||
| JackWinMMEInputPort::WriteInError(const char *jack_func, const char *mm_func, | |||
| MMRESULT result) | |||
| { | |||
| char error_message[MAXERRORLENGTH]; | |||
| GetInErrorString(result, error_message); | |||
| jack_error("%s - %s: %s", jack_func, mm_func, error_message); | |||
| } | |||
| @@ -0,0 +1,85 @@ | |||
| /* | |||
| Copyright (C) 2011 Devin Anderson | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #ifndef __JackWinMMEInputPort__ | |||
| #define __JackWinMMEInputPort__ | |||
| #include <mmsystem.h> | |||
| #include "JackMidiAsyncQueue.h" | |||
| #include "JackMidiBufferWriteQueue.h" | |||
| #include "JackWinMMEPort.h" | |||
| namespace Jack { | |||
| class JackWinMMEInputPort : public JackWinMMEPort { | |||
| private: | |||
| static void CALLBACK | |||
| HandleMidiInputEvent(HMIDIIN handle, UINT message, DWORD port, | |||
| DWORD param1, DWORD param2); | |||
| void | |||
| EnqueueMessage(jack_nframes_t time, size_t length, | |||
| jack_midi_data_t *data); | |||
| void | |||
| ProcessWinMME(UINT message, DWORD param1, DWORD param2); | |||
| HMIDIIN handle; | |||
| jack_midi_event_t *jack_event; | |||
| jack_midi_data_t *sysex_buffer; | |||
| MIDIHDR sysex_header; | |||
| JackMidiAsyncQueue *thread_queue; | |||
| JackMidiBufferWriteQueue *write_queue; | |||
| bool started; | |||
| void | |||
| WriteInError(const char *jack_func, const char *mm_func, | |||
| MMRESULT result); | |||
| void | |||
| GetInErrorString(MMRESULT error, LPTSTR text); | |||
| public: | |||
| JackWinMMEInputPort(const char *alias_name, const char *client_name, | |||
| const char *driver_name, UINT index, | |||
| size_t max_bytes=4096, size_t max_messages=1024); | |||
| ~JackWinMMEInputPort(); | |||
| void | |||
| ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames); | |||
| bool | |||
| Start(); | |||
| bool | |||
| Stop(); | |||
| }; | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,374 @@ | |||
| /* | |||
| Copyright (C) 2011 Devin Anderson | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #include <memory> | |||
| #include <stdexcept> | |||
| #include "JackMidiUtil.h" | |||
| #include "JackTime.h" | |||
| #include "JackWinMMEOutputPort.h" | |||
| using Jack::JackWinMMEOutputPort; | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| // Static callbacks | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| void CALLBACK | |||
| JackWinMMEOutputPort::HandleMessageEvent(HMIDIOUT handle, UINT message, | |||
| DWORD_PTR port, DWORD_PTR param1, | |||
| DWORD_PTR param2) | |||
| { | |||
| ((JackWinMMEOutputPort *) port)->HandleMessage(message, param1, param2); | |||
| } | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| // Class | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| JackWinMMEOutputPort::JackWinMMEOutputPort(const char *alias_name, | |||
| const char *client_name, | |||
| const char *driver_name, UINT index, | |||
| size_t max_bytes, | |||
| size_t max_messages) | |||
| { | |||
| read_queue = new JackMidiBufferReadQueue(); | |||
| std::auto_ptr<JackMidiBufferReadQueue> read_queue_ptr(read_queue); | |||
| thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages); | |||
| std::auto_ptr<JackMidiAsyncQueue> thread_queue_ptr(thread_queue); | |||
| thread = new JackThread(this); | |||
| std::auto_ptr<JackThread> thread_ptr(thread); | |||
| char error_message[MAXERRORLENGTH]; | |||
| MMRESULT result = midiOutOpen(&handle, index, (DWORD)HandleMessageEvent, | |||
| (DWORD)this, CALLBACK_FUNCTION); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| GetOutErrorString(result, error_message); | |||
| goto raise_exception; | |||
| } | |||
| thread_queue_semaphore = CreateSemaphore(NULL, 0, max_messages, NULL); | |||
| if (thread_queue_semaphore == NULL) { | |||
| GetOSErrorString(error_message); | |||
| goto close_handle; | |||
| } | |||
| sysex_semaphore = CreateSemaphore(NULL, 0, 1, NULL); | |||
| if (sysex_semaphore == NULL) { | |||
| GetOSErrorString(error_message); | |||
| goto destroy_thread_queue_semaphore; | |||
| } | |||
| MIDIOUTCAPS capabilities; | |||
| char *name_tmp; | |||
| result = midiOutGetDevCaps(index, &capabilities, sizeof(capabilities)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteOutError("JackWinMMEOutputPort [constructor]", "midiOutGetDevCaps", | |||
| result); | |||
| name_tmp = (char*)driver_name; | |||
| } else { | |||
| name_tmp = capabilities.szPname; | |||
| } | |||
| snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", alias_name, name_tmp, | |||
| index + 1); | |||
| snprintf(name, sizeof(name) - 1, "%s:playback_%d", client_name, index + 1); | |||
| thread_ptr.release(); | |||
| thread_queue_ptr.release(); | |||
| return; | |||
| destroy_thread_queue_semaphore: | |||
| if (! CloseHandle(thread_queue_semaphore)) { | |||
| WriteOSError("JackWinMMEOutputPort [constructor]", "CloseHandle"); | |||
| } | |||
| close_handle: | |||
| result = midiOutClose(handle); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteOutError("JackWinMMEOutputPort [constructor]", "midiOutClose", | |||
| result); | |||
| } | |||
| raise_exception: | |||
| throw std::runtime_error(error_message); | |||
| } | |||
| JackWinMMEOutputPort::~JackWinMMEOutputPort() | |||
| { | |||
| Stop(); | |||
| MMRESULT result = midiOutReset(handle); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteOutError("JackWinMMEOutputPort [destructor]", "midiOutReset", | |||
| result); | |||
| } | |||
| result = midiOutClose(handle); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteOutError("JackWinMMEOutputPort [destructor]", "midiOutClose", | |||
| result); | |||
| } | |||
| if (! CloseHandle(sysex_semaphore)) { | |||
| WriteOSError("JackWinMMEOutputPort [destructor]", "CloseHandle"); | |||
| } | |||
| if (! CloseHandle(thread_queue_semaphore)) { | |||
| WriteOSError("JackWinMMEOutputPort [destructor]", "CloseHandle"); | |||
| } | |||
| delete read_queue; | |||
| delete thread_queue; | |||
| } | |||
| bool | |||
| JackWinMMEOutputPort::Execute() | |||
| { | |||
| for (;;) { | |||
| jack_log("JackWinMMEOutputPort::Execute TOTO"); | |||
| JackSleep(100000); | |||
| if (! Wait(thread_queue_semaphore)) { | |||
| jack_log("JackWinMMEOutputPort::Execute BREAK"); | |||
| break; | |||
| } | |||
| /* | |||
| jack_midi_event_t *event = thread_queue->DequeueEvent(); | |||
| if (! event) { | |||
| break; | |||
| } | |||
| jack_time_t frame_time = GetTimeFromFrames(event->time); | |||
| for (jack_time_t current_time = GetMicroSeconds(); | |||
| frame_time > current_time; current_time = GetMicroSeconds()) { | |||
| jack_time_t sleep_time = frame_time - current_time; | |||
| // Windows has a millisecond sleep resolution for its Sleep calls. | |||
| // This is unfortunate, as MIDI timing often requires a higher | |||
| // resolution. For now, we attempt to compensate by letting an | |||
| // event be sent if we're less than 500 microseconds from sending | |||
| // the event. We assume that it's better to let an event go out | |||
| // 499 microseconds early than let an event go out 501 microseconds | |||
| // late. Of course, that's assuming optimal sleep times, which is | |||
| // a whole different Windows issue ... | |||
| if (sleep_time < 500) { | |||
| break; | |||
| } | |||
| if (sleep_time < 1000) { | |||
| sleep_time = 1000; | |||
| } | |||
| JackSleep(sleep_time); | |||
| } | |||
| jack_midi_data_t *data = event->buffer; | |||
| DWORD message = 0; | |||
| MMRESULT result; | |||
| size_t size = event->size; | |||
| switch (size) { | |||
| case 3: | |||
| message |= (((DWORD) data[2]) << 16); | |||
| // Fallthrough on purpose. | |||
| case 2: | |||
| message |= (((DWORD) data[1]) << 8); | |||
| // Fallthrough on purpose. | |||
| case 1: | |||
| message |= (DWORD) data[0]; | |||
| result = midiOutShortMsg(handle, message); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteOutError("JackWinMMEOutputPort::Execute", | |||
| "midiOutShortMsg", result); | |||
| } | |||
| continue; | |||
| } | |||
| MIDIHDR header; | |||
| header.dwBufferLength = size; | |||
| header.dwBytesRecorded = size; | |||
| header.dwFlags = 0; | |||
| header.dwOffset = 0; | |||
| header.dwUser = 0; | |||
| header.lpData = (LPSTR)data; | |||
| result = midiOutPrepareHeader(handle, &header, sizeof(MIDIHDR)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteOutError("JackWinMMEOutputPort::Execute", | |||
| "midiOutPrepareHeader", result); | |||
| continue; | |||
| } | |||
| result = midiOutLongMsg(handle, &header, sizeof(MIDIHDR)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteOutError("JackWinMMEOutputPort::Execute", "midiOutLongMsg", | |||
| result); | |||
| continue; | |||
| } | |||
| // System exclusive messages may be sent synchronously or | |||
| // asynchronously. The choice is up to the WinMME driver. So, we wait | |||
| // until the message is sent, regardless of the driver's choice. | |||
| if (! Wait(sysex_semaphore)) { | |||
| break; | |||
| } | |||
| result = midiOutUnprepareHeader(handle, &header, sizeof(MIDIHDR)); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| WriteOutError("JackWinMMEOutputPort::Execute", | |||
| "midiOutUnprepareHeader", result); | |||
| break; | |||
| } | |||
| */ | |||
| } | |||
| stop_execution: | |||
| return false; | |||
| } | |||
| void | |||
| JackWinMMEOutputPort::HandleMessage(UINT message, DWORD_PTR param1, | |||
| DWORD_PTR param2) | |||
| { | |||
| set_threaded_log_function(); | |||
| switch (message) { | |||
| case MOM_CLOSE: | |||
| jack_info("JackWinMMEOutputPort::HandleMessage - MIDI device closed."); | |||
| break; | |||
| case MOM_DONE: | |||
| Signal(sysex_semaphore); | |||
| break; | |||
| case MOM_OPEN: | |||
| jack_info("JackWinMMEOutputPort::HandleMessage - MIDI device opened."); | |||
| break; | |||
| case MOM_POSITIONCB: | |||
| LPMIDIHDR header = (LPMIDIHDR) param2; | |||
| jack_info("JackWinMMEOutputPort::HandleMessage - %d bytes out of %d " | |||
| "bytes of the current sysex message have been sent.", | |||
| header->dwOffset, header->dwBytesRecorded); | |||
| } | |||
| } | |||
| bool | |||
| JackWinMMEOutputPort::Init() | |||
| { | |||
| set_threaded_log_function(); | |||
| // XX: Can more be done? Ideally, this thread should have the JACK server | |||
| // thread priority + 1. | |||
| if (thread->AcquireSelfRealTime()) { | |||
| jack_error("JackWinMMEOutputPort::Init - could not acquire realtime " | |||
| "scheduling. Continuing anyway."); | |||
| } | |||
| return true; | |||
| } | |||
| void | |||
| JackWinMMEOutputPort::ProcessJack(JackMidiBuffer *port_buffer, | |||
| jack_nframes_t frames) | |||
| { | |||
| read_queue->ResetMidiBuffer(port_buffer); | |||
| for (jack_midi_event_t *event = read_queue->DequeueEvent(); event; | |||
| event = read_queue->DequeueEvent()) { | |||
| switch (thread_queue->EnqueueEvent(event, frames)) { | |||
| case JackMidiWriteQueue::BUFFER_FULL: | |||
| jack_error("JackWinMMEOutputPort::ProcessJack - The thread queue " | |||
| "buffer is full. Dropping event."); | |||
| break; | |||
| case JackMidiWriteQueue::BUFFER_TOO_SMALL: | |||
| jack_error("JackWinMMEOutputPort::ProcessJack - The thread queue " | |||
| "couldn't enqueue a %d-byte event. Dropping event.", | |||
| event->size); | |||
| break; | |||
| default: | |||
| Signal(thread_queue_semaphore); | |||
| } | |||
| } | |||
| } | |||
| bool | |||
| JackWinMMEOutputPort::Signal(HANDLE semaphore) | |||
| { | |||
| bool result = (bool) ReleaseSemaphore(semaphore, 1, NULL); | |||
| if (! result) { | |||
| WriteOSError("JackWinMMEOutputPort::Signal", "ReleaseSemaphore"); | |||
| } | |||
| return result; | |||
| } | |||
| bool | |||
| JackWinMMEOutputPort::Start() | |||
| { | |||
| bool result = thread->GetStatus() != JackThread::kIdle; | |||
| if (! result) { | |||
| result = ! thread->StartSync(); | |||
| if (! result) { | |||
| jack_error("JackWinMMEOutputPort::Start - failed to start MIDI " | |||
| "processing thread."); | |||
| } | |||
| } | |||
| return result; | |||
| } | |||
| bool | |||
| JackWinMMEOutputPort::Stop() | |||
| { | |||
| jack_info("JackWinMMEOutputPort::Stop - stopping MIDI output port " | |||
| "processing thread."); | |||
| int result; | |||
| const char *verb; | |||
| switch (thread->GetStatus()) { | |||
| case JackThread::kIniting: | |||
| case JackThread::kStarting: | |||
| result = thread->Kill(); | |||
| verb = "kill"; | |||
| break; | |||
| case JackThread::kRunning: | |||
| Signal(thread_queue_semaphore); | |||
| result = thread->Stop(); | |||
| verb = "stop"; | |||
| break; | |||
| default: | |||
| return true; | |||
| } | |||
| if (result) { | |||
| jack_error("JackWinMMEOutputPort::Stop - could not %s MIDI processing " | |||
| "thread.", verb); | |||
| } | |||
| return ! result; | |||
| } | |||
| bool | |||
| JackWinMMEOutputPort::Wait(HANDLE semaphore) | |||
| { | |||
| jack_log("JackWinMMEOutputPort::Wait %d", semaphore); | |||
| DWORD result = WaitForSingleObject(semaphore, INFINITE); | |||
| switch (result) { | |||
| case WAIT_FAILED: | |||
| WriteOSError("JackWinMMEOutputPort::Wait", "WaitForSingleObject"); | |||
| break; | |||
| case WAIT_OBJECT_0: | |||
| return true; | |||
| default: | |||
| jack_error("JackWinMMEOutputPort::Wait - unexpected result from " | |||
| "'WaitForSingleObject'."); | |||
| } | |||
| return false; | |||
| } | |||
| void | |||
| JackWinMMEOutputPort::GetOutErrorString(MMRESULT error, LPTSTR text) | |||
| { | |||
| MMRESULT result = midiOutGetErrorText(error, text, MAXERRORLENGTH); | |||
| if (result != MMSYSERR_NOERROR) { | |||
| snprintf(text, MAXERRORLENGTH, "Unknown MM error code '%d'", error); | |||
| } | |||
| } | |||
| void | |||
| JackWinMMEOutputPort::WriteOutError(const char *jack_func, const char *mm_func, | |||
| MMRESULT result) | |||
| { | |||
| char error_message[MAXERRORLENGTH]; | |||
| GetOutErrorString(result, error_message); | |||
| jack_error("%s - %s: %s", jack_func, mm_func, error_message); | |||
| } | |||
| @@ -0,0 +1,89 @@ | |||
| /* | |||
| Copyright (C) 2011 Devin Anderson | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #ifndef __JackWinMMEOutputPort__ | |||
| #define __JackWinMMEOutputPort__ | |||
| #include "JackMidiAsyncQueue.h" | |||
| #include "JackMidiBufferReadQueue.h" | |||
| #include "JackThread.h" | |||
| #include "JackWinMMEPort.h" | |||
| namespace Jack { | |||
| class JackWinMMEOutputPort : | |||
| public JackWinMMEPort, public JackRunnableInterface { | |||
| private: | |||
| static void CALLBACK | |||
| HandleMessageEvent(HMIDIOUT handle, UINT message, DWORD_PTR port, | |||
| DWORD_PTR param1, DWORD_PTR param2); | |||
| void | |||
| HandleMessage(UINT message, DWORD_PTR param1, DWORD_PTR param2); | |||
| bool | |||
| Signal(HANDLE semaphore); | |||
| bool | |||
| Wait(HANDLE semaphore); | |||
| HMIDIOUT handle; | |||
| JackMidiBufferReadQueue *read_queue; | |||
| HANDLE sysex_semaphore; | |||
| JackThread *thread; | |||
| JackMidiAsyncQueue *thread_queue; | |||
| HANDLE thread_queue_semaphore; | |||
| void | |||
| GetOutErrorString(MMRESULT error, LPTSTR text); | |||
| void | |||
| WriteOutError(const char *jack_func, const char *mm_func, | |||
| MMRESULT result); | |||
| public: | |||
| JackWinMMEOutputPort(const char *alias_name, const char *client_name, | |||
| const char *driver_name, UINT index, | |||
| size_t max_bytes=4096, size_t max_messages=1024); | |||
| ~JackWinMMEOutputPort(); | |||
| bool | |||
| Execute(); | |||
| bool | |||
| Init(); | |||
| void | |||
| ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames); | |||
| bool | |||
| Start(); | |||
| bool | |||
| Stop(); | |||
| }; | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,68 @@ | |||
| /* | |||
| Copyright (C) 2011 Devin Anderson | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #include <memory> | |||
| #include <stdexcept> | |||
| #include "JackWinMMEPort.h" | |||
| #include "JackError.h" | |||
| using Jack::JackWinMMEPort; | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| // Class | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| JackWinMMEPort::JackWinMMEPort() | |||
| {} | |||
| JackWinMMEPort::~JackWinMMEPort() | |||
| {} | |||
| const char * | |||
| JackWinMMEPort::GetAlias() | |||
| { | |||
| return alias; | |||
| } | |||
| const char * | |||
| JackWinMMEPort::GetName() | |||
| { | |||
| return name; | |||
| } | |||
| void | |||
| JackWinMMEPort::GetOSErrorString(LPTSTR text) | |||
| { | |||
| DWORD error = GetLastError(); | |||
| if (! FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, | |||
| MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), text, | |||
| MAXERRORLENGTH, NULL)) { | |||
| snprintf(text, MAXERRORLENGTH, "Unknown OS error code '%d'", error); | |||
| } | |||
| } | |||
| void | |||
| JackWinMMEPort::WriteOSError(const char *jack_func, const char *os_func) | |||
| { | |||
| char error_message[MAXERRORLENGTH]; | |||
| GetOSErrorString(error_message); | |||
| jack_error("%s - %s: %s", jack_func, os_func, error_message); | |||
| } | |||
| @@ -0,0 +1,59 @@ | |||
| /* | |||
| Copyright (C) 2011 Devin Anderson | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation; either version 2 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #ifndef __JackWinMMEPort__ | |||
| #define __JackWinMMEPort__ | |||
| #include <windows.h> | |||
| #include <mmsystem.h> | |||
| #include "JackConstants.h" | |||
| namespace Jack { | |||
| class JackWinMMEPort { | |||
| protected: | |||
| char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
| char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; | |||
| public: | |||
| JackWinMMEPort(); | |||
| ~JackWinMMEPort(); | |||
| const char * | |||
| GetAlias(); | |||
| const char * | |||
| GetName(); | |||
| void | |||
| GetOSErrorString(LPTSTR text); | |||
| void | |||
| WriteOSError(const char *jack_func, const char *os_func); | |||
| }; | |||
| } | |||
| #endif | |||