| @@ -37,7 +37,7 @@ namespace Jack { | |||||
| BUFFER_FULL, | BUFFER_FULL, | ||||
| BUFFER_TOO_SMALL, | BUFFER_TOO_SMALL, | ||||
| EVENT_EARLY, | EVENT_EARLY, | ||||
| ERROR, | |||||
| EN_ERROR, | |||||
| OK | OK | ||||
| }; | }; | ||||
| @@ -54,7 +54,7 @@ namespace Jack { | |||||
| * if the write queue isn't able to accept the event right now, | * 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 | * `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 | * 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. | * occurs that cannot be specified by another return code. | ||||
| */ | */ | ||||
| @@ -151,8 +151,16 @@ namespace Jack | |||||
| //allocate midi ports lists | //allocate midi ports lists | ||||
| fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels]; | fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels]; | ||||
| fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels]; | 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 | //register jack ports | ||||
| if ( AllocPorts() != 0 ) | if ( AllocPorts() != 0 ) | ||||
| @@ -362,20 +370,32 @@ namespace Jack | |||||
| { | { | ||||
| jack_log ( "JackNetDriver::FreePorts" ); | 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; | return 0; | ||||
| } | } | ||||
| @@ -14,7 +14,7 @@ extern "C" | |||||
| { | { | ||||
| #endif | #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 MAX_SHM_ID 256 /* generally about 16 per server */ | ||||
| #define JACK_SERVER_NAME_SIZE 256 /* maximum length of server name */ | #define JACK_SERVER_NAME_SIZE 256 /* maximum length of server name */ | ||||
| #define JACK_SHM_MAGIC 0x4a41434b /* shm magic number: "JACK" */ | #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: " | jack_error("JackALSARawMidiSendQueue::EnqueueEvent - snd_rawmidi_write: " | ||||
| "%s", snd_strerror(result)); | "%s", snd_strerror(result)); | ||||
| return ERROR; | |||||
| return EN_ERROR; | |||||
| } | } | ||||
| bool | bool | ||||
| @@ -108,42 +108,6 @@ | |||||
| /* Begin PBXBuildFile section */ | /* Begin PBXBuildFile section */ | ||||
| 4B0A28ED0D520852002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; }; | 4B0A28ED0D520852002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; }; | ||||
| 4B0A29260D52108E002EFF74 /* 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 */; }; | 4B193991133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; }; | ||||
| 4B193992133F321500547810 /* 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 */; }; | 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, ); }; }; | 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, ); }; }; | 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, ); }; }; | 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 */; }; | 4B9A25B50DBF8330006E9FBC /* JackError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9A25B30DBF8330006E9FBC /* JackError.cpp */; }; | ||||
| 4B9A25B60DBF8330006E9FBC /* 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, ); }; }; | 4B9A26010DBF8584006E9FBC /* jslist.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B9A26000DBF8584006E9FBC /* jslist.h */; settings = {ATTRIBUTES = (Public, ); }; }; | ||||
| @@ -3454,6 +3454,15 @@ | |||||
| 4B8A38C4117B814000664E07 /* JackSocketServerNotifyChannel.h in Headers */, | 4B8A38C4117B814000664E07 /* JackSocketServerNotifyChannel.h in Headers */, | ||||
| 4B5160AA13215ED900BB7DCB /* systemdeps.h in Headers */, | 4B5160AA13215ED900BB7DCB /* systemdeps.h in Headers */, | ||||
| 4B193995133F321500547810 /* JackFilters.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; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -3917,6 +3926,15 @@ | |||||
| 4B2209E712F6BC0300E5DC26 /* JackSocket.h in Headers */, | 4B2209E712F6BC0300E5DC26 /* JackSocket.h in Headers */, | ||||
| 4B2209EA12F6BC1600E5DC26 /* JackSocketNotifyChannel.h in Headers */, | 4B2209EA12F6BC1600E5DC26 /* JackSocketNotifyChannel.h in Headers */, | ||||
| 4B193992133F321500547810 /* JackFilters.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; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -4152,15 +4170,6 @@ | |||||
| 4B370A3F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */, | 4B370A3F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */, | ||||
| 4B370A41133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */, | 4B370A41133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */, | ||||
| 4B370A43133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.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; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -4229,15 +4238,6 @@ | |||||
| 4B370A2F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */, | 4B370A2F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */, | ||||
| 4B370A31133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */, | 4B370A31133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */, | ||||
| 4B370A33133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.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; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -6885,6 +6885,15 @@ | |||||
| 4B8A38AE117B811100664E07 /* JackSocketNotifyChannel.cpp in Sources */, | 4B8A38AE117B811100664E07 /* JackSocketNotifyChannel.cpp in Sources */, | ||||
| 4B8A38B1117B812D00664E07 /* JackSocketServerChannel.cpp in Sources */, | 4B8A38B1117B812D00664E07 /* JackSocketServerChannel.cpp in Sources */, | ||||
| 4B8A38B2117B813400664E07 /* JackSocketServerNotifyChannel.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; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -7337,6 +7346,15 @@ | |||||
| 4B2209E312F6BBF500E5DC26 /* JackSocketServerNotifyChannel.cpp in Sources */, | 4B2209E312F6BBF500E5DC26 /* JackSocketServerNotifyChannel.cpp in Sources */, | ||||
| 4B2209E612F6BC0200E5DC26 /* JackSocket.cpp in Sources */, | 4B2209E612F6BC0200E5DC26 /* JackSocket.cpp in Sources */, | ||||
| 4B2209E912F6BC1500E5DC26 /* JackSocketNotifyChannel.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; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -7575,15 +7593,6 @@ | |||||
| 4B370A3E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */, | 4B370A3E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */, | ||||
| 4B370A40133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */, | 4B370A40133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */, | ||||
| 4B370A42133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.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; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -7657,15 +7666,6 @@ | |||||
| 4B370A2E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */, | 4B370A2E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */, | ||||
| 4B370A30133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */, | 4B370A30133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */, | ||||
| 4B370A32133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.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; | runOnlyForDeploymentPostprocessing = 0; | ||||
| }; | }; | ||||
| @@ -972,14 +972,14 @@ int main (int argc, char *argv[]) | |||||
| float factor = 0.5f; | float factor = 0.5f; | ||||
| old_buffer_size = jack_get_buffer_size(client1); | 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; | linebuf = linecount; | ||||
| if (jack_set_buffer_size(client1, (jack_nframes_t)(old_buffer_size * factor)) < 0) { | if (jack_set_buffer_size(client1, (jack_nframes_t)(old_buffer_size * factor)) < 0) { | ||||
| printf("!!! ERROR !!! jack_set_buffer_size fails !\n"); | printf("!!! ERROR !!! jack_set_buffer_size fails !\n"); | ||||
| } | } | ||||
| jack_sleep(1 * 1000); | jack_sleep(1 * 1000); | ||||
| cur_buffer_size = jack_get_buffer_size(client1); | 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("!!! ERROR !!! Buffer size has not been changed !\n"); | ||||
| printf("!!! Maybe jack was compiled without the '--enable-resize' flag...\n"); | printf("!!! Maybe jack was compiled without the '--enable-resize' flag...\n"); | ||||
| } else { | } else { | ||||
| @@ -106,6 +106,12 @@ | |||||
| <Option compilerVar="WINDRES" /> | <Option compilerVar="WINDRES" /> | ||||
| </Unit> | </Unit> | ||||
| <Unit filename="winmme\JackWinMMEDriver.cpp" /> | <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> | <Extensions> | ||||
| <code_completion /> | <code_completion /> | ||||
| <envvars /> | <envvars /> | ||||
| @@ -56,7 +56,7 @@ | |||||
| <Project filename="multiple_metro.cbp"> | <Project filename="multiple_metro.cbp"> | ||||
| <Depends filename="libjack.cbp" /> | <Depends filename="libjack.cbp" /> | ||||
| </Project> | </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> | </Workspace> | ||||
| </CodeBlocks_workspace_file> | </CodeBlocks_workspace_file> | ||||
| @@ -150,12 +150,16 @@ | |||||
| <Unit filename="..\common\JackLoopbackDriver.cpp" /> | <Unit filename="..\common\JackLoopbackDriver.cpp" /> | ||||
| <Unit filename="..\common\JackMessageBuffer.cpp" /> | <Unit filename="..\common\JackMessageBuffer.cpp" /> | ||||
| <Unit filename="..\common\JackMidiAPI.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\JackMidiDriver.cpp" /> | ||||
| <Unit filename="..\common\JackMidiPort.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\JackNetInterface.cpp" /> | ||||
| <Unit filename="..\common\JackNetTool.cpp" /> | <Unit filename="..\common\JackNetTool.cpp" /> | ||||
| <Unit filename="..\common\JackPhysicalMidiInput.cpp" /> | |||||
| <Unit filename="..\common\JackPhysicalMidiOutput.cpp" /> | |||||
| <Unit filename="..\common\JackPort.cpp" /> | <Unit filename="..\common\JackPort.cpp" /> | ||||
| <Unit filename="..\common\JackPortType.cpp" /> | <Unit filename="..\common\JackPortType.cpp" /> | ||||
| <Unit filename="..\common\JackRestartThreadedDriver.cpp" /> | <Unit filename="..\common\JackRestartThreadedDriver.cpp" /> | ||||
| @@ -248,7 +248,7 @@ error: | |||||
| } else { | } else { | ||||
| JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails | JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails | ||||
| // PortAudio specific | // PortAudio specific | ||||
| UpdateLatencies(); | |||||
| JackAudioDriver::UpdateLatencies(); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,6 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2009 Grame | Copyright (C) 2009 Grame | ||||
| Copyright (C) 2011 Devin Anderson | |||||
| This program is free software; you can redistribute it and/or modify | 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 | 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 "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; | 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; | 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; | 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 | #ifdef __cplusplus | ||||
| extern "C" | extern "C" | ||||
| { | { | ||||
| @@ -1,5 +1,6 @@ | |||||
| /* | /* | ||||
| Copyright (C) 2009 Grame | Copyright (C) 2009 Grame | ||||
| Copyright (C) 2011 Devin Anderson | |||||
| This program is free software; you can redistribute it and/or modify | 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 | 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__ | #define __JackWinMMEDriver__ | ||||
| #include "JackMidiDriver.h" | #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 | #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 | |||||