Browse Source

Merge branch 'newer-midi-with-winmme-driver' into newer-midi

tags/1.9.8
Stephane Letz 14 years ago
parent
commit
fa70a32415
18 changed files with 1362 additions and 476 deletions
  1. +2
    -2
      common/JackMidiWriteQueue.h
  2. +36
    -16
      common/JackNetDriver.cpp
  3. +1
    -1
      common/shm.h
  4. +1
    -1
      linux/alsarawmidi/JackALSARawMidiSendQueue.cpp
  5. +72
    -72
      macosx/Jackdmp.xcodeproj/project.pbxproj
  6. +2
    -2
      tests/test.cpp
  7. +6
    -0
      windows/jack_winmme.cbp
  8. +2
    -2
      windows/jackd.workspace
  9. +6
    -2
      windows/libjackserver.cbp
  10. +1
    -1
      windows/portaudio/JackPortAudioDriver.cpp
  11. +233
    -331
      windows/winmme/JackWinMMEDriver.cpp
  12. +31
    -46
      windows/winmme/JackWinMMEDriver.h
  13. +294
    -0
      windows/winmme/JackWinMMEInputPort.cpp
  14. +85
    -0
      windows/winmme/JackWinMMEInputPort.h
  15. +374
    -0
      windows/winmme/JackWinMMEOutputPort.cpp
  16. +89
    -0
      windows/winmme/JackWinMMEOutputPort.h
  17. +68
    -0
      windows/winmme/JackWinMMEPort.cpp
  18. +59
    -0
      windows/winmme/JackWinMMEPort.h

+ 2
- 2
common/JackMidiWriteQueue.h View File

@@ -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.
*/



+ 36
- 16
common/JackNetDriver.cpp View File

@@ -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;
}



+ 1
- 1
common/shm.h View File

@@ -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" */


+ 1
- 1
linux/alsarawmidi/JackALSARawMidiSendQueue.cpp View File

@@ -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


+ 72
- 72
macosx/Jackdmp.xcodeproj/project.pbxproj View File

@@ -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;
};


+ 2
- 2
tests/test.cpp View File

@@ -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 {


+ 6
- 0
windows/jack_winmme.cbp View File

@@ -106,6 +106,12 @@
<Option compilerVar="WINDRES" />
</Unit>
<Unit filename="winmme\JackWinMMEDriver.cpp" />
<Unit filename="winmme\JackWinMMEDriver.h" />
<Unit filename="winmme\JackWinMMEInputPort.cpp" />
<Unit filename="winmme\JackWinMMEInputPort.h" />
<Unit filename="winmme\JackWinMMEOutputPort.cpp" />
<Unit filename="winmme\JackWinMMEOutputPort.h" />
<Unit filename="winmme\JackWinMMEPort.cpp" />
<Extensions>
<code_completion />
<envvars />


+ 2
- 2
windows/jackd.workspace View File

@@ -56,7 +56,7 @@
<Project filename="multiple_metro.cbp">
<Depends filename="libjack.cbp" />
</Project>
<Project filename="jack_winmme.cbp" />
<Project filename="jack_loopback.cbp" active="1" />
<Project filename="jack_winmme.cbp" active="1" />
<Project filename="jack_loopback.cbp" />
</Workspace>
</CodeBlocks_workspace_file>

+ 6
- 2
windows/libjackserver.cbp View File

@@ -150,12 +150,16 @@
<Unit filename="..\common\JackLoopbackDriver.cpp" />
<Unit filename="..\common\JackMessageBuffer.cpp" />
<Unit filename="..\common\JackMidiAPI.cpp" />
<Unit filename="..\common\JackMidiAsyncQueue.cpp" />
<Unit filename="..\common\JackMidiBufferReadQueue.cpp" />
<Unit filename="..\common\JackMidiBufferWriteQueue.cpp" />
<Unit filename="..\common\JackMidiDriver.cpp" />
<Unit filename="..\common\JackMidiPort.cpp" />
<Unit filename="..\common\JackMidiReadQueue.cpp" />
<Unit filename="..\common\JackMidiUtil.cpp" />
<Unit filename="..\common\JackMidiWriteQueue.cpp" />
<Unit filename="..\common\JackNetInterface.cpp" />
<Unit filename="..\common\JackNetTool.cpp" />
<Unit filename="..\common\JackPhysicalMidiInput.cpp" />
<Unit filename="..\common\JackPhysicalMidiOutput.cpp" />
<Unit filename="..\common\JackPort.cpp" />
<Unit filename="..\common\JackPortType.cpp" />
<Unit filename="..\common\JackRestartThreadedDriver.cpp" />


+ 1
- 1
windows/portaudio/JackPortAudioDriver.cpp View File

@@ -248,7 +248,7 @@ error:
} else {
JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails
// PortAudio specific
UpdateLatencies();
JackAudioDriver::UpdateLatencies();
return 0;
}
}


+ 233
- 331
windows/winmme/JackWinMMEDriver.cpp View File

@@ -1,5 +1,6 @@
/*
Copyright (C) 2009 Grame
Copyright (C) 2011 Devin Anderson

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,401 +18,302 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "JackWinMMEDriver.h"
#include "JackGraphManager.h"
#include "JackEngineControl.h"
#include "JackDriverLoader.h"

#include <assert.h>
#include <iostream>
#include <sstream>
#include <string>

#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include "JackWinMMEDriver.h"

namespace Jack
{
using Jack::JackWinMMEDriver;

static bool InitHeaders(MidiSlot* slot)
JackWinMMEDriver::JackWinMMEDriver(const char *name, const char *alias,
JackLockedEngine *engine,
JackSynchro *table):
JackMidiDriver(name, alias, engine, table)
{
slot->fHeader = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, sizeof(MIDIHDR) + kBuffSize);
if (!slot->fHeader)
return false;

slot->fHeader->lpData = (LPSTR)((LPBYTE)slot->fHeader + sizeof(MIDIHDR));
slot->fHeader->dwBufferLength = kBuffSize;
slot->fHeader->dwFlags = 0;
slot->fHeader->dwUser = 0;
slot->fHeader->lpNext = 0;
slot->fHeader->dwBytesRecorded = 0;
return true;
fCaptureChannels = 0;
fPlaybackChannels = 0;
input_ports = 0;
output_ports = 0;
}

void CALLBACK JackWinMMEDriver::MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD userData, DWORD dwParam1, DWORD dwParam2)
JackWinMMEDriver::~JackWinMMEDriver()
{
jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)userData;
//jack_info("JackWinMMEDriver::MidiInProc 0\n");

switch (wMsg) {
case MIM_OPEN:
break;

case MIM_ERROR:
case MIM_DATA: {

//jack_info("JackWinMMEDriver::MidiInProc");

// One event
unsigned int num_packet = 1;
jack_ringbuffer_write(ringbuffer, (char*)&num_packet, sizeof(unsigned int));

// Write event actual data
jack_ringbuffer_write(ringbuffer, (char*)&dwParam1, 3);
break;
}

case MIM_LONGERROR:
case MIM_LONGDATA:
/*
Nothing for now
*/
break;
}
Stop();
Close();
}

JackWinMMEDriver::JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
: JackMidiDriver(name, alias, engine, table),
fRealCaptureChannels(0),
fRealPlaybackChannels(0),
fMidiSource(NULL),
fMidiDestination(NULL)
{}

JackWinMMEDriver::~JackWinMMEDriver()
{}

int JackWinMMEDriver::Open(bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency)
int
JackWinMMEDriver::Attach()
{

jack_log("JackWinMMEDriver::Open");

fRealCaptureChannels = midiInGetNumDevs();
fRealPlaybackChannels = midiOutGetNumDevs();

// Generic JackMidiDriver Open
if (JackMidiDriver::Open(capturing, playing, fRealCaptureChannels, fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
return -1;

fMidiDestination = new MidiSlot[fRealCaptureChannels];
assert(fMidiDestination);

// Real input
int devindex = 0;
for (int i = 0; i < fRealCaptureChannels; i++) {

HMIDIIN handle;
fMidiDestination[devindex].fIndex = i;
MMRESULT ret = midiInOpen(&handle, fMidiDestination[devindex].fIndex, (DWORD)MidiInProc, (DWORD)fRingBuffer[devindex], CALLBACK_FUNCTION);

if (ret == MMSYSERR_NOERROR) {
fMidiDestination[devindex].fHandle = handle;
if (!InitHeaders(&fMidiDestination[devindex])) {
jack_error("memory allocation failed");
midiInClose(handle);
continue;
}
ret = midiInPrepareHeader(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR));

if (ret == MMSYSERR_NOERROR) {
fMidiDestination[devindex].fHeader->dwUser = 1;
ret = midiInAddBuffer(handle, fMidiDestination[devindex].fHeader, sizeof(MIDIHDR));
if (ret == MMSYSERR_NOERROR) {
ret = midiInStart(handle);
if (ret != MMSYSERR_NOERROR) {
jack_error("midiInStart error");
CloseInput(&fMidiDestination[devindex]);
continue;
}
} else {
jack_error ("midiInAddBuffer error");
CloseInput(&fMidiDestination[devindex]);
continue;
}
} else {
jack_error("midiInPrepareHeader error");
midiInClose(handle);
continue;
}
} else {
jack_error ("midiInOpen error");
continue;
jack_nframes_t buffer_size = fEngineControl->fBufferSize;
jack_port_id_t index;
jack_nframes_t latency = buffer_size;
jack_latency_range_t latency_range;
const char *name;
JackPort *port;
latency_range.max = latency;
latency_range.min = latency;

jack_info("JackWinMMEDriver::Attach - fCaptureChannels %d", fCaptureChannels);
jack_info("JackWinMMEDriver::Attach - fPlaybackChannels %d", fPlaybackChannels);

// Inputs
for (int i = 0; i < fCaptureChannels; i++) {
JackWinMMEInputPort *input_port = input_ports[i];
name = input_port->GetName();
index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
JACK_DEFAULT_MIDI_TYPE,
CaptureDriverFlags, buffer_size);
if (index == NO_PORT) {
jack_error("JackWinMMEDriver::Attach - cannot register input port "
"with name '%s'.", name);
// X: Do we need to deallocate ports?
return -1;
}
devindex += 1;
port = fGraphManager->GetPort(index);
port->SetAlias(input_port->GetAlias());
port->SetLatencyRange(JackCaptureLatency, &latency_range);
fCapturePortList[i] = index;
}
fRealCaptureChannels = devindex;
fCaptureChannels = devindex;

fMidiSource = new MidiSlot[fRealPlaybackChannels];
assert(fMidiSource);

// Real output
devindex = 0;
for (int i = 0; i < fRealPlaybackChannels; i++) {
MMRESULT res;
HMIDIOUT handle;
fMidiSource[devindex].fIndex = i;
UINT ret = midiOutOpen(&handle, fMidiSource[devindex].fIndex, 0L, 0L, CALLBACK_NULL);
if (ret == MMSYSERR_NOERROR) {
fMidiSource[devindex].fHandle = handle;
if (!InitHeaders(&fMidiSource[devindex])) {
jack_error("memory allocation failed");
midiOutClose(handle);
continue;
}
res = midiOutPrepareHeader(handle, fMidiSource[devindex].fHeader, sizeof(MIDIHDR));
if (res != MMSYSERR_NOERROR) {
jack_error("midiOutPrepareHeader error %d %d %d", i, handle, res);
continue;
} else {
fMidiSource[devindex].fHeader->dwUser = 1;
}
} else {
jack_error("midiOutOpen error");
continue;

if (! fEngineControl->fSyncMode) {
latency += buffer_size;
latency_range.max = latency;
latency_range.min = latency;
}

// Outputs
for (int i = 0; i < fPlaybackChannels; i++) {
JackWinMMEOutputPort *output_port = output_ports[i];
name = output_port->GetName();
index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
JACK_DEFAULT_MIDI_TYPE,
PlaybackDriverFlags, buffer_size);
if (index == NO_PORT) {
jack_error("JackWinMMEDriver::Attach - cannot register output "
"port with name '%s'.", name);
// X: Do we need to deallocate ports?
return -1;
}
devindex += 1;
port = fGraphManager->GetPort(index);
port->SetAlias(output_port->GetAlias());
port->SetLatencyRange(JackPlaybackLatency, &latency_range);
fPlaybackPortList[i] = index;
}
fRealPlaybackChannels = devindex;
fPlaybackChannels = devindex;

return 0;
}

void JackWinMMEDriver::CloseInput(MidiSlot* slot)
int
JackWinMMEDriver::Close()
{
MMRESULT res;
int retry = 0;

if (slot->fHandle == 0)
return;

HMIDIIN handle = (HMIDIIN)slot->fHandle;
slot->fHeader->dwUser = 0;
res = midiInStop(handle);
if (res != MMSYSERR_NOERROR) {
jack_error("midiInStop error");
}
res = midiInReset(handle);
if (res != MMSYSERR_NOERROR) {
jack_error("midiInReset error");
}
res = midiInUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
if (res != MMSYSERR_NOERROR) {
jack_error("midiInUnprepareHeader error");
int result = JackMidiDriver::Close();
if (input_ports) {
for (int i = 0; i < fCaptureChannels; i++) {
delete input_ports[i];
}
delete[] input_ports;
input_ports = 0;
}
do {
res = midiInClose(handle);
if (res != MMSYSERR_NOERROR) {
jack_error("midiInClose error");
if (output_ports) {
for (int i = 0; i < fPlaybackChannels; i++) {
delete output_ports[i];
}
if (res == MIDIERR_STILLPLAYING)
midiInReset(handle);
Sleep (10);
retry++;
} while ((res == MIDIERR_STILLPLAYING) && (retry < 10));

if (slot->fHeader) {
GlobalFreePtr(slot->fHeader);
delete[] output_ports;
output_ports = 0;
}
return result;
}

void JackWinMMEDriver::CloseOutput(MidiSlot* slot)
int
JackWinMMEDriver::Open(bool capturing, bool playing, int in_channels,
int out_channels, bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency)
{
MMRESULT res;
int retry = 0;

if (slot->fHandle == 0)
return;

HMIDIOUT handle = (HMIDIOUT)slot->fHandle;
res = midiOutReset(handle);
if (res != MMSYSERR_NOERROR)
jack_error("midiOutReset error");
midiOutUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
do {
res = midiOutClose(handle);
if (res != MMSYSERR_NOERROR)
jack_error("midiOutClose error");
Sleep(10);
retry++;
} while ((res == MIDIERR_STILLPLAYING) && (retry < 10));

if (slot->fHeader) {
GlobalFreePtr(slot->fHeader);
const char *client_name = fClientControl.fName;
int input_count = 0;
int output_count = 0;
int num_potential_inputs = midiInGetNumDevs();
int num_potential_outputs = midiOutGetNumDevs();

jack_info("JackWinMMEDriver::Open - num_potential_inputs %d", num_potential_inputs);
jack_info("JackWinMMEDriver::Open - num_potential_outputs %d", num_potential_outputs);

if (num_potential_inputs) {
try {
input_ports = new JackWinMMEInputPort *[num_potential_inputs];
} catch (std::exception e) {
jack_error("JackWinMMEDriver::Open - while creating input port "
"array: %s", e.what());
return -1;
}
for (int i = 0; i < num_potential_inputs; i++) {
try {
input_ports[input_count] =
new JackWinMMEInputPort(fAliasName, client_name,
capture_driver_name, i);
} catch (std::exception e) {
jack_error("JackWinMMEDriver::Open - while creating input "
"port: %s", e.what());
continue;
}
input_count++;
}
}
if (num_potential_outputs) {
try {
output_ports = new JackWinMMEOutputPort *[num_potential_outputs];
} catch (std::exception e) {
jack_error("JackWinMMEDriver::Open - while creating output port "
"array: %s", e.what());
goto destroy_input_ports;
}
for (int i = 0; i < num_potential_outputs; i++) {
try {
output_ports[output_count] =
new JackWinMMEOutputPort(fAliasName, client_name,
playback_driver_name, i);
} catch (std::exception e) {
jack_error("JackWinMMEDriver::Open - while creating output "
"port: %s", e.what());
continue;
}
output_count++;
}
}
}

int JackWinMMEDriver::Close()
{
jack_log("JackWinMMEDriver::Close");
jack_info("JackWinMMEDriver::Open - input_count %d", input_count);
jack_info("JackWinMMEDriver::Open - output_count %d", output_count);

// Generic midi driver close
int res = JackMidiDriver::Close();

// Close input
if (fMidiDestination) {
for (int i = 0; i < fRealCaptureChannels; i++) {
CloseInput(&fMidiDestination[i]);
}
delete[] fMidiDestination;
if (! (input_count || output_count)) {
jack_error("JackWinMMEDriver::Open - no WinMME inputs or outputs "
"allocated.");
} else if (! JackMidiDriver::Open(capturing, playing, input_count,
output_count, monitor,
capture_driver_name,
playback_driver_name, capture_latency,
playback_latency)) {
return 0;
}

// Close output
if (fMidiSource) {
for (int i = 0; i < fRealPlaybackChannels; i++) {
CloseOutput(&fMidiSource[i]);
destroy_input_ports:
if (input_ports) {
for (int i = 0; i < input_count; i++) {
delete input_ports[i];
}
delete[] fMidiSource;
delete[] input_ports;
input_ports = 0;
}

return res;
return -1;
}

int JackWinMMEDriver::Attach()
int
JackWinMMEDriver::Read()
{
JackPort* port;
jack_port_id_t port_index;
char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
MMRESULT res;
int i;

jack_log("JackMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);

for (i = 0; i < fCaptureChannels; i++) {
MIDIINCAPS caps;
res = midiInGetDevCaps(fMidiDestination[i].fIndex, &caps, sizeof(caps));
if (res == MMSYSERR_NOERROR) {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
} else {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
}
snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);

if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, CaptureDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
jack_error("driver: cannot register port for %s", name);
return -1;
}
port = fGraphManager->GetPort(port_index);
port->SetAlias(alias);
fCapturePortList[i] = port_index;
jack_log("JackMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
}

for (i = 0; i < fPlaybackChannels; i++) {
MIDIOUTCAPS caps;
res = midiOutGetDevCaps(fMidiSource[i].fIndex, &caps, sizeof(caps));
if (res == MMSYSERR_NOERROR) {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
} else {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fPlaybackDriverName, i + 1);
}
snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);

if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, PlaybackDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) {
jack_error("driver: cannot register port for %s", name);
return -1;
}
port = fGraphManager->GetPort(port_index);
port->SetAlias(alias);
fPlaybackPortList[i] = port_index;
jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
jack_nframes_t buffer_size = fEngineControl->fBufferSize;
for (int i = 0; i < fCaptureChannels; i++) {
input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
}

return 0;
}

int JackWinMMEDriver::Read()

int
JackWinMMEDriver::Write()
{
size_t size;
/*
jack_nframes_t buffer_size = fEngineControl->fBufferSize;
for (int i = 0; i < fPlaybackChannels; i++) {
output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
}
*/
return 0;
}

for (int chan = 0; chan < fCaptureChannels; chan++) {
int
JackWinMMEDriver::Start()
{
jack_info("JackWinMMEDriver::Start - Starting driver.");

if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) {
JackMidiDriver::Start();

JackMidiBuffer* midi_buffer = GetInputBuffer(chan);
int input_count = 0;
int output_count = 0;

if (jack_ringbuffer_read_space (fRingBuffer[chan]) == 0) {
// Reset buffer
midi_buffer->Reset(midi_buffer->nframes);
} else {
jack_info("JackWinMMEDriver::Start - Enabling input ports.");

while ((size = jack_ringbuffer_read_space (fRingBuffer[chan])) > 0) {
for (; input_count < fCaptureChannels; input_count++) {
if (input_ports[input_count]->Start() < 0) {
jack_error("JackWinMMEDriver::Start - Failed to enable input "
"port.");
goto stop_input_ports;
}
}

//jack_info("jack_ringbuffer_read_space %d", size);
int ev_count = 0;
jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int));
jack_info("JackWinMMEDriver::Start - Enabling output ports.");

if (ev_count > 0) {
for (int j = 0; j < ev_count; j++) {
unsigned int event_len = 3;
// Read event actual data
jack_midi_data_t* dest = midi_buffer->ReserveEvent(0, event_len);
jack_ringbuffer_read(fRingBuffer[chan], (char*)dest, event_len);
}
}
}
}
} else {
//jack_info("Consume ring buffer");
jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan]));
for (; output_count < fPlaybackChannels; output_count++) {
if (output_ports[output_count]->Start() < 0) {
jack_error("JackWinMMEDriver::Start - Failed to enable output "
"port.");
goto stop_output_ports;
}
}

jack_info("JackWinMMEDriver::Start - Driver started.");

return 0;

stop_output_ports:
for (int i = 0; i < output_count; i++) {
if (output_ports[i]->Stop() < 0) {
jack_error("JackWinMMEDriver::Start - Failed to disable output "
"port.");
}
}
stop_input_ports:
for (int i = 0; i < input_count; i++) {
if (input_ports[i]->Stop() < 0) {
jack_error("JackWinMMEDriver::Start - Failed to disable input "
"port.");
}
}

return -1;
}

int JackWinMMEDriver::Write()
int
JackWinMMEDriver::Stop()
{
for (int chan = 0; chan < fPlaybackChannels; chan++) {
int result = 0;

if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) {
jack_info("JackWinMMEDriver::Stop - disabling input ports.");

JackMidiBuffer* midi_buffer = GetOutputBuffer(chan);

// TODO : use timestamp
for (int i = 0; i < fCaptureChannels; i++) {
if (input_ports[i]->Stop() < 0) {
jack_error("JackWinMMEDriver::Stop - Failed to disable input "
"port.");
result = -1;
}
}

for (unsigned int j = 0; j < midi_buffer->event_count; j++) {
JackMidiEvent* ev = &midi_buffer->events[j];
if (ev->size <= 3) {
jack_midi_data_t *d = ev->GetData(midi_buffer);
DWORD winev = 0;
if (ev->size > 0) winev |= d[0];
if (ev->size > 1) winev |= (d[1] << 8);
if (ev->size > 2) winev |= (d[2] << 16);
MMRESULT res = midiOutShortMsg((HMIDIOUT)fMidiSource[chan].fHandle, winev);
if (res != MMSYSERR_NOERROR)
jack_error ("midiOutShortMsg error res %d", res);
} else {
jack_info("JackWinMMEDriver::Stop - disabling output ports.");

}
}
for (int i = 0; i < fPlaybackChannels; i++) {
if (output_ports[i]->Stop() < 0) {
jack_error("JackWinMMEDriver::Stop - Failed to disable output "
"port.");
result = -1;
}
}

return 0;
return result;
}

} // end of namespace

#ifdef __cplusplus
extern "C"
{


+ 31
- 46
windows/winmme/JackWinMMEDriver.h View File

@@ -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

+ 294
- 0
windows/winmme/JackWinMMEInputPort.cpp View File

@@ -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);
}


+ 85
- 0
windows/winmme/JackWinMMEInputPort.h View File

@@ -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

+ 374
- 0
windows/winmme/JackWinMMEOutputPort.cpp View File

@@ -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);
}

+ 89
- 0
windows/winmme/JackWinMMEOutputPort.h View File

@@ -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

+ 68
- 0
windows/winmme/JackWinMMEPort.cpp View File

@@ -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);
}


+ 59
- 0
windows/winmme/JackWinMMEPort.h View File

@@ -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

Loading…
Cancel
Save