From 34ff05a8ca3b3785bb3767f3833b939cc55f9c00 Mon Sep 17 00:00:00 2001 From: sletz Date: Tue, 7 Apr 2009 12:26:59 +0000 Subject: [PATCH] Native MIDI backend (JackCoreMidiDriver, JackWinMMEDriver) in progress. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3498 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 4 + common/JackAudioDriver.cpp | 2 +- common/JackClient.cpp | 4 +- common/JackConnectionManager.cpp | 4 +- common/JackConstants.h | 8 +- common/JackControlAPI.cpp | 21 ++++ common/JackControlAPI.h | 7 ++ common/JackDriver.cpp | 44 ++++++- common/JackDriver.h | 22 ++++ common/JackDriverLoader.cpp | 5 +- common/JackDriverLoader.h | 6 + common/JackMidiDriver.cpp | 7 +- common/JackMidiDriver.h | 5 +- common/JackMidiPort.cpp | 6 +- common/JackMidiPort.h | 3 +- common/JackServer.cpp | 62 ++++++---- common/JackServer.h | 6 +- common/JackThreadedDriver.h | 13 ++ common/Jackdmp.cpp | 78 ++++++++---- common/jack/control.h | 8 ++ common/wscript | 2 +- example-clients/midisine.c | 20 ++-- macosx/coremidi/JackCoreMidiDriver.cpp | 97 +++++++++++++-- macosx/coremidi/JackCoreMidiDriver.h | 4 +- macosx/wscript | 17 +++ windows/winmme/JackWinMMEDriver.cpp | 158 ++++++++++++------------- windows/winmme/JackWinMMEDriver.h | 58 +++++---- 27 files changed, 456 insertions(+), 215 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9cebbb23..b749c620 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,10 @@ Paul Davis Jackdmp changes log --------------------------- +2009-04-08 Stephane Letz + + * Native MIDI backend (JackCoreMidiDriver, JackWinMMEDriver) in progress. + 2009-04-03 Stephane Letz * Simplify JackClient RT code, jack_thread_wait API marked deprecated." diff --git a/common/JackAudioDriver.cpp b/common/JackAudioDriver.cpp index 943571f0..fc753123 100644 --- a/common/JackAudioDriver.cpp +++ b/common/JackAudioDriver.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2001 Paul Davis -Copyright (C) 2004-2008 GramefClientControl. +Copyright (C) 2004-2008 Grame. 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 diff --git a/common/JackClient.cpp b/common/JackClient.cpp index 310b3c78..5bc45334 100644 --- a/common/JackClient.cpp +++ b/common/JackClient.cpp @@ -120,12 +120,12 @@ void JackClient::SetupDriverSync(bool freewheel) jack_log("JackClient::SetupDriverSync driver sem in flush mode"); fSynchroTable[AUDIO_DRIVER_REFNUM].SetFlush(true); fSynchroTable[FREEWHEEL_DRIVER_REFNUM].SetFlush(true); - fSynchroTable[LOOPBACK_DRIVER_REFNUM].SetFlush(true); + fSynchroTable[MIDI_DRIVER_REFNUM].SetFlush(true); } else { jack_log("JackClient::SetupDriverSync driver sem in normal mode"); fSynchroTable[AUDIO_DRIVER_REFNUM].SetFlush(false); fSynchroTable[FREEWHEEL_DRIVER_REFNUM].SetFlush(false); - fSynchroTable[LOOPBACK_DRIVER_REFNUM].SetFlush(false); + fSynchroTable[MIDI_DRIVER_REFNUM].SetFlush(false); } } diff --git a/common/JackConnectionManager.cpp b/common/JackConnectionManager.cpp index 5108ddcd..08fa92ca 100644 --- a/common/JackConnectionManager.cpp +++ b/common/JackConnectionManager.cpp @@ -58,8 +58,8 @@ bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const || ref2 == AUDIO_DRIVER_REFNUM || ref1 == FREEWHEEL_DRIVER_REFNUM || ref2 == FREEWHEEL_DRIVER_REFNUM - || ref1 == LOOPBACK_DRIVER_REFNUM - || ref2 == LOOPBACK_DRIVER_REFNUM) { + || ref1 == MIDI_DRIVER_REFNUM + || ref2 == MIDI_DRIVER_REFNUM) { return false; } else if (ref1 == ref2) { // Same refnum return true; diff --git a/common/JackConstants.h b/common/JackConstants.h index 5d4a136e..fbc552a7 100644 --- a/common/JackConstants.h +++ b/common/JackConstants.h @@ -47,10 +47,10 @@ #define CLIENT_NUM 64 #endif -#define AUDIO_DRIVER_REFNUM 0 // Audio driver is initialized first, it will get the refnum 0 -#define FREEWHEEL_DRIVER_REFNUM 1 // Freewheel driver is initialized second, it will get the refnum 1 -#define LOOPBACK_DRIVER_REFNUM 2 // Loopback driver is initialized third, it will get the refnum 2 -#define REAL_REFNUM LOOPBACK_DRIVER_REFNUM + 1 // Real clients start at LOOPBACK_DRIVER_REFNUM + 1 +#define AUDIO_DRIVER_REFNUM 0 // Audio driver is initialized first, it will get the refnum 0 +#define FREEWHEEL_DRIVER_REFNUM 1 // Freewheel driver is initialized second, it will get the refnum 1 +#define MIDI_DRIVER_REFNUM 2 // Loopback driver is initialized third, it will get the refnum 2 +#define REAL_REFNUM MIDI_DRIVER_REFNUM + 1 // Real clients start at MIDI_DRIVER_REFNUM + 1 #define JACK_DEFAULT_SERVER_NAME "default" diff --git a/common/JackControlAPI.cpp b/common/JackControlAPI.cpp index 0bec8906..8a0a36b6 100644 --- a/common/JackControlAPI.cpp +++ b/common/JackControlAPI.cpp @@ -42,6 +42,7 @@ #include "JackControlAPI.h" #include "JackLockedEngine.h" #include "JackConstants.h" +#include "JackDriverLoader.h" using namespace Jack; @@ -95,6 +96,7 @@ struct jackctl_driver jack_driver_desc_t * desc_ptr; JSList * parameters; JSList * set_parameters; + JackDriverInfo* info; }; struct jackctl_internal @@ -1161,4 +1163,23 @@ EXPORT bool jackctl_server_unload_internal( } } +EXPORT bool jackctl_server_load_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) +{ + if (server_ptr->engine != NULL) { + driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); + return (driver_ptr->info != 0); + } else { + return false; + } +} + +EXPORT bool jackctl_server_unload_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) +{ + if (server_ptr->engine != NULL) { + server_ptr->engine->RemoveSlave(driver_ptr->info); + return true; + } else { + return false; + } +} diff --git a/common/JackControlAPI.h b/common/JackControlAPI.h index 7fc73243..54be6f3f 100644 --- a/common/JackControlAPI.h +++ b/common/JackControlAPI.h @@ -219,6 +219,13 @@ EXPORT bool jackctl_server_load_internal( EXPORT bool jackctl_server_unload_internal( jackctl_server * server, jackctl_internal * internal); + +EXPORT bool jackctl_server_load_slave(jackctl_server_t * server, + jackctl_driver_t * driver); + +EXPORT bool jackctl_server_unload_slave(jackctl_server_t * server, + jackctl_driver_t * driver); + #if 0 { /* Adjust editor indent */ diff --git a/common/JackDriver.cpp b/common/JackDriver.cpp index 682b6f78..f5098771 100644 --- a/common/JackDriver.cpp +++ b/common/JackDriver.cpp @@ -68,7 +68,7 @@ int JackDriver::Open() int refnum = -1; if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) { - jack_error("Cannot allocate internal client for audio driver"); + jack_error("Cannot allocate internal client for driver"); return -1; } @@ -79,6 +79,46 @@ int JackDriver::Open() return 0; } +int JackDriver::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) +{ + jack_log("JackDriver::Open capture_driver_name = %s", capture_driver_name); + jack_log("JackDriver::Open playback_driver_name = %s", playback_driver_name); + int refnum = -1; + + if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) { + jack_error("Cannot allocate internal client for driver"); + return -1; + } + + fClientControl.fRefNum = refnum; + fClientControl.fActive = true; + fCaptureLatency = capture_latency; + fPlaybackLatency = playback_latency; + + assert(strlen(capture_driver_name) < JACK_CLIENT_NAME_SIZE); + assert(strlen(playback_driver_name) < JACK_CLIENT_NAME_SIZE); + + strcpy(fCaptureDriverName, capture_driver_name); + strcpy(fPlaybackDriverName, playback_driver_name); + + fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // in microsec + if (!fEngineControl->fTimeOut) + fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs); + + //fGraphManager->SetBufferSize(fEngineControl->fBufferSize); + fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode + SetupDriverSync(fClientControl.fRefNum, false); + return 0; +} + int JackDriver::Open(jack_nframes_t buffer_size, jack_nframes_t samplerate, bool capturing, @@ -96,7 +136,7 @@ int JackDriver::Open(jack_nframes_t buffer_size, int refnum = -1; if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) { - jack_error("Cannot allocate internal client for audio driver"); + jack_error("Cannot allocate internal client for driver"); return -1; } diff --git a/common/JackDriver.h b/common/JackDriver.h index a6027905..9c99d7c4 100644 --- a/common/JackDriver.h +++ b/common/JackDriver.h @@ -50,6 +50,17 @@ class SERVER_EXPORT JackDriverInterface {} virtual int Open() = 0; + + virtual int 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) = 0; + virtual int Open(jack_nframes_t buffer_size, jack_nframes_t samplerate, bool capturing, @@ -142,6 +153,17 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface int ProcessSlaves(); virtual int Open(); + + virtual int 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); + virtual int Open(jack_nframes_t buffer_size, jack_nframes_t samplerate, bool capturing, diff --git a/common/JackDriverLoader.cpp b/common/JackDriverLoader.cpp index 37ac7479..52c4aeed 100644 --- a/common/JackDriverLoader.cpp +++ b/common/JackDriverLoader.cpp @@ -800,7 +800,8 @@ Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver jack_error("no initialize function in shared object %s\n", driver_desc->file); return NULL; } - - return fInitialize(engine, synchro, params); + + fBackend = fInitialize(engine, synchro, params); + return fBackend; } diff --git a/common/JackDriverLoader.h b/common/JackDriverLoader.h index c72183ac..f68fb041 100644 --- a/common/JackDriverLoader.h +++ b/common/JackDriverLoader.h @@ -42,6 +42,7 @@ class JackDriverInfo driverInitialize fInitialize; DRIVER_HANDLE fHandle; + Jack::JackDriverClientInterface* fBackend; public: @@ -54,6 +55,11 @@ class JackDriverInfo } Jack::JackDriverClientInterface* Open(jack_driver_desc_t* driver_desc, Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*); + + Jack::JackDriverClientInterface* GetBackend() + { + return fBackend; + } }; diff --git a/common/JackMidiDriver.cpp b/common/JackMidiDriver.cpp index 11c92c99..b5bfd4c4 100644 --- a/common/JackMidiDriver.cpp +++ b/common/JackMidiDriver.cpp @@ -24,7 +24,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackEngineControl.h" #include "JackPort.h" #include "JackGraphManager.h" -#include "JackLockedEngine.h" #include "JackException.h" #include @@ -49,9 +48,7 @@ JackMidiDriver::~JackMidiDriver() } } -int JackMidiDriver::Open(jack_nframes_t buffer_size, - jack_nframes_t samplerate, - bool capturing, +int JackMidiDriver::Open(bool capturing, bool playing, int inchannels, int outchannels, @@ -68,7 +65,7 @@ int JackMidiDriver::Open(jack_nframes_t buffer_size, fRingBuffer[i] = jack_ringbuffer_create(sizeof(float) * BUFFER_SIZE_MAX); } - return JackDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency); + return JackDriver::Open(capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency); } int JackMidiDriver::Attach() diff --git a/common/JackMidiDriver.h b/common/JackMidiDriver.h index 23848467..7c5bc5e0 100644 --- a/common/JackMidiDriver.h +++ b/common/JackMidiDriver.h @@ -22,6 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackDriver.h" #include "JackMidiPort.h" +#include "JackLockedEngine.h" #include "ringbuffer.h" namespace Jack @@ -52,9 +53,7 @@ class SERVER_EXPORT JackMidiDriver : public JackDriver JackMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); virtual ~JackMidiDriver(); - virtual int Open(jack_nframes_t buffer_size, - jack_nframes_t samplerate, - bool capturing, + virtual int Open(bool capturing, bool playing, int inchannels, int outchannels, diff --git a/common/JackMidiPort.cpp b/common/JackMidiPort.cpp index 41dcb151..fb933c85 100644 --- a/common/JackMidiPort.cpp +++ b/common/JackMidiPort.cpp @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. namespace Jack { -void JackMidiBuffer::Reset(jack_nframes_t nframes) +SERVER_EXPORT void JackMidiBuffer::Reset(jack_nframes_t nframes) { /* This line ate 1 hour of my life... dsbaikov */ this->nframes = nframes; @@ -37,7 +37,7 @@ void JackMidiBuffer::Reset(jack_nframes_t nframes) mix_index = 0; } -jack_shmsize_t JackMidiBuffer::MaxEventSize() const +SERVER_EXPORT jack_shmsize_t JackMidiBuffer::MaxEventSize() const { assert (((jack_shmsize_t) - 1) < 0); // jack_shmsize_t should be signed jack_shmsize_t left = buffer_size - (sizeof(JackMidiBuffer) + sizeof(JackMidiEvent) * (event_count + 1) + write_pos); @@ -48,7 +48,7 @@ jack_shmsize_t JackMidiBuffer::MaxEventSize() const return left; } -jack_midi_data_t* JackMidiBuffer::ReserveEvent(jack_nframes_t time, jack_shmsize_t size) +SERVER_EXPORT jack_midi_data_t* JackMidiBuffer::ReserveEvent(jack_nframes_t time, jack_shmsize_t size) { jack_shmsize_t space = MaxEventSize(); if (space == 0 || size > space) { diff --git a/common/JackMidiPort.h b/common/JackMidiPort.h index 0b22944c..0dbfcb9a 100644 --- a/common/JackMidiPort.h +++ b/common/JackMidiPort.h @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "types.h" #include "JackConstants.h" +#include "JackPlatformPlug.h" #include /** Type for raw event data contained in @ref jack_midi_event_t. */ @@ -42,7 +43,7 @@ struct jack_midi_event_t namespace Jack { -struct JackMidiEvent +struct SERVER_EXPORT JackMidiEvent { // Most MIDI events are < 4 bytes in size, so we can save a lot, storing them inplace. enum { INLINE_SIZE_MAX = sizeof(jack_shmsize_t) }; diff --git a/common/JackServer.cpp b/common/JackServer.cpp index 8dcf2bfb..77c80121 100644 --- a/common/JackServer.cpp +++ b/common/JackServer.cpp @@ -22,7 +22,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackServerGlobals.h" #include "JackTime.h" #include "JackFreewheelDriver.h" -#include "JackLoopbackDriver.h" +#ifdef __APPLE__ +#include "macosx/coremidi/JackCoreMidiDriver.h" +#else +#include "JackMidiDriver.h" +#endif #include "JackThreadedDriver.h" #include "JackGlobals.h" #include "JackLockedEngine.h" @@ -50,10 +54,8 @@ JackServer::JackServer(bool sync, bool temporary, long timeout, bool rt, long pr fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, server_name); fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl); fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver(fEngine, GetSynchroTable())); - fLoopbackDriver = new JackLoopbackDriver(fEngine, GetSynchroTable()); fAudioDriver = NULL; fFreewheel = false; - fLoopback = loopback; JackServerGlobals::fInstance = this; // Unique instance JackServerGlobals::fUserCount = 1; // One user jack_verbose = verbose; @@ -64,7 +66,6 @@ JackServer::~JackServer() delete fGraphManager; delete fAudioDriver; delete fFreewheelDriver; - delete fLoopbackDriver; delete fEngine; delete fEngineControl; } @@ -94,35 +95,17 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params) goto fail_close4; } - if (fLoopbackDriver->Open(fEngineControl->fBufferSize, fEngineControl->fSampleRate, 1, 1, fLoopback, fLoopback, false, "loopback", "loopback", 0, 0) != 0) { - jack_error("Cannot open driver"); - goto fail_close5; - } - if (fAudioDriver->Attach() != 0) { jack_error("Cannot attach audio driver"); - goto fail_close6; - } - - if (fLoopback > 0 && fLoopbackDriver->Attach() != 0) { - jack_error("Cannot attach loopback driver"); - goto fail_close7; + goto fail_close5; } fFreewheelDriver->SetMaster(false); fAudioDriver->SetMaster(true); - if (fLoopback > 0) - fAudioDriver->AddSlave(fLoopbackDriver); fAudioDriver->AddSlave(fFreewheelDriver); // After ??? InitTime(); return 0; - -fail_close7: - fAudioDriver->Detach(); -fail_close6: - fLoopbackDriver->Close(); - fail_close5: fFreewheelDriver->Close(); @@ -145,11 +128,8 @@ int JackServer::Close() jack_log("JackServer::Close"); fChannel.Close(); fAudioDriver->Detach(); - if (fLoopback > 0) - fLoopbackDriver->Detach(); fAudioDriver->Close(); fFreewheelDriver->Close(); - fLoopbackDriver->Close(); fEngine->Close(); // TODO: move that in reworked JackServerGlobals::Destroy() JackMessageBuffer::Destroy(); @@ -305,6 +285,36 @@ void JackServer::ClientKill(int refnum) } } +//---------------------- +// Backend management +//---------------------- + +JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params) +{ + JackDriverInfo* info = new JackDriverInfo(); + JackDriverClientInterface* backend = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params); + if (backend == NULL) { + delete info; + return NULL; + } else { + //Stop(); + backend->Attach(); + fAudioDriver->AddSlave(backend); + //Start(); + return info; + } +} + +void JackServer::RemoveSlave(JackDriverInfo* info) +{ + JackDriverClientInterface* backend = info->GetBackend(); + //Stop(); + fAudioDriver->RemoveSlave(info->GetBackend()); + backend->Detach(); + backend->Close(); + //Start(); +} + //---------------------- // Transport management //---------------------- diff --git a/common/JackServer.h b/common/JackServer.h index d802965a..fb88101a 100644 --- a/common/JackServer.h +++ b/common/JackServer.h @@ -50,7 +50,6 @@ class SERVER_EXPORT JackServer JackDriverInfo fDriverInfo; JackDriverClientInterface* fAudioDriver; JackDriverClientInterface* fFreewheelDriver; - JackDriverClientInterface* fLoopbackDriver; JackLockedEngine* fEngine; JackEngineControl* fEngineControl; JackGraphManager* fGraphManager; @@ -58,7 +57,6 @@ class SERVER_EXPORT JackServer JackConnectionManager fConnectionState; JackSynchro fSynchroTable[CLIENT_NUM]; bool fFreewheel; - long fLoopback; int InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int* status); @@ -86,6 +84,10 @@ class SERVER_EXPORT JackServer // Transport management int ReleaseTimebase(int refnum); int SetTimebaseCallback(int refnum, int conditional); + + // Backend management + JackDriverInfo* AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params); + void RemoveSlave(JackDriverInfo* info); // Object access JackLockedEngine* GetEngine(); diff --git a/common/JackThreadedDriver.h b/common/JackThreadedDriver.h index abd9f0d4..8705e2c4 100644 --- a/common/JackThreadedDriver.h +++ b/common/JackThreadedDriver.h @@ -45,6 +45,19 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi virtual ~JackThreadedDriver(); virtual int Open(); + + virtual int 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) + { + return -1; + } virtual int Open(jack_nframes_t buffer_size, jack_nframes_t samplerate, bool capturing, diff --git a/common/Jackdmp.cpp b/common/Jackdmp.cpp index feedff80..b3110b9d 100644 --- a/common/Jackdmp.cpp +++ b/common/Jackdmp.cpp @@ -95,14 +95,14 @@ static void usage(FILE* file) "usage: jackdmp [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n" " [ --name OR -n server-name ]\n" " [ --timeout OR -t client-timeout-in-msecs ]\n" - " [ --loopback OR -L loopback-port-number ]\n" + " [ --loopback OR -X midi-driver ]\n" " [ --verbose OR -v ]\n" " [ --replace-registry OR -r ]\n" " [ --silent OR -s ]\n" " [ --sync OR -S ]\n" " [ --temporary OR -T ]\n" " [ --version OR -V ]\n" - " -d driver [ ... driver args ... ]\n" + " -d audio-driver [ ... driver args ... ]\n" " where driver can be `alsa', `coreaudio', 'portaudio' or `dummy'\n" " jackdmp -d driver --help\n" " to display options for each driver\n\n"); @@ -154,10 +154,12 @@ int main(int argc, char* argv[]) jackctl_server_t * server_ctl; const JSList * server_parameters; const char* server_name = "default"; - jackctl_driver_t * driver_ctl; - const char *options = "-ad:P:uvrshVRL:STFl:t:mn:p:"; + jackctl_driver_t * audio_driver_ctl; + jackctl_driver_t * midi_driver_ctl; + const char *options = "-ad:X:P:uvrshVRL:STFl:t:mn:p:"; struct option long_options[] = { - { "driver", 1, 0, 'd' }, + { "audio-driver", 1, 0, 'd' }, + { "midi-driver", 1, 0, 'X' }, { "verbose", 0, 0, 'v' }, { "help", 0, 0, 'h' }, { "port-max", 1, 0, 'p' }, @@ -177,10 +179,14 @@ int main(int argc, char* argv[]) }; int i,opt = 0; int option_index = 0; - bool seen_driver = false; - char *driver_name = NULL; - char **driver_args = NULL; - int driver_nargs = 1; + bool seen_audio_driver = false; + bool seen_midi_driver = false; + char *audio_driver_name = NULL; + char **audio_driver_args = NULL; + int audio_driver_nargs = 1; + char *midi_driver_name = NULL; + char **midi_driver_args = NULL; + int midi_driver_nargs = 1; int port_max = 512; int do_mlock = 1; int do_unlock = 0; @@ -200,14 +206,19 @@ int main(int argc, char* argv[]) server_parameters = jackctl_server_get_parameters(server_ctl); opterr = 0; - while (!seen_driver && + while (!seen_audio_driver && (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { switch (opt) { case 'd': - seen_driver = true; - driver_name = optarg; + seen_audio_driver = true; + audio_driver_name = optarg; + break; + + case 'X': + seen_midi_driver = true; + midi_driver_name = optarg; break; case 'p': @@ -306,6 +317,7 @@ int main(int argc, char* argv[]) default: fprintf(stderr, "unknown option character %c\n", optopt); /*fallthru*/ + case 'h': usage(stdout); goto fail_free; @@ -320,45 +332,59 @@ int main(int argc, char* argv[]) return -1; } - if (!seen_driver) { + if (!seen_audio_driver) { usage(stderr); goto fail_free; } - - driver_ctl = jackctl_server_get_driver(server_ctl, driver_name); - if (driver_ctl == NULL) { - fprintf(stderr, "Unkown driver \"%s\"\n", driver_name); + + // Audio driver + audio_driver_ctl = jackctl_server_get_driver(server_ctl, audio_driver_name); + if (audio_driver_ctl == NULL) { + fprintf(stderr, "Unkown driver \"%s\"\n", audio_driver_name); goto fail_free; } if (optind < argc) { - driver_nargs = 1 + argc - optind; + audio_driver_nargs = 1 + argc - optind; } else { - driver_nargs = 1; + audio_driver_nargs = 1; } - if (driver_nargs == 0) { + if (audio_driver_nargs == 0) { fprintf(stderr, "No driver specified ... hmm. JACK won't do" " anything when run like this.\n"); goto fail_free; } - driver_args = (char **) malloc(sizeof(char *) * driver_nargs); - driver_args[0] = driver_name; + audio_driver_args = (char **) malloc(sizeof(char *) * audio_driver_nargs); + audio_driver_args[0] = audio_driver_name; - for (i = 1; i < driver_nargs; i++) { - driver_args[i] = argv[optind++]; + for (i = 1; i < audio_driver_nargs; i++) { + audio_driver_args[i] = argv[optind++]; } - if (jackctl_parse_driver_params(driver_ctl, driver_nargs, driver_args)) { + if (jackctl_parse_driver_params(audio_driver_ctl, audio_driver_nargs, audio_driver_args)) { goto fail_free; } - if (!jackctl_server_start(server_ctl, driver_ctl)) { + // Start server + if (!jackctl_server_start(server_ctl, audio_driver_ctl)) { fprintf(stderr, "Failed to start server\n"); goto fail_free; } + // MIDI driver + if (seen_midi_driver) { + + midi_driver_ctl = jackctl_server_get_driver(server_ctl, midi_driver_name); + if (midi_driver_ctl == NULL) { + fprintf(stderr, "Unkown driver \"%s\"\n", midi_driver_name); + goto fail_free; + } + + jackctl_server_load_slave(server_ctl, midi_driver_ctl); + } + notify_server_start(server_name); // Waits for signal diff --git a/common/jack/control.h b/common/jack/control.h index 17436f07..87d62e72 100644 --- a/common/jack/control.h +++ b/common/jack/control.h @@ -510,6 +510,14 @@ jack_log( /* @} */ +bool +jackctl_server_load_slave(jackctl_server_t * server, + jackctl_driver_t * driver); + +bool +jackctl_server_unload_slave(jackctl_server_t * server, + jackctl_driver_t * driver); + #if 0 { /* Adjust editor indent */ #endif diff --git a/common/wscript b/common/wscript index 9f245a77..f0d9150b 100644 --- a/common/wscript +++ b/common/wscript @@ -171,7 +171,7 @@ def build(bld): serverlib.env.append_value("CPPFLAGS", "-fvisibility=hidden") serverlib.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc") #serverlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework vecLib -single_module -arch i386 -arch ppc") - serverlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework vecLib -single_module") + serverlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework CoreFoundation -framework vecLib -single_module") serverlib.env.append_value("LINKFLAGS", "-compatibility_version 1 -current_version 1") if bld.env['IS_SUN']: diff --git a/example-clients/midisine.c b/example-clients/midisine.c index 38299138..89ff7f75 100644 --- a/example-clients/midisine.c +++ b/example-clients/midisine.c @@ -71,17 +71,21 @@ static int process(jack_nframes_t nframes, void *arg) /* printf("1st byte of 1st event addr is %p\n", in_events[0].buffer);*/ } jack_midi_event_get(&in_event, port_buf, 0); - for(i=0; i #include #include @@ -90,18 +93,16 @@ JackCoreMidiDriver::JackCoreMidiDriver(const char* name, const char* alias, Jack JackCoreMidiDriver::~JackCoreMidiDriver() {} -int JackCoreMidiDriver::Open(jack_nframes_t buffer_size, - jack_nframes_t samplerate, - 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 JackCoreMidiDriver::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) + { OSStatus err; CFStringRef coutputStr; std::string str; @@ -111,7 +112,7 @@ int JackCoreMidiDriver::Open(jack_nframes_t buffer_size, fRealPlaybackChannels = MIDIGetNumberOfDestinations(); // Generic JackMidiDriver Open - if (JackMidiDriver::Open(buffer_size, samplerate, capturing, playing, inchannels + fRealCaptureChannels, outchannels + fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) + if (JackMidiDriver::Open(capturing, playing, inchannels + fRealCaptureChannels, outchannels + fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) return -1; coutputStr = CFStringCreateWithCString(0, "JackMidi", CFStringGetSystemEncoding()); @@ -352,4 +353,74 @@ int JackCoreMidiDriver::Write() } // end of namespace +#ifdef __cplusplus +extern "C" +{ +#endif + + SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor() + { + jack_driver_desc_t * desc; + unsigned int i; + + desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t)); + strcpy(desc->name, "coremidi"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 + strcpy(desc->desc, "Apple CoreMIDI API based MIDI backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 + + desc->nparams = 2; + desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); + + i = 0; + strcpy(desc->params[i].name, "inchannels"); + desc->params[i].character = 'i'; + desc->params[i].type = JackDriverParamInt; + desc->params[i].value.ui = 0; + strcpy(desc->params[i].short_desc, "CoreMIDI virtual bus"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + i++; + strcpy(desc->params[i].name, "outchannels"); + desc->params[i].character = 'o'; + desc->params[i].type = JackDriverParamInt; + desc->params[i].value.ui = 0; + strcpy(desc->params[i].short_desc, "CoreMIDI virtual bus"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + + return desc; + } + + SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) + { + const JSList * node; + const jack_driver_param_t * param; + int virtual_in = 0; + int virtual_out = 0; + + for (node = params; node; node = jack_slist_next (node)) { + param = (const jack_driver_param_t *) node->data; + + switch (param->character) { + + case 'i': + virtual_in = param->value.ui; + break; + + case 'o': + virtual_out = param->value.ui; + break; + } + } + + Jack::JackDriverClientInterface* driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table); + if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) { + return driver; + } else { + delete driver; + return NULL; + } + } + +#ifdef __cplusplus +} +#endif diff --git a/macosx/coremidi/JackCoreMidiDriver.h b/macosx/coremidi/JackCoreMidiDriver.h index 0025d2a9..190e9cd2 100644 --- a/macosx/coremidi/JackCoreMidiDriver.h +++ b/macosx/coremidi/JackCoreMidiDriver.h @@ -57,9 +57,7 @@ class JackCoreMidiDriver : public JackMidiDriver JackCoreMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); virtual ~JackCoreMidiDriver(); - int Open(jack_nframes_t buffer_size, - jack_nframes_t samplerate, - bool capturing, + int Open( bool capturing, bool playing, int chan_in, int chan_out, diff --git a/macosx/wscript b/macosx/wscript index a67869c0..198edef6 100644 --- a/macosx/wscript +++ b/macosx/wscript @@ -30,6 +30,21 @@ def create_jack_audio_driver_obj(bld, target, sources, uselib = None): driver.uselib = uselib return driver +def create_jack_midi_driver_obj(bld, target, sources, uselib = None): + driver = bld.new_task_gen('cxx', 'shlib') + driver.features.append('cc') + driver.env['shlib_PATTERN'] = 'jack_%s.so' + driver.defines = 'HAVE_CONFIG_H' + driver.includes = ['.', '../macosx', '../posix', '../common', '../common/jack'] + driver.target = target + driver.source = sources + driver.install_path = '${ADDON_DIR}/' + driver.uselib_local = 'serverlib' + driver.env.append_value("LINKFLAGS", "-framework CoreMIDI -framework CoreServices -framework AudioUnit") + if uselib: + driver.uselib = uselib + return driver + def build(bld): jackd = bld.new_task_gen('cxx', 'program') jackd.includes = ['.', '../macosx', '../posix', '../common', '../common/jack'] @@ -43,6 +58,8 @@ def build(bld): create_jack_driver_obj(bld, 'dummy', '../common/JackDummyDriver.cpp') create_jack_audio_driver_obj(bld, 'coreaudio', 'coreaudio/JackCoreAudioDriver.cpp') + + create_jack_midi_driver_obj(bld, 'coremidi', 'coremidi/JackCoreMidiDriver.cpp') portaudio_src = [ '../windows/JackPortAudioDriver.cpp', diff --git a/windows/winmme/JackWinMMEDriver.cpp b/windows/winmme/JackWinMMEDriver.cpp index 49a12dca..42577633 100644 --- a/windows/winmme/JackWinMMEDriver.cpp +++ b/windows/winmme/JackWinMMEDriver.cpp @@ -1,37 +1,37 @@ -/* -Copyright (C) 2009 Grame - -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 "JackWinMMEDriver.h" -#include "JackGraphManager.h" +/* +Copyright (C) 2009 Grame + +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 "JackWinMMEDriver.h" +#include "JackGraphManager.h" #include "JackEngineControl.h" #include "JackDriverLoader.h" - -#include -#include -#include + +#include +#include +#include #include #include #include -#include - -namespace Jack +#include + +namespace Jack { static bool InitHeaders(MidiSlot* slot) @@ -80,29 +80,29 @@ void CALLBACK JackWinMMEDriver::MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD use break; } } - -JackWinMMEDriver::JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) + +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(jack_nframes_t buffer_size, - jack_nframes_t samplerate, - 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) + fMidiDestination(NULL) +{} + +JackWinMMEDriver::~JackWinMMEDriver() +{} + +int JackWinMMEDriver::Open(jack_nframes_t buffer_size, + jack_nframes_t samplerate, + 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) { jack_log("JackWinMMEDriver::Open"); @@ -190,12 +190,12 @@ int JackWinMMEDriver::Open(jack_nframes_t buffer_size, goto error; } } - - return 0; - -error: - Close(); - return -1; + + return 0; + +error: + Close(); + return -1; } void JackWinMMEDriver::CloseInput(MidiSlot* slot) @@ -260,9 +260,9 @@ void JackWinMMEDriver::CloseOutput(MidiSlot* slot) if (slot->fHeader) { GlobalFreePtr(slot->fHeader); } -} - -int JackWinMMEDriver::Close() +} + +int JackWinMMEDriver::Close() { jack_log("JackWinMMEDriver::Close"); @@ -281,9 +281,9 @@ int JackWinMMEDriver::Close() } delete[] fMidiSource; } - - return 0; -} + + return 0; +} int JackWinMMEDriver::Attach() { @@ -341,8 +341,8 @@ int JackWinMMEDriver::Attach() return 0; } - -int JackWinMMEDriver::Read() + +int JackWinMMEDriver::Read() { size_t size; @@ -377,11 +377,11 @@ int JackWinMMEDriver::Read() //jack_info("Consume ring buffer"); jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan])); } - } - return 0; -} - -int JackWinMMEDriver::Write() + } + return 0; +} + +int JackWinMMEDriver::Write() { for (int chan = 0; chan < fPlaybackChannels; chan++) { @@ -403,10 +403,10 @@ int JackWinMMEDriver::Write() } } } - - return 0; -} - + + return 0; +} + } // end of namespace #ifdef __cplusplus @@ -414,7 +414,8 @@ extern "C" { #endif - SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor () { + SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor() + { jack_driver_desc_t * desc; unsigned int i; @@ -428,11 +429,8 @@ extern "C" return desc; } - SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) { - - - jack_nframes_t sample_rate = 48000; - jack_nframes_t period_size = 1024; + SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) + { /* unsigned int capture_ports = 2; unsigned int playback_ports = 2; @@ -474,7 +472,7 @@ extern "C" */ Jack::JackDriverClientInterface* driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table); - if (driver->Open(period_size, sample_rate, 1, 1, 0, 0, false, "in", "out", 0, 0) == 0) { + if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) { return driver; } else { delete driver; @@ -485,8 +483,8 @@ extern "C" #ifdef __cplusplus } #endif - - + + /* jack_connect system:midi_capture_1 system_midi:playback_1 jack_connect system:midi_capture_1 system_midi:playback_2 @@ -500,8 +498,6 @@ jack_connect system:midi_capture_1 system_midi:playback_1 jack_connect system_midi:capture_1 system:midi_playback_1 jack_connect system_midi:capture_2 system:midi_playback_1 - jack_connect system_midi:capture_1 system_midi:playback_1 - */ diff --git a/windows/winmme/JackWinMMEDriver.h b/windows/winmme/JackWinMMEDriver.h index e4da94cf..6c28a0ef 100644 --- a/windows/winmme/JackWinMMEDriver.h +++ b/windows/winmme/JackWinMMEDriver.h @@ -28,35 +28,35 @@ 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) - {} - -}; +*/ + +#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: - - int fRealCaptureChannels; - int fRealPlaybackChannels; - - MidiSlot* fMidiSource; - MidiSlot* fMidiDestination; - - void CloseInput(MidiSlot* slot); - void CloseOutput(MidiSlot* slot); - + private: + + int fRealCaptureChannels; + int fRealPlaybackChannels; + + MidiSlot* fMidiSource; + MidiSlot* fMidiDestination; + + void CloseInput(MidiSlot* slot); + void CloseOutput(MidiSlot* slot); + static void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2); public: @@ -64,9 +64,7 @@ class JackWinMMEDriver : public JackMidiDriver JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); virtual ~JackWinMMEDriver(); - int Open(jack_nframes_t buffer_size, - jack_nframes_t samplerate, - bool capturing, + int Open(bool capturing, bool playing, int chan_in, int chan_out, @@ -75,8 +73,8 @@ class JackWinMMEDriver : public JackMidiDriver const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency); - int Close(); - + int Close(); + int Attach(); int Read();