diff --git a/common/JackMidiWriteQueue.h b/common/JackMidiWriteQueue.h
index a39776c9..f21a58ff 100644
--- a/common/JackMidiWriteQueue.h
+++ b/common/JackMidiWriteQueue.h
@@ -37,7 +37,7 @@ namespace Jack {
BUFFER_FULL,
BUFFER_TOO_SMALL,
EVENT_EARLY,
- ERROR,
+ EN_ERROR,
OK
};
@@ -54,7 +54,7 @@ namespace Jack {
* if the write queue isn't able to accept the event right now,
* `BUFFER_TOO_SMALL` if this write queue will never be able to accept
* the event because the event is too large, `EVENT_EARLY` if this
- * queue cannot schedule events ahead of time, and `ERROR` if an error
+ * queue cannot schedule events ahead of time, and `EN_ERROR` if an error
* occurs that cannot be specified by another return code.
*/
diff --git a/common/JackNetDriver.cpp b/common/JackNetDriver.cpp
index d2327eb1..66e4f7dd 100644
--- a/common/JackNetDriver.cpp
+++ b/common/JackNetDriver.cpp
@@ -151,8 +151,16 @@ namespace Jack
//allocate midi ports lists
fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels];
fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels];
- assert ( fMidiCapturePortList );
- assert ( fMidiPlaybackPortList );
+
+ assert(fMidiCapturePortList);
+ assert(fMidiPlaybackPortList);
+
+ for (uint midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
+ fMidiCapturePortList[midi_port_index] = NULL;
+ }
+ for (uint midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
+ fMidiPlaybackPortList[midi_port_index] = NULL;
+ }
//register jack ports
if ( AllocPorts() != 0 )
@@ -362,20 +370,32 @@ namespace Jack
{
jack_log ( "JackNetDriver::FreePorts" );
- int audio_port_index;
- uint midi_port_index;
- for ( audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++ )
- if (fCapturePortList[audio_port_index] > 0)
- fGraphManager->ReleasePort ( fClientControl.fRefNum, fCapturePortList[audio_port_index] );
- for ( audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++ )
- if (fPlaybackPortList[audio_port_index] > 0)
- fGraphManager->ReleasePort ( fClientControl.fRefNum, fPlaybackPortList[audio_port_index] );
- for ( midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++ )
- if (fMidiCapturePortList[midi_port_index] > 0)
- fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiCapturePortList[midi_port_index] );
- for ( midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++ )
- if (fMidiPlaybackPortList[midi_port_index] > 0)
- fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index] );
+ for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
+ if (fCapturePortList[audio_port_index] > 0) {
+ fGraphManager->ReleasePort ( fClientControl.fRefNum, fCapturePortList[audio_port_index]);
+ }
+ }
+
+ for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
+ if (fPlaybackPortList[audio_port_index] > 0) {
+ fGraphManager->ReleasePort ( fClientControl.fRefNum, fPlaybackPortList[audio_port_index]);
+ }
+ }
+
+ for (uint midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
+ if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) {
+ fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]);
+ }
+ }
+
+ for (uint midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
+ if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) {
+ fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]);
+ }
+ }
+ // Clear MIDI channels
+ fParams.fSendMidiChannels = 0;
+ fParams.fReturnMidiChannels = 0;
return 0;
}
diff --git a/common/shm.h b/common/shm.h
index ed5a953f..f1edc8ed 100644
--- a/common/shm.h
+++ b/common/shm.h
@@ -14,7 +14,7 @@ extern "C"
{
#endif
-#define MAX_SERVERS 8 /* maximum concurrent servers */
+#define MAX_SERVERS 64 /* maximum concurrent servers */
#define MAX_SHM_ID 256 /* generally about 16 per server */
#define JACK_SERVER_NAME_SIZE 256 /* maximum length of server name */
#define JACK_SHM_MAGIC 0x4a41434b /* shm magic number: "JACK" */
diff --git a/linux/alsarawmidi/JackALSARawMidiSendQueue.cpp b/linux/alsarawmidi/JackALSARawMidiSendQueue.cpp
index 5f314263..80a11b56 100755
--- a/linux/alsarawmidi/JackALSARawMidiSendQueue.cpp
+++ b/linux/alsarawmidi/JackALSARawMidiSendQueue.cpp
@@ -30,7 +30,7 @@ JackALSARawMidiSendQueue::EnqueueEvent(jack_nframes_t time, size_t size,
}
jack_error("JackALSARawMidiSendQueue::EnqueueEvent - snd_rawmidi_write: "
"%s", snd_strerror(result));
- return ERROR;
+ return EN_ERROR;
}
bool
diff --git a/macosx/Jackdmp.xcodeproj/project.pbxproj b/macosx/Jackdmp.xcodeproj/project.pbxproj
index 195dd976..eb5eb758 100644
--- a/macosx/Jackdmp.xcodeproj/project.pbxproj
+++ b/macosx/Jackdmp.xcodeproj/project.pbxproj
@@ -108,42 +108,6 @@
/* Begin PBXBuildFile section */
4B0A28ED0D520852002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; };
4B0A29260D52108E002EFF74 /* tw.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A28EC0D520852002EFF74 /* tw.c */; };
- 4B193933133F311400547810 /* JackMidiAsyncQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */; };
- 4B193934133F311400547810 /* JackMidiAsyncQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193932133F311400547810 /* JackMidiAsyncQueue.h */; };
- 4B193935133F311400547810 /* JackMidiAsyncQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */; };
- 4B193936133F311400547810 /* JackMidiAsyncQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193932133F311400547810 /* JackMidiAsyncQueue.h */; };
- 4B19393D133F313000547810 /* JackMidiAsyncWaitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */; };
- 4B19393E133F313000547810 /* JackMidiAsyncWaitQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */; };
- 4B19393F133F313000547810 /* JackMidiAsyncWaitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */; };
- 4B193940133F313000547810 /* JackMidiAsyncWaitQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */; };
- 4B193947133F315300547810 /* JackMidiReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193945133F315200547810 /* JackMidiReadQueue.cpp */; };
- 4B193948133F315300547810 /* JackMidiReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193946133F315200547810 /* JackMidiReadQueue.h */; };
- 4B193949133F315300547810 /* JackMidiReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193945133F315200547810 /* JackMidiReadQueue.cpp */; };
- 4B19394A133F315300547810 /* JackMidiReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193946133F315200547810 /* JackMidiReadQueue.h */; };
- 4B19395F133F317300547810 /* JackMidiBufferReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */; };
- 4B193960133F317300547810 /* JackMidiBufferReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */; };
- 4B193961133F317300547810 /* JackMidiBufferReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */; };
- 4B193962133F317300547810 /* JackMidiBufferReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */; };
- 4B19396A133F319000547810 /* JackMidiBufferWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */; };
- 4B19396B133F319000547810 /* JackMidiBufferWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */; };
- 4B19396C133F319000547810 /* JackMidiBufferWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */; };
- 4B19396D133F319000547810 /* JackMidiBufferWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */; };
- 4B19397B133F31CB00547810 /* JackMidiReceiveQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */; };
- 4B19397C133F31CB00547810 /* JackMidiReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */; };
- 4B19397D133F31CB00547810 /* JackMidiSendQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */; };
- 4B19397E133F31CB00547810 /* JackMidiSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193976133F31CB00547810 /* JackMidiSendQueue.h */; };
- 4B19397F133F31CB00547810 /* JackMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193977133F31CB00547810 /* JackMidiUtil.cpp */; };
- 4B193980133F31CB00547810 /* JackMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193978133F31CB00547810 /* JackMidiUtil.h */; };
- 4B193981133F31CB00547810 /* JackMidiWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */; };
- 4B193982133F31CB00547810 /* JackMidiWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */; };
- 4B193983133F31CB00547810 /* JackMidiReceiveQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */; };
- 4B193984133F31CB00547810 /* JackMidiReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */; };
- 4B193985133F31CB00547810 /* JackMidiSendQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */; };
- 4B193986133F31CB00547810 /* JackMidiSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193976133F31CB00547810 /* JackMidiSendQueue.h */; };
- 4B193987133F31CB00547810 /* JackMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193977133F31CB00547810 /* JackMidiUtil.cpp */; };
- 4B193988133F31CB00547810 /* JackMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193978133F31CB00547810 /* JackMidiUtil.h */; };
- 4B193989133F31CB00547810 /* JackMidiWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */; };
- 4B19398A133F31CB00547810 /* JackMidiWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */; };
4B193991133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; };
4B193992133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; };
4B193993133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; };
@@ -671,6 +635,42 @@
4B94334A10A5E666002A187F /* systemdeps.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B94334910A5E666002A187F /* systemdeps.h */; settings = {ATTRIBUTES = (Public, ); }; };
4B94334B10A5E666002A187F /* systemdeps.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B94334910A5E666002A187F /* systemdeps.h */; settings = {ATTRIBUTES = (Public, ); }; };
4B95BCAE0D913073000F7695 /* control.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B95BCAD0D913073000F7695 /* control.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4B97B6381344B3C100794F57 /* JackMidiAsyncQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */; };
+ 4B97B6391344B3C300794F57 /* JackMidiAsyncQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193932133F311400547810 /* JackMidiAsyncQueue.h */; };
+ 4B97B63A1344B3C700794F57 /* JackMidiAsyncWaitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */; };
+ 4B97B63D1344B3EC00794F57 /* JackMidiAsyncWaitQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */; };
+ 4B97B63E1344B3F100794F57 /* JackMidiBufferReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */; };
+ 4B97B6411344B40C00794F57 /* JackMidiBufferReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */; };
+ 4B97B6531344B41E00794F57 /* JackMidiBufferWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */; };
+ 4B97B6541344B42400794F57 /* JackMidiBufferWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */; };
+ 4B97B6561344B43600794F57 /* JackMidiReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193946133F315200547810 /* JackMidiReadQueue.h */; };
+ 4B97B6571344B43A00794F57 /* JackMidiReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193945133F315200547810 /* JackMidiReadQueue.cpp */; };
+ 4B97B6581344B43F00794F57 /* JackMidiReceiveQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */; };
+ 4B97B6591344B44800794F57 /* JackMidiReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */; };
+ 4B97B65A1344B44F00794F57 /* JackMidiSendQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */; };
+ 4B97B65B1344B45600794F57 /* JackMidiSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193976133F31CB00547810 /* JackMidiSendQueue.h */; };
+ 4B97B65C1344B45D00794F57 /* JackMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193977133F31CB00547810 /* JackMidiUtil.cpp */; };
+ 4B97B65D1344B46400794F57 /* JackMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193978133F31CB00547810 /* JackMidiUtil.h */; };
+ 4B97B65E1344B46B00794F57 /* JackMidiWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */; };
+ 4B97B65F1344B47100794F57 /* JackMidiWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */; };
+ 4B97B6601344B48F00794F57 /* JackMidiAsyncQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */; };
+ 4B97B6611344B49500794F57 /* JackMidiAsyncQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193932133F311400547810 /* JackMidiAsyncQueue.h */; };
+ 4B97B6621344B49C00794F57 /* JackMidiAsyncWaitQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */; };
+ 4B97B6631344B4A800794F57 /* JackMidiAsyncWaitQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */; };
+ 4B97B6641344B4AE00794F57 /* JackMidiBufferReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */; };
+ 4B97B6651344B4B500794F57 /* JackMidiBufferReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */; };
+ 4B97B6671344B4C700794F57 /* JackMidiBufferWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */; };
+ 4B97B6691344B4CE00794F57 /* JackMidiBufferWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */; };
+ 4B97B66E1344B4D500794F57 /* JackMidiReadQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193945133F315200547810 /* JackMidiReadQueue.cpp */; };
+ 4B97B66F1344B4DC00794F57 /* JackMidiReadQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193946133F315200547810 /* JackMidiReadQueue.h */; };
+ 4B97B6701344B4E300794F57 /* JackMidiReceiveQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */; };
+ 4B97B6711344B4EA00794F57 /* JackMidiReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */; };
+ 4B97B6721344B4F000794F57 /* JackMidiSendQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */; };
+ 4B97B6781344B50800794F57 /* JackMidiSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193976133F31CB00547810 /* JackMidiSendQueue.h */; };
+ 4B97B6791344B50F00794F57 /* JackMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193977133F31CB00547810 /* JackMidiUtil.cpp */; };
+ 4B97B67A1344B51600794F57 /* JackMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193978133F31CB00547810 /* JackMidiUtil.h */; };
+ 4B97B67B1344B51D00794F57 /* JackMidiWriteQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */; };
+ 4B97B67C1344B52800794F57 /* JackMidiWriteQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */; };
4B9A25B50DBF8330006E9FBC /* JackError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9A25B30DBF8330006E9FBC /* JackError.cpp */; };
4B9A25B60DBF8330006E9FBC /* JackError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9A25B30DBF8330006E9FBC /* JackError.cpp */; };
4B9A26010DBF8584006E9FBC /* jslist.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B9A26000DBF8584006E9FBC /* jslist.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -3454,6 +3454,15 @@
4B8A38C4117B814000664E07 /* JackSocketServerNotifyChannel.h in Headers */,
4B5160AA13215ED900BB7DCB /* systemdeps.h in Headers */,
4B193995133F321500547810 /* JackFilters.h in Headers */,
+ 4B97B6611344B49500794F57 /* JackMidiAsyncQueue.h in Headers */,
+ 4B97B6631344B4A800794F57 /* JackMidiAsyncWaitQueue.h in Headers */,
+ 4B97B6651344B4B500794F57 /* JackMidiBufferReadQueue.h in Headers */,
+ 4B97B6671344B4C700794F57 /* JackMidiBufferWriteQueue.h in Headers */,
+ 4B97B66F1344B4DC00794F57 /* JackMidiReadQueue.h in Headers */,
+ 4B97B6711344B4EA00794F57 /* JackMidiReceiveQueue.h in Headers */,
+ 4B97B6781344B50800794F57 /* JackMidiSendQueue.h in Headers */,
+ 4B97B67A1344B51600794F57 /* JackMidiUtil.h in Headers */,
+ 4B97B67C1344B52800794F57 /* JackMidiWriteQueue.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3917,6 +3926,15 @@
4B2209E712F6BC0300E5DC26 /* JackSocket.h in Headers */,
4B2209EA12F6BC1600E5DC26 /* JackSocketNotifyChannel.h in Headers */,
4B193992133F321500547810 /* JackFilters.h in Headers */,
+ 4B97B6391344B3C300794F57 /* JackMidiAsyncQueue.h in Headers */,
+ 4B97B63D1344B3EC00794F57 /* JackMidiAsyncWaitQueue.h in Headers */,
+ 4B97B6411344B40C00794F57 /* JackMidiBufferReadQueue.h in Headers */,
+ 4B97B6541344B42400794F57 /* JackMidiBufferWriteQueue.h in Headers */,
+ 4B97B6561344B43600794F57 /* JackMidiReadQueue.h in Headers */,
+ 4B97B6591344B44800794F57 /* JackMidiReceiveQueue.h in Headers */,
+ 4B97B65B1344B45600794F57 /* JackMidiSendQueue.h in Headers */,
+ 4B97B65D1344B46400794F57 /* JackMidiUtil.h in Headers */,
+ 4B97B65F1344B47100794F57 /* JackMidiWriteQueue.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -4152,15 +4170,6 @@
4B370A3F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */,
4B370A41133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */,
4B370A43133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h in Headers */,
- 4B193936133F311400547810 /* JackMidiAsyncQueue.h in Headers */,
- 4B193940133F313000547810 /* JackMidiAsyncWaitQueue.h in Headers */,
- 4B19394A133F315300547810 /* JackMidiReadQueue.h in Headers */,
- 4B193962133F317300547810 /* JackMidiBufferReadQueue.h in Headers */,
- 4B19396D133F319000547810 /* JackMidiBufferWriteQueue.h in Headers */,
- 4B193984133F31CB00547810 /* JackMidiReceiveQueue.h in Headers */,
- 4B193986133F31CB00547810 /* JackMidiSendQueue.h in Headers */,
- 4B193988133F31CB00547810 /* JackMidiUtil.h in Headers */,
- 4B19398A133F31CB00547810 /* JackMidiWriteQueue.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -4229,15 +4238,6 @@
4B370A2F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */,
4B370A31133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */,
4B370A33133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h in Headers */,
- 4B193934133F311400547810 /* JackMidiAsyncQueue.h in Headers */,
- 4B19393E133F313000547810 /* JackMidiAsyncWaitQueue.h in Headers */,
- 4B193948133F315300547810 /* JackMidiReadQueue.h in Headers */,
- 4B193960133F317300547810 /* JackMidiBufferReadQueue.h in Headers */,
- 4B19396B133F319000547810 /* JackMidiBufferWriteQueue.h in Headers */,
- 4B19397C133F31CB00547810 /* JackMidiReceiveQueue.h in Headers */,
- 4B19397E133F31CB00547810 /* JackMidiSendQueue.h in Headers */,
- 4B193980133F31CB00547810 /* JackMidiUtil.h in Headers */,
- 4B193982133F31CB00547810 /* JackMidiWriteQueue.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -6885,6 +6885,15 @@
4B8A38AE117B811100664E07 /* JackSocketNotifyChannel.cpp in Sources */,
4B8A38B1117B812D00664E07 /* JackSocketServerChannel.cpp in Sources */,
4B8A38B2117B813400664E07 /* JackSocketServerNotifyChannel.cpp in Sources */,
+ 4B97B6601344B48F00794F57 /* JackMidiAsyncQueue.cpp in Sources */,
+ 4B97B6621344B49C00794F57 /* JackMidiAsyncWaitQueue.cpp in Sources */,
+ 4B97B6641344B4AE00794F57 /* JackMidiBufferReadQueue.cpp in Sources */,
+ 4B97B6691344B4CE00794F57 /* JackMidiBufferWriteQueue.cpp in Sources */,
+ 4B97B66E1344B4D500794F57 /* JackMidiReadQueue.cpp in Sources */,
+ 4B97B6701344B4E300794F57 /* JackMidiReceiveQueue.cpp in Sources */,
+ 4B97B6721344B4F000794F57 /* JackMidiSendQueue.cpp in Sources */,
+ 4B97B6791344B50F00794F57 /* JackMidiUtil.cpp in Sources */,
+ 4B97B67B1344B51D00794F57 /* JackMidiWriteQueue.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -7337,6 +7346,15 @@
4B2209E312F6BBF500E5DC26 /* JackSocketServerNotifyChannel.cpp in Sources */,
4B2209E612F6BC0200E5DC26 /* JackSocket.cpp in Sources */,
4B2209E912F6BC1500E5DC26 /* JackSocketNotifyChannel.cpp in Sources */,
+ 4B97B6381344B3C100794F57 /* JackMidiAsyncQueue.cpp in Sources */,
+ 4B97B63A1344B3C700794F57 /* JackMidiAsyncWaitQueue.cpp in Sources */,
+ 4B97B63E1344B3F100794F57 /* JackMidiBufferReadQueue.cpp in Sources */,
+ 4B97B6531344B41E00794F57 /* JackMidiBufferWriteQueue.cpp in Sources */,
+ 4B97B6571344B43A00794F57 /* JackMidiReadQueue.cpp in Sources */,
+ 4B97B6581344B43F00794F57 /* JackMidiReceiveQueue.cpp in Sources */,
+ 4B97B65A1344B44F00794F57 /* JackMidiSendQueue.cpp in Sources */,
+ 4B97B65C1344B45D00794F57 /* JackMidiUtil.cpp in Sources */,
+ 4B97B65E1344B46B00794F57 /* JackMidiWriteQueue.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -7575,15 +7593,6 @@
4B370A3E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */,
4B370A40133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */,
4B370A42133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp in Sources */,
- 4B193935133F311400547810 /* JackMidiAsyncQueue.cpp in Sources */,
- 4B19393F133F313000547810 /* JackMidiAsyncWaitQueue.cpp in Sources */,
- 4B193949133F315300547810 /* JackMidiReadQueue.cpp in Sources */,
- 4B193961133F317300547810 /* JackMidiBufferReadQueue.cpp in Sources */,
- 4B19396C133F319000547810 /* JackMidiBufferWriteQueue.cpp in Sources */,
- 4B193983133F31CB00547810 /* JackMidiReceiveQueue.cpp in Sources */,
- 4B193985133F31CB00547810 /* JackMidiSendQueue.cpp in Sources */,
- 4B193987133F31CB00547810 /* JackMidiUtil.cpp in Sources */,
- 4B193989133F31CB00547810 /* JackMidiWriteQueue.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -7657,15 +7666,6 @@
4B370A2E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */,
4B370A30133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */,
4B370A32133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp in Sources */,
- 4B193933133F311400547810 /* JackMidiAsyncQueue.cpp in Sources */,
- 4B19393D133F313000547810 /* JackMidiAsyncWaitQueue.cpp in Sources */,
- 4B193947133F315300547810 /* JackMidiReadQueue.cpp in Sources */,
- 4B19395F133F317300547810 /* JackMidiBufferReadQueue.cpp in Sources */,
- 4B19396A133F319000547810 /* JackMidiBufferWriteQueue.cpp in Sources */,
- 4B19397B133F31CB00547810 /* JackMidiReceiveQueue.cpp in Sources */,
- 4B19397D133F31CB00547810 /* JackMidiSendQueue.cpp in Sources */,
- 4B19397F133F31CB00547810 /* JackMidiUtil.cpp in Sources */,
- 4B193981133F31CB00547810 /* JackMidiWriteQueue.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/tests/test.cpp b/tests/test.cpp
index 1a6e4a05..7c3f5b5e 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -972,14 +972,14 @@ int main (int argc, char *argv[])
float factor = 0.5f;
old_buffer_size = jack_get_buffer_size(client1);
- Log("Testing BufferSize change & Callback...\n--> Current buffer size : %i.\n", old_buffer_size);
+ Log("Testing BufferSize change & Callback...\n--> Current buffer size : %d.\n", old_buffer_size);
linebuf = linecount;
if (jack_set_buffer_size(client1, (jack_nframes_t)(old_buffer_size * factor)) < 0) {
printf("!!! ERROR !!! jack_set_buffer_size fails !\n");
}
jack_sleep(1 * 1000);
cur_buffer_size = jack_get_buffer_size(client1);
- if ((old_buffer_size * factor) != cur_buffer_size) {
+ if (abs((old_buffer_size * factor) - cur_buffer_size) > 5) { // Tolerance needed for dummy driver...
printf("!!! ERROR !!! Buffer size has not been changed !\n");
printf("!!! Maybe jack was compiled without the '--enable-resize' flag...\n");
} else {
diff --git a/windows/jack_winmme.cbp b/windows/jack_winmme.cbp
index 2c6d8bbe..7fe93703 100644
--- a/windows/jack_winmme.cbp
+++ b/windows/jack_winmme.cbp
@@ -106,6 +106,12 @@
+
+
+
+
+
+
diff --git a/windows/jackd.workspace b/windows/jackd.workspace
index 05f5b3d1..c424a7b4 100644
--- a/windows/jackd.workspace
+++ b/windows/jackd.workspace
@@ -56,7 +56,7 @@
-
-
+
+
diff --git a/windows/libjackserver.cbp b/windows/libjackserver.cbp
index e4db2136..84b8985d 100644
--- a/windows/libjackserver.cbp
+++ b/windows/libjackserver.cbp
@@ -150,12 +150,16 @@
+
+
+
+
+
+
-
-
diff --git a/windows/portaudio/JackPortAudioDriver.cpp b/windows/portaudio/JackPortAudioDriver.cpp
index 790bcda1..f7611add 100644
--- a/windows/portaudio/JackPortAudioDriver.cpp
+++ b/windows/portaudio/JackPortAudioDriver.cpp
@@ -248,7 +248,7 @@ error:
} else {
JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails
// PortAudio specific
- UpdateLatencies();
+ JackAudioDriver::UpdateLatencies();
return 0;
}
}
diff --git a/windows/winmme/JackWinMMEDriver.cpp b/windows/winmme/JackWinMMEDriver.cpp
index d3635c64..96bebda1 100644
--- a/windows/winmme/JackWinMMEDriver.cpp
+++ b/windows/winmme/JackWinMMEDriver.cpp
@@ -1,5 +1,6 @@
/*
Copyright (C) 2009 Grame
+Copyright (C) 2011 Devin Anderson
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,401 +18,302 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "JackWinMMEDriver.h"
-#include "JackGraphManager.h"
#include "JackEngineControl.h"
-#include "JackDriverLoader.h"
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
+#include "JackWinMMEDriver.h"
-namespace Jack
-{
+using Jack::JackWinMMEDriver;
-static bool InitHeaders(MidiSlot* slot)
+JackWinMMEDriver::JackWinMMEDriver(const char *name, const char *alias,
+ JackLockedEngine *engine,
+ JackSynchro *table):
+ JackMidiDriver(name, alias, engine, table)
{
- slot->fHeader = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, sizeof(MIDIHDR) + kBuffSize);
- if (!slot->fHeader)
- return false;
-
- slot->fHeader->lpData = (LPSTR)((LPBYTE)slot->fHeader + sizeof(MIDIHDR));
- slot->fHeader->dwBufferLength = kBuffSize;
- slot->fHeader->dwFlags = 0;
- slot->fHeader->dwUser = 0;
- slot->fHeader->lpNext = 0;
- slot->fHeader->dwBytesRecorded = 0;
- return true;
+ fCaptureChannels = 0;
+ fPlaybackChannels = 0;
+ input_ports = 0;
+ output_ports = 0;
}
-void CALLBACK JackWinMMEDriver::MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD userData, DWORD dwParam1, DWORD dwParam2)
+JackWinMMEDriver::~JackWinMMEDriver()
{
- jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)userData;
- //jack_info("JackWinMMEDriver::MidiInProc 0\n");
-
- switch (wMsg) {
- case MIM_OPEN:
- break;
-
- case MIM_ERROR:
- case MIM_DATA: {
-
- //jack_info("JackWinMMEDriver::MidiInProc");
-
- // One event
- unsigned int num_packet = 1;
- jack_ringbuffer_write(ringbuffer, (char*)&num_packet, sizeof(unsigned int));
-
- // Write event actual data
- jack_ringbuffer_write(ringbuffer, (char*)&dwParam1, 3);
- break;
- }
-
- case MIM_LONGERROR:
- case MIM_LONGDATA:
- /*
- Nothing for now
- */
- break;
- }
+ Stop();
+ Close();
}
-JackWinMMEDriver::JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
- : JackMidiDriver(name, alias, engine, table),
- fRealCaptureChannels(0),
- fRealPlaybackChannels(0),
- fMidiSource(NULL),
- fMidiDestination(NULL)
-{}
-
-JackWinMMEDriver::~JackWinMMEDriver()
-{}
-
-int JackWinMMEDriver::Open(bool capturing,
- bool playing,
- int inchannels,
- int outchannels,
- bool monitor,
- const char* capture_driver_name,
- const char* playback_driver_name,
- jack_nframes_t capture_latency,
- jack_nframes_t playback_latency)
+int
+JackWinMMEDriver::Attach()
{
-
- jack_log("JackWinMMEDriver::Open");
-
- fRealCaptureChannels = midiInGetNumDevs();
- fRealPlaybackChannels = midiOutGetNumDevs();
-
- // Generic JackMidiDriver Open
- if (JackMidiDriver::Open(capturing, playing, fRealCaptureChannels, fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
- return -1;
-
- fMidiDestination = new MidiSlot[fRealCaptureChannels];
- assert(fMidiDestination);
-
- // Real input
- int devindex = 0;
- for (int i = 0; i < fRealCaptureChannels; i++) {
-
- HMIDIIN handle;
- fMidiDestination[devindex].fIndex = i;
- MMRESULT ret = midiInOpen(&handle, fMidiDestination[devindex].fIndex, (DWORD)MidiInProc, (DWORD)fRingBuffer[devindex], CALLBACK_FUNCTION);
-
- if (ret == MMSYSERR_NOERROR) {
- fMidiDestination[devindex].fHandle = handle;
- if (!InitHeaders(&fMidiDestination[devindex])) {
- jack_error("memory allocation failed");
- midiInClose(handle);
- continue;
- }
- ret = midiInPrepareHeader(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR));
-
- if (ret == MMSYSERR_NOERROR) {
- fMidiDestination[devindex].fHeader->dwUser = 1;
- ret = midiInAddBuffer(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR));
- if (ret == MMSYSERR_NOERROR) {
- ret = midiInStart(handle);
- if (ret != MMSYSERR_NOERROR) {
- jack_error("midiInStart error");
- CloseInput(&fMidiDestination[devindex]);
- continue;
- }
- } else {
- jack_error ("midiInAddBuffer error");
- CloseInput(&fMidiDestination[devindex]);
- continue;
- }
- } else {
- jack_error("midiInPrepareHeader error");
- midiInClose(handle);
- continue;
- }
- } else {
- jack_error ("midiInOpen error");
- continue;
+ jack_nframes_t buffer_size = fEngineControl->fBufferSize;
+ jack_port_id_t index;
+ jack_nframes_t latency = buffer_size;
+ jack_latency_range_t latency_range;
+ const char *name;
+ JackPort *port;
+ latency_range.max = latency;
+ latency_range.min = latency;
+
+ jack_info("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels);
+ jack_info("JackWinMMEDriver::Attach - fPlaybackChannels %d", fPlaybackChannels);
+
+ // Inputs
+ for (int i = 0; i < fCaptureChannels; i++) {
+ JackWinMMEInputPort *input_port = input_ports[i];
+ name = input_port->GetName();
+ index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
+ JACK_DEFAULT_MIDI_TYPE,
+ CaptureDriverFlags, buffer_size);
+ if (index == NO_PORT) {
+ jack_error("JackWinMMEDriver::Attach - cannot register input port "
+ "with name '%s'.", name);
+ // X: Do we need to deallocate ports?
+ return -1;
}
- devindex += 1;
+ port = fGraphManager->GetPort(index);
+ port->SetAlias(input_port->GetAlias());
+ port->SetLatencyRange(JackCaptureLatency, &latency_range);
+ fCapturePortList[i] = index;
}
- fRealCaptureChannels = devindex;
- fCaptureChannels = devindex;
-
- fMidiSource = new MidiSlot[fRealPlaybackChannels];
- assert(fMidiSource);
-
- // Real output
- devindex = 0;
- for (int i = 0; i < fRealPlaybackChannels; i++) {
- MMRESULT res;
- HMIDIOUT handle;
- fMidiSource[devindex].fIndex = i;
- UINT ret = midiOutOpen(&handle, fMidiSource[devindex].fIndex, 0L, 0L, CALLBACK_NULL);
- if (ret == MMSYSERR_NOERROR) {
- fMidiSource[devindex].fHandle = handle;
- if (!InitHeaders(&fMidiSource[devindex])) {
- jack_error("memory allocation failed");
- midiOutClose(handle);
- continue;
- }
- res = midiOutPrepareHeader(handle, fMidiSource[devindex].fHeader, sizeof(MIDIHDR));
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiOutPrepareHeader error %d %d %d", i, handle, res);
- continue;
- } else {
- fMidiSource[devindex].fHeader->dwUser = 1;
- }
- } else {
- jack_error("midiOutOpen error");
- continue;
+
+ if (! fEngineControl->fSyncMode) {
+ latency += buffer_size;
+ latency_range.max = latency;
+ latency_range.min = latency;
+ }
+
+ // Outputs
+ for (int i = 0; i < fPlaybackChannels; i++) {
+ JackWinMMEOutputPort *output_port = output_ports[i];
+ name = output_port->GetName();
+ index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
+ JACK_DEFAULT_MIDI_TYPE,
+ PlaybackDriverFlags, buffer_size);
+ if (index == NO_PORT) {
+ jack_error("JackWinMMEDriver::Attach - cannot register output "
+ "port with name '%s'.", name);
+ // X: Do we need to deallocate ports?
+ return -1;
}
- devindex += 1;
+ port = fGraphManager->GetPort(index);
+ port->SetAlias(output_port->GetAlias());
+ port->SetLatencyRange(JackPlaybackLatency, &latency_range);
+ fPlaybackPortList[i] = index;
}
- fRealPlaybackChannels = devindex;
- fPlaybackChannels = devindex;
+
return 0;
}
-void JackWinMMEDriver::CloseInput(MidiSlot* slot)
+int
+JackWinMMEDriver::Close()
{
- MMRESULT res;
- int retry = 0;
-
- if (slot->fHandle == 0)
- return;
-
- HMIDIIN handle = (HMIDIIN)slot->fHandle;
- slot->fHeader->dwUser = 0;
- res = midiInStop(handle);
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiInStop error");
- }
- res = midiInReset(handle);
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiInReset error");
- }
- res = midiInUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiInUnprepareHeader error");
+ int result = JackMidiDriver::Close();
+ if (input_ports) {
+ for (int i = 0; i < fCaptureChannels; i++) {
+ delete input_ports[i];
+ }
+ delete[] input_ports;
+ input_ports = 0;
}
- do {
- res = midiInClose(handle);
- if (res != MMSYSERR_NOERROR) {
- jack_error("midiInClose error");
+ if (output_ports) {
+ for (int i = 0; i < fPlaybackChannels; i++) {
+ delete output_ports[i];
}
- if (res == MIDIERR_STILLPLAYING)
- midiInReset(handle);
- Sleep (10);
- retry++;
- } while ((res == MIDIERR_STILLPLAYING) && (retry < 10));
-
- if (slot->fHeader) {
- GlobalFreePtr(slot->fHeader);
+ delete[] output_ports;
+ output_ports = 0;
}
+ return result;
}
-void JackWinMMEDriver::CloseOutput(MidiSlot* slot)
+int
+JackWinMMEDriver::Open(bool capturing, bool playing, int in_channels,
+ int out_channels, bool monitor,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency)
{
- MMRESULT res;
- int retry = 0;
-
- if (slot->fHandle == 0)
- return;
-
- HMIDIOUT handle = (HMIDIOUT)slot->fHandle;
- res = midiOutReset(handle);
- if (res != MMSYSERR_NOERROR)
- jack_error("midiOutReset error");
- midiOutUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
- do {
- res = midiOutClose(handle);
- if (res != MMSYSERR_NOERROR)
- jack_error("midiOutClose error");
- Sleep(10);
- retry++;
- } while ((res == MIDIERR_STILLPLAYING) && (retry < 10));
-
- if (slot->fHeader) {
- GlobalFreePtr(slot->fHeader);
+ const char *client_name = fClientControl.fName;
+ int input_count = 0;
+ int output_count = 0;
+ int num_potential_inputs = midiInGetNumDevs();
+ int num_potential_outputs = midiOutGetNumDevs();
+
+ jack_info("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs);
+ jack_info("JackWinMMEDriver::Open - num_potential_outputs %d", num_potential_outputs);
+
+ if (num_potential_inputs) {
+ try {
+ input_ports = new JackWinMMEInputPort *[num_potential_inputs];
+ } catch (std::exception e) {
+ jack_error("JackWinMMEDriver::Open - while creating input port "
+ "array: %s", e.what());
+ return -1;
+ }
+ for (int i = 0; i < num_potential_inputs; i++) {
+ try {
+ input_ports[input_count] =
+ new JackWinMMEInputPort(fAliasName, client_name,
+ capture_driver_name, i);
+ } catch (std::exception e) {
+ jack_error("JackWinMMEDriver::Open - while creating input "
+ "port: %s", e.what());
+ continue;
+ }
+ input_count++;
+ }
+ }
+ if (num_potential_outputs) {
+ try {
+ output_ports = new JackWinMMEOutputPort *[num_potential_outputs];
+ } catch (std::exception e) {
+ jack_error("JackWinMMEDriver::Open - while creating output port "
+ "array: %s", e.what());
+ goto destroy_input_ports;
+ }
+ for (int i = 0; i < num_potential_outputs; i++) {
+ try {
+ output_ports[output_count] =
+ new JackWinMMEOutputPort(fAliasName, client_name,
+ playback_driver_name, i);
+ } catch (std::exception e) {
+ jack_error("JackWinMMEDriver::Open - while creating output "
+ "port: %s", e.what());
+ continue;
+ }
+ output_count++;
+ }
}
-}
-int JackWinMMEDriver::Close()
-{
- jack_log("JackWinMMEDriver::Close");
+ jack_info("JackWinMMEDriver::Open - input_count %d", input_count);
+ jack_info("JackWinMMEDriver::Open - output_count %d", output_count);
- // Generic midi driver close
- int res = JackMidiDriver::Close();
- // Close input
- if (fMidiDestination) {
- for (int i = 0; i < fRealCaptureChannels; i++) {
- CloseInput(&fMidiDestination[i]);
- }
- delete[] fMidiDestination;
+ if (! (input_count || output_count)) {
+ jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs "
+ "allocated.");
+ } else if (! JackMidiDriver::Open(capturing, playing, input_count,
+ output_count, monitor,
+ capture_driver_name,
+ playback_driver_name, capture_latency,
+ playback_latency)) {
+ return 0;
}
- // Close output
- if (fMidiSource) {
- for (int i = 0; i < fRealPlaybackChannels; i++) {
- CloseOutput(&fMidiSource[i]);
+ destroy_input_ports:
+ if (input_ports) {
+ for (int i = 0; i < input_count; i++) {
+ delete input_ports[i];
}
- delete[] fMidiSource;
+ delete[] input_ports;
+ input_ports = 0;
}
-
- return res;
+ return -1;
}
-int JackWinMMEDriver::Attach()
+int
+JackWinMMEDriver::Read()
{
- JackPort* port;
- jack_port_id_t port_index;
- char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
- char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
- MMRESULT res;
- int i;
-
- jack_log("JackMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
-
- for (i = 0; i < fCaptureChannels; i++) {
- MIDIINCAPS caps;
- res = midiInGetDevCaps(fMidiDestination[i].fIndex, &caps, sizeof(caps));
- if (res == MMSYSERR_NOERROR) {
- snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
- } else {
- snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
- }
- snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
-
- if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
- jack_error("driver: cannot register port for %s", name);
- return -1;
- }
- port = fGraphManager->GetPort(port_index);
- port->SetAlias(alias);
- fCapturePortList[i] = port_index;
- jack_log("JackMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
- }
- for (i = 0; i < fPlaybackChannels; i++) {
- MIDIOUTCAPS caps;
- res = midiOutGetDevCaps(fMidiSource[i].fIndex, &caps, sizeof(caps));
- if (res == MMSYSERR_NOERROR) {
- snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
- } else {
- snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fPlaybackDriverName, i + 1);
- }
- snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
-
- if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
- jack_error("driver: cannot register port for %s", name);
- return -1;
- }
- port = fGraphManager->GetPort(port_index);
- port->SetAlias(alias);
- fPlaybackPortList[i] = port_index;
- jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
+ jack_nframes_t buffer_size = fEngineControl->fBufferSize;
+ for (int i = 0; i < fCaptureChannels; i++) {
+ input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
}
return 0;
}
-int JackWinMMEDriver::Read()
+
+int
+JackWinMMEDriver::Write()
{
- size_t size;
+ /*
+ jack_nframes_t buffer_size = fEngineControl->fBufferSize;
+ for (int i = 0; i < fPlaybackChannels; i++) {
+ output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
+ }
+ */
+ return 0;
+}
- for (int chan = 0; chan < fCaptureChannels; chan++) {
+int
+JackWinMMEDriver::Start()
+{
+ jack_info("JackWinMMEDriver::Start - Starting driver.");
- if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) {
+ JackMidiDriver::Start();
- JackMidiBuffer* midi_buffer = GetInputBuffer(chan);
+ int input_count = 0;
+ int output_count = 0;
- if (jack_ringbuffer_read_space (fRingBuffer[chan]) == 0) {
- // Reset buffer
- midi_buffer->Reset(midi_buffer->nframes);
- } else {
+ jack_info("JackWinMMEDriver::Start - Enabling input ports.");
- while ((size = jack_ringbuffer_read_space (fRingBuffer[chan])) > 0) {
+ for (; input_count < fCaptureChannels; input_count++) {
+ if (input_ports[input_count]->Start() < 0) {
+ jack_error("JackWinMMEDriver::Start - Failed to enable input "
+ "port.");
+ goto stop_input_ports;
+ }
+ }
- //jack_info("jack_ringbuffer_read_space %d", size);
- int ev_count = 0;
- jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int));
+ jack_info("JackWinMMEDriver::Start - Enabling output ports.");
- if (ev_count > 0) {
- for (int j = 0; j < ev_count; j++) {
- unsigned int event_len = 3;
- // Read event actual data
- jack_midi_data_t* dest = midi_buffer->ReserveEvent(0, event_len);
- jack_ringbuffer_read(fRingBuffer[chan], (char*)dest, event_len);
- }
- }
- }
- }
- } else {
- //jack_info("Consume ring buffer");
- jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan]));
+ for (; output_count < fPlaybackChannels; output_count++) {
+ if (output_ports[output_count]->Start() < 0) {
+ jack_error("JackWinMMEDriver::Start - Failed to enable output "
+ "port.");
+ goto stop_output_ports;
}
}
+
+ jack_info("JackWinMMEDriver::Start - Driver started.");
+
return 0;
+
+ stop_output_ports:
+ for (int i = 0; i < output_count; i++) {
+ if (output_ports[i]->Stop() < 0) {
+ jack_error("JackWinMMEDriver::Start - Failed to disable output "
+ "port.");
+ }
+ }
+ stop_input_ports:
+ for (int i = 0; i < input_count; i++) {
+ if (input_ports[i]->Stop() < 0) {
+ jack_error("JackWinMMEDriver::Start - Failed to disable input "
+ "port.");
+ }
+ }
+
+ return -1;
}
-int JackWinMMEDriver::Write()
+int
+JackWinMMEDriver::Stop()
{
- for (int chan = 0; chan < fPlaybackChannels; chan++) {
+ int result = 0;
- if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) {
+ jack_info("JackWinMMEDriver::Stop - disabling input ports.");
- JackMidiBuffer* midi_buffer = GetOutputBuffer(chan);
-
- // TODO : use timestamp
+ for (int i = 0; i < fCaptureChannels; i++) {
+ if (input_ports[i]->Stop() < 0) {
+ jack_error("JackWinMMEDriver::Stop - Failed to disable input "
+ "port.");
+ result = -1;
+ }
+ }
- for (unsigned int j = 0; j < midi_buffer->event_count; j++) {
- JackMidiEvent* ev = &midi_buffer->events[j];
- if (ev->size <= 3) {
- jack_midi_data_t *d = ev->GetData(midi_buffer);
- DWORD winev = 0;
- if (ev->size > 0) winev |= d[0];
- if (ev->size > 1) winev |= (d[1] << 8);
- if (ev->size > 2) winev |= (d[2] << 16);
- MMRESULT res = midiOutShortMsg((HMIDIOUT)fMidiSource[chan].fHandle, winev);
- if (res != MMSYSERR_NOERROR)
- jack_error ("midiOutShortMsg error res %d", res);
- } else {
+ jack_info("JackWinMMEDriver::Stop - disabling output ports.");
- }
- }
+ for (int i = 0; i < fPlaybackChannels; i++) {
+ if (output_ports[i]->Stop() < 0) {
+ jack_error("JackWinMMEDriver::Stop - Failed to disable output "
+ "port.");
+ result = -1;
}
}
- return 0;
+ return result;
}
-} // end of namespace
-
#ifdef __cplusplus
extern "C"
{
diff --git a/windows/winmme/JackWinMMEDriver.h b/windows/winmme/JackWinMMEDriver.h
index 6c28a0ef..52ae5f2b 100644
--- a/windows/winmme/JackWinMMEDriver.h
+++ b/windows/winmme/JackWinMMEDriver.h
@@ -1,5 +1,6 @@
/*
Copyright (C) 2009 Grame
+Copyright (C) 2011 Devin Anderson
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,67 +22,51 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#define __JackWinMMEDriver__
#include "JackMidiDriver.h"
-#include "JackTime.h"
+#include "JackWinMMEInputPort.h"
+#include "JackWinMMEOutputPort.h"
-namespace Jack
-{
+namespace Jack {
-/*!
-\brief The WinMME driver.
-*/
-
-#define kBuffSize 512
-
-struct MidiSlot {
-
- LPVOID fHandle; // MMSystem handler
- short fIndex; // MMSystem dev index
- LPMIDIHDR fHeader; // for long msg output
-
- MidiSlot():fHandle(0),fIndex(0)
- {}
+ class JackWinMMEDriver : public JackMidiDriver {
-};
+ private:
-class JackWinMMEDriver : public JackMidiDriver
-{
+ JackWinMMEInputPort **input_ports;
+ JackWinMMEOutputPort **output_ports;
- private:
+ public:
- int fRealCaptureChannels;
- int fRealPlaybackChannels;
+ JackWinMMEDriver(const char* name, const char* alias,
+ JackLockedEngine* engine, JackSynchro* table);
- MidiSlot* fMidiSource;
- MidiSlot* fMidiDestination;
+ ~JackWinMMEDriver();
- void CloseInput(MidiSlot* slot);
- void CloseOutput(MidiSlot* slot);
+ int
+ Attach();
- static void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
+ int
+ Close();
- public:
+ int
+ Open(bool capturing, bool playing, int num_inputs, int num_outputs,
+ bool monitor, const char* capture_driver_name,
+ const char* playback_driver_name, jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency);
- JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);
- virtual ~JackWinMMEDriver();
+ int
+ Read();
- int Open(bool capturing,
- bool playing,
- int chan_in,
- int chan_out,
- bool monitor,
- const char* capture_driver_name,
- const char* playback_driver_name,
- jack_nframes_t capture_latency,
- jack_nframes_t playback_latency);
- int Close();
+ int
+ Start();
- int Attach();
+ int
+ Stop();
- int Read();
- int Write();
+ int
+ Write();
-};
+ };
-} // end of namespace
+}
#endif
diff --git a/windows/winmme/JackWinMMEInputPort.cpp b/windows/winmme/JackWinMMEInputPort.cpp
new file mode 100644
index 00000000..c3b04453
--- /dev/null
+++ b/windows/winmme/JackWinMMEInputPort.cpp
@@ -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
+#include
+#include
+
+#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 thread_queue_ptr(thread_queue);
+ write_queue = new JackMidiBufferWriteQueue();
+ std::auto_ptr 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);
+}
+
diff --git a/windows/winmme/JackWinMMEInputPort.h b/windows/winmme/JackWinMMEInputPort.h
new file mode 100644
index 00000000..13eb32a6
--- /dev/null
+++ b/windows/winmme/JackWinMMEInputPort.h
@@ -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
+
+#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
diff --git a/windows/winmme/JackWinMMEOutputPort.cpp b/windows/winmme/JackWinMMEOutputPort.cpp
new file mode 100644
index 00000000..51a9ddbd
--- /dev/null
+++ b/windows/winmme/JackWinMMEOutputPort.cpp
@@ -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
+#include
+
+#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 read_queue_ptr(read_queue);
+ thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
+ std::auto_ptr thread_queue_ptr(thread_queue);
+ thread = new JackThread(this);
+ std::auto_ptr 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);
+}
diff --git a/windows/winmme/JackWinMMEOutputPort.h b/windows/winmme/JackWinMMEOutputPort.h
new file mode 100644
index 00000000..d43eae35
--- /dev/null
+++ b/windows/winmme/JackWinMMEOutputPort.h
@@ -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
diff --git a/windows/winmme/JackWinMMEPort.cpp b/windows/winmme/JackWinMMEPort.cpp
new file mode 100644
index 00000000..46c4546b
--- /dev/null
+++ b/windows/winmme/JackWinMMEPort.cpp
@@ -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
+#include
+
+#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);
+}
+
diff --git a/windows/winmme/JackWinMMEPort.h b/windows/winmme/JackWinMMEPort.h
new file mode 100644
index 00000000..a544c4a6
--- /dev/null
+++ b/windows/winmme/JackWinMMEPort.h
@@ -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
+#include
+
+#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