diff --git a/ChangeLog b/ChangeLog index 06afa7d8..d80e2903 100644 --- a/ChangeLog +++ b/ChangeLog @@ -34,6 +34,31 @@ Valerio Pilo Jackdmp changes log --------------------------- +2011-04-04 Stephane Letz + + * Correct driver lifetime management. + +2011-04-03 Stephane Letz + + * Fix in JackCoreAudioDriver::Read when there is no inputs. + +2011-04-02 Stephane Letz + + * Netdriver can now ask for in/out values from the master (in progress). + * Correct drivers parameter settings. + +2011-04-01 Stephane Letz + + * Merge newer-midi branch (Devin Anderson redesign of the MIDI drivers: alsarawmidi, ffado, coremidi and winmme). + * Cleanup JackThreadedDriver::Stop. + * Correct JackNetOneDriver::Close. + * Correction in jackdmp.cpp: notify_server_stop should be done after server destruction. + * Improve error management in JackNetDriver. + +2011-03-30 Stephane Letz + + * Version 1.9.8 started. + 2011-03-29 Stephane Letz * Synchronize JackWeakAPI.cpp with new APIs. diff --git a/README b/README index b9a0a533..1b35ab15 100644 --- a/README +++ b/README @@ -20,7 +20,7 @@ The audible result of this mode is that if a client is not activated during one Linux version -------------- -The published version still uses fifos for server/client synchronization. The use of POSIX named semaphore is implemented but still a bit unstable. Sockets are used for server/client communications. The ALSA backend derived from jackd implementation is used. To build jackdmp, a "waf" (http://code.google.com/p/waf/) based compilation system is available. The code has to be compiled on a machine where ALSA and possibly freeboot (FFADO) headers and libraries are corrected installed. +The published version still uses fifos for server/client synchronization. The use of POSIX named semaphore is implemented but still a bit unstable. Sockets are used for server/client communications. The ALSA backend derived from jackd implementation is used. To build jackdmp, a "waf" (http://code.google.com/p/waf/) based compilation system is available. The code has to be compiled on a machine where ALSA and possibly freebob (FFADO) headers and libraries are corrected installed. In the top folder do : @@ -212,7 +212,7 @@ Note : To experiment with the -S option, jackdmp must be launched in a console. 1.9.4 : Solaris boomer backend now working in capture or playback only mode. Add a -G parameter in CoreAudio backend (the computation value in RT thread expressed as percent of period). Use SNDCTL_DSP_SYNCGROUP/SNDCTL_DSP_SYNCSTART API to synchronize input and output in Solaris boomer backend. Big endian bug fix in memops.c. Fix issues in JackNetDriver::DecodeTransportData and JackNetDriver::Initialize. Correct CPU timing in JackNetDriver, now take cycle begin time after Read. Simplify transport in NetJack2: master only can control transport. Change CoreAudio notification thread setup for OSX Snow Leopard. Correct server temporary mode : now set a global and quit after server/client message handling is finished. Add a string parameter to server ==> client notification, add a new JackInfoShutdownCallback type. CoreAudio backend now issue a JackInfoShutdownCallback when an unrecoverable error is detected (sampling rate change, stream configuration changeÉ). Correct jackdmp.cpp (failures case were not correct..). Improve JackCoreAudioDriver code. Raise default port number to 2048. Correct JackProcessSync::LockedTimedWait. Correct JACK_MESSAGE_SIZE value, particularly in OSX RPC code. Now start server channel thread only when backend has been started (so in JackServer::Start). Should solve race conditions at start time. jack_verbose moved to JackGlobals class. Improve aggregate device management in JackCoreAudioDriver : now a "private" device only and cleanup properly. Aggregate device code added to JackCoreAudioAdapter. Implement "hog mode" (exclusive access of the audio device) in JackCoreAudioDriver. Fix jack_set_sample_rate_callback to have he same behavior as in JACK1. Dynamic system version detection in JackCoreAudioDriver to either create public or private aggregate device. In JackCoreAudioDriver, force the SR value to the wanted one *before* creating aggregate device (otherwise creation will fail). In JackCoreAudioDriver, better cleanup of AD when intermediate open failure. In JackCoreAudioDriver::Start, wait for the audio driver to effectively start (use the MeasureCallback). In JackCoreAudioDriver, improve management of input/output channels: -1 is now used internally to indicate a wanted max value. In JackCoreAudioDriver::OpenAUHAL, correct stream format setup and cleanup. Correct crash bug in JackAudioAdapterInterface when not input is used in adapter (temporary fixÉ). Sync JackCoreAudioAdapter code on JackCoreAudioDriver one. JACK_SCHED_POLICY switched to SCHED_FIFO. Now can aggregate device that are themselves AD. No reason to make jack_on_shutdown deprecated, so revert the incorrect change. Thread AcquireRealTime and DropRealTime were (incorrectly) using fThread field. Use pthread_self()) (or GetCurrentThread() on Windows) to get the calling thread. Correctly save and restore RT mode state in freewheel mode. Correct freewheel code on client side. Fix AcquireRealTime and DropRealTime: now distinguish when called from another thread (AcquireRealTime/DropRealTime) and from the thread itself (AcquireSelfRealTime/DropSelfRealTime). Correct JackPosixThread::StartImp : thread priority setting now done in the RT case only. Correct JackGraphManager::GetBuffer for the "client loop with one connection" case : buffer must be copied. Correct JackInfoShutdownCallback prototype, two new JackClientProcessFailure and JackClientZombie JackStatus code. Correct JackCoreAudio driver when empty strings are given as -C, -P or -d parameter. Better memory allocation error checking on client (library) side. Better memory allocation error checking in ringbuffer.c, weak import improvements. Memory allocation error checking for jack_client_new and jack_client_open (server and client side). Memory allocation error checking in server for RPC. Simplify server temporary mode : now use a JackTemporaryException. Lock/Unlock shared memory segments (to test...). Sync with JACK1 : -r parameter now used for no-realtime, realtime (-R) is now default, usable backend given vie platform. In JackCoreAudio driver, (possibly) clock drift compensation when needed in aggregated devices. In JackCoreAudio driver, clock drift compensation in aggregated devices working. In JackCoreAudio driver, clock drift compensation semantic changed a bit : when on, does not activate if not needed (same clock domain). Sync JackCoreAudioAdapter code with JackCoreAudioDriver. 1.9.5 : Dynamic choice of maximum port number. More robust sample rate change handling code in JackCoreAudioDriver. Devin Anderson patch for Jack FFADO driver issues with lost MIDI bytes between periods (and more). Fix port_rename callback : now both old name and new name are given as parameters. Special code in JackCoreAudio driver to handle completely buggy Digidesign CoreAudio user-land driver. Ensure that client-side message buffer thread calls thread_init callback if/when it is set by the client (backport of JACK1 rev 3838). Check dynamic port-max value. Fix JackCoreMidiDriver::ReadProcAux when ring buffer is full (thanks Devin Anderson). Josh Green ALSA driver capture only patch. When threads are cancelled, the exception has to be rethrown. Use a QUIT notification to properly quit the server channel, the server channel thread can then be 'stopped' instead of 'canceled'. Mario Lang alsa_io time calculation overflow patch. Shared memory manager was calling abort in case of fatal error, now return an error in caller. Change JackEngineProfiling and JackAudioAdapterInterface gnuplot scripts to output SVG instead of PDF. 1.9.6 : Improve JackCoreAudioDriver and JackCoreAudioAdapter : when no devices are described, takes default input and output and aggregate them.Correct JackGraphManager::DeactivatePort. Correct JackMachServerChannel::Execute : keep running even in error cases. Raise JACK_PROTOCOL_VERSION number. Arnold Krille firewire patch. Raise JACK_DRIVER_PARAM_STRING_MAX and JACK_PARAM_STRING_MAX to 127 otherwise some audio drivers cannot be loaded on OSX. Fix some file header to have library side code use LGPL. On Windows, now use TRE library for regexp (BSD license instead of GPL license). ffado-portname-sync.patch from ticket #163 applied. Remove call to exit in library code. Make jack_connect/jack_disconnect wait for effective port connection/disconnection. Add tests to validate intclient.h API. On Linux, inter-process synchronization primitive switched to POSIX semaphore. In JackCoreAudioDriver, move code called in MeasureCallback to be called once in IO thread. David Garcia Garzon netone patch. Fix from Fernando Lopez-Lezcano for compilation on fc13. Fix JackPosixSemaphore::TimedWait : same behavior as JackPosixSemaphore::Wait regarding EINTR. David Garcia Garzon unused_pkt_buf_field_jack2 netone patch. Arnold Krille firewire snooping patch. Jan Engelhardt patch for get_cycles on SPARC. Adrian Knoth hurd.patch, kfreebsd-fix.patch and alpha_ia64-sigsegv.patch from ticket 177. Adrian Knoth fix for linux cycle.h (ticket 188). In JackCoreAudioDriver, fix an issue when no value is given for input. -1.9.7 : Sync JackAlsaDriver::alsa_driver_check_card_type with JACK1 backend. Correct JackServer::Open to avoid a race when control API is used on OSX. Improve backend error handling: fatal error returned by Read/Write now cause a Process failure (so a thread exit for blocking backends). Recoverable ones (XRuns..) are now treated internally in ALSA, FreeBob and FFADO backends. In jackdmp.cpp, jackctl_setup_signals moved before jackctl_server_start. Correct symbols export in backends on OSX. ALSA backend : suspend/resume handling. Correct dummy driver. Adrian Knoth jack_lsp patch. Remove JackPortIsActive flag. New latency API implementation. ComputeTotalLatencies now a client/server call. Add latent test client for latency API. Also print playback and capture latency in jack_lsp. jack_client_has_session_callback implementation. Check requested buffer size and limit to 1..8192 - avoids weird behaviour caused by jack_bufsize foobar. jack_port_type_get_buffer_size implementation. Stop using alloca and allocate buffer on the heap for alsa_io. Rename jdelay to jack_iodelay as per Fons' request. Call buffer size callback in activate (actually this is done on client side in the RT thread Init method). Add jack_midi_dump client. Synchronize net JACK1 with JACK1 version. Synchronize jack_connect/jack_disconnect with JACK1 version. Correct JackNetMaster::SetBufferSize. Use jack_default_audio_sample_t instead of float consistently, fix ticket #201. -X now allows to add several slave backends, add -I to load several internal clients. Rework internal slave driver management, JackServerGlobals now handle same parameters as jackdmp. Correct JackEngine::NotifyGraphReorder, update JackDebugClient with latest API. Devin Anderson server-ctl-proposal branch merged on trunk: improved control API, slave backend reworked. Implement renaming in JackDriver::Open to avoid name collision (thanks Devin Anderson). Correct alsa_driver_restart (thanks Devin Anderson). Correction of jack_connect/jack_disconnect: use of jack_activate and volatile keyword for thread shared variable. Correction of JackNetOneDriver for latest CELT API. Synchronize JackWeakAPI.cpp with new APIs. +1.9.7 : Sync JackAlsaDriver::alsa_driver_check_card_type with JACK1 backend. Correct JackServer::Open to avoid a race when control API is used on OSX. Improve backend error handling: fatal error returned by Read/Write now cause a Process failure (so a thread exit for blocking backends). Recoverable ones (XRuns..) are now treated internally in ALSA, FreeBob and FFADO backends. In jackdmp.cpp, jackctl_setup_signals moved before jackctl_server_start. Correct symbols export in backends on OSX. ALSA backend : suspend/resume handling. Correct dummy driver. Adrian Knoth jack_lsp patch. Remove JackPortIsActive flag. New latency API implementation. ComputeTotalLatencies now a client/server call. Add latent test client for latency API. Also print playback and capture latency in jack_lsp. jack_client_has_session_callback implementation. Check requested buffer size and limit to 1..8192 - avoids weird behaviour caused by jack_bufsize foobar. jack_port_type_get_buffer_size implementation. Stop using alloca and allocate buffer on the heap for alsa_io. Rename jdelay to jack_iodelay as per Fons' request. Call buffer size callback in activate (actually this is done on client side in the RT thread Init method). Add jack_midi_dump client. Synchronize net JACK1 with JACK1 version. Synchronize jack_connect/jack_disconnect with JACK1 version. Correct JackNetMaster::SetBufferSize. Use jack_default_audio_sample_t instead of float consistently, fix ticket #201. -X now allows to add several slave backends, add -I to load several internal clients. Rework internal slave driver management, JackServerGlobals now handle same parameters as jackdmp. Correct JackEngine::NotifyGraphReorder, update JackDebugClient with latest API. Devin Anderson server-ctl-proposal branch merged on trunk: improved control API, slave backend reworked. Implement renaming in JackDriver::Open to avoid name collision (thanks Devin Anderson). Correct alsa_driver_restart (thanks Devin Anderson). Correction of jack_connect/jack_disconnect: use of jack_activate and volatile keyword for thread shared variable. Correction of JackNetOneDriver for latest CELT API. Synchronize JackWeakAPI.cpp with new APIs. This is a work in progress but the implementation is now stable enough to be tested. jackdmp has been used successfully with the following applications : Ardour, Hydrogen, Jamin, QjackCtl, Jack-Rack, SooperLooper, AlsaPlayer... diff --git a/common/JackAudioDriver.cpp b/common/JackAudioDriver.cpp index 272c1e66..31b8a51b 100644 --- a/common/JackAudioDriver.cpp +++ b/common/JackAudioDriver.cpp @@ -44,12 +44,17 @@ JackAudioDriver::~JackAudioDriver() int JackAudioDriver::SetBufferSize(jack_nframes_t buffer_size) { + // Update engine and graph manager state fEngineControl->fBufferSize = buffer_size; fGraphManager->SetBufferSize(buffer_size); 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); - return 0; + + UpdateLatencies(); + + // Redirect on slaves drivers... + return JackDriver::SetBufferSize(buffer_size); } int JackAudioDriver::SetSampleRate(jack_nframes_t sample_rate) @@ -58,7 +63,8 @@ int JackAudioDriver::SetSampleRate(jack_nframes_t sample_rate) 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); - return 0; + + return JackDriver::SetSampleRate(sample_rate); } int JackAudioDriver::Open(jack_nframes_t buffer_size, @@ -76,6 +82,9 @@ int JackAudioDriver::Open(jack_nframes_t buffer_size, fCaptureChannels = inchannels; fPlaybackChannels = outchannels; fWithMonitorPorts = monitor; + memset(fCapturePortList, 0, sizeof(jack_port_id_t) * DRIVER_PORT_NUM); + memset(fPlaybackPortList, 0, sizeof(jack_port_id_t) * DRIVER_PORT_NUM); + memset(fMonitorPortList, 0, sizeof(jack_port_id_t) * DRIVER_PORT_NUM); return JackDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency); } @@ -92,16 +101,39 @@ int JackAudioDriver::Open(bool capturing, fCaptureChannels = inchannels; fPlaybackChannels = outchannels; fWithMonitorPorts = monitor; + memset(fCapturePortList, 0, sizeof(jack_port_id_t) * DRIVER_PORT_NUM); + memset(fPlaybackPortList, 0, sizeof(jack_port_id_t) * DRIVER_PORT_NUM); + memset(fMonitorPortList, 0, sizeof(jack_port_id_t) * DRIVER_PORT_NUM); return JackDriver::Open(capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency); } +void JackAudioDriver::UpdateLatencies() +{ + jack_latency_range_t range; + + for (int i = 0; i < fCaptureChannels; i++) { + range.max = range.min = fEngineControl->fBufferSize; + fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &range); + } + + for (int i = 0; i < fPlaybackChannels; i++) { + if (! fEngineControl->fSyncMode) { + range.max = range.min = fEngineControl->fBufferSize * 2; + } + fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &range); + if (fWithMonitorPorts) { + range.min = range.max = fEngineControl->fBufferSize; + fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &range); + } + } +} + int JackAudioDriver::Attach() { 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]; - jack_latency_range_t range; int i; jack_log("JackAudioDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); @@ -115,8 +147,6 @@ int JackAudioDriver::Attach() } port = fGraphManager->GetPort(port_index); port->SetAlias(alias); - range.min = range.max = fEngineControl->fBufferSize + fCaptureLatency; - port->SetLatencyRange(JackCaptureLatency, &range); fCapturePortList[i] = port_index; jack_log("JackAudioDriver::Attach fCapturePortList[i] port_index = %ld", port_index); } @@ -130,9 +160,6 @@ int JackAudioDriver::Attach() } port = fGraphManager->GetPort(port_index); port->SetAlias(alias); - // Add more latency if "async" mode is used... - range.min = range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + fPlaybackLatency; - port->SetLatencyRange(JackPlaybackLatency, &range); fPlaybackPortList[i] = port_index; jack_log("JackAudioDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); @@ -144,14 +171,12 @@ int JackAudioDriver::Attach() jack_error("Cannot register monitor port for %s", name); return -1; } else { - port = fGraphManager->GetPort(port_index); - range.min = range.max = fEngineControl->fBufferSize; - port->SetLatencyRange(JackCaptureLatency, &range); - fMonitorPortList[i] = port_index; + fMonitorPortList[i] = port_index; } } } + UpdateLatencies(); return 0; } @@ -193,9 +218,9 @@ int JackAudioDriver::ProcessNull() JackDriver::CycleTakeBeginTime(); if (fEngineControl->fSyncMode) { - ProcessGraphSync(); + ProcessGraphSyncMaster(); } else { - ProcessGraphAsync(); + ProcessGraphAsyncMaster(); } // Keep end cycle time @@ -230,9 +255,9 @@ int JackAudioDriver::ProcessAsync() // Process graph if (fIsMaster) { - ProcessGraphAsync(); + ProcessGraphAsyncMaster(); } else { - fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); + ProcessGraphAsyncSlave(); } // Keep end cycle time @@ -255,12 +280,12 @@ int JackAudioDriver::ProcessSync() // Process graph if (fIsMaster) { - if (ProcessGraphSync() < 0) { + if (ProcessGraphSyncMaster() < 0) { jack_error("JackAudioDriver::ProcessSync: process error, skip cycle..."); goto end; } } else { - if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { + if (ProcessGraphSyncSlave() < 0) { jack_error("JackAudioDriver::ProcessSync: process error, skip cycle..."); goto end; } @@ -279,27 +304,50 @@ end: return 0; } -void JackAudioDriver::ProcessGraphAsync() +void JackAudioDriver::ProcessGraphAsyncMaster() { // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle if (!fEngine->Process(fBeginDateUst, fEndDateUst)) - jack_error("JackAudioDriver::ProcessGraphAsync: Process error"); - fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); - if (ProcessSlaves() < 0) - jack_error("JackAudioDriver::ProcessGraphAsync: ProcessSlaves error"); + jack_error("JackAudioDriver::ProcessGraphAsyncMaster: Process error"); + + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) + jack_error("JackAudioDriver::ProcessGraphAsyncMaster: ResumeRefNum error"); + + if (ProcessReadSlaves() < 0) + jack_error("JackAudioDriver::ProcessGraphAsyncMaster: ProcessReadSlaves error"); + + if (ProcessWriteSlaves() < 0) + jack_error("JackAudioDriver::ProcessGraphAsyncMaster: ProcessWriteSlaves error"); +} + +void JackAudioDriver::ProcessGraphAsyncSlave() +{ + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) + jack_error("JackAudioDriver::ProcessGraphAsyncSlave: ResumeRefNum error"); } -int JackAudioDriver::ProcessGraphSync() +int JackAudioDriver::ProcessGraphSyncMaster() { int res = 0; // fBeginDateUst is set in the "low level" layer, fEndDateUst is from previous cycle if (fEngine->Process(fBeginDateUst, fEndDateUst)) { - fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); - if (ProcessSlaves() < 0) { - jack_error("JackAudioDriver::ProcessGraphSync: ProcessSlaves error, engine may now behave abnormally!!"); + + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { + jack_error("JackAudioDriver::ProcessGraphSyncMaster: ResumeRefNum error"); res = -1; } + + if (ProcessReadSlaves() < 0) { + jack_error("JackAudioDriver::ProcessGraphSync: ProcessReadSlaves error, engine may now behave abnormally!!"); + res = -1; + } + + if (ProcessWriteSlaves() < 0) { + jack_error("JackAudioDriver::ProcessGraphSync: ProcessWriteSlaves error, engine may now behave abnormally!!"); + res = -1; + } + if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) { jack_error("JackAudioDriver::ProcessGraphSync: SuspendRefNum error, engine may now behave abnormally!!"); res = -1; @@ -312,6 +360,11 @@ int JackAudioDriver::ProcessGraphSync() return res; } +int JackAudioDriver::ProcessGraphSyncSlave() +{ + return fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); +} + int JackAudioDriver::Start() { int res = JackDriver::Start(); @@ -342,20 +395,23 @@ void JackAudioDriver::WaitUntilNextCycle() jack_default_audio_sample_t* JackAudioDriver::GetInputBuffer(int port_index) { - assert(fCapturePortList[port_index]); - return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[port_index], fEngineControl->fBufferSize); + return fCapturePortList[port_index] + ? (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[port_index], fEngineControl->fBufferSize) + : NULL; } jack_default_audio_sample_t* JackAudioDriver::GetOutputBuffer(int port_index) { - assert(fPlaybackPortList[port_index]); - return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[port_index], fEngineControl->fBufferSize); + return fPlaybackPortList[port_index] + ? (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[port_index], fEngineControl->fBufferSize) + : NULL; } jack_default_audio_sample_t* JackAudioDriver::GetMonitorBuffer(int port_index) { - assert(fPlaybackPortList[port_index]); - return (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize); + return fPlaybackPortList[port_index] + ? (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_index], fEngineControl->fBufferSize) + : NULL; } int JackAudioDriver::ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2) diff --git a/common/JackAudioDriver.h b/common/JackAudioDriver.h index 8eaca692..83b0ba53 100644 --- a/common/JackAudioDriver.h +++ b/common/JackAudioDriver.h @@ -35,8 +35,12 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver protected: - void ProcessGraphAsync(); - int ProcessGraphSync(); + void ProcessGraphAsyncMaster(); + void ProcessGraphAsyncSlave(); + + int ProcessGraphSyncMaster(); + int ProcessGraphSyncSlave(); + void WaitUntilNextCycle(); virtual int ProcessAsync(); @@ -58,6 +62,7 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver jack_default_audio_sample_t* GetMonitorBuffer(int port_index); void HandleLatencyCallback(int status); + void UpdateLatencies(); public: diff --git a/common/JackChannel.h b/common/JackChannel.h index c9ee89e5..69d25e00 100644 --- a/common/JackChannel.h +++ b/common/JackChannel.h @@ -20,7 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef __JackChannel__ #define __JackChannel__ -#include "session.h" +#include "types.h" +#include "JackSession.h" namespace Jack { diff --git a/common/JackClient.h b/common/JackClient.h index a03e17d2..7d8e0864 100644 --- a/common/JackClient.h +++ b/common/JackClient.h @@ -27,7 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackSynchro.h" #include "JackPlatformPlug.h" #include "JackChannel.h" -#include "session.h" #include "varargs.h" #include diff --git a/common/JackClientControl.h b/common/JackClientControl.h index 29e4a5b7..d035ccd0 100644 --- a/common/JackClientControl.h +++ b/common/JackClientControl.h @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackPort.h" #include "JackSynchro.h" #include "JackNotification.h" -#include "session.h" +#include "JackSession.h" namespace Jack { diff --git a/common/JackConstants.h b/common/JackConstants.h index 33d52cbd..c4c816da 100644 --- a/common/JackConstants.h +++ b/common/JackConstants.h @@ -24,7 +24,7 @@ #include "config.h" #endif -#define VERSION "1.9.7" +#define VERSION "1.9.8" #define BUFFER_SIZE_MAX 8192 @@ -71,7 +71,7 @@ #define SOCKET_TIME_OUT 5 // in sec #define DRIVER_OPEN_TIMEOUT 5 // in sec #define FREEWHEEL_DRIVER_TIMEOUT 10 // in sec -#define DRIVER_TIMEOUT_FACTOR 10 +#define DRIVER_TIMEOUT_FACTOR 10 #define NO_PORT 0xFFFE diff --git a/common/JackControlAPI.cpp b/common/JackControlAPI.cpp index 4ff69adc..2490a65e 100644 --- a/common/JackControlAPI.cpp +++ b/common/JackControlAPI.cpp @@ -101,7 +101,7 @@ struct jackctl_driver jack_driver_desc_t * desc_ptr; JSList * parameters; JSList * set_parameters; - JackDriverInfo* info; + JSList * infos; }; struct jackctl_internal @@ -215,7 +215,8 @@ bool jackctl_add_driver_parameters( struct jackctl_driver * driver_ptr) { - uint32_t i; + unsigned int i; + union jackctl_parameter_value jackctl_value; jackctl_param_type_t jackctl_type; struct jackctl_parameter * parameter_ptr; @@ -308,6 +309,7 @@ jackctl_drivers_load( driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data; driver_ptr->parameters = NULL; driver_ptr->set_parameters = NULL; + driver_ptr->infos = NULL; if (!jackctl_add_driver_parameters(driver_ptr)) { @@ -377,6 +379,7 @@ jackctl_internals_load( internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data; internal_ptr->parameters = NULL; internal_ptr->set_parameters = NULL; + internal_ptr->refnum = -1; if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr)) { @@ -1214,8 +1217,13 @@ EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver jack_error("cannot add a slave in a running server"); return false; } else { - driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); - return (driver_ptr->info != 0); + JackDriverInfo* info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); + if (info) { + driver_ptr->infos = jack_slist_append(driver_ptr->infos, info); + return true; + } else { + return false; + } } } else { return false; @@ -1228,10 +1236,17 @@ EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_dri if (server_ptr->engine->IsRunning()) { jack_error("cannot remove a slave from a running server"); return false; - } else { - server_ptr->engine->RemoveSlave(driver_ptr->info); - delete driver_ptr->info; - return true; + } else { + if (driver_ptr->infos) { + JackDriverInfo* info = (JackDriverInfo*)driver_ptr->infos->data; + assert(info); + driver_ptr->infos = jack_slist_remove(driver_ptr->infos, info); + server_ptr->engine->RemoveSlave(info); + delete info; + return true; + } else { + return false; + } } } else { return false; diff --git a/common/JackControlAPI.h b/common/JackControlAPI.h index 8e87d513..65b8528e 100644 --- a/common/JackControlAPI.h +++ b/common/JackControlAPI.h @@ -27,7 +27,8 @@ #ifdef WIN32 #ifdef __MINGW32__ -#include +#include +typedef _sigset_t sigset_t; #else typedef HANDLE sigset_t; #endif @@ -169,11 +170,11 @@ jackctl_parameter_set_value( EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value( jackctl_parameter_t * parameter); - -EXPORT union jackctl_parameter_value + +EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value( jackctl_parameter *parameter_ptr); - + EXPORT bool jackctl_parameter_has_range_constraint( jackctl_parameter_t * parameter_ptr); @@ -210,33 +211,33 @@ EXPORT bool jackctl_parameter_constraint_is_fake_value( jackctl_parameter_t * parameter_ptr); -EXPORT const JSList * +EXPORT const JSList * jackctl_server_get_internals_list( jackctl_server *server_ptr); - -EXPORT const char * + +EXPORT const char * jackctl_internal_get_name( jackctl_internal *internal_ptr); - -EXPORT const JSList * + +EXPORT const JSList * jackctl_internal_get_parameters( jackctl_internal *internal_ptr); - + EXPORT bool jackctl_server_load_internal( jackctl_server * server, jackctl_internal * internal); - + EXPORT bool jackctl_server_unload_internal( jackctl_server * server, jackctl_internal * internal); - + EXPORT bool jackctl_server_add_slave(jackctl_server_t * server, jackctl_driver_t * driver); EXPORT bool jackctl_server_remove_slave(jackctl_server_t * server, jackctl_driver_t * driver); -EXPORT bool +EXPORT bool jackctl_server_switch_master(jackctl_server_t * server, jackctl_driver_t * driver); diff --git a/common/JackDriver.cpp b/common/JackDriver.cpp index ce860468..e424ce28 100644 --- a/common/JackDriver.cpp +++ b/common/JackDriver.cpp @@ -56,6 +56,7 @@ JackDriver::JackDriver() fEngine = NULL; fGraphManager = NULL; fBeginDateUst = 0; + fDelayedUsecs = 0.f; fIsMaster = true; fIsRunning = false; } @@ -300,19 +301,42 @@ void JackDriver::RemoveSlave(JackDriverInterface* slave) fSlaveList.remove(slave); } -int JackDriver::ProcessSlaves() +int JackDriver::ProcessReadSlaves() { int res = 0; list::const_iterator it; for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) { JackDriverInterface* slave = *it; - if (slave->Process() < 0) + if (slave->ProcessRead() < 0) res = -1; } return res; } +int JackDriver::ProcessWriteSlaves() +{ + int res = 0; + list::const_iterator it; + for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) { + JackDriverInterface* slave = *it; + if (slave->ProcessWrite() < 0) + res = -1; + + } + return res; +} + +int JackDriver::ProcessRead() +{ + return 0; +} + +int JackDriver::ProcessWrite() +{ + return 0; +} + int JackDriver::Process() { return 0; @@ -352,6 +376,12 @@ int JackDriver::Start() return 0; } +int JackDriver::Stop() +{ + fIsRunning = false; + return 0; +} + int JackDriver::StartSlaves() { int res = 0; @@ -370,12 +400,6 @@ int JackDriver::StartSlaves() return res; } -int JackDriver::Stop() -{ - fIsRunning = false; - return 0; -} - int JackDriver::StopSlaves() { int res = 0; @@ -395,12 +419,28 @@ bool JackDriver::IsFixedBufferSize() int JackDriver::SetBufferSize(jack_nframes_t buffer_size) { - return 0; + int res = 0; + + list::const_iterator it; + for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) { + JackDriverInterface* slave = *it; + if (slave->SetBufferSize(buffer_size) < 0) + res = -1; + } + + return res; } int JackDriver::SetSampleRate(jack_nframes_t sample_rate) { - return 0; + int res = 0; + list::const_iterator it; + for (it = fSlaveList.begin(); it != fSlaveList.end(); it++) { + JackDriverInterface* slave = *it; + if (slave->SetSampleRate(sample_rate) < 0) + res = -1; + } + return res; } bool JackDriver::Initialize() diff --git a/common/JackDriver.h b/common/JackDriver.h index 68f937c2..45d695af 100644 --- a/common/JackDriver.h +++ b/common/JackDriver.h @@ -34,6 +34,7 @@ namespace Jack class JackLockedEngine; class JackGraphManager; struct JackEngineControl; +class JackSlaveDriverInterface; /*! \brief The base interface for drivers. @@ -91,10 +92,17 @@ class SERVER_EXPORT JackDriverInterface virtual void SetMaster(bool onoff) = 0; virtual bool GetMaster() = 0; + virtual void AddSlave(JackDriverInterface* slave) = 0; virtual void RemoveSlave(JackDriverInterface* slave) = 0; + virtual std::list GetSlaves() = 0; - virtual int ProcessSlaves() = 0; + + virtual int ProcessReadSlaves() = 0; + virtual int ProcessWriteSlaves() = 0; + + virtual int ProcessRead() = 0; + virtual int ProcessWrite() = 0; virtual bool IsRealTime() const = 0; virtual bool IsRunning() const = 0; @@ -159,11 +167,11 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface void AddSlave(JackDriverInterface* slave); void RemoveSlave(JackDriverInterface* slave); + std::list GetSlaves() { return fSlaveList; } - int ProcessSlaves(); virtual int Open(); @@ -200,10 +208,17 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface virtual int Write(); virtual int Start(); - virtual int StartSlaves(); virtual int Stop(); + + virtual int StartSlaves(); virtual int StopSlaves(); + int ProcessReadSlaves(); + int ProcessWriteSlaves(); + + int ProcessRead(); + int ProcessWrite(); + virtual bool IsFixedBufferSize(); virtual int SetBufferSize(jack_nframes_t buffer_size); virtual int SetSampleRate(jack_nframes_t sample_rate); diff --git a/common/JackDriverLoader.cpp b/common/JackDriverLoader.cpp index 2d270656..84a97a54 100644 --- a/common/JackDriverLoader.cpp +++ b/common/JackDriverLoader.cpp @@ -531,7 +531,7 @@ jack_drivers_load (JSList * drivers) { HANDLE file; const char * ptr = NULL; JSList * driver_list = NULL; - jack_driver_desc_t * desc; + jack_driver_desc_t * desc = NULL; if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path @@ -551,6 +551,11 @@ jack_drivers_load (JSList * drivers) { } do { + /* check the filename is of the right format */ + if (strncmp ("jack_", filedata.cFileName, 5) != 0) { + continue; + } + ptr = strrchr (filedata.cFileName, '.'); if (!ptr) { continue; @@ -560,6 +565,11 @@ jack_drivers_load (JSList * drivers) { continue; } + /* check if dll is an internal client */ + if (check_symbol(filedata.cFileName, "jack_internal_initialize")) { + continue; + } + desc = jack_get_descriptor (drivers, filedata.cFileName, "driver_get_descriptor"); if (desc) { driver_list = jack_slist_append (driver_list, desc); @@ -586,7 +596,7 @@ jack_drivers_load (JSList * drivers) { const char * ptr; int err; JSList * driver_list = NULL; - jack_driver_desc_t * desc; + jack_driver_desc_t * desc = NULL; const char* driver_dir; if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { @@ -618,8 +628,12 @@ jack_drivers_load (JSList * drivers) { continue; } - desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor"); + /* check if dll is an internal client */ + if (check_symbol(dir_entry->d_name, "jack_internal_initialize")) { + continue; + } + desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor"); if (desc) { driver_list = jack_slist_append (driver_list, desc); } else { @@ -669,7 +683,7 @@ jack_internals_load (JSList * internals) { file = (HANDLE )FindFirstFile(dll_filename, &filedata); if (file == INVALID_HANDLE_VALUE) { - jack_error("error"); + jack_error("could not open driver directory %s", driver_dir); return NULL; } diff --git a/common/JackDriverLoader.h b/common/JackDriverLoader.h index c194304d..719881e8 100644 --- a/common/JackDriverLoader.h +++ b/common/JackDriverLoader.h @@ -30,7 +30,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. typedef jack_driver_desc_t * (*JackDriverDescFunction) (); typedef Jack::JackDriverClientInterface* (*driverInitialize) (Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*); -class JackDriverInfo +class SERVER_EXPORT JackDriverInfo { private: diff --git a/common/JackDummyDriver.cpp b/common/JackDummyDriver.cpp index fb996a11..4c084f06 100644 --- a/common/JackDummyDriver.cpp +++ b/common/JackDummyDriver.cpp @@ -78,6 +78,7 @@ int JackDummyDriver::Process() int JackDummyDriver::SetBufferSize(jack_nframes_t buffer_size) { + // Generic change, never fails JackAudioDriver::SetBufferSize(buffer_size); fWaitTime = (unsigned long)((((float)buffer_size) / ((float)fEngineControl->fSampleRate)) * 1000000.0f); return 0; diff --git a/common/JackExternalClient.cpp b/common/JackExternalClient.cpp index 1dca599a..54342f97 100644 --- a/common/JackExternalClient.cpp +++ b/common/JackExternalClient.cpp @@ -71,6 +71,7 @@ int JackExternalClient::Open(const char* name, int pid, int refnum, int uuid, in int JackExternalClient::Close() { + jack_log("JackExternalClient::Close"); fChannel.Close(); if (fClientControl) { fClientControl->~JackClientControl(); diff --git a/common/JackFreewheelDriver.cpp b/common/JackFreewheelDriver.cpp index c28e30c3..2928b211 100644 --- a/common/JackFreewheelDriver.cpp +++ b/common/JackFreewheelDriver.cpp @@ -28,26 +28,72 @@ namespace Jack int JackFreewheelDriver::Process() { - if (fIsMaster) { - jack_log("JackFreewheelDriver::Process master %lld", fEngineControl->fTimeOutUsecs); - JackDriver::CycleTakeBeginTime(); - fEngine->Process(fBeginDateUst, fEndDateUst); - fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); // Signal all clients + int res = 0; + + jack_log("JackFreewheelDriver::Process master %lld", fEngineControl->fTimeOutUsecs); + JackDriver::CycleTakeBeginTime(); + + if (fEngine->Process(fBeginDateUst, fEndDateUst)) { + + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable)) { // Signal all clients + jack_error("JackFreewheelDriver::Process: ResumeRefNum error"); + res = -1; + } + if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, FREEWHEEL_DRIVER_TIMEOUT * 1000000) < 0) { // Wait for all clients to finish for 10 sec - jack_error("JackFreewheelDriver::ProcessSync SuspendRefNum error"); + jack_error("JackFreewheelDriver::ProcessSync: SuspendRefNum error"); /* We have a client time-out error, but still continue to process, until a better recovery strategy is chosen */ return 0; } - } else { - fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); // Signal all clients - if (fEngineControl->fSyncMode) { - if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) { - jack_error("JackFreewheelDriver::ProcessSync SuspendRefNum error"); - return -1; - } - } + + } else { // Graph not finished: do not activate it + jack_error("JackFreewheelDriver::Process: Process error"); + res = -1; + } + + return res; +} + +int JackFreewheelDriver::ProcessRead() +{ + return (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync(); +} + +int JackFreewheelDriver::ProcessWrite() +{ + return (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync(); +} + +int JackFreewheelDriver::ProcessReadSync() +{ + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { // Signal all clients + jack_error("JackFreewheelDriver::ProcessReadSync: ResumeRefNum error"); + return -1; + } + return 0; +} + +int JackFreewheelDriver::ProcessWriteSync() +{ + if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) { + jack_error("JackFreewheelDriver::ProcessSync SuspendRefNum error"); + return -1; + } + return 0; +} + +int JackFreewheelDriver::ProcessReadAsync() +{ + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { // Signal all clients + jack_error("JackFreewheelDriver::ProcessReadAsync: ResumeRefNum error"); + return -1; } return 0; } +int JackFreewheelDriver::ProcessWriteAsync() +{ + return 0; +} + } // end of namespace diff --git a/common/JackFreewheelDriver.h b/common/JackFreewheelDriver.h index b988ffb0..02a9cf76 100644 --- a/common/JackFreewheelDriver.h +++ b/common/JackFreewheelDriver.h @@ -46,6 +46,16 @@ class JackFreewheelDriver : public JackDriver } int Process(); + + int ProcessRead(); + int ProcessWrite(); + + int ProcessReadSync(); + int ProcessWriteSync(); + + int ProcessReadAsync(); + int ProcessWriteAsync(); + }; } // end of namespace diff --git a/common/JackLibGlobals.h b/common/JackLibGlobals.h index 8d312295..a2f87ed1 100644 --- a/common/JackLibGlobals.h +++ b/common/JackLibGlobals.h @@ -32,6 +32,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include +#ifdef WIN32 +#ifdef __MINGW32__ +#include +typedef _sigset_t sigset_t; +#else +typedef HANDLE sigset_t; +#endif +#endif namespace Jack { diff --git a/common/JackLibSampleRateResampler.cpp b/common/JackLibSampleRateResampler.cpp index ea70438d..4213a731 100644 --- a/common/JackLibSampleRateResampler.cpp +++ b/common/JackLibSampleRateResampler.cpp @@ -148,7 +148,7 @@ unsigned int JackLibSampleRateResampler::WriteResample(jack_default_audio_sample res = src_process(fResampler, &src_data); if (res != 0) { - jack_error("JackLibSampleRateResampler::ReadResample ratio = %f err = %s", fRatio, src_strerror(res)); + jack_error("JackLibSampleRateResampler::WriteResample ratio = %f err = %s", fRatio, src_strerror(res)); return 0; } @@ -167,7 +167,7 @@ unsigned int JackLibSampleRateResampler::WriteResample(jack_default_audio_sample if (read_frames < frames) { jack_error("Input available = %ld", available_frames); - jack_error("JackLibSampleRateResampler::ReadResample error read_frames = %ld", read_frames); + jack_error("JackLibSampleRateResampler::WriteResample error read_frames = %ld", read_frames); } return read_frames; diff --git a/common/JackLoopbackDriver.cpp b/common/JackLoopbackDriver.cpp index e91cce1e..07778417 100644 --- a/common/JackLoopbackDriver.cpp +++ b/common/JackLoopbackDriver.cpp @@ -30,20 +30,61 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. namespace Jack { -int JackLoopbackDriver::Process() +int JackLoopbackDriver::ProcessRead() { + return (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync(); +} + +int JackLoopbackDriver::ProcessWrite() +{ + return (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync(); +} + +int JackLoopbackDriver::ProcessReadSync() +{ + int res = 0; + // Loopback copy for (int i = 0; i < fCaptureChannels; i++) { memcpy(GetInputBuffer(i), GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); } - fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); // Signal all clients - if (fEngineControl->fSyncMode) { - if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) { - jack_error("JackLoopbackDriver::ProcessSync SuspendRefNum error"); - return -1; - } + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { + jack_error("JackLoopbackDriver::ProcessReadSync - ResumeRefNum error"); + res = -1; + } + + return res; +} + +int JackLoopbackDriver::ProcessWriteSync() +{ + if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, DRIVER_TIMEOUT_FACTOR * fEngineControl->fTimeOutUsecs) < 0) { + jack_error("JackLoopbackDriver::ProcessWriteSync SuspendRefNum error"); + return -1; + } + return 0; +} + +int JackLoopbackDriver::ProcessReadAsync() +{ + int res = 0; + + // Loopback copy + for (int i = 0; i < fCaptureChannels; i++) { + memcpy(GetInputBuffer(i), GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); + } + + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { + jack_error("JackLoopbackDriver::ProcessReadAsync - ResumeRefNum error"); + res = -1; } + + return res; +} + +int JackLoopbackDriver::ProcessWriteAsync() +{ return 0; } diff --git a/common/JackLoopbackDriver.h b/common/JackLoopbackDriver.h index 5c542e3a..247f852e 100644 --- a/common/JackLoopbackDriver.h +++ b/common/JackLoopbackDriver.h @@ -33,15 +33,24 @@ namespace Jack class JackLoopbackDriver : public JackAudioDriver { + private: + + virtual int ProcessReadSync(); + virtual int ProcessWriteSync(); + + virtual int ProcessReadAsync(); + virtual int ProcessWriteAsync(); + public: JackLoopbackDriver(JackLockedEngine* engine, JackSynchro* table) - : JackAudioDriver("loopback", "", engine, table) + : JackAudioDriver("loopback", "loopback", engine, table) {} virtual ~JackLoopbackDriver() {} - int Process(); + virtual int ProcessRead(); + virtual int ProcessWrite(); }; } // end of namespace diff --git a/common/JackMidiAsyncQueue.cpp b/common/JackMidiAsyncQueue.cpp new file mode 100644 index 00000000..0cfa42dc --- /dev/null +++ b/common/JackMidiAsyncQueue.cpp @@ -0,0 +1,103 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include "JackMidiAsyncQueue.h" + +using Jack::JackMidiAsyncQueue; + +JackMidiAsyncQueue::JackMidiAsyncQueue(size_t max_bytes, size_t max_messages) +{ + data_buffer = new jack_midi_data_t[max_bytes]; + byte_ring = jack_ringbuffer_create((max_bytes * sizeof(jack_midi_data_t)) + + 1); + if (byte_ring) { + info_ring = jack_ringbuffer_create((max_messages * INFO_SIZE) + 1); + if (info_ring) { + jack_ringbuffer_mlock(byte_ring); + jack_ringbuffer_mlock(info_ring); + this->max_bytes = max_bytes; + return; + } + jack_ringbuffer_free(byte_ring); + } + delete data_buffer; + throw std::bad_alloc(); +} + +JackMidiAsyncQueue::~JackMidiAsyncQueue() +{ + jack_ringbuffer_free(byte_ring); + jack_ringbuffer_free(info_ring); + delete[] data_buffer; +} + +jack_midi_event_t * +JackMidiAsyncQueue::DequeueEvent() +{ + jack_midi_event_t *event = 0; + if (jack_ringbuffer_read_space(info_ring) >= INFO_SIZE) { + event = &dequeue_event; + jack_ringbuffer_read(info_ring, (char *) &(event->time), + sizeof(jack_nframes_t)); + size_t size; + jack_ringbuffer_read(info_ring, (char *) &size, sizeof(size_t)); + event->buffer = data_buffer; + event->size = size; + jack_ringbuffer_data_t vector[2]; + jack_ringbuffer_get_read_vector(byte_ring, vector); + size_t size1 = vector[0].len; + memcpy(data_buffer, vector[0].buf, size1 * sizeof(jack_midi_data_t)); + if (size1 < size) { + memcpy(data_buffer + size1, vector[1].buf, + (size - size1) * sizeof(jack_midi_data_t)); + } + jack_ringbuffer_read_advance(byte_ring, + size * sizeof(jack_midi_data_t)); + } + return event; +} + +Jack::JackMidiWriteQueue::EnqueueResult +JackMidiAsyncQueue::EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer) +{ + if (size > max_bytes) { + return BUFFER_TOO_SMALL; + } + if (! ((jack_ringbuffer_write_space(info_ring) >= INFO_SIZE) && + (jack_ringbuffer_write_space(byte_ring) >= + (size * sizeof(jack_midi_data_t))))) { + return BUFFER_FULL; + } + jack_ringbuffer_write(byte_ring, (const char *) buffer, + size * sizeof(jack_midi_data_t)); + jack_ringbuffer_write(info_ring, (const char *) (&time), + sizeof(jack_nframes_t)); + jack_ringbuffer_write(info_ring, (const char *) (&size), sizeof(size_t)); + return OK; +} + +size_t +JackMidiAsyncQueue::GetAvailableSpace() +{ + return jack_ringbuffer_write_space(info_ring) < INFO_SIZE ? 0 : + max_bytes - jack_ringbuffer_read_space(byte_ring); +} diff --git a/common/JackMidiAsyncQueue.h b/common/JackMidiAsyncQueue.h new file mode 100644 index 00000000..a9ac84ce --- /dev/null +++ b/common/JackMidiAsyncQueue.h @@ -0,0 +1,98 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiAsyncQueue__ +#define __JackMidiAsyncQueue__ + +#include "JackMidiPort.h" +#include "JackMidiReadQueue.h" +#include "JackMidiWriteQueue.h" +#include "ringbuffer.h" + +namespace Jack { + + /** + * This is a MIDI message queue designed to allow two threads to pass MIDI + * messages between two threads (though it can also be used to buffer + * events internally). This is especially useful if the MIDI API + * you're attempting to interface with doesn't provide the ability to + * schedule MIDI events ahead of time and/or has blocking send/receive + * calls, as it allows a separate thread to handle input/output while the + * JACK process thread copies events from a `JackMidiBufferReadQueue` to + * this queue, or from this queue to a `JackMidiBufferWriteQueue`. + */ + + class SERVER_EXPORT JackMidiAsyncQueue: + public JackMidiReadQueue, public JackMidiWriteQueue { + + private: + + static const size_t INFO_SIZE = + sizeof(jack_nframes_t) + sizeof(size_t); + + jack_ringbuffer_t *byte_ring; + jack_midi_data_t *data_buffer; + jack_midi_event_t dequeue_event; + jack_ringbuffer_t *info_ring; + size_t max_bytes; + + public: + + using JackMidiWriteQueue::EnqueueEvent; + + /** + * Creates a new asynchronous MIDI message queue. The queue can store + * up to `max_messages` MIDI messages and up to `max_bytes` of MIDI + * data before it starts rejecting messages. + */ + + JackMidiAsyncQueue(size_t max_bytes=4096, size_t max_messages=1024); + + virtual ~JackMidiAsyncQueue(); + + /** + * Dequeues and returns a MIDI event. Returns '0' if there are no MIDI + * events available. This method may be overridden. + */ + + virtual jack_midi_event_t * + DequeueEvent(); + + /** + * Enqueues the MIDI event specified by the arguments. The return + * value indiciates whether or not the event was successfully enqueued. + * This method may be overridden. + */ + + virtual EnqueueResult + EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer); + + /** + * Returns the maximum size event that can be enqueued right *now*. + */ + + size_t + GetAvailableSpace(); + + }; + +} + +#endif diff --git a/common/JackMidiAsyncWaitQueue.cpp b/common/JackMidiAsyncWaitQueue.cpp new file mode 100644 index 00000000..016737cb --- /dev/null +++ b/common/JackMidiAsyncWaitQueue.cpp @@ -0,0 +1,85 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include "JackMidiAsyncWaitQueue.h" +#include "JackMidiUtil.h" +#include "JackTime.h" + +using Jack::JackMidiAsyncWaitQueue; + +JackMidiAsyncWaitQueue::JackMidiAsyncWaitQueue(size_t max_bytes, + size_t max_messages): + JackMidiAsyncQueue(max_bytes, max_messages) +{ + if (semaphore.Allocate("JackMidiAsyncWaitQueue", "midi-thread", 0)) { + throw std::bad_alloc(); + } +} + +JackMidiAsyncWaitQueue::~JackMidiAsyncWaitQueue() +{ + semaphore.Destroy(); +} + +jack_midi_event_t * +JackMidiAsyncWaitQueue::DequeueEvent() +{ + return DequeueEvent((long) 0); +} + +jack_midi_event_t * +JackMidiAsyncWaitQueue::DequeueEvent(jack_nframes_t frame) +{ + + // XXX: I worry about timer resolution on Solaris and Windows. When the + // resolution for the `JackSynchro` object is milliseconds, the worst-case + // scenario for processor objects is that the wait time becomes less than a + // millisecond, and the processor object continually calls this method, + // expecting to wait a certain amount of microseconds, and ends up not + // waiting at all each time, essentially busy-waiting until the current + // frame is reached. Perhaps there should be a #define that indicates the + // wait time resolution for `JackSynchro` objects so that we can wait a + // little longer if necessary. + + jack_time_t frame_time = GetTimeFromFrames(frame); + jack_time_t current_time = GetMicroSeconds(); + return DequeueEvent((frame_time < current_time) ? 0 : + (long) (frame_time - current_time)); +} + +jack_midi_event_t * +JackMidiAsyncWaitQueue::DequeueEvent(long usec) +{ + return ((usec < 0) ? semaphore.Wait() : semaphore.TimedWait(usec)) ? + JackMidiAsyncQueue::DequeueEvent() : 0; +} + +Jack::JackMidiWriteQueue::EnqueueResult +JackMidiAsyncWaitQueue::EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer) +{ + EnqueueResult result = JackMidiAsyncQueue::EnqueueEvent(time, size, + buffer); + if (result == OK) { + semaphore.Signal(); + } + return result; +} diff --git a/common/JackMidiAsyncWaitQueue.h b/common/JackMidiAsyncWaitQueue.h new file mode 100644 index 00000000..8499f688 --- /dev/null +++ b/common/JackMidiAsyncWaitQueue.h @@ -0,0 +1,99 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiAsyncWaitQueue__ +#define __JackMidiAsyncWaitQueue__ + +#include "JackMidiAsyncQueue.h" + +namespace Jack { + + /** + * This is an asynchronous wait queue that allows a thread to wait for a + * message, either indefinitely or for a specified time. This is one + * example of a way that the `JackMidiAsyncQueue` class can be extended so + * that process threads can interact with non-process threads to send MIDI + * events. + * + * XXX: As of right now, this code hasn't been tested. Also, note the + * warning in the JackMidiAsyncWaitQueue.cpp about semaphore wait + * resolution. + */ + + class SERVER_EXPORT JackMidiAsyncWaitQueue: public JackMidiAsyncQueue { + + private: + + JackSynchro semaphore; + + public: + + using JackMidiAsyncQueue::EnqueueEvent; + + /** + * Creates a new asynchronous MIDI wait message queue. The queue can + * store up to `max_messages` MIDI messages and up to `max_bytes` of + * MIDI data before it starts rejecting messages. + */ + + JackMidiAsyncWaitQueue(size_t max_bytes=4096, + size_t max_messages=1024); + + ~JackMidiAsyncWaitQueue(); + + /** + * Dequeues and returns a MIDI event. Returns '0' if there are no MIDI + * events available right now. + */ + + jack_midi_event_t * + DequeueEvent(); + + /** + * Waits a specified time for a MIDI event to be available, or + * indefinitely if the time is negative. Returns the MIDI event, or + * '0' if time runs out and no MIDI event is available. + */ + + jack_midi_event_t * + DequeueEvent(long usecs); + + /** + * Waits until the specified frame for a MIDI event to be available. + * Returns the MIDI event, or '0' if time runs out and no MIDI event is + * available. + */ + + jack_midi_event_t * + DequeueEvent(jack_nframes_t frame); + + /** + * Enqueues the MIDI event specified by the arguments. The return + * value indiciates whether or not the event was successfully enqueued. + */ + + EnqueueResult + EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer); + + }; + +} + +#endif diff --git a/common/JackMidiBufferReadQueue.cpp b/common/JackMidiBufferReadQueue.cpp new file mode 100644 index 00000000..c53e596c --- /dev/null +++ b/common/JackMidiBufferReadQueue.cpp @@ -0,0 +1,67 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackMidiBufferReadQueue.h" +#include "JackMidiUtil.h" + +using Jack::JackMidiBufferReadQueue; + +JackMidiBufferReadQueue::JackMidiBufferReadQueue() +{ + event_count = 0; + index = 0; +} + +jack_midi_event_t * +JackMidiBufferReadQueue::DequeueEvent() +{ + jack_midi_event_t *e = 0; + if (index < event_count) { + JackMidiEvent *event = &(buffer->events[index]); + midi_event.buffer = event->GetData(buffer); + midi_event.size = event->size; + midi_event.time = last_frame_time + event->time; + e = &midi_event; + index++; + } + return e; +} + +void +JackMidiBufferReadQueue::ResetMidiBuffer(JackMidiBuffer *buffer) +{ + event_count = 0; + index = 0; + if (! buffer) { + jack_error("JackMidiBufferReadQueue::ResetMidiBuffer - buffer reset " + "to NULL"); + } else if (! buffer->IsValid()) { + jack_error("JackMidiBufferReadQueue::ResetMidiBuffer - buffer reset " + "to invalid buffer"); + } else { + uint32_t lost_events = buffer->lost_events; + if (lost_events) { + jack_error("JackMidiBufferReadQueue::ResetMidiBuffer - %d events " + "lost during mixdown", lost_events); + } + this->buffer = buffer; + event_count = buffer->event_count; + last_frame_time = GetLastFrame(); + } +} diff --git a/common/JackMidiBufferReadQueue.h b/common/JackMidiBufferReadQueue.h new file mode 100644 index 00000000..84337e42 --- /dev/null +++ b/common/JackMidiBufferReadQueue.h @@ -0,0 +1,60 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiBufferReadQueue__ +#define __JackMidiBufferReadQueue__ + +#include "JackMidiReadQueue.h" + +namespace Jack { + + /** + * Wrapper class to present a JackMidiBuffer in a read queue interface. + */ + + class SERVER_EXPORT JackMidiBufferReadQueue: public JackMidiReadQueue { + + private: + + JackMidiBuffer *buffer; + jack_nframes_t event_count; + jack_nframes_t index; + jack_nframes_t last_frame_time; + jack_midi_event_t midi_event; + + public: + + JackMidiBufferReadQueue(); + + jack_midi_event_t * + DequeueEvent(); + + /** + * This method must be called each period to reset the MIDI buffer for + * processing. + */ + + void + ResetMidiBuffer(JackMidiBuffer *buffer); + + }; + +} + +#endif diff --git a/common/JackMidiBufferWriteQueue.cpp b/common/JackMidiBufferWriteQueue.cpp new file mode 100644 index 00000000..7e6ae67f --- /dev/null +++ b/common/JackMidiBufferWriteQueue.cpp @@ -0,0 +1,65 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackMidiBufferWriteQueue.h" +#include "JackMidiUtil.h" + +using Jack::JackMidiBufferWriteQueue; + +JackMidiBufferWriteQueue::JackMidiBufferWriteQueue() +{ + // Empty +} + +Jack::JackMidiWriteQueue::EnqueueResult +JackMidiBufferWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *data) +{ + if (time >= next_frame_time) { + return EVENT_EARLY; + } + if (time < last_frame_time) { + time = last_frame_time; + } + jack_midi_data_t *dst = buffer->ReserveEvent(time - last_frame_time, size); + if (! dst) { + return size > max_bytes ? BUFFER_TOO_SMALL : BUFFER_FULL; + } + memcpy(dst, data, size); + return OK; +} + +void +JackMidiBufferWriteQueue::ResetMidiBuffer(JackMidiBuffer *buffer, + jack_nframes_t frames) +{ + if (! buffer) { + jack_error("JackMidiBufferWriteQueue::ResetMidiBuffer - buffer reset " + "to NULL"); + } else if (! buffer->IsValid()) { + jack_error("JackMidiBufferWriteQueue::ResetMidiBuffer - buffer reset " + "to invalid buffer"); + } else { + this->buffer = buffer; + buffer->Reset(frames); + last_frame_time = GetLastFrame(); + max_bytes = buffer->MaxEventSize(); + next_frame_time = last_frame_time + frames; + } +} diff --git a/common/JackMidiBufferWriteQueue.h b/common/JackMidiBufferWriteQueue.h new file mode 100644 index 00000000..90d5cbf1 --- /dev/null +++ b/common/JackMidiBufferWriteQueue.h @@ -0,0 +1,62 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiBufferWriteQueue__ +#define __JackMidiBufferWriteQueue__ + +#include "JackMidiWriteQueue.h" + +namespace Jack { + + /** + * Wrapper class to present a JackMidiBuffer in a write queue interface. + */ + + class SERVER_EXPORT JackMidiBufferWriteQueue: public JackMidiWriteQueue { + + private: + + JackMidiBuffer *buffer; + jack_nframes_t last_frame_time; + size_t max_bytes; + jack_nframes_t next_frame_time; + + public: + + using JackMidiWriteQueue::EnqueueEvent; + + JackMidiBufferWriteQueue(); + + EnqueueResult + EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer); + + /** + * This method must be called each period to reset the MIDI buffer for + * processing. + */ + + void + ResetMidiBuffer(JackMidiBuffer *buffer, jack_nframes_t frames); + + }; + +} + +#endif diff --git a/common/JackMidiDriver.cpp b/common/JackMidiDriver.cpp index 15d507b1..1fbd1e38 100644 --- a/common/JackMidiDriver.cpp +++ b/common/JackMidiDriver.cpp @@ -34,19 +34,10 @@ JackMidiDriver::JackMidiDriver(const char* name, const char* alias, JackLockedEn : JackDriver(name, alias, engine, table), fCaptureChannels(0), fPlaybackChannels(0) -{ - for (int i = 0; i < DRIVER_PORT_NUM; i++) { - fRingBuffer[i] = NULL; - } -} +{} JackMidiDriver::~JackMidiDriver() -{ - for (int i = 0; i < fCaptureChannels; i++) { - if (fRingBuffer[i]) - jack_ringbuffer_free(fRingBuffer[i]); - } -} +{} int JackMidiDriver::Open(bool capturing, bool playing, @@ -60,11 +51,6 @@ int JackMidiDriver::Open(bool capturing, { fCaptureChannels = inchannels; fPlaybackChannels = outchannels; - - for (int i = 0; i < fCaptureChannels; i++) { - fRingBuffer[i] = jack_ringbuffer_create(sizeof(jack_default_audio_sample_t) * BUFFER_SIZE_MAX); - } - return JackDriver::Open(capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency); } @@ -104,6 +90,7 @@ int JackMidiDriver::Attach() jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); } + UpdateLatencies(); return 0; } @@ -133,33 +120,108 @@ int JackMidiDriver::Write() return 0; } +void JackMidiDriver::UpdateLatencies() +{ + jack_latency_range_t range; + + for (int i = 0; i < fCaptureChannels; i++) { + range.max = range.min = fEngineControl->fBufferSize; + fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &range); + } + + for (int i = 0; i < fPlaybackChannels; i++) { + if (! fEngineControl->fSyncMode) { + range.max = range.min = fEngineControl->fBufferSize * 2; + } + fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &range); + } +} + +int JackMidiDriver::SetBufferSize(jack_nframes_t buffer_size) +{ + UpdateLatencies(); + return 0; +} + int JackMidiDriver::ProcessNull() { return 0; } -int JackMidiDriver::Process() +int JackMidiDriver::ProcessRead() { + return (fEngineControl->fSyncMode) ? ProcessReadSync() : ProcessReadAsync(); +} + +int JackMidiDriver::ProcessWrite() +{ + return (fEngineControl->fSyncMode) ? ProcessWriteSync() : ProcessWriteAsync(); +} + +int JackMidiDriver::ProcessReadSync() +{ + int res = 0; + // Read input buffers for the current cycle if (Read() < 0) { - jack_error("JackMidiDriver::Process: read error, skip cycle"); - return 0; // Skip cycle, but continue processing... + jack_error("JackMidiDriver::ProcessReadSync: read error, skip cycle"); + res = -1; } - fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); - if (fEngineControl->fSyncMode) { - if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, fEngineControl->fTimeOutUsecs) < 0) { - jack_error("JackFreewheelDriver::ProcessSync SuspendRefNum error"); - return -1; - } + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { + jack_error("JackMidiDriver::ProcessReadSync - ResumeRefNum error"); + res = -1; + } + + return res; +} + +int JackMidiDriver::ProcessWriteSync() +{ + int res = 0; + + if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, + DRIVER_TIMEOUT_FACTOR * + fEngineControl->fTimeOutUsecs) < 0) { + jack_error("JackMidiDriver::ProcessWriteSync - SuspendRefNum error"); + res = -1; } - // Write output buffers for the current cycle + // Write output buffers from the current cycle if (Write() < 0) { - jack_error("JackMidiDriver::Process: write error, skip cycle"); - return 0; // Skip cycle, but continue processing... + jack_error("JackMidiDriver::ProcessWriteSync - Write error"); + res = -1; } + return res; +} + +int JackMidiDriver::ProcessReadAsync() +{ + int res = 0; + + // Read input buffers for the current cycle + if (Read() < 0) { + jack_error("JackMidiDriver::ProcessReadAsync: read error, skip cycle"); + res = -1; + } + + // Write output buffers from the previous cycle + if (Write() < 0) { + jack_error("JackMidiDriver::ProcessReadAsync - Write error"); + res = -1; + } + + if (fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable) < 0) { + jack_error("JackMidiDriver::ProcessReadAsync - ResumeRefNum error"); + res = -1; + } + + return res; +} + +int JackMidiDriver::ProcessWriteAsync() +{ return 0; } diff --git a/common/JackMidiDriver.h b/common/JackMidiDriver.h index 7c5bc5e0..b7584bbe 100644 --- a/common/JackMidiDriver.h +++ b/common/JackMidiDriver.h @@ -39,15 +39,21 @@ class SERVER_EXPORT JackMidiDriver : public JackDriver int fCaptureChannels; int fPlaybackChannels; - - jack_ringbuffer_t* fRingBuffer[DRIVER_PORT_NUM]; jack_port_id_t fCapturePortList[DRIVER_PORT_NUM]; jack_port_id_t fPlaybackPortList[DRIVER_PORT_NUM]; - + JackMidiBuffer* GetInputBuffer(int port_index); JackMidiBuffer* GetOutputBuffer(int port_index); - + + virtual int ProcessReadSync(); + virtual int ProcessWriteSync(); + + virtual int ProcessReadAsync(); + virtual int ProcessWriteAsync(); + + virtual void UpdateLatencies(); + public: JackMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); @@ -62,16 +68,20 @@ class SERVER_EXPORT JackMidiDriver : public JackDriver const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency); - - virtual int Process(); + + virtual int SetBufferSize(jack_nframes_t buffer_size); + + virtual int ProcessRead(); + virtual int ProcessWrite(); + virtual int ProcessNull(); virtual int Attach(); virtual int Detach(); - + virtual int Read(); virtual int Write(); - + }; } // end of namespace diff --git a/common/JackMidiPort.cpp b/common/JackMidiPort.cpp index 42ee245c..5bd82341 100644 --- a/common/JackMidiPort.cpp +++ b/common/JackMidiPort.cpp @@ -55,7 +55,6 @@ SERVER_EXPORT jack_midi_data_t* JackMidiBuffer::ReserveEvent(jack_nframes_t time lost_events++; return 0; } - JackMidiEvent* event = &events[event_count++]; event->time = time; event->size = size; @@ -90,7 +89,7 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count { JackMidiBuffer* mix = static_cast(mixbuffer); if (!mix->IsValid()) { - jack_error("MIDI: invalid mix buffer"); + jack_error("Jack::MidiBufferMixdown - invalid mix buffer"); return; } mix->Reset(nframes); @@ -98,8 +97,10 @@ static void MidiBufferMixdown(void* mixbuffer, void** src_buffers, int src_count int event_count = 0; for (int i = 0; i < src_count; ++i) { JackMidiBuffer* buf = static_cast(src_buffers[i]); - if (!buf->IsValid()) + if (!buf->IsValid()) { + jack_error("Jack::MidiBufferMixdown - invalid source buffer"); return; + } buf->mix_index = 0; event_count += buf->event_count; mix->lost_events += buf->lost_events; diff --git a/common/JackMidiRawInputWriteQueue.cpp b/common/JackMidiRawInputWriteQueue.cpp new file mode 100644 index 00000000..f2853160 --- /dev/null +++ b/common/JackMidiRawInputWriteQueue.cpp @@ -0,0 +1,300 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include +#include +#include + +#include "JackMidiRawInputWriteQueue.h" + +using Jack::JackMidiRawInputWriteQueue; + +JackMidiRawInputWriteQueue:: +JackMidiRawInputWriteQueue(JackMidiWriteQueue *write_queue, + size_t max_packet_data, size_t max_packets) +{ + packet_queue = new JackMidiAsyncQueue(max_packet_data, max_packets); + std::auto_ptr packet_queue_ptr(packet_queue); + input_ring = jack_ringbuffer_create(max_packet_data + 1); + if (! input_ring) { + throw std::bad_alloc(); + } + jack_ringbuffer_mlock(input_ring); + Clear(); + expected_bytes = 0; + event_pending = false; + packet = 0; + status_byte = 0; + this->write_queue = write_queue; + packet_queue_ptr.release(); +} + +JackMidiRawInputWriteQueue::~JackMidiRawInputWriteQueue() +{ + jack_ringbuffer_free(input_ring); + delete packet_queue; +} + +void +JackMidiRawInputWriteQueue::Clear() +{ + jack_ringbuffer_reset(input_ring); + total_bytes = 0; + unbuffered_bytes = 0; +} + +Jack::JackMidiWriteQueue::EnqueueResult +JackMidiRawInputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer) +{ + return packet_queue->EnqueueEvent(time, size, buffer); +} + +void +JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_bytes, + size_t total_bytes) +{ + jack_error("JackMidiRawInputWriteQueue::HandleBufferFailure - %d MIDI " + "byte(s) of a %d byte message could not be buffered. The " + "message has been dropped.", unbuffered_bytes, total_bytes); +} + +void +JackMidiRawInputWriteQueue::HandleEventLoss(jack_midi_event_t *event) +{ + jack_error("JackMidiRawInputWriteQueue::HandleEventLoss - A %d byte MIDI " + "event scheduled for frame '%d' could not be processed because " + "the write queue cannot accomodate an event of that size. The " + "event has been discarded.", event->size, event->time); +} + +void +JackMidiRawInputWriteQueue::HandleIncompleteMessage(size_t total_bytes) +{ + jack_error("JackMidiRawInputWriteQueue::HandleIncompleteMessage - " + "Discarding %d MIDI byte(s) of an incomplete message. The " + "MIDI cable may have been unplugged.", total_bytes); +} + +void +JackMidiRawInputWriteQueue::HandleInvalidStatusByte(jack_midi_data_t byte) +{ + jack_error("JackMidiRawInputWriteQueue::HandleInvalidStatusByte - " + "Dropping invalid MIDI status byte '%x'.", (unsigned int) byte); +} + +void +JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd(size_t total_bytes) +{ + jack_error("JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd - " + "Received a sysex end byte without first receiving a sysex " + "start byte. Discarding %d MIDI byte(s). The cable may have " + "been unplugged.", total_bytes); +} + +bool +JackMidiRawInputWriteQueue::PrepareBufferedEvent(jack_nframes_t time) +{ + bool result = ! unbuffered_bytes; + if (! result) { + HandleBufferFailure(unbuffered_bytes, total_bytes); + } else { + size_t size = jack_ringbuffer_read_space(input_ring); + jack_ringbuffer_data_t vector[2]; + jack_ringbuffer_get_read_vector(input_ring, vector); + // We don't worry about the second part of the vector, as we reset the + // ringbuffer after each parsed message. + PrepareEvent(time, size, (jack_midi_data_t *) vector[0].buf); + } + Clear(); + if (status_byte >= 0xf0) { + expected_bytes = 0; + status_byte = 0; + } + return result; +} + +bool +JackMidiRawInputWriteQueue::PrepareByteEvent(jack_nframes_t time, + jack_midi_data_t byte) +{ + event_byte = byte; + PrepareEvent(time, 1, &event_byte); + return true; +} + +void +JackMidiRawInputWriteQueue::PrepareEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer) +{ + event.buffer = buffer; + event.size = size; + event.time = time; + event_pending = true; +} + +jack_nframes_t +JackMidiRawInputWriteQueue::Process(jack_nframes_t boundary_frame) +{ + if (event_pending) { + if (! WriteEvent(boundary_frame)) { + return event.time; + } + } + if (! packet) { + packet = packet_queue->DequeueEvent(); + } + for (; packet; packet = packet_queue->DequeueEvent()) { + for (; packet->size; (packet->buffer)++, (packet->size)--) { + if (ProcessByte(packet->time, *(packet->buffer))) { + if (! WriteEvent(boundary_frame)) { + (packet->buffer)++; + (packet->size)--; + return event.time; + } + } + } + } + return 0; +} + +bool +JackMidiRawInputWriteQueue::ProcessByte(jack_nframes_t time, + jack_midi_data_t byte) +{ + if (byte >= 0xf8) { + // Realtime + if (byte == 0xfd) { + HandleInvalidStatusByte(byte); + return false; + } + return PrepareByteEvent(time, byte); + } + if (byte == 0xf7) { + // Sysex end + if (status_byte == 0xf0) { + RecordByte(byte); + return PrepareBufferedEvent(time); + } + HandleUnexpectedSysexEnd(total_bytes); + Clear(); + expected_bytes = 0; + status_byte = 0; + return false; + } + if (byte >= 0x80) { + // Non-realtime status byte + if (total_bytes) { + HandleIncompleteMessage(total_bytes); + Clear(); + } + status_byte = byte; + switch (byte & 0xf0) { + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: + case 0xe0: + // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel + expected_bytes = 3; + break; + case 0xc0: + case 0xd0: + // Program Change, Channel Pressure + expected_bytes = 2; + break; + case 0xf0: + switch (byte) { + case 0xf0: + // Sysex + expected_bytes = 0; + break; + case 0xf1: + case 0xf3: + // MTC Quarter Frame, Song Select + expected_bytes = 2; + break; + case 0xf2: + // Song Position + expected_bytes = 3; + break; + case 0xf4: + case 0xf5: + // Undefined + HandleInvalidStatusByte(byte); + expected_bytes = 0; + status_byte = 0; + return false; + case 0xf6: + // Tune Request + bool result = PrepareByteEvent(time, byte); + if (result) { + expected_bytes = 0; + status_byte = 0; + } + return result; + } + } + RecordByte(byte); + return false; + } + // Data byte + if (! status_byte) { + // Data bytes without a status will be discarded. + total_bytes++; + unbuffered_bytes++; + return false; + } + if (! total_bytes) { + // Apply running status. + RecordByte(status_byte); + } + RecordByte(byte); + return (total_bytes == expected_bytes) ? PrepareBufferedEvent(time) : + false; +} + +void +JackMidiRawInputWriteQueue::RecordByte(jack_midi_data_t byte) +{ + if (jack_ringbuffer_write(input_ring, (const char *) &byte, 1) != 1) { + unbuffered_bytes++; + } + total_bytes++; +} + +bool +JackMidiRawInputWriteQueue::WriteEvent(jack_nframes_t boundary_frame) +{ + if ((! boundary_frame) || (event.time < boundary_frame)) { + switch (write_queue->EnqueueEvent(&event)) { + case BUFFER_TOO_SMALL: + HandleEventLoss(&event); + // Fallthrough on purpose + case OK: + event_pending = false; + return true; + default: + // This is here to stop compilers from warning us about not + // handling enumeration values. + ; + } + } + return false; +} diff --git a/common/JackMidiRawInputWriteQueue.h b/common/JackMidiRawInputWriteQueue.h new file mode 100644 index 00000000..4639107f --- /dev/null +++ b/common/JackMidiRawInputWriteQueue.h @@ -0,0 +1,170 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiRawInputWriteQueue__ +#define __JackMidiRawInputWriteQueue__ + +#include "JackMidiAsyncQueue.h" +#include "JackMidiWriteQueue.h" +#include "ringbuffer.h" + +namespace Jack { + + /** + * This queue enqueues raw, unparsed MIDI packets, and outputs complete + * MIDI messages to a write queue. + * + * Use this queue if the MIDI API you're interfacing with gives you raw + * MIDI bytes that must be parsed. + */ + + class SERVER_EXPORT JackMidiRawInputWriteQueue: public JackMidiWriteQueue { + + private: + + jack_midi_event_t event; + jack_midi_data_t event_byte; + bool event_pending; + size_t expected_bytes; + jack_ringbuffer_t *input_ring; + jack_midi_event_t *packet; + JackMidiAsyncQueue *packet_queue; + jack_midi_data_t status_byte; + size_t total_bytes; + size_t unbuffered_bytes; + JackMidiWriteQueue *write_queue; + + void + Clear(); + + bool + PrepareBufferedEvent(jack_nframes_t time); + + bool + PrepareByteEvent(jack_nframes_t time, jack_midi_data_t byte); + + void + PrepareEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer); + + bool + ProcessByte(jack_nframes_t time, jack_midi_data_t byte); + + void + RecordByte(jack_midi_data_t byte); + + bool + WriteEvent(jack_nframes_t boundary_frame); + + protected: + + /** + * Override this method to specify what happens when there isn't enough + * room in the ringbuffer to contain a parsed event. The default + * method outputs an error message. + */ + + virtual void + HandleBufferFailure(size_t unbuffered_bytes, size_t total_bytes); + + /** + * Override this method to specify what happens when a parsed event + * can't be written to the write queue because the event's size exceeds + * the total possible space in the write queue. The default method + * outputs an error message. + */ + + virtual void + HandleEventLoss(jack_midi_event_t *event); + + /** + * Override this method to specify what happens when an incomplete MIDI + * message is parsed. The default method outputs an error message. + */ + + virtual void + HandleIncompleteMessage(size_t total_bytes); + + /** + * Override this method to specify what happens when an invalid MIDI + * status byte is parsed. The default method outputs an error message. + */ + + virtual void + HandleInvalidStatusByte(jack_midi_data_t byte); + + /** + * Override this method to specify what happens when a sysex end byte + * is parsed without first parsing a sysex begin byte. The default + * method outputs an error message. + */ + + virtual void + HandleUnexpectedSysexEnd(size_t total_bytes); + + public: + + using JackMidiWriteQueue::EnqueueEvent; + + /** + * Called to create a new raw input write queue. The `write_queue` + * argument is the queue to write parsed messages to. The optional + * `max_packets` argument specifies the number of packets that can be + * enqueued in the internal queue. The optional `max_packet_data` + * argument specifies the total number of MIDI bytes that can be put in + * the internal queue, AND the maximum size for an event that can be + * written to the write queue. + */ + + JackMidiRawInputWriteQueue(JackMidiWriteQueue *write_queue, + size_t max_packet_data=4096, + size_t max_packets=1024); + + ~JackMidiRawInputWriteQueue(); + + EnqueueResult + EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer); + + /** + * The `Process()` method should be called each time the + * `EnqueueEvent()` method returns `OK`. The `Process()` method will + * return the next frame at which an event should be sent. The return + * value from `Process()` depends upon the result of writing bytes to + * the write queue: + * + * -If the return value is '0', then all *complete* events have been + * sent successfully to the write queue. Don't call `Process()` again + * until another event has been enqueued. + * + * -If the return value is a non-zero value, then it specifies the + * frame that a pending event is scheduled to sent at. If the frame is + * in the future, then `Process()` should be called again at that time; + * otherwise, `Process()` should be called as soon as the write queue + * will accept events again. + */ + + jack_nframes_t + Process(jack_nframes_t boundary_frame=0); + + }; + +} + +#endif diff --git a/common/JackMidiRawOutputWriteQueue.cpp b/common/JackMidiRawOutputWriteQueue.cpp new file mode 100644 index 00000000..6624c47c --- /dev/null +++ b/common/JackMidiRawOutputWriteQueue.cpp @@ -0,0 +1,228 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include +#include + +#include "JackError.h" +#include "JackMidiRawOutputWriteQueue.h" +#include "JackMidiUtil.h" + +using Jack::JackMidiRawOutputWriteQueue; + +#define STILL_TIME(c, b) ((! (b)) || ((c) < (b))) + +JackMidiRawOutputWriteQueue:: +JackMidiRawOutputWriteQueue(JackMidiSendQueue *send_queue, size_t non_rt_size, + size_t max_non_rt_messages, size_t max_rt_messages) +{ + non_rt_queue = new JackMidiAsyncQueue(non_rt_size, max_non_rt_messages); + std::auto_ptr non_rt_ptr(non_rt_queue); + rt_queue = new JackMidiAsyncQueue(max_rt_messages, max_rt_messages); + std::auto_ptr rt_ptr(rt_queue); + non_rt_event = 0; + rt_event = 0; + running_status = 0; + this->send_queue = send_queue; + rt_ptr.release(); + non_rt_ptr.release(); +} + +JackMidiRawOutputWriteQueue::~JackMidiRawOutputWriteQueue() +{ + delete non_rt_queue; + delete rt_queue; +} + +bool +JackMidiRawOutputWriteQueue::DequeueNonRealtimeEvent() +{ + non_rt_event = non_rt_queue->DequeueEvent(); + bool result = non_rt_event != 0; + if (result) { + non_rt_event_time = non_rt_event->time; + running_status = ApplyRunningStatus(non_rt_event, running_status); + } + return result; +} + +bool +JackMidiRawOutputWriteQueue::DequeueRealtimeEvent() +{ + rt_event = rt_queue->DequeueEvent(); + bool result = rt_event != 0; + if (result) { + rt_event_time = rt_event->time; + } + return result; +} + +Jack::JackMidiWriteQueue::EnqueueResult +JackMidiRawOutputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer) +{ + JackMidiAsyncQueue *queue = (size == 1) && (*buffer >= 0xf8) ? rt_queue : + non_rt_queue; + EnqueueResult result = queue->EnqueueEvent(time, size, buffer); + if (result == OK) { + last_enqueued_message_time = time; + } + return result; +} + +void +JackMidiRawOutputWriteQueue::HandleWriteQueueBug(jack_nframes_t time, + jack_midi_data_t byte) +{ + jack_error("JackMidiRawOutputWriteQueue::HandleWriteQueueBug - **BUG** " + "The write queue told us that it couldn't enqueue a 1-byte " + "MIDI event scheduled for frame '%d'. This is probably a bug " + "in the write queue implementation.", time); +} + +jack_nframes_t +JackMidiRawOutputWriteQueue::Process(jack_nframes_t boundary_frame) +{ + jack_nframes_t current_frame = send_queue->GetNextScheduleFrame(); + while (STILL_TIME(current_frame, boundary_frame)) { + if (! non_rt_event) { + DequeueNonRealtimeEvent(); + } + if (! rt_event) { + DequeueRealtimeEvent(); + } + if (! (non_rt_event || rt_event)) { + return 0; + } + if (! WriteRealtimeEvents(boundary_frame)) { + break; + } + jack_nframes_t non_rt_boundary = + rt_event && STILL_TIME(rt_event_time, boundary_frame) ? + rt_event_time : boundary_frame; + if (! WriteNonRealtimeEvents(non_rt_boundary)) { + break; + } + current_frame = send_queue->GetNextScheduleFrame(); + } + + // If we get here, that means there is some sort of message available, and + // that either we can't currently write to the write queue or we have + // reached the boundary frame. Return the earliest time that a message is + // scheduled to be sent. + + return ! non_rt_event ? rt_event_time : + non_rt_event->size > 1 ? current_frame : + ! rt_event ? non_rt_event_time : + non_rt_event_time < rt_event_time ? non_rt_event_time : rt_event_time; +} + +bool +JackMidiRawOutputWriteQueue::SendByte(jack_nframes_t time, + jack_midi_data_t byte) +{ + switch (send_queue->EnqueueEvent(time, 1, &byte)) { + case BUFFER_TOO_SMALL: + HandleWriteQueueBug(time, byte); + case OK: + return true; + default: + // This is here to stop compilers from warning us about not handling + // enumeration values. + ; + } + return false; +} + +bool +JackMidiRawOutputWriteQueue:: +WriteNonRealtimeEvents(jack_nframes_t boundary_frame) +{ + if (! non_rt_event) { + if (! DequeueNonRealtimeEvent()) { + return true; + } + } + jack_nframes_t current_frame = send_queue->GetNextScheduleFrame(); + do { + + // Send out as much of the non-realtime buffer as we can, save for one + // byte which we will send out when the message is supposed to arrive. + + for (; non_rt_event->size > 1; + (non_rt_event->size)--, (non_rt_event->buffer)++) { + if (! STILL_TIME(current_frame, boundary_frame)) { + return true; + } + if (! SendByte(current_frame, *(non_rt_event->buffer))) { + return false; + } + current_frame = send_queue->GetNextScheduleFrame(); + } + if (! (STILL_TIME(current_frame, boundary_frame) && + STILL_TIME(non_rt_event_time, boundary_frame))) { + return true; + } + + // There's still time. Try to send the byte. + + if (! SendByte(non_rt_event_time, *(non_rt_event->buffer))) { + return false; + } + current_frame = send_queue->GetNextScheduleFrame(); + if (! DequeueNonRealtimeEvent()) { + break; + } + } while (STILL_TIME(current_frame, boundary_frame)); + return true; +} + +bool +JackMidiRawOutputWriteQueue::WriteRealtimeEvents(jack_nframes_t boundary_frame) +{ + jack_nframes_t current_frame = send_queue->GetNextScheduleFrame(); + if (! rt_event) { + if (! DequeueRealtimeEvent()) { + return true; + } + } + for (;;) { + if (! STILL_TIME(current_frame, boundary_frame)) { + return false; + } + + // If: + // -there's still time before we need to send the realtime event + // -there's a non-realtime event available for sending + // -non-realtime data can be scheduled before this event + + if ((rt_event_time > current_frame) && non_rt_event && + ((non_rt_event->size > 1) || + (non_rt_event_time < rt_event_time))) { + return true; + } + if (! SendByte(rt_event_time, *(rt_event->buffer))) { + return false; + } + current_frame = send_queue->GetNextScheduleFrame(); + if (! DequeueRealtimeEvent()) { + return true; + } + } +} diff --git a/common/JackMidiRawOutputWriteQueue.h b/common/JackMidiRawOutputWriteQueue.h new file mode 100644 index 00000000..0437ec93 --- /dev/null +++ b/common/JackMidiRawOutputWriteQueue.h @@ -0,0 +1,147 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiRawOutputWriteQueue__ +#define __JackMidiRawOutputWriteQueue__ + +#include "JackMidiAsyncQueue.h" +#include "JackMidiSendQueue.h" + +namespace Jack { + + /** + * This queue enqueues valid MIDI events and modifies them for raw output + * to a write queue. It has a number of advantages over straight MIDI + * event copying: + * + * -Running status: Status bytes can be omitted when the status byte of the + * current MIDI message is the same as the status byte of the last sent + * MIDI message. + * + * -Realtime messages: Realtime messages are given priority over + * non-realtime messages. Realtime bytes are interspersed with + * non-realtime bytes so that realtime messages can be sent as close as + * possible to the time they're scheduled for sending. + * + * -Time optimization: Bytes in non-realtime messages are sent out early + * when possible, with the last byte of the message being sent out as close + * to the specified event time as possible. + * + * Use this queue if the MIDI API you're interfacing with allows you to + * send raw MIDI bytes. + */ + + class SERVER_EXPORT JackMidiRawOutputWriteQueue: + public JackMidiWriteQueue { + + private: + + jack_nframes_t last_enqueued_message_time; + jack_midi_event_t *non_rt_event; + jack_nframes_t non_rt_event_time; + JackMidiAsyncQueue *non_rt_queue; + jack_midi_event_t *rt_event; + jack_nframes_t rt_event_time; + JackMidiAsyncQueue *rt_queue; + jack_midi_data_t running_status; + JackMidiSendQueue *send_queue; + + bool + DequeueNonRealtimeEvent(); + + bool + DequeueRealtimeEvent(); + + bool + SendByte(jack_nframes_t time, jack_midi_data_t byte); + + bool + WriteNonRealtimeEvents(jack_nframes_t boundary_frame); + + bool + WriteRealtimeEvents(jack_nframes_t boundary_frame); + + protected: + + /** + * Override this method to specify what happens when the write queue + * says that a 1-byte event is too large for its buffer. Basically, + * this should never happen. + */ + + virtual void + HandleWriteQueueBug(jack_nframes_t time, jack_midi_data_t byte); + + public: + + using JackMidiWriteQueue::EnqueueEvent; + + /** + * Called to create a new raw write queue. The `send_queue` argument + * is the queue to write raw bytes to. The optional `max_rt_messages` + * argument specifies the number of messages that can be enqueued in + * the internal realtime queue. The optional `max_non_rt_messages` + * argument specifies the number of messages that can be enqueued in + * the internal non-realtime queue. The optional `non_rt_size` + * argument specifies the total number of MIDI bytes that can be put in + * the non-realtime queue. + */ + + JackMidiRawOutputWriteQueue(JackMidiSendQueue *send_queue, + size_t non_rt_size=4096, + size_t max_non_rt_messages=1024, + size_t max_rt_messages=128); + + ~JackMidiRawOutputWriteQueue(); + + EnqueueResult + EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer); + + /** + * The `Process()` method should be called each time the + * `EnqueueEvent()` method returns 'OK'. The `Process()` method will + * return the next frame at which an event should be sent. The return + * value from `Process()` depends upon the result of writing bytes to + * the write queue: + * + * -If the return value is '0', then all events that have been enqueued + * in this queue have been sent successfully to the write queue. Don't + * call `Process()` again until another event has been enqueued. + * + * -If the return value is an earlier frame or the current frame, it + * means that the write queue returned 'BUFFER_FULL', 'ERROR', or + * 'EVENT_EARLY' when this queue attempted to send the next byte, and + * that the byte should have already been sent, or is scheduled to be + * sent *now*. `Process()` should be called again when the write queue + * can enqueue events again successfully. How to determine when this + * will happen is left up to the caller. + * + * -If the return value is in the future, then `Process()` should be + * called again at that time, or after another event is enqueued. + */ + + jack_nframes_t + Process(jack_nframes_t boundary_frame=0); + + }; + +} + +#endif diff --git a/common/JackMidiReadQueue.cpp b/common/JackMidiReadQueue.cpp new file mode 100644 index 00000000..a6869691 --- /dev/null +++ b/common/JackMidiReadQueue.cpp @@ -0,0 +1,27 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackMidiReadQueue.h" + +using Jack::JackMidiReadQueue; + +JackMidiReadQueue::~JackMidiReadQueue() +{ + // Empty +} diff --git a/common/JackMidiReadQueue.h b/common/JackMidiReadQueue.h new file mode 100644 index 00000000..0f4ca692 --- /dev/null +++ b/common/JackMidiReadQueue.h @@ -0,0 +1,55 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiReadQueue__ +#define __JackMidiReadQueue__ + +#include "JackMidiPort.h" + +namespace Jack { + + /** + * Interface for objects that MIDI events can be read from. + */ + + class SERVER_EXPORT JackMidiReadQueue { + + public: + + virtual + ~JackMidiReadQueue(); + + /** + * Dequeues an event from the queue. Returns the event, or 0 if no + * events are available for reading. + * + * An event dequeued from the read queue is guaranteed to be valid up + * until another event is dequeued, at which all bets are off. Make + * sure that you handle each event you dequeue before dequeueing the + * next event. + */ + + virtual jack_midi_event_t * + DequeueEvent() = 0; + + }; + +} + +#endif diff --git a/common/JackMidiReceiveQueue.cpp b/common/JackMidiReceiveQueue.cpp new file mode 100644 index 00000000..3eb3573e --- /dev/null +++ b/common/JackMidiReceiveQueue.cpp @@ -0,0 +1,27 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackMidiReceiveQueue.h" + +using Jack::JackMidiReceiveQueue; + +JackMidiReceiveQueue::~JackMidiReceiveQueue() +{ + // Empty +} diff --git a/common/JackMidiReceiveQueue.h b/common/JackMidiReceiveQueue.h new file mode 100644 index 00000000..1d19c3c1 --- /dev/null +++ b/common/JackMidiReceiveQueue.h @@ -0,0 +1,42 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiReceiveQueue__ +#define __JackMidiReceiveQueue__ + +#include "JackMidiReadQueue.h" + +namespace Jack { + + /** + * Implemented by MIDI input connections. + */ + + class SERVER_EXPORT JackMidiReceiveQueue: public JackMidiReadQueue { + + public: + + virtual + ~JackMidiReceiveQueue(); + + }; + +} + +#endif diff --git a/common/JackMidiSendQueue.cpp b/common/JackMidiSendQueue.cpp new file mode 100644 index 00000000..ac66d812 --- /dev/null +++ b/common/JackMidiSendQueue.cpp @@ -0,0 +1,34 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackMidiSendQueue.h" +#include "JackMidiUtil.h" + +using Jack::JackMidiSendQueue; + +JackMidiSendQueue::~JackMidiSendQueue() +{ + // Empty +} + +jack_nframes_t +JackMidiSendQueue::GetNextScheduleFrame() +{ + return GetCurrentFrame(); +} diff --git a/common/JackMidiSendQueue.h b/common/JackMidiSendQueue.h new file mode 100644 index 00000000..0cb8df44 --- /dev/null +++ b/common/JackMidiSendQueue.h @@ -0,0 +1,52 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiSendQueue__ +#define __JackMidiSendQueue__ + +#include "JackMidiWriteQueue.h" + +namespace Jack { + + /** + * Implemented by MIDI output connections. + */ + + class SERVER_EXPORT JackMidiSendQueue: public JackMidiWriteQueue { + + public: + + using JackMidiWriteQueue::EnqueueEvent; + + virtual + ~JackMidiSendQueue(); + + /** + * Returns the next frame that a MIDI message can be sent at. The + * default method returns the current frame. + */ + + virtual jack_nframes_t + GetNextScheduleFrame(); + + }; + +} + +#endif diff --git a/common/JackMidiUtil.cpp b/common/JackMidiUtil.cpp new file mode 100644 index 00000000..94871ce5 --- /dev/null +++ b/common/JackMidiUtil.cpp @@ -0,0 +1,120 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackEngineControl.h" +#include "JackFrameTimer.h" +#include "JackGlobals.h" +#include "JackMidiUtil.h" +#include "JackTime.h" + +jack_midi_data_t +Jack::ApplyRunningStatus(size_t *size, jack_midi_data_t **buffer, + jack_midi_data_t running_status) +{ + + // Stolen and modified from alsa/midi_pack.h + + jack_midi_data_t status = **buffer; + if ((status >= 0x80) && (status < 0xf0)) { + if (status == running_status) { + (*buffer)++; + (*size)--; + } else { + running_status = status; + } + } else if (status < 0xf8) { + running_status = 0; + } + return running_status; +} + +jack_midi_data_t +Jack::ApplyRunningStatus(jack_midi_event_t *event, + jack_midi_data_t running_status) +{ + return ApplyRunningStatus(&(event->size), &(event->buffer), + running_status); +} + +jack_nframes_t +Jack::GetCurrentFrame() +{ + JackEngineControl *control = GetEngineControl(); + JackTimer timer; + control->ReadFrameTime(&timer); + return timer.Time2Frames(GetMicroSeconds(), control->fBufferSize); +} + +jack_nframes_t +Jack::GetFramesFromTime(jack_time_t time) +{ + JackEngineControl* control = GetEngineControl(); + JackTimer timer; + control->ReadFrameTime(&timer); + return timer.Time2Frames(time, control->fBufferSize); +} + +jack_nframes_t +Jack::GetLastFrame() +{ + return GetEngineControl()->fFrameTimer.ReadCurrentState()->CurFrame(); +} + +int +Jack::GetMessageLength(jack_midi_data_t status_byte) +{ + switch (status_byte & 0xf0) { + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: + case 0xe0: + return 3; + case 0xc0: + case 0xd0: + return 2; + case 0xf0: + switch (status_byte) { + case 0xf0: + return 0; + case 0xf1: + case 0xf3: + return 2; + case 0xf2: + return 3; + case 0xf4: + case 0xf5: + case 0xf7: + case 0xfd: + break; + default: + return 1; + } + } + return -1; +} + +jack_time_t +Jack::GetTimeFromFrames(jack_nframes_t frames) +{ + JackEngineControl* control = GetEngineControl(); + JackTimer timer; + control->ReadFrameTime(&timer); + return timer.Frames2Time(frames, control->fBufferSize); +} diff --git a/common/JackMidiUtil.h b/common/JackMidiUtil.h new file mode 100644 index 00000000..52db64c8 --- /dev/null +++ b/common/JackMidiUtil.h @@ -0,0 +1,102 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiUtil__ +#define __JackMidiUtil__ + +#include "JackMidiPort.h" + +namespace Jack { + + /** + * Use this function to optimize MIDI output by omitting unnecessary status + * bytes. This can't be used with all MIDI APIs, so before using this + * function, make sure that your MIDI API doesn't require complete MIDI + * messages to be sent. + * + * To start using this function, call this method with pointers to the + * `size` and `buffer` arguments of the MIDI message you want to send, and + * set the `running_status` argument to '0'. For each subsequent MIDI + * message, call this method with pointers to its `size` and `buffer` + * arguments, and set the `running_status` argument to the return value of + * the previous call to this function. + * + * Note: This function will alter the `size` and `buffer` of your MIDI + * message for each message that can be optimized. + */ + + SERVER_EXPORT jack_midi_data_t + ApplyRunningStatus(size_t *size, jack_midi_data_t **buffer, + jack_midi_data_t running_status=0); + + /** + * A wrapper function for the above `ApplyRunningStatus` function. + */ + + SERVER_EXPORT jack_midi_data_t + ApplyRunningStatus(jack_midi_event_t *event, + jack_midi_data_t running_status); + + /** + * Gets the estimated current time in frames. This function has the same + * functionality as the JACK client API function `jack_frame_time`. + */ + + SERVER_EXPORT jack_nframes_t + GetCurrentFrame(); + + /** + * Gets the estimated frame that will be occurring at the given time. This + * function has the same functionality as the JACK client API function + * `jack_time_to_frames`. + */ + + SERVER_EXPORT jack_nframes_t + GetFramesFromTime(jack_time_t time); + + /** + * Gets the precise time at the start of the current process cycle. This + * function has the same functionality as the JACK client API function + * `jack_last_frame_time`. + */ + + SERVER_EXPORT jack_nframes_t + GetLastFrame(); + + /** + * Returns the expected message length for the status byte. Returns 0 if + * the status byte is a system exclusive status byte, or -1 if the status + * byte is invalid. + */ + + SERVER_EXPORT int + GetMessageLength(jack_midi_data_t status_byte); + + /** + * Gets the estimated time at which the given frame will occur. This + * function has the same functionality as the JACK client API function + * `jack_frames_to_time`. + */ + + SERVER_EXPORT jack_time_t + GetTimeFromFrames(jack_nframes_t frames); + +}; + +#endif diff --git a/common/JackMidiWriteQueue.cpp b/common/JackMidiWriteQueue.cpp new file mode 100644 index 00000000..37fd9067 --- /dev/null +++ b/common/JackMidiWriteQueue.cpp @@ -0,0 +1,27 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackMidiWriteQueue.h" + +using Jack::JackMidiWriteQueue; + +JackMidiWriteQueue::~JackMidiWriteQueue() +{ + // Empty +} diff --git a/common/JackMidiWriteQueue.h b/common/JackMidiWriteQueue.h new file mode 100644 index 00000000..f21a58ff --- /dev/null +++ b/common/JackMidiWriteQueue.h @@ -0,0 +1,82 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackMidiWriteQueue__ +#define __JackMidiWriteQueue__ + +#include "JackMidiPort.h" + +namespace Jack { + + /** + * Interface for classes that act as write queues for MIDI messages. Write + * queues are used by processors to transfer data to the next processor. + */ + + class SERVER_EXPORT JackMidiWriteQueue { + + public: + + enum EnqueueResult { + BUFFER_FULL, + BUFFER_TOO_SMALL, + EVENT_EARLY, + EN_ERROR, + OK + }; + + virtual ~JackMidiWriteQueue(); + + /** + * Enqueues a data packet in the write queue of `size` bytes contained + * in `buffer` that will be sent the absolute time specified by `time`. + * This method should not block unless 1.) this write queue represents + * the actual outbound MIDI connection, 2.) the MIDI event is being + * sent *now*, meaning that `time` is less than or equal to *now*, and + * 3.) the method is *not* being called in the process thread. The + * method should return `OK` if the event was enqueued, `BUFFER_FULL` + * 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 `EN_ERROR` if an error + * occurs that cannot be specified by another return code. + */ + + virtual EnqueueResult + EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer) = 0; + + /** + * A wrapper method for the `EnqueueEvent` method above. The optional + * 'frame_offset' argument is an amount of frames to add to the event's + * time. + */ + + inline EnqueueResult + EnqueueEvent(jack_midi_event_t *event, jack_nframes_t frame_offset=0) + { + return EnqueueEvent(event->time + frame_offset, event->size, + event->buffer); + } + + }; + +} + +#endif diff --git a/common/JackNetAdapter.cpp b/common/JackNetAdapter.cpp index d33572cd..864ddba4 100644 --- a/common/JackNetAdapter.cpp +++ b/common/JackNetAdapter.cpp @@ -164,6 +164,7 @@ namespace Jack #ifdef JACK_MONITOR fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize); #endif + fSocket.Close(); switch ( fThread.GetStatus() ) { @@ -177,7 +178,7 @@ namespace Jack } break; // Stop when the thread cycle is finished - + case JackThread::kRunning: if ( fThread.Stop() < 0 ) { @@ -185,11 +186,11 @@ namespace Jack return -1; } break; - + default: break; } - fSocket.Close(); + return 0; } @@ -242,16 +243,16 @@ namespace Jack //set audio adapter parameters SetAdaptedBufferSize ( fParams.fPeriodSize ); SetAdaptedSampleRate ( fParams.fSampleRate ); - + // Will do "something" on OSX only... fThread.SetParams(GetEngineControl()->fPeriod, GetEngineControl()->fComputation, GetEngineControl()->fConstraint); - + if (fThread.AcquireSelfRealTime(GetEngineControl()->fClientPriority) < 0) { jack_error("AcquireSelfRealTime error"); } else { set_threaded_log_function(); } - + //init done, display parameters SessionParamsDisplay ( &fParams ); return true; @@ -294,13 +295,13 @@ namespace Jack jack_transport_stop ( fJackClient ); jack_info ( "NetMaster : transport stops." ); break; - + case JackTransportStarting : jack_transport_reposition ( fJackClient, &fSendTransportData.fPosition ); jack_transport_start ( fJackClient ); jack_info ( "NetMaster : transport starts." ); break; - + case JackTransportRolling : //TODO , we need to : // - find a way to call TransportEngine->SetNetworkSync() @@ -362,7 +363,7 @@ namespace Jack int JackNetAdapter::Write() { EncodeSyncPacket(); - + if ( SyncSend() == SOCKET_ERROR ) return SOCKET_ERROR; @@ -376,7 +377,7 @@ namespace Jack //in case of fatal network error, stop the process if (Read() == SOCKET_ERROR) return SOCKET_ERROR; - + PushAndPull(fSoftCaptureBuffer, fSoftPlaybackBuffer, fAdaptedBufferSize); //then write data to network @@ -386,7 +387,7 @@ namespace Jack return 0; } - + } // namespace Jack //loader------------------------------------------------------------------------------ @@ -403,10 +404,10 @@ extern "C" SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor() { jack_driver_desc_t* desc = ( jack_driver_desc_t* ) calloc ( 1, sizeof ( jack_driver_desc_t ) ); - + strcpy(desc->name, "netadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 strcpy(desc->desc, "netjack net <==> audio backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 - + desc->nparams = 11; desc->params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) ); @@ -473,7 +474,7 @@ extern "C" strcpy ( desc->params[i].value.str, "slow" ); strcpy ( desc->params[i].short_desc, "Slow, Normal or Fast mode." ); strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); - + i++; strcpy(desc->params[i].name, "quality"); desc->params[i].character = 'q'; @@ -481,7 +482,7 @@ extern "C" desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "ring-buffer"); desc->params[i].character = 'g'; @@ -489,7 +490,7 @@ extern "C" desc->params[i].value.ui = 32768; strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)"); - + i++; strcpy ( desc->params[i].name, "auto-connect" ); desc->params[i].character = 'c'; @@ -497,7 +498,7 @@ extern "C" desc->params[i].value.i = false; strcpy ( desc->params[i].short_desc, "Auto connect netmaster to system ports" ); strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); - + return desc; } @@ -508,20 +509,19 @@ extern "C" Jack::JackAudioAdapter* adapter; jack_nframes_t buffer_size = jack_get_buffer_size ( jack_client ); jack_nframes_t sample_rate = jack_get_sample_rate ( jack_client ); - + try { - + adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackNetAdapter(jack_client, buffer_size, sample_rate, params), params, false); assert ( adapter ); - if ( adapter->Open() == 0 ) + if (adapter->Open() == 0) { return 0; - else - { + } else { delete adapter; return 1; } - + } catch (...) { return 1; } diff --git a/common/JackNetAdapter.h b/common/JackNetAdapter.h index f6b7675b..d90a1d97 100644 --- a/common/JackNetAdapter.h +++ b/common/JackNetAdapter.h @@ -30,44 +30,48 @@ namespace Jack \brief Net adapter. */ - class JackNetAdapter : public JackAudioAdapterInterface, public JackNetSlaveInterface, public JackRunnableInterface + class JackNetAdapter : public JackAudioAdapterInterface, + public JackNetSlaveInterface, + public JackRunnableInterface { - private: - //jack data - jack_client_t* fJackClient; - //transport data - int fLastTransportState; - int fLastTimebaseMaster; - - //sample buffers - sample_t** fSoftCaptureBuffer; - sample_t** fSoftPlaybackBuffer; + private: - //adapter thread - JackThread fThread; + //jack data + jack_client_t* fJackClient; - //transport - void EncodeTransportData(); - void DecodeTransportData(); + //transport data + int fLastTransportState; + int fLastTimebaseMaster; - public: + //sample buffers + sample_t** fSoftCaptureBuffer; + sample_t** fSoftPlaybackBuffer; - JackNetAdapter ( jack_client_t* jack_client, jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params ); - ~JackNetAdapter(); + //adapter thread + JackThread fThread; - int Open(); - int Close(); + //transport + void EncodeTransportData(); + void DecodeTransportData(); - int SetBufferSize ( jack_nframes_t buffer_size ); + public: - bool Init(); - bool Execute(); + JackNetAdapter(jack_client_t* jack_client, jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params); + ~JackNetAdapter(); - int Read(); - int Write(); + int Open(); + int Close(); - int Process(); + int SetBufferSize(jack_nframes_t buffer_size); + + bool Init(); + bool Execute(); + + int Read(); + int Write(); + + int Process(); }; } diff --git a/common/JackNetDriver.cpp b/common/JackNetDriver.cpp index f587411d..6f20a628 100644 --- a/common/JackNetDriver.cpp +++ b/common/JackNetDriver.cpp @@ -125,6 +125,7 @@ namespace Jack bool JackNetDriver::Initialize() { jack_log("JackNetDriver::Initialize()"); + FreePorts(); //new loading, but existing socket, restart the driver if (fSocket.IsSocket()) { @@ -143,7 +144,7 @@ namespace Jack //init network if (!JackNetSlaveInterface::Init()) { - jack_error("JackNetSlaveInterface::Init() error..." ); + jack_error("Starting network fails..."); return false; } @@ -153,21 +154,32 @@ namespace Jack return false; } + // If -1 at conection time, in/out channels count is sent by the master + fCaptureChannels = fParams.fSendAudioChannels; + fPlaybackChannels = fParams.fReturnAudioChannels; + //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 (int midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) { + fMidiCapturePortList[midi_port_index] = 0; + } + for (int midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) { + fMidiPlaybackPortList[midi_port_index] = 0; + } //register jack ports - if ( AllocPorts() != 0 ) - { - jack_error ( "Can't allocate ports." ); + if (AllocPorts() != 0) { + jack_error("Can't allocate ports."); return false; } //init done, display parameters - SessionParamsDisplay ( &fParams ); + SessionParamsDisplay(&fParams); //monitor #ifdef JACK_MONITOR @@ -257,7 +269,7 @@ namespace Jack char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; unsigned long port_flags; int audio_port_index; - uint midi_port_index; + int midi_port_index; jack_latency_range_t range; //audio @@ -365,22 +377,38 @@ namespace Jack int JackNetDriver::FreePorts() { - jack_log ( "JackNetDriver::FreePorts" ); + jack_log("JackNetDriver::FreePorts"); - int audio_port_index; - uint midi_port_index; - for ( audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++ ) - if (fCapturePortList[audio_port_index] > 0) - fGraphManager->ReleasePort ( fClientControl.fRefNum, fCapturePortList[audio_port_index] ); - for ( audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++ ) - if (fPlaybackPortList[audio_port_index] > 0) - fGraphManager->ReleasePort ( fClientControl.fRefNum, fPlaybackPortList[audio_port_index] ); - for ( midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++ ) - if (fMidiCapturePortList[midi_port_index] > 0) - fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiCapturePortList[midi_port_index] ); - for ( midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++ ) - if (fMidiPlaybackPortList[midi_port_index] > 0) - fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index] ); + for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) { + if (fCapturePortList[audio_port_index] > 0) { + fGraphManager->ReleasePort(fClientControl.fRefNum, fCapturePortList[audio_port_index]); + fCapturePortList[audio_port_index] = 0; + } + } + + 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]); + fPlaybackPortList[audio_port_index] = 0; + } + } + + for (int 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]); + fMidiCapturePortList[midi_port_index] = 0; + } + } + + for (int 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]); + fMidiPlaybackPortList[midi_port_index] = 0; + } + } + // Clear MIDI channels + fParams.fSendMidiChannels = 0; + fParams.fReturnMidiChannels = 0; return 0; } @@ -479,8 +507,8 @@ namespace Jack //driver processes-------------------------------------------------------------------- int JackNetDriver::Read() { - uint midi_port_index; - uint audio_port_index; + int midi_port_index; + int audio_port_index; //buffers for ( midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++ ) @@ -524,7 +552,7 @@ namespace Jack int JackNetDriver::Write() { - uint midi_port_index; + int midi_port_index; int audio_port_index; //buffers @@ -603,17 +631,17 @@ namespace Jack strcpy ( desc->params[i].name, "input_ports" ); desc->params[i].character = 'C'; desc->params[i].type = JackDriverParamInt; - desc->params[i].value.i = 2; + desc->params[i].value.i = -1; strcpy ( desc->params[i].short_desc, "Number of audio input ports" ); - strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); + strcpy ( desc->params[i].long_desc, "Number of audio input ports. If -1, audio physical input from the master"); i++; strcpy ( desc->params[i].name, "output_ports" ); desc->params[i].character = 'P'; desc->params[i].type = JackDriverParamInt; - desc->params[i].value.i = 2; + desc->params[i].value.i = -1; strcpy ( desc->params[i].short_desc, "Number of audio output ports" ); - strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); + strcpy ( desc->params[i].long_desc, "Number of audio output ports. If -1, audio physical output from the master"); i++; strcpy ( desc->params[i].name, "midi_in_ports" ); @@ -626,7 +654,7 @@ namespace Jack i++; strcpy ( desc->params[i].name, "midi_out_ports" ); desc->params[i].character = 'o'; - desc->params[i].type = JackDriverParamUInt; + desc->params[i].type = JackDriverParamInt; desc->params[i].value.i = 0; strcpy ( desc->params[i].short_desc, "Number of midi output ports" ); strcpy ( desc->params[i].long_desc, desc->params[i].short_desc ); @@ -668,8 +696,8 @@ namespace Jack uint transport_sync = 1; jack_nframes_t period_size = 128; jack_nframes_t sample_rate = 48000; - int audio_capture_ports = 2; - int audio_playback_ports = 2; + int audio_capture_ports = -1; + int audio_playback_ports = -1; int midi_input_ports = 0; int midi_output_ports = 0; bool monitor = false; diff --git a/common/JackNetDriver.h b/common/JackNetDriver.h index af137b43..7c4635ae 100644 --- a/common/JackNetDriver.h +++ b/common/JackNetDriver.h @@ -36,15 +36,17 @@ namespace Jack class JackNetDriver : public JackAudioDriver, public JackNetSlaveInterface { + private: + //jack data jack_port_id_t* fMidiCapturePortList; jack_port_id_t* fMidiPlaybackPortList; - + //transport int fLastTransportState; int fLastTimebaseMaster; - + //monitoring #ifdef JACK_MONITOR JackGnuPlotMonitor* fNetTimeMon; @@ -53,7 +55,7 @@ namespace Jack bool Initialize(); void FreeAll(); - + int AllocPorts(); int FreePorts(); @@ -65,6 +67,7 @@ namespace Jack JackMidiBuffer* GetMidiOutputBuffer ( int port_index ); public: + JackNetDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, const char* ip, int port, int mtu, int midi_input_ports, int midi_output_ports, char* net_name, uint transport_sync, char network_master_mode ); diff --git a/common/JackNetInterface.cpp b/common/JackNetInterface.cpp index 65562ceb..6ee89ede 100644 --- a/common/JackNetInterface.cpp +++ b/common/JackNetInterface.cpp @@ -27,9 +27,9 @@ using namespace std; #define PACKET_AVAILABLE_SIZE (fParams.fMtu - sizeof(packet_header_t)) #define HEADER_SIZE (sizeof(packet_header_t)) -/* - TODO : since midi buffers now uses up to BUFFER_SIZE_MAX frames, - probably also use BUFFER_SIZE_MAX in everything related to MIDI events +/* + TODO : since midi buffers now uses up to BUFFER_SIZE_MAX frames, + probably also use BUFFER_SIZE_MAX in everything related to MIDI events handling (see MidiBufferInit in JackMidiPort.cpp) */ @@ -169,7 +169,7 @@ namespace Jack //timeout on receive (for init) if ( fSocket.SetTimeOut ( MASTER_INIT_TIMEOUT ) < 0 ) jack_error ( "Can't set timeout : %s", StrError ( NET_ERROR_CODE ) ); - + //connect if ( fSocket.Connect() == SOCKET_ERROR ) { jack_error ( "Can't connect : %s", StrError ( NET_ERROR_CODE ) ); @@ -184,17 +184,17 @@ namespace Jack memset(&net_params, 0, sizeof ( session_params_t )); SetPacketType ( &fParams, SLAVE_SETUP ); SessionParamsHToN(&fParams, &net_params); - + if ( fSocket.Send ( &net_params, sizeof ( session_params_t ), 0 ) == SOCKET_ERROR ) jack_error ( "Error in send : ", StrError ( NET_ERROR_CODE ) ); - + memset(&net_params, 0, sizeof (session_params_t)); if (((rx_bytes = fSocket.Recv(&net_params, sizeof(session_params_t), 0)) == SOCKET_ERROR) && (fSocket.GetError() != NET_NO_DATA)) { jack_error ( "Problem with network." ); return false; } - + SessionParamsNToH(&net_params, &host_params); } while ( ( GetPacketType ( &host_params ) != START_MASTER ) && ( ++attempt < SLAVE_SETUP_RETRY ) ); @@ -320,7 +320,7 @@ namespace Jack jack_info ( "Exiting '%s'", fParams.fName ); SetPacketType ( &fParams, KILL_MASTER ); JackNetSocket mcast_socket ( fMulticastIP, fSocket.GetPort() ); - + session_params_t net_params; memset(&net_params, 0, sizeof ( session_params_t )); SessionParamsHToN(&fParams, &net_params); @@ -329,7 +329,7 @@ namespace Jack jack_error ( "Can't create socket : %s", StrError ( NET_ERROR_CODE ) ); if ( mcast_socket.SendTo ( &net_params, sizeof ( session_params_t ), 0, fMulticastIP ) == SOCKET_ERROR ) jack_error ( "Can't send suicide request : %s", StrError ( NET_ERROR_CODE ) ); - + mcast_socket.Close(); } @@ -347,32 +347,32 @@ namespace Jack jack_error ( "'%s' : %s, exiting.", fParams.fName, StrError(NET_ERROR_CODE)); //ask to the manager to properly remove the master Exit(); - + // UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine. ThreadExit(); } else { jack_error ( "Error in master receive : %s", StrError(NET_ERROR_CODE)); } } - + packet_header_t* header = reinterpret_cast(fRxBuffer); PacketHeaderNToH(header, header); return rx_bytes; } - + int JackNetMasterInterface::Send(size_t size, int flags) { int tx_bytes; packet_header_t* header = reinterpret_cast(fTxBuffer); PacketHeaderHToN(header, header); - + if (((tx_bytes = fSocket.Send(fTxBuffer, size, flags)) == SOCKET_ERROR) && fRunning) { net_error_t error = fSocket.GetError(); if (error == NET_CONN_ERROR) { //fatal connection issue, exit jack_error ("'%s' : %s, exiting.", fParams.fName, StrError (NET_ERROR_CODE)); Exit(); - + // UGLY temporary way to be sure the thread does not call code possibly causing a deadlock in JackEngine. ThreadExit(); } else { @@ -381,7 +381,7 @@ namespace Jack } return tx_bytes; } - + bool JackNetMasterInterface::IsSynched() { if (fParams.fNetworkMode == 's') { @@ -390,7 +390,7 @@ namespace Jack return true; } } - + int JackNetMasterInterface::SyncSend() { fTxHeader.fCycle++; @@ -452,12 +452,12 @@ namespace Jack { packet_header_t* rx_head = reinterpret_cast ( fRxBuffer ); int rx_bytes = Recv(HEADER_SIZE, MSG_PEEK); - + if ( ( rx_bytes == 0 ) || ( rx_bytes == SOCKET_ERROR ) ) return rx_bytes; fCycleOffset = fTxHeader.fCycle - rx_head->fCycle; - + switch ( fParams.fNetworkMode ) { case 's' : @@ -468,12 +468,12 @@ namespace Jack //the slow mode is the safest mode because it wait twice the bandwidth relative time (send/return + process) /* - if (fCycleOffset < CYCLE_OFFSET_SLOW) { - return 0; - } else { - rx_bytes = Recv ( rx_head->fPacketSize, 0 ); - } - */ + if (fCycleOffset < CYCLE_OFFSET_SLOW) { + return 0; + } else { + rx_bytes = Recv ( rx_head->fPacketSize, 0 ); + } + */ rx_bytes = Recv ( rx_head->fPacketSize, 0 ); @@ -481,7 +481,7 @@ namespace Jack jack_info("Warning : '%s' runs in slow network mode, but data received too late (%d cycle(s) offset)", fParams.fName, fCycleOffset); fLastfCycleOffset = fCycleOffset; break; - + case 'n' : //normal use of the network : // - extra latency is set to one cycle, what is the time needed to receive streams using full network bandwidth @@ -492,12 +492,12 @@ namespace Jack } else { rx_bytes = Recv ( rx_head->fPacketSize, 0 ); } - + if (fCycleOffset > CYCLE_OFFSET_NORMAL) { jack_info("'%s' can't run in normal network mode, data received too late (%d cycle(s) offset)", fParams.fName, fCycleOffset); } break; - + case 'f' : //fast mode suppose the network bandwith is larger than required for the transmission (only a few channels for example) // - packets can be quickly received, quickly is here relative to the cycle duration @@ -514,7 +514,7 @@ namespace Jack fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; return rx_bytes; } - + int JackNetMasterInterface::DataRecv() { int rx_bytes = 0; @@ -522,12 +522,12 @@ namespace Jack uint recvd_audio_pckt = 0; packet_header_t* rx_head = reinterpret_cast ( fRxBuffer ); - + while ( !fRxHeader.fIsLastPckt ) { //how much data is queued on the rx buffer ? rx_bytes = Recv(HEADER_SIZE, MSG_PEEK); - + //error here, problem with recv, just skip the cycle (return -1) if ( rx_bytes == SOCKET_ERROR ) return rx_bytes; @@ -569,7 +569,7 @@ namespace Jack return rx_bytes; } - + void JackNetMasterInterface::EncodeSyncPacket() { //this method contains every step of sync packet informations coding @@ -637,9 +637,9 @@ namespace Jack return true; } - + // Separate the connection protocol into two separated step - + bool JackNetSlaveInterface::InitConnection(int time_out) { jack_log("JackNetSlaveInterface::InitConnection()"); @@ -659,10 +659,10 @@ namespace Jack return false; } while (status != NET_CONNECTED && --try_count > 0); - + return (try_count != 0); } - + bool JackNetSlaveInterface::InitRendering() { jack_log("JackNetSlaveInterface::InitRendering()"); @@ -676,8 +676,8 @@ namespace Jack if (status == NET_ERROR) return false; } - while (status != NET_ROLLING); - + while (status != NET_ROLLING); + return true; } @@ -701,7 +701,7 @@ namespace Jack } //timeout on receive - if ( fSocket.SetTimeOut ( SLAVE_INIT_TIMEOUT ) == SOCKET_ERROR ) + if ( fSocket.SetTimeOut ( SLAVE_INIT_TIMEOUT ) == SOCKET_ERROR ) jack_error ( "Can't set timeout : %s", StrError ( NET_ERROR_CODE ) ); //disable local loop @@ -718,7 +718,7 @@ namespace Jack SessionParamsHToN(&fParams, &net_params); if ( fSocket.SendTo ( &net_params, sizeof ( session_params_t ), 0, fMulticastIP ) == SOCKET_ERROR ) jack_error ( "Error in data send : %s", StrError ( NET_ERROR_CODE ) ); - + //filter incoming packets : don't exit while no error is detected memset(&net_params, 0, sizeof ( session_params_t )); rx_bytes = fSocket.CatchHost ( &net_params, sizeof ( session_params_t ), 0 ); @@ -768,7 +768,7 @@ namespace Jack bool JackNetSlaveInterface::SetParams() { - jack_log ( "JackNetSlaveInterface::SetParams" ); + jack_log("JackNetSlaveInterface::SetParams"); JackNetInterface::SetParams(); @@ -861,7 +861,7 @@ namespace Jack jack_error ( "Fatal error in slave receive : %s", StrError ( NET_ERROR_CODE ) ); } } - + packet_header_t* header = reinterpret_cast(fRxBuffer); PacketHeaderNToH(header, header); return rx_bytes; @@ -872,7 +872,7 @@ namespace Jack packet_header_t* header = reinterpret_cast(fTxBuffer); PacketHeaderHToN(header, header); int tx_bytes = fSocket.Send ( fTxBuffer, size, flags ); - + //handle errors if ( tx_bytes == SOCKET_ERROR ) { @@ -902,7 +902,7 @@ namespace Jack return rx_bytes; } while ((strcmp(rx_head->fPacketType, "header") != 0) && (rx_head->fDataType != 's')); - + fRxHeader.fIsLastPckt = rx_head->fIsLastPckt; return rx_bytes; } @@ -1020,7 +1020,7 @@ namespace Jack } return 0; } - + //network sync------------------------------------------------------------------------ void JackNetSlaveInterface::EncodeSyncPacket() { @@ -1037,7 +1037,7 @@ namespace Jack //then others //... } - + void JackNetSlaveInterface::DecodeSyncPacket() { //this method contains every step of sync packet informations decoding process diff --git a/common/JackNetInterface.h b/common/JackNetInterface.h index 8e3aab93..a3ec7660 100644 --- a/common/JackNetInterface.h +++ b/common/JackNetInterface.h @@ -31,12 +31,10 @@ namespace Jack class SERVER_EXPORT JackNetInterface { - private: + protected: void Initialize(); - protected: - session_params_t fParams; JackNetSocket fSocket; char fMulticastIP[32]; @@ -44,7 +42,7 @@ namespace Jack //headers packet_header_t fTxHeader; packet_header_t fRxHeader; - + // transport net_transport_data_t fSendTransportData; net_transport_data_t fReturnTransportData; @@ -90,7 +88,9 @@ namespace Jack JackNetInterface ( session_params_t& params, JackNetSocket& socket, const char* multicast_ip ); public: + virtual ~JackNetInterface(); + }; /** @@ -99,7 +99,9 @@ namespace Jack class SERVER_EXPORT JackNetMasterInterface : public JackNetInterface { + protected: + bool fRunning; int fCycleOffset; int fLastfCycleOffset; @@ -107,22 +109,22 @@ namespace Jack bool Init(); int SetRxTimeout(); bool SetParams(); - + void Exit(); - + int SyncRecv(); int SyncSend(); - + int DataRecv(); int DataSend(); - + //sync packet void EncodeSyncPacket(); void DecodeSyncPacket(); int Send ( size_t size, int flags ); int Recv ( size_t size, int flags ); - + bool IsSynched(); public: @@ -141,25 +143,26 @@ namespace Jack class SERVER_EXPORT JackNetSlaveInterface : public JackNetInterface { + protected: - + static uint fSlaveCounter; - + bool Init(); bool InitConnection(int time_out); bool InitRendering(); - + net_status_t SendAvailableToMaster(long count = LONG_MAX); // long here (and not int...) net_status_t SendStartToMaster(); - + bool SetParams(); - + int SyncRecv(); int SyncSend(); - + int DataRecv(); int DataSend(); - + //sync packet void EncodeSyncPacket(); void DecodeSyncPacket(); @@ -168,6 +171,7 @@ namespace Jack int Send ( size_t size, int flags ); public: + JackNetSlaveInterface() : JackNetInterface() { //open Socket API with the first slave @@ -180,6 +184,7 @@ namespace Jack } } } + JackNetSlaveInterface ( const char* ip, int port ) : JackNetInterface ( ip, port ) { //open Socket API with the first slave @@ -192,6 +197,7 @@ namespace Jack } } } + ~JackNetSlaveInterface() { //close Socket API with the last slave diff --git a/common/JackNetManager.cpp b/common/JackNetManager.cpp index fbe8aef1..55f981d9 100644 --- a/common/JackNetManager.cpp +++ b/common/JackNetManager.cpp @@ -37,7 +37,7 @@ namespace Jack fSendTransportData.fState = -1; fReturnTransportData.fState = -1; fLastTransportState = -1; - uint port_index; + int port_index; //jack audio ports fAudioCapturePorts = new jack_port_t* [fParams.fSendAudioChannels]; @@ -169,7 +169,7 @@ namespace Jack //jack ports-------------------------------------------------------------------------- int JackNetMaster::AllocPorts() { - uint i; + int i; char name[24]; jack_nframes_t port_latency = jack_get_buffer_size ( fJackClient ); jack_latency_range_t range; @@ -251,7 +251,7 @@ namespace Jack ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); if (ports != NULL) { - for (unsigned int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { + for (int i = 0; i < fParams.fSendAudioChannels && ports[i]; i++) { jack_connect(fJackClient, ports[i], jack_port_name(fAudioCapturePorts[i])); } free(ports); @@ -259,7 +259,7 @@ namespace Jack ports = jack_get_ports(fJackClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput); if (ports != NULL) { - for (unsigned int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { + for (int i = 0; i < fParams.fReturnAudioChannels && ports[i]; i++) { jack_connect(fJackClient, jack_port_name(fAudioPlaybackPorts[i]), ports[i]); } free(ports); @@ -270,7 +270,7 @@ namespace Jack { jack_log ( "JackNetMaster::FreePorts, ID %u", fParams.fID ); - uint port_index; + int port_index; for ( port_index = 0; port_index < fParams.fSendAudioChannels; port_index++ ) if ( fAudioCapturePorts[port_index] ) jack_port_unregister ( fJackClient, fAudioCapturePorts[port_index] ); @@ -396,7 +396,7 @@ namespace Jack { JackNetMaster* obj = static_cast(arg); if (nframes != obj->fParams.fPeriodSize) { - jack_error("Cannot handle bufer size change, so JackNetMaster proxy will be removed..."); + jack_error("Cannot handle buffer size change, so JackNetMaster proxy will be removed..."); obj->Exit(); } return 0; @@ -413,7 +413,7 @@ namespace Jack if ( !fRunning ) return 0; - uint port_index; + int port_index; int res = 0; #ifdef JACK_MONITOR @@ -546,6 +546,19 @@ namespace Jack SocketAPIEnd(); } + int JackNetMasterManager::CountIO(int flags) + { + const char **ports; + int count = 0; + + ports = jack_get_ports(fManagerClient, NULL, NULL, flags); + if (ports != NULL) { + while(ports[count]) count++; + free(ports); + } + return count; + } + int JackNetMasterManager::SetSyncCallback ( jack_transport_state_t state, jack_position_t* pos, void* arg ) { return static_cast ( arg )->SyncCallback ( state, pos ); @@ -670,13 +683,23 @@ namespace Jack params.fID = ++fGlobalID; params.fSampleRate = jack_get_sample_rate ( fManagerClient ); params.fPeriodSize = jack_get_buffer_size ( fManagerClient ); - SetSlaveName ( params ); + + if (params.fSendAudioChannels == -1) { + params.fSendAudioChannels = CountIO(JackPortIsPhysical | JackPortIsOutput); + jack_info("Takes physical %d inputs for client", params.fSendAudioChannels); + } + + if (params.fReturnAudioChannels == -1) { + params.fReturnAudioChannels = CountIO(JackPortIsPhysical | JackPortIsInput); + jack_info("Takes physical %d outputs for client", params.fReturnAudioChannels); + } + + SetSlaveName (params); //create a new master and add it to the list JackNetMaster* master = new JackNetMaster(fSocket, params, fMulticastIP); - if ( master->Init(fAutoConnect) ) - { - fMasterList.push_back ( master ); + if (master->Init(fAutoConnect)) { + fMasterList.push_back(master); return master; } delete master; diff --git a/common/JackNetManager.h b/common/JackNetManager.h index cbeaee9e..48b6c25c 100644 --- a/common/JackNetManager.h +++ b/common/JackNetManager.h @@ -37,7 +37,9 @@ namespace Jack class JackNetMaster : public JackNetMasterInterface { friend class JackNetMasterManager; + private: + static int SetProcess ( jack_nframes_t nframes, void* arg ); static int SetBufferSize (jack_nframes_t nframes, void* arg); static void SetTimebaseCallback ( jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg ); @@ -74,6 +76,7 @@ namespace Jack void ConnectPorts(); public: + JackNetMaster ( JackNetSocket& socket, session_params_t& params, const char* multicast_ip); ~JackNetMaster (); @@ -90,7 +93,9 @@ namespace Jack class JackNetMasterManager { friend class JackNetMaster; + private: + static int SetSyncCallback ( jack_transport_state_t state, jack_position_t* pos, void* arg ); static void* NetManagerThread ( void* arg ); @@ -111,7 +116,11 @@ namespace Jack void SetSlaveName ( session_params_t& params ); int SyncCallback ( jack_transport_state_t state, jack_position_t* pos ); + + int CountIO(int flags); + public: + JackNetMasterManager ( jack_client_t* jack_client, const JSList* params); ~JackNetMasterManager(); }; diff --git a/common/JackNetOneDriver.cpp b/common/JackNetOneDriver.cpp index 93adecdd..b235b1c5 100644 --- a/common/JackNetOneDriver.cpp +++ b/common/JackNetOneDriver.cpp @@ -45,421 +45,415 @@ using namespace std; namespace Jack { - JackNetOneDriver::JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, - int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, - int sample_rate, int period_size, int resample_factor, - const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, - int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val ) - : JackAudioDriver ( name, alias, engine, table ) - { - jack_log ( "JackNetOneDriver::JackNetOneDriver port %d", port ); - - #ifdef WIN32 - WSADATA wsa; - int rc = WSAStartup(MAKEWORD(2,0),&wsa); - #endif - - netjack_init( & (this->netj), - NULL, // client - name, - capture_ports, - playback_ports, - midi_input_ports, - midi_output_ports, - sample_rate, - period_size, - port, - transport_sync, - resample_factor, - 0, - bitdepth, - use_autoconfig, - latency, - redundancy, - dont_htonl_floats, - always_deadline, - jitter_val); - } +JackNetOneDriver::JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, + int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, + int sample_rate, int period_size, int resample_factor, + const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, + int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val ) + : JackAudioDriver ( name, alias, engine, table ) +{ + jack_log ( "JackNetOneDriver::JackNetOneDriver port %d", port ); - JackNetOneDriver::~JackNetOneDriver() - { - // No destructor yet. - } +#ifdef WIN32 + WSADATA wsa; + int rc = WSAStartup(MAKEWORD(2, 0), &wsa); +#endif -//open, close, attach and detach------------------------------------------------------ - int JackNetOneDriver::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 ) - { - if ( JackAudioDriver::Open ( buffer_size, - samplerate, - capturing, - playing, - inchannels, - outchannels, - monitor, - capture_driver_name, - playback_driver_name, - capture_latency, - playback_latency ) == 0 ) - { - fEngineControl->fPeriod = 0; - fEngineControl->fComputation = 500 * 1000; - fEngineControl->fConstraint = 500 * 1000; - return 0; - } - else - { - jack_error( "open fail" ); - return -1; - } - } + netjack_init( & (this->netj), + NULL, // client + name, + capture_ports, + playback_ports, + midi_input_ports, + midi_output_ports, + sample_rate, + period_size, + port, + transport_sync, + resample_factor, + 0, + bitdepth, + use_autoconfig, + latency, + redundancy, + dont_htonl_floats, + always_deadline, + jitter_val); +} - int JackNetOneDriver::Close() - { - FreePorts(); - netjack_release( &netj ); - return JackDriver::Close(); - } +JackNetOneDriver::~JackNetOneDriver() +{ + // No destructor yet. +} - int JackNetOneDriver::Attach() - { +//open, close, attach and detach------------------------------------------------------ +int JackNetOneDriver::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 ) +{ + if ( JackAudioDriver::Open ( buffer_size, + samplerate, + capturing, + playing, + inchannels, + outchannels, + monitor, + capture_driver_name, + playback_driver_name, + capture_latency, + playback_latency ) == 0 ) { + fEngineControl->fPeriod = 0; + fEngineControl->fComputation = 500 * 1000; + fEngineControl->fConstraint = 500 * 1000; return 0; + } else { + jack_error( "open fail" ); + return -1; } +} - int JackNetOneDriver::Detach() - { - return 0; - } +int JackNetOneDriver::Close() +{ + // Generic audio driver close + int res = JackAudioDriver::Close(); - int JackNetOneDriver::AllocPorts() - { - jack_port_id_t port_id; - char buf[64]; - unsigned int chn; + FreePorts(); + netjack_release(&netj); + return res; +} - //if (netj.handle_transport_sync) - // jack_set_sync_callback(netj.client, (JackSyncCallback) net_driver_sync_cb, NULL); +int JackNetOneDriver::Attach() +{ + return 0; +} - for (chn = 0; chn < netj.capture_channels_audio; chn++) { - snprintf (buf, sizeof(buf) - 1, "system:capture_%u", chn + 1); +int JackNetOneDriver::Detach() +{ + return 0; +} - if ( ( port_id = fGraphManager->AllocatePort ( fClientControl.fRefNum, buf, JACK_DEFAULT_AUDIO_TYPE, - CaptureDriverFlags, fEngineControl->fBufferSize ) ) == NO_PORT ) - { - jack_error ( "driver: cannot register port for %s", buf ); - return -1; - } - //port = fGraphManager->GetPort ( port_id ); - - netj.capture_ports = jack_slist_append (netj.capture_ports, (void *)(intptr_t)port_id); - - if( netj.bitdepth == CELT_MODE ) { - #if HAVE_CELT - #if HAVE_CELT_API_0_11 - celt_int32 lookahead; - CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); - netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create_custom( celt_mode, 1, NULL ) ); - #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 - celt_int32 lookahead; - CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); - netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); - #else - celt_int32_t lookahead; - CELTMode *celt_mode = celt_mode_create( netj.sample_rate, 1, netj.period_size, NULL ); - netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create( celt_mode ) ); - #endif - celt_mode_info( celt_mode, CELT_GET_LOOKAHEAD, &lookahead ); - netj.codec_latency = 2*lookahead; - #endif - } else { - #if HAVE_SAMPLERATE - netj.capture_srcs = jack_slist_append(netj.capture_srcs, (void *)src_new(SRC_LINEAR, 1, NULL)); - #endif - } - } - for (chn = netj.capture_channels_audio; chn < netj.capture_channels; chn++) { - snprintf (buf, sizeof(buf) - 1, "system:capture_%u", chn + 1); +int JackNetOneDriver::AllocPorts() +{ + jack_port_id_t port_id; + char buf[64]; + unsigned int chn; - if ( ( port_id = fGraphManager->AllocatePort ( fClientControl.fRefNum, buf, JACK_DEFAULT_MIDI_TYPE, - CaptureDriverFlags, fEngineControl->fBufferSize ) ) == NO_PORT ) - { - jack_error ( "driver: cannot register port for %s", buf ); - return -1; - } - //port = fGraphManager->GetPort ( port_id ); + //if (netj.handle_transport_sync) + // jack_set_sync_callback(netj.client, (JackSyncCallback) net_driver_sync_cb, NULL); - netj.capture_ports = - jack_slist_append (netj.capture_ports, (void *)(intptr_t)port_id); + for (chn = 0; chn < netj.capture_channels_audio; chn++) { + snprintf (buf, sizeof(buf) - 1, "system:capture_%u", chn + 1); + + if ( ( port_id = fGraphManager->AllocatePort ( fClientControl.fRefNum, buf, JACK_DEFAULT_AUDIO_TYPE, + CaptureDriverFlags, fEngineControl->fBufferSize ) ) == NO_PORT ) { + jack_error ( "driver: cannot register port for %s", buf ); + return -1; } + //port = fGraphManager->GetPort ( port_id ); - for (chn = 0; chn < netj.playback_channels_audio; chn++) { - snprintf (buf, sizeof(buf) - 1, "system:playback_%u", chn + 1); + netj.capture_ports = jack_slist_append (netj.capture_ports, (void *)(intptr_t)port_id); - if ( ( port_id = fGraphManager->AllocatePort ( fClientControl.fRefNum, buf, JACK_DEFAULT_AUDIO_TYPE, - PlaybackDriverFlags, fEngineControl->fBufferSize ) ) == NO_PORT ) - { - jack_error ( "driver: cannot register port for %s", buf ); - return -1; - } - //port = fGraphManager->GetPort ( port_id ); - - netj.playback_ports = jack_slist_append (netj.playback_ports, (void *)(intptr_t)port_id); - if( netj.bitdepth == CELT_MODE ) { - #if HAVE_CELT - #if HAVE_CELT_API_0_11 - CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); - netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create_custom( celt_mode, 1, NULL ) ); - #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 - CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); - netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); - #else - CELTMode *celt_mode = celt_mode_create( netj.sample_rate, 1, netj.period_size, NULL ); - netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create( celt_mode ) ); - #endif - #endif - } else { - #if HAVE_SAMPLERATE - netj.playback_srcs = jack_slist_append(netj.playback_srcs, (void *)src_new(SRC_LINEAR, 1, NULL)); - #endif - } + if( netj.bitdepth == CELT_MODE ) { +#if HAVE_CELT +#if HAVE_CELT_API_0_11 + celt_int32 lookahead; + CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); + netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create_custom( celt_mode, 1, NULL ) ); +#elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 + celt_int32 lookahead; + CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); + netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) ); +#else + celt_int32_t lookahead; + CELTMode *celt_mode = celt_mode_create( netj.sample_rate, 1, netj.period_size, NULL ); + netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create( celt_mode ) ); +#endif + celt_mode_info( celt_mode, CELT_GET_LOOKAHEAD, &lookahead ); + netj.codec_latency = 2 * lookahead; +#endif + } else { +#if HAVE_SAMPLERATE + netj.capture_srcs = jack_slist_append(netj.capture_srcs, (void *)src_new(SRC_LINEAR, 1, NULL)); +#endif } - for (chn = netj.playback_channels_audio; chn < netj.playback_channels; chn++) { - snprintf (buf, sizeof(buf) - 1, "system:playback_%u", chn + 1); - - if ( ( port_id = fGraphManager->AllocatePort ( fClientControl.fRefNum, buf, JACK_DEFAULT_MIDI_TYPE, - PlaybackDriverFlags, fEngineControl->fBufferSize ) ) == NO_PORT ) - { - jack_error ( "driver: cannot register port for %s", buf ); - return -1; - } - //port = fGraphManager->GetPort ( port_id ); + } + for (chn = netj.capture_channels_audio; chn < netj.capture_channels; chn++) { + snprintf (buf, sizeof(buf) - 1, "system:capture_%u", chn + 1); - netj.playback_ports = - jack_slist_append (netj.playback_ports, (void *)(intptr_t)port_id); + if ( ( port_id = fGraphManager->AllocatePort ( fClientControl.fRefNum, buf, JACK_DEFAULT_MIDI_TYPE, + CaptureDriverFlags, fEngineControl->fBufferSize ) ) == NO_PORT ) { + jack_error ( "driver: cannot register port for %s", buf ); + return -1; } - return 0; + //port = fGraphManager->GetPort ( port_id ); + + netj.capture_ports = + jack_slist_append (netj.capture_ports, (void *)(intptr_t)port_id); } -//init and restart-------------------------------------------------------------------- - bool JackNetOneDriver::Initialize() - { - jack_log ( "JackNetOneDriver::Init()" ); + for (chn = 0; chn < netj.playback_channels_audio; chn++) { + snprintf (buf, sizeof(buf) - 1, "system:playback_%u", chn + 1); - FreePorts(); - netjack_release( &netj ); + if ( ( port_id = fGraphManager->AllocatePort ( fClientControl.fRefNum, buf, JACK_DEFAULT_AUDIO_TYPE, + PlaybackDriverFlags, fEngineControl->fBufferSize ) ) == NO_PORT ) { + jack_error ( "driver: cannot register port for %s", buf ); + return -1; + } + //port = fGraphManager->GetPort ( port_id ); - //display some additional infos - jack_info ( "NetOne driver started" ); - if( netjack_startup( &netj ) ) { - return false; + netj.playback_ports = jack_slist_append (netj.playback_ports, (void *)(intptr_t)port_id); + if( netj.bitdepth == CELT_MODE ) { +#if HAVE_CELT +#if HAVE_CELT_API_0_11 + CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); + netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create_custom( celt_mode, 1, NULL ) ); +#elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 + CELTMode *celt_mode = celt_mode_create( netj.sample_rate, netj.period_size, NULL ); + netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) ); +#else + CELTMode *celt_mode = celt_mode_create( netj.sample_rate, 1, netj.period_size, NULL ); + netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create( celt_mode ) ); +#endif +#endif + } else { +#if HAVE_SAMPLERATE + netj.playback_srcs = jack_slist_append(netj.playback_srcs, (void *)src_new(SRC_LINEAR, 1, NULL)); +#endif } + } + for (chn = netj.playback_channels_audio; chn < netj.playback_channels; chn++) { + snprintf (buf, sizeof(buf) - 1, "system:playback_%u", chn + 1); - //register jack ports - if ( AllocPorts() != 0 ) - { - jack_error ( "Can't allocate ports." ); - return false; + if ( ( port_id = fGraphManager->AllocatePort ( fClientControl.fRefNum, buf, JACK_DEFAULT_MIDI_TYPE, + PlaybackDriverFlags, fEngineControl->fBufferSize ) ) == NO_PORT ) { + jack_error ( "driver: cannot register port for %s", buf ); + return -1; } + //port = fGraphManager->GetPort ( port_id ); + + netj.playback_ports = + jack_slist_append (netj.playback_ports, (void *)(intptr_t)port_id); + } + return 0; +} - //monitor - //driver parametering - JackAudioDriver::SetBufferSize ( netj.period_size ); - JackAudioDriver::SetSampleRate ( netj.sample_rate ); +//init and restart-------------------------------------------------------------------- +bool JackNetOneDriver::Initialize() +{ + jack_log ( "JackNetOneDriver::Init()" ); - JackDriver::NotifyBufferSize ( netj.period_size ); - JackDriver::NotifySampleRate ( netj.sample_rate ); + FreePorts(); + netjack_release( &netj ); - //transport engine parametering - fEngineControl->fTransport.SetNetworkSync ( true ); - return true; + //display some additional infos + jack_info ( "NetOne driver started" ); + if( netjack_startup( &netj ) ) { + return false; } + //register jack ports + if ( AllocPorts() != 0 ) { + jack_error ( "Can't allocate ports." ); + return false; + } -//jack ports and buffers-------------------------------------------------------------- + //monitor + //driver parametering + JackAudioDriver::SetBufferSize ( netj.period_size ); + JackAudioDriver::SetSampleRate ( netj.sample_rate ); -//driver processes-------------------------------------------------------------------- - int JackNetOneDriver::Read() - { - int delay; - delay = netjack_wait( &netj ); - if( delay ) { - NotifyXRun(fBeginDateUst, (float) delay); - jack_error( "netxruns... duration: %dms", delay/1000 ); - } + JackDriver::NotifyBufferSize ( netj.period_size ); + JackDriver::NotifySampleRate ( netj.sample_rate ); - if( (netj.num_lost_packets * netj.period_size / netj.sample_rate) > 2 ) - JackTools::ThrowJackNetException(); + //transport engine parametering + fEngineControl->fTransport.SetNetworkSync ( true ); + return true; +} - //netjack_read( &netj, netj.period_size ); - JackDriver::CycleTakeBeginTime(); - jack_position_t local_trans_pos; - jack_transport_state_t local_trans_state; +//jack ports and buffers-------------------------------------------------------------- - unsigned int *packet_buf, *packet_bufX; +//driver processes-------------------------------------------------------------------- +int JackNetOneDriver::Read() +{ + int delay; + delay = netjack_wait( &netj ); + if( delay ) { + NotifyXRun(fBeginDateUst, (float) delay); + jack_error( "netxruns... duration: %dms", delay / 1000 ); + } - if( ! netj.packet_data_valid ) { - jack_log( "data not valid" ); - render_payload_to_jack_ports (netj.bitdepth, NULL, netj.net_period_down, netj.capture_ports, netj.capture_srcs, netj.period_size, netj.dont_htonl_floats ); - return 0; - } - packet_buf = netj.rx_buf; + if( (netj.num_lost_packets * netj.period_size / netj.sample_rate) > 2 ) + JackTools::ThrowJackNetException(); - jacknet_packet_header *pkthdr = (jacknet_packet_header *)packet_buf; + //netjack_read( &netj, netj.period_size ); + JackDriver::CycleTakeBeginTime(); - packet_bufX = packet_buf + sizeof(jacknet_packet_header) / sizeof(jack_default_audio_sample_t); + jack_position_t local_trans_pos; + jack_transport_state_t local_trans_state; - netj.reply_port = pkthdr->reply_port; - netj.latency = pkthdr->latency; + unsigned int *packet_buf, *packet_bufX; - // Special handling for latency=0 - if( netj.latency == 0 ) - netj.resync_threshold = 0; - else - netj.resync_threshold = MIN( 15, pkthdr->latency-1 ); + if( ! netj.packet_data_valid ) { + jack_log( "data not valid" ); + render_payload_to_jack_ports (netj.bitdepth, NULL, netj.net_period_down, netj.capture_ports, netj.capture_srcs, netj.period_size, netj.dont_htonl_floats ); + return 0; + } + packet_buf = netj.rx_buf; - // check whether, we should handle the transport sync stuff, or leave trnasports untouched. - if (netj.handle_transport_sync) { - #if 1 - unsigned int compensated_tranport_pos = (pkthdr->transport_frame + (pkthdr->latency * netj.period_size) + netj.codec_latency); + jacknet_packet_header *pkthdr = (jacknet_packet_header *)packet_buf; - // read local transport info.... - //local_trans_state = jack_transport_query(netj.client, &local_trans_pos); + packet_bufX = packet_buf + sizeof(jacknet_packet_header) / sizeof(jack_default_audio_sample_t); - local_trans_state = fEngineControl->fTransport.Query ( &local_trans_pos ); + netj.reply_port = pkthdr->reply_port; + netj.latency = pkthdr->latency; - // Now check if we have to start or stop local transport to sync to remote... - switch (pkthdr->transport_state) { + // Special handling for latency=0 + if( netj.latency == 0 ) + netj.resync_threshold = 0; + else + netj.resync_threshold = MIN( 15, pkthdr->latency - 1 ); - case JackTransportStarting: - // the master transport is starting... so we set our reply to the sync_callback; - if (local_trans_state == JackTransportStopped) { - fEngineControl->fTransport.SetCommand ( TransportCommandStart ); - //jack_transport_start(netj.client); - //last_transport_state = JackTransportStopped; - netj.sync_state = 0; - jack_info("locally stopped... starting..."); - } + // check whether, we should handle the transport sync stuff, or leave trnasports untouched. + if (netj.handle_transport_sync) { +#if 1 + unsigned int compensated_tranport_pos = (pkthdr->transport_frame + (pkthdr->latency * netj.period_size) + netj.codec_latency); - if (local_trans_pos.frame != compensated_tranport_pos) { - jack_position_t new_pos = local_trans_pos; - new_pos.frame = compensated_tranport_pos + 2*netj.period_size; - new_pos.valid = (jack_position_bits_t) 0; + // read local transport info.... + //local_trans_state = jack_transport_query(netj.client, &local_trans_pos); + local_trans_state = fEngineControl->fTransport.Query ( &local_trans_pos ); - fEngineControl->fTransport.RequestNewPos ( &new_pos ); - //jack_transport_locate(netj.client, compensated_tranport_pos); - //last_transport_state = JackTransportRolling; - netj.sync_state = 0; - jack_info("starting locate to %d", compensated_tranport_pos ); - } - break; + // Now check if we have to start or stop local transport to sync to remote... + switch (pkthdr->transport_state) { - case JackTransportStopped: - netj.sync_state = 1; - if (local_trans_pos.frame != (pkthdr->transport_frame)) { - jack_position_t new_pos = local_trans_pos; - new_pos.frame = pkthdr->transport_frame; - new_pos.valid = (jack_position_bits_t)0; - fEngineControl->fTransport.RequestNewPos ( &new_pos ); - //jack_transport_locate(netj.client, (pkthdr->transport_frame)); - jack_info("transport is stopped locate to %d", pkthdr->transport_frame); - } - if (local_trans_state != JackTransportStopped) - //jack_transport_stop(netj.client); - fEngineControl->fTransport.SetCommand ( TransportCommandStop ); - break; + case JackTransportStarting: + // the master transport is starting... so we set our reply to the sync_callback; + if (local_trans_state == JackTransportStopped) { + fEngineControl->fTransport.SetCommand ( TransportCommandStart ); + //jack_transport_start(netj.client); + //last_transport_state = JackTransportStopped; + netj.sync_state = 0; + jack_info("locally stopped... starting..."); + } - case JackTransportRolling: - netj.sync_state = 1; - // if(local_trans_pos.frame != (pkthdr->transport_frame + (pkthdr->latency) * netj.period_size)) { - // jack_transport_locate(netj.client, (pkthdr->transport_frame + (pkthdr->latency + 2) * netj.period_size)); - // jack_info("running locate to %d", pkthdr->transport_frame + (pkthdr->latency)*netj.period_size); - // } - if (local_trans_state != JackTransportRolling) - fEngineControl->fTransport.SetState ( JackTransportRolling ); - break; + if (local_trans_pos.frame != compensated_tranport_pos) { + jack_position_t new_pos = local_trans_pos; + new_pos.frame = compensated_tranport_pos + 2 * netj.period_size; + new_pos.valid = (jack_position_bits_t) 0; - case JackTransportLooping: - break; - } -#endif - } - render_payload_to_jack_ports (netj.bitdepth, packet_bufX, netj.net_period_down, netj.capture_ports, netj.capture_srcs, netj.period_size, netj.dont_htonl_floats ); - packet_cache_release_packet(netj.packcache, netj.expected_framecnt ); - return 0; + fEngineControl->fTransport.RequestNewPos ( &new_pos ); + //jack_transport_locate(netj.client, compensated_tranport_pos); + //last_transport_state = JackTransportRolling; + netj.sync_state = 0; + jack_info("starting locate to %d", compensated_tranport_pos ); + } + break; + + case JackTransportStopped: + netj.sync_state = 1; + if (local_trans_pos.frame != (pkthdr->transport_frame)) { + jack_position_t new_pos = local_trans_pos; + new_pos.frame = pkthdr->transport_frame; + new_pos.valid = (jack_position_bits_t)0; + fEngineControl->fTransport.RequestNewPos ( &new_pos ); + //jack_transport_locate(netj.client, (pkthdr->transport_frame)); + jack_info("transport is stopped locate to %d", pkthdr->transport_frame); + } + if (local_trans_state != JackTransportStopped) + //jack_transport_stop(netj.client); + fEngineControl->fTransport.SetCommand ( TransportCommandStop ); + break; + + case JackTransportRolling: + netj.sync_state = 1; + // if(local_trans_pos.frame != (pkthdr->transport_frame + (pkthdr->latency) * netj.period_size)) { + // jack_transport_locate(netj.client, (pkthdr->transport_frame + (pkthdr->latency + 2) * netj.period_size)); + // jack_info("running locate to %d", pkthdr->transport_frame + (pkthdr->latency)*netj.period_size); + // } + if (local_trans_state != JackTransportRolling) + fEngineControl->fTransport.SetState ( JackTransportRolling ); + break; + + case JackTransportLooping: + break; + } +#endif } - int JackNetOneDriver::Write() - { - int syncstate = netj.sync_state | ((fEngineControl->fTransport.GetState() == JackTransportNetStarting) ? 1 : 0 ); - uint32_t *packet_buf, *packet_bufX; + render_payload_to_jack_ports (netj.bitdepth, packet_bufX, netj.net_period_down, netj.capture_ports, netj.capture_srcs, netj.period_size, netj.dont_htonl_floats ); + packet_cache_release_packet(netj.packcache, netj.expected_framecnt ); + return 0; +} + +int JackNetOneDriver::Write() +{ + int syncstate = netj.sync_state | ((fEngineControl->fTransport.GetState() == JackTransportNetStarting) ? 1 : 0 ); + uint32_t *packet_buf, *packet_bufX; - int packet_size = get_sample_size(netj.bitdepth) * netj.playback_channels * netj.net_period_up + sizeof(jacknet_packet_header); - jacknet_packet_header *pkthdr; + int packet_size = get_sample_size(netj.bitdepth) * netj.playback_channels * netj.net_period_up + sizeof(jacknet_packet_header); + jacknet_packet_header *pkthdr; - packet_buf = (uint32_t *) alloca(packet_size); - pkthdr = (jacknet_packet_header *)packet_buf; + packet_buf = (uint32_t *) alloca(packet_size); + pkthdr = (jacknet_packet_header *)packet_buf; - if( netj.running_free ) { - return 0; - } + if( netj.running_free ) { + return 0; + } - // offset packet_bufX by the packetheader. - packet_bufX = packet_buf + sizeof(jacknet_packet_header) / sizeof(jack_default_audio_sample_t); + // offset packet_bufX by the packetheader. + packet_bufX = packet_buf + sizeof(jacknet_packet_header) / sizeof(jack_default_audio_sample_t); - pkthdr->sync_state = syncstate;; - pkthdr->latency = netj.time_to_deadline; - //printf( "time to deadline = %d goodness=%d\n", (int)netj.time_to_deadline, netj.deadline_goodness ); - pkthdr->framecnt = netj.expected_framecnt; + pkthdr->sync_state = syncstate;; + pkthdr->latency = netj.time_to_deadline; + //printf( "time to deadline = %d goodness=%d\n", (int)netj.time_to_deadline, netj.deadline_goodness ); + pkthdr->framecnt = netj.expected_framecnt; - render_jack_ports_to_payload(netj.bitdepth, netj.playback_ports, netj.playback_srcs, netj.period_size, packet_bufX, netj.net_period_up, netj.dont_htonl_floats ); + render_jack_ports_to_payload(netj.bitdepth, netj.playback_ports, netj.playback_srcs, netj.period_size, packet_bufX, netj.net_period_up, netj.dont_htonl_floats ); - packet_header_hton(pkthdr); - if (netj.srcaddress_valid) - { - unsigned int r; - static const int flag = 0; + packet_header_hton(pkthdr); + if (netj.srcaddress_valid) { + unsigned int r; + static const int flag = 0; - if (netj.reply_port) + if (netj.reply_port) netj.syncsource_address.sin_port = htons(netj.reply_port); - for( r=0; rdata; - node = jack_slist_remove_link( node, this_node ); - jack_slist_free_1( this_node ); - fGraphManager->ReleasePort( fClientControl.fRefNum, port_id ); - } - netj.capture_ports = NULL; - - node = netj.playback_ports; - while( node != NULL ) { - JSList *this_node = node; - jack_port_id_t port_id = (jack_port_id_t)(intptr_t) node->data; - node = jack_slist_remove_link( node, this_node ); - jack_slist_free_1( this_node ); - fGraphManager->ReleasePort( fClientControl.fRefNum, port_id ); - } - netj.playback_ports = NULL; +void +JackNetOneDriver::FreePorts () +{ + JSList *node = netj.capture_ports; + + while( node != NULL ) { + JSList *this_node = node; + jack_port_id_t port_id = (jack_port_id_t)(intptr_t) node->data; + node = jack_slist_remove_link( node, this_node ); + jack_slist_free_1( this_node ); + fGraphManager->ReleasePort( fClientControl.fRefNum, port_id ); + } + netj.capture_ports = NULL; + + node = netj.playback_ports; + while( node != NULL ) { + JSList *this_node = node; + jack_port_id_t port_id = (jack_port_id_t)(intptr_t) node->data; + node = jack_slist_remove_link( node, this_node ); + jack_slist_free_1( this_node ); + fGraphManager->ReleasePort( fClientControl.fRefNum, port_id ); + } + netj.playback_ports = NULL; - if( netj.bitdepth == CELT_MODE ) { - #if HAVE_CELT + if( netj.bitdepth == CELT_MODE ) { +#if HAVE_CELT node = netj.playback_srcs; while( node != NULL ) { JSList *this_node = node; @@ -479,9 +473,9 @@ namespace Jack celt_decoder_destroy( dec ); } netj.capture_srcs = NULL; - #endif - } else { - #if HAVE_SAMPLERATE +#endif + } else { +#if HAVE_SAMPLERATE node = netj.playback_srcs; while( node != NULL ) { JSList *this_node = node; @@ -501,518 +495,487 @@ namespace Jack src_delete( state ); } netj.capture_srcs = NULL; - #endif - } +#endif } +} //Render functions-------------------------------------------------------------------- // render functions for float - void - JackNetOneDriver::render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats) - { - uint32_t chn = 0; - JSList *node = capture_ports; - #if HAVE_SAMPLERATE - JSList *src_node = capture_srcs; - #endif +void +JackNetOneDriver::render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats) +{ + uint32_t chn = 0; + JSList *node = capture_ports; +#if HAVE_SAMPLERATE + JSList *src_node = capture_srcs; +#endif - uint32_t *packet_bufX = (uint32_t *)packet_payload; + uint32_t *packet_bufX = (uint32_t *)packet_payload; - if( !packet_payload ) - return; + if( !packet_payload ) + return; - while (node != NULL) - { - unsigned int i; - int_float_t val; - #if HAVE_SAMPLERATE - SRC_DATA src; - #endif - jack_port_id_t port_id = (jack_port_id_t)(intptr_t) node->data; - JackPort *port = fGraphManager->GetPort( port_id ); + while (node != NULL) { + unsigned int i; + int_float_t val; +#if HAVE_SAMPLERATE + SRC_DATA src; +#endif + jack_port_id_t port_id = (jack_port_id_t)(intptr_t) node->data; + JackPort *port = fGraphManager->GetPort( port_id ); - jack_default_audio_sample_t* buf = - (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_id, fEngineControl->fBufferSize); + jack_default_audio_sample_t* buf = + (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_id, fEngineControl->fBufferSize); - const char *porttype = port->GetType(); + const char *porttype = port->GetType(); - if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) - { - #if HAVE_SAMPLERATE - // audio port, resample if necessary - if (net_period_down != nframes) - { - SRC_STATE *src_state = (SRC_STATE *)src_node->data; - for (i = 0; i < net_period_down; i++) - { - packet_bufX[i] = ntohl (packet_bufX[i]); - } + if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { +#if HAVE_SAMPLERATE + // audio port, resample if necessary + if (net_period_down != nframes) { + SRC_STATE *src_state = (SRC_STATE *)src_node->data; + for (i = 0; i < net_period_down; i++) { + packet_bufX[i] = ntohl (packet_bufX[i]); + } - src.data_in = (float *) packet_bufX; - src.input_frames = net_period_down; + src.data_in = (float *) packet_bufX; + src.input_frames = net_period_down; - src.data_out = buf; - src.output_frames = nframes; + src.data_out = buf; + src.output_frames = nframes; - src.src_ratio = (float) nframes / (float) net_period_down; - src.end_of_input = 0; + src.src_ratio = (float) nframes / (float) net_period_down; + src.end_of_input = 0; - src_set_ratio (src_state, src.src_ratio); - src_process (src_state, &src); - src_node = jack_slist_next (src_node); - } - else - #endif - { - if( dont_htonl_floats ) - { - memcpy( buf, packet_bufX, net_period_down*sizeof(jack_default_audio_sample_t)); - } - else - { - for (i = 0; i < net_period_down; i++) - { - val.i = packet_bufX[i]; - val.i = ntohl (val.i); - buf[i] = val.f; - } + src_set_ratio (src_state, src.src_ratio); + src_process (src_state, &src); + src_node = jack_slist_next (src_node); + } else +#endif + { + if( dont_htonl_floats ) { + memcpy( buf, packet_bufX, net_period_down * sizeof(jack_default_audio_sample_t)); + } else { + for (i = 0; i < net_period_down; i++) { + val.i = packet_bufX[i]; + val.i = ntohl (val.i); + buf[i] = val.f; } } } - else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) - { - // midi port, decode midi events - // convert the data buffer to a standard format (uint32_t based) - unsigned int buffer_size_uint32 = net_period_down; - uint32_t * buffer_uint32 = (uint32_t*)packet_bufX; - decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); - } - packet_bufX = (packet_bufX + net_period_down); - node = jack_slist_next (node); - chn++; + } else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { + // midi port, decode midi events + // convert the data buffer to a standard format (uint32_t based) + unsigned int buffer_size_uint32 = net_period_down; + uint32_t * buffer_uint32 = (uint32_t*)packet_bufX; + decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } + packet_bufX = (packet_bufX + net_period_down); + node = jack_slist_next (node); + chn++; + } } - void - JackNetOneDriver::render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ) - { - uint32_t chn = 0; - JSList *node = playback_ports; - #if HAVE_SAMPLERATE - JSList *src_node = playback_srcs; - #endif - - uint32_t *packet_bufX = (uint32_t *) packet_payload; - - while (node != NULL) - { - #if HAVE_SAMPLERATE - SRC_DATA src; - #endif - unsigned int i; - int_float_t val; - jack_port_id_t port_id = (jack_port_id_t)(intptr_t) node->data; - JackPort *port = fGraphManager->GetPort( port_id ); - - jack_default_audio_sample_t* buf = - (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_id, fEngineControl->fBufferSize); - - const char *porttype = port->GetType(); - - if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) - { - // audio port, resample if necessary +void +JackNetOneDriver::render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ) +{ + uint32_t chn = 0; + JSList *node = playback_ports; +#if HAVE_SAMPLERATE + JSList *src_node = playback_srcs; +#endif + + uint32_t *packet_bufX = (uint32_t *) packet_payload; - #if HAVE_SAMPLERATE - if (net_period_up != nframes) { - SRC_STATE *src_state = (SRC_STATE *) src_node->data; - src.data_in = buf; - src.input_frames = nframes; + while (node != NULL) { +#if HAVE_SAMPLERATE + SRC_DATA src; +#endif + unsigned int i; + int_float_t val; + jack_port_id_t port_id = (jack_port_id_t)(intptr_t) node->data; + JackPort *port = fGraphManager->GetPort( port_id ); - src.data_out = (float *) packet_bufX; - src.output_frames = net_period_up; + jack_default_audio_sample_t* buf = + (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_id, fEngineControl->fBufferSize); - src.src_ratio = (float) net_period_up / (float) nframes; - src.end_of_input = 0; + const char *porttype = port->GetType(); - src_set_ratio (src_state, src.src_ratio); - src_process (src_state, &src); + if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { + // audio port, resample if necessary - for (i = 0; i < net_period_up; i++) - { - packet_bufX[i] = htonl (packet_bufX[i]); - } - src_node = jack_slist_next (src_node); +#if HAVE_SAMPLERATE + if (net_period_up != nframes) { + SRC_STATE *src_state = (SRC_STATE *) src_node->data; + src.data_in = buf; + src.input_frames = nframes; + + src.data_out = (float *) packet_bufX; + src.output_frames = net_period_up; + + src.src_ratio = (float) net_period_up / (float) nframes; + src.end_of_input = 0; + + src_set_ratio (src_state, src.src_ratio); + src_process (src_state, &src); + + for (i = 0; i < net_period_up; i++) { + packet_bufX[i] = htonl (packet_bufX[i]); } - else - #endif - { - if( dont_htonl_floats ) - { - memcpy( packet_bufX, buf, net_period_up*sizeof(jack_default_audio_sample_t) ); - } - else - { - for (i = 0; i < net_period_up; i++) - { - val.f = buf[i]; - val.i = htonl (val.i); - packet_bufX[i] = val.i; - } + src_node = jack_slist_next (src_node); + } else +#endif + { + if( dont_htonl_floats ) { + memcpy( packet_bufX, buf, net_period_up * sizeof(jack_default_audio_sample_t) ); + } else { + for (i = 0; i < net_period_up; i++) { + val.f = buf[i]; + val.i = htonl (val.i); + packet_bufX[i] = val.i; } } } - else if (strncmp(porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) - { - // encode midi events from port to packet - // convert the data buffer to a standard format (uint32_t based) - unsigned int buffer_size_uint32 = net_period_up; - uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; - encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); - } - packet_bufX = (packet_bufX + net_period_up); - node = jack_slist_next (node); - chn++; + } else if (strncmp(porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { + // encode midi events from port to packet + // convert the data buffer to a standard format (uint32_t based) + unsigned int buffer_size_uint32 = net_period_up; + uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; + encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } + packet_bufX = (packet_bufX + net_period_up); + node = jack_slist_next (node); + chn++; } +} - #if HAVE_CELT - // render functions for celt. - void - JackNetOneDriver::render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes) - { - uint32_t chn = 0; - JSList *node = capture_ports; - JSList *src_node = capture_srcs; - unsigned char *packet_bufX = (unsigned char *)packet_payload; +#if HAVE_CELT +// render functions for celt. +void +JackNetOneDriver::render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes) +{ + uint32_t chn = 0; + JSList *node = capture_ports; + JSList *src_node = capture_srcs; + unsigned char *packet_bufX = (unsigned char *)packet_payload; - while (node != NULL) - { - jack_port_id_t port_id = (jack_port_id_t) (intptr_t)node->data; - JackPort *port = fGraphManager->GetPort( port_id ); + while (node != NULL) { + jack_port_id_t port_id = (jack_port_id_t) (intptr_t)node->data; + JackPort *port = fGraphManager->GetPort( port_id ); - jack_default_audio_sample_t* buf = - (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_id, fEngineControl->fBufferSize); + jack_default_audio_sample_t* buf = + (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_id, fEngineControl->fBufferSize); - const char *portname = port->GetType(); + const char *portname = port->GetType(); - if (strncmp(portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) - { - // audio port, decode celt data. - CELTDecoder *decoder = (CELTDecoder *)src_node->data; - - #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 - if( !packet_payload ) - celt_decode_float( decoder, NULL, net_period_down, buf, nframes ); - else - celt_decode_float( decoder, packet_bufX, net_period_down, buf, nframes ); - #else - if( !packet_payload ) - celt_decode_float( decoder, NULL, net_period_down, buf ); - else - celt_decode_float( decoder, packet_bufX, net_period_down, buf ); - #endif + if (strncmp(portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { + // audio port, decode celt data. + CELTDecoder *decoder = (CELTDecoder *)src_node->data; - src_node = jack_slist_next (src_node); - } - else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) - { - // midi port, decode midi events - // convert the data buffer to a standard format (uint32_t based) - unsigned int buffer_size_uint32 = net_period_down / 2; - uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; +#if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 + if( !packet_payload ) + celt_decode_float( decoder, NULL, net_period_down, buf, nframes ); + else + celt_decode_float( decoder, packet_bufX, net_period_down, buf, nframes ); +#else + if( !packet_payload ) + celt_decode_float( decoder, NULL, net_period_down, buf ); + else + celt_decode_float( decoder, packet_bufX, net_period_down, buf ); +#endif + + src_node = jack_slist_next (src_node); + } else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { + // midi port, decode midi events + // convert the data buffer to a standard format (uint32_t based) + unsigned int buffer_size_uint32 = net_period_down / 2; + uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; if( packet_payload ) decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); - } - packet_bufX = (packet_bufX + net_period_down); - node = jack_slist_next (node); - chn++; } + packet_bufX = (packet_bufX + net_period_down); + node = jack_slist_next (node); + chn++; } +} - void - JackNetOneDriver::render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up) - { - uint32_t chn = 0; - JSList *node = playback_ports; - JSList *src_node = playback_srcs; +void +JackNetOneDriver::render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up) +{ + uint32_t chn = 0; + JSList *node = playback_ports; + JSList *src_node = playback_srcs; - unsigned char *packet_bufX = (unsigned char *)packet_payload; + unsigned char *packet_bufX = (unsigned char *)packet_payload; - while (node != NULL) - { - jack_port_id_t port_id = (jack_port_id_t) (intptr_t) node->data; - JackPort *port = fGraphManager->GetPort( port_id ); + while (node != NULL) { + jack_port_id_t port_id = (jack_port_id_t) (intptr_t) node->data; + JackPort *port = fGraphManager->GetPort( port_id ); - jack_default_audio_sample_t* buf = - (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_id, fEngineControl->fBufferSize); + jack_default_audio_sample_t* buf = + (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_id, fEngineControl->fBufferSize); - const char *portname = port->GetType(); + const char *portname = port->GetType(); - if (strncmp (portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) - { - // audio port, encode celt data. + if (strncmp (portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { + // audio port, encode celt data. int encoded_bytes; jack_default_audio_sample_t *floatbuf = (jack_default_audio_sample_t *)alloca (sizeof(jack_default_audio_sample_t) * nframes ); memcpy( floatbuf, buf, nframes * sizeof(jack_default_audio_sample_t) ); CELTEncoder *encoder = (CELTEncoder *)src_node->data; - #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 +#if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 encoded_bytes = celt_encode_float( encoder, floatbuf, nframes, packet_bufX, net_period_up ); #else encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up ); #endif - if( encoded_bytes != (int)net_period_up ) - jack_error( "something in celt changed. netjack needs to be changed to handle this." ); + if( encoded_bytes != (int)net_period_up ) + jack_error( "something in celt changed. netjack needs to be changed to handle this." ); src_node = jack_slist_next( src_node ); - } - else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) - { - // encode midi events from port to packet - // convert the data buffer to a standard format (uint32_t based) - unsigned int buffer_size_uint32 = net_period_up / 2; - uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; - encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); - } - packet_bufX = (packet_bufX + net_period_up); - node = jack_slist_next (node); - chn++; + } else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { + // encode midi events from port to packet + // convert the data buffer to a standard format (uint32_t based) + unsigned int buffer_size_uint32 = net_period_up / 2; + uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; + encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); } + packet_bufX = (packet_bufX + net_period_up); + node = jack_slist_next (node); + chn++; } +} - #endif - /* Wrapper functions with bitdepth argument... */ - void - JackNetOneDriver::render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats) - { - #if HAVE_CELT - if (bitdepth == CELT_MODE) - render_payload_to_jack_ports_celt (packet_payload, net_period_down, capture_ports, capture_srcs, nframes); - else - #endif - render_payload_to_jack_ports_float (packet_payload, net_period_down, capture_ports, capture_srcs, nframes, dont_htonl_floats); - } +#endif +/* Wrapper functions with bitdepth argument... */ +void +JackNetOneDriver::render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats) +{ +#if HAVE_CELT + if (bitdepth == CELT_MODE) + render_payload_to_jack_ports_celt (packet_payload, net_period_down, capture_ports, capture_srcs, nframes); + else +#endif + render_payload_to_jack_ports_float (packet_payload, net_period_down, capture_ports, capture_srcs, nframes, dont_htonl_floats); +} - void - JackNetOneDriver::render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats) - { - #if HAVE_CELT - if (bitdepth == CELT_MODE) - render_jack_ports_to_payload_celt (playback_ports, playback_srcs, nframes, packet_payload, net_period_up); - else - #endif - render_jack_ports_to_payload_float (playback_ports, playback_srcs, nframes, packet_payload, net_period_up, dont_htonl_floats); - } +void +JackNetOneDriver::render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats) +{ +#if HAVE_CELT + if (bitdepth == CELT_MODE) + render_jack_ports_to_payload_celt (playback_ports, playback_srcs, nframes, packet_payload, net_period_up); + else +#endif + render_jack_ports_to_payload_float (playback_ports, playback_srcs, nframes, packet_payload, net_period_up, dont_htonl_floats); +} + +//driver loader----------------------------------------------------------------------- - //driver loader----------------------------------------------------------------------- - - #ifdef __cplusplus - extern "C" - { - #endif - SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor () - { - jack_driver_desc_t* desc = ( jack_driver_desc_t* ) calloc ( 1, sizeof ( jack_driver_desc_t ) ); - jack_driver_param_desc_t * params; - - strcpy ( desc->name, "netone" ); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 - strcpy ( desc->desc, "netjack one slave backend component" ); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 - - desc->nparams = 18; - params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) ); - - int i = 0; - strcpy (params[i].name, "audio-ins"); - params[i].character = 'i'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 2U; - strcpy (params[i].short_desc, "Number of capture channels (defaults to 2)"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "audio-outs"); - params[i].character = 'o'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 2U; - strcpy (params[i].short_desc, "Number of playback channels (defaults to 2)"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "midi-ins"); - params[i].character = 'I'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 1U; - strcpy (params[i].short_desc, "Number of midi capture channels (defaults to 1)"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "midi-outs"); - params[i].character = 'O'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 1U; - strcpy (params[i].short_desc, "Number of midi playback channels (defaults to 1)"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "rate"); - params[i].character = 'r'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 48000U; - strcpy (params[i].short_desc, "Sample rate"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "period"); - params[i].character = 'p'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 1024U; - strcpy (params[i].short_desc, "Frames per period"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "num-periods"); - params[i].character = 'n'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 5U; - strcpy (params[i].short_desc, +#ifdef __cplusplus +extern "C" +{ +#endif + SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor () + { + jack_driver_desc_t* desc = ( jack_driver_desc_t* ) calloc ( 1, sizeof ( jack_driver_desc_t ) ); + jack_driver_param_desc_t * params; + + strcpy ( desc->name, "netone" ); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 + strcpy ( desc->desc, "netjack one slave backend component" ); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 + + desc->nparams = 18; + params = ( jack_driver_param_desc_t* ) calloc ( desc->nparams, sizeof ( jack_driver_param_desc_t ) ); + + int i = 0; + strcpy (params[i].name, "audio-ins"); + params[i].character = 'i'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 2U; + strcpy (params[i].short_desc, "Number of capture channels (defaults to 2)"); + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "audio-outs"); + params[i].character = 'o'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 2U; + strcpy (params[i].short_desc, "Number of playback channels (defaults to 2)"); + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "midi-ins"); + params[i].character = 'I'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 1U; + strcpy (params[i].short_desc, "Number of midi capture channels (defaults to 1)"); + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "midi-outs"); + params[i].character = 'O'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 1U; + strcpy (params[i].short_desc, "Number of midi playback channels (defaults to 1)"); + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "rate"); + params[i].character = 'r'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 48000U; + strcpy (params[i].short_desc, "Sample rate"); + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "period"); + params[i].character = 'p'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 1024U; + strcpy (params[i].short_desc, "Frames per period"); + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "num-periods"); + params[i].character = 'n'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 5U; + strcpy (params[i].short_desc, "Network latency setting in no. of periods"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "listen-port"); - params[i].character = 'l'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 3000U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "listen-port"); + params[i].character = 'l'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 3000U; + strcpy (params[i].short_desc, "The socket port we are listening on for sync packets"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "factor"); - params[i].character = 'f'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 1U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "factor"); + params[i].character = 'f'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 1U; + strcpy (params[i].short_desc, "Factor for sample rate reduction"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "upstream-factor"); - params[i].character = 'u'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 0U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "upstream-factor"); + params[i].character = 'u'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 0U; + strcpy (params[i].short_desc, "Factor for sample rate reduction on the upstream"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "celt"); - params[i].character = 'c'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 0U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "celt"); + params[i].character = 'c'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 0U; + strcpy (params[i].short_desc, "sets celt encoding and number of kbits per channel"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "bit-depth"); - params[i].character = 'b'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 0U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "bit-depth"); + params[i].character = 'b'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 0U; + strcpy (params[i].short_desc, "Sample bit-depth (0 for float, 8 for 8bit and 16 for 16bit)"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "transport-sync"); - params[i].character = 't'; - params[i].type = JackDriverParamBool; - params[i].value.ui = 1U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "transport-sync"); + params[i].character = 't'; + params[i].type = JackDriverParamBool; + params[i].value.ui = 1U; + strcpy (params[i].short_desc, "Whether to slave the transport to the master transport"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "autoconf"); - params[i].character = 'a'; - params[i].type = JackDriverParamBool; - params[i].value.ui = 1U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "autoconf"); + params[i].character = 'a'; + params[i].type = JackDriverParamBool; + params[i].value.ui = 1U; + strcpy (params[i].short_desc, "Whether to use Autoconfig, or just start."); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "redundancy"); - params[i].character = 'R'; - params[i].type = JackDriverParamUInt; - params[i].value.ui = 1U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "redundancy"); + params[i].character = 'R'; + params[i].type = JackDriverParamUInt; + params[i].value.ui = 1U; + strcpy (params[i].short_desc, "Send packets N times"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "native-endian"); - params[i].character = 'e'; - params[i].type = JackDriverParamBool; - params[i].value.ui = 0U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "native-endian"); + params[i].character = 'e'; + params[i].type = JackDriverParamBool; + params[i].value.ui = 0U; + strcpy (params[i].short_desc, "Dont convert samples to network byte order."); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "jitterval"); - params[i].character = 'J'; - params[i].type = JackDriverParamInt; - params[i].value.i = 0; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "jitterval"); + params[i].character = 'J'; + params[i].type = JackDriverParamInt; + params[i].value.i = 0; + strcpy (params[i].short_desc, "attempted jitterbuffer microseconds on master"); - strcpy (params[i].long_desc, params[i].short_desc); - - i++; - strcpy (params[i].name, "always-deadline"); - params[i].character = 'D'; - params[i].type = JackDriverParamBool; - params[i].value.ui = 0U; - strcpy (params[i].short_desc, + strcpy (params[i].long_desc, params[i].short_desc); + + i++; + strcpy (params[i].name, "always-deadline"); + params[i].character = 'D'; + params[i].type = JackDriverParamBool; + params[i].value.ui = 0U; + strcpy (params[i].short_desc, "always use deadline"); - strcpy (params[i].long_desc, params[i].short_desc); + strcpy (params[i].long_desc, params[i].short_desc); - desc->params = params; + desc->params = params; - return desc; - } + 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 resample_factor = 1; - jack_nframes_t period_size = 1024; - unsigned int capture_ports = 2; - unsigned int playback_ports = 2; - unsigned int capture_ports_midi = 1; - unsigned int playback_ports_midi = 1; - unsigned int listen_port = 3000; - unsigned int bitdepth = 0; - unsigned int handle_transport_sync = 1; - unsigned int use_autoconfig = 1; - unsigned int latency = 5; - unsigned int redundancy = 1; - unsigned int mtu = 1400; - #if HAVE_SAMPLERATE - unsigned int resample_factor_up = 1; - #endif - int dont_htonl_floats = 0; - int always_deadline = 0; - int jitter_val = 0; - const JSList * node; - const jack_driver_param_t * param; - - for ( node = params; node; node = jack_slist_next ( node ) ) - { - param = ( const jack_driver_param_t* ) node->data; - switch ( param->character ) - { + SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize ( Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params ) + { + jack_nframes_t sample_rate = 48000; + jack_nframes_t resample_factor = 1; + jack_nframes_t period_size = 1024; + unsigned int capture_ports = 2; + unsigned int playback_ports = 2; + unsigned int capture_ports_midi = 1; + unsigned int playback_ports_midi = 1; + unsigned int listen_port = 3000; + unsigned int bitdepth = 0; + unsigned int handle_transport_sync = 1; + unsigned int use_autoconfig = 1; + unsigned int latency = 5; + unsigned int redundancy = 1; + unsigned int mtu = 1400; +#if HAVE_SAMPLERATE + unsigned int resample_factor_up = 1; +#endif + int dont_htonl_floats = 0; + int always_deadline = 0; + int jitter_val = 0; + const JSList * node; + const jack_driver_param_t * param; + + for ( node = params; node; node = jack_slist_next ( node ) ) { + param = ( const jack_driver_param_t* ) node->data; + switch ( param->character ) { case 'i': capture_ports = param->value.ui; break; @@ -1042,21 +1005,21 @@ namespace Jack break; case 'f': - #if HAVE_SAMPLERATE +#if HAVE_SAMPLERATE resample_factor = param->value.ui; - #else +#else jack_error( "not built with libsamplerate support" ); return NULL; - #endif +#endif break; case 'u': - #if HAVE_SAMPLERATE +#if HAVE_SAMPLERATE resample_factor_up = param->value.ui; - #else +#else jack_error( "not built with libsamplerate support" ); return NULL; - #endif +#endif break; case 'b': @@ -1064,13 +1027,13 @@ namespace Jack break; case 'c': - #if HAVE_CELT +#if HAVE_CELT bitdepth = CELT_MODE; resample_factor = param->value.ui; - #else +#else jack_error( "not built with celt support" ); return NULL; - #endif +#endif break; case 't': @@ -1100,38 +1063,32 @@ namespace Jack case 'D': always_deadline = param->value.ui; break; - } - } - - try - { - Jack::JackDriverClientInterface* driver = - new Jack::JackWaitThreadedDriver ( - new Jack::JackNetOneDriver ( "system", "net_pcm", engine, table, listen_port, mtu, - capture_ports_midi, playback_ports_midi, capture_ports, playback_ports, - sample_rate, period_size, resample_factor, - "net_pcm", handle_transport_sync, bitdepth, use_autoconfig, latency, redundancy, - dont_htonl_floats, always_deadline, jitter_val ) ); - - if ( driver->Open ( period_size, sample_rate, 1, 1, capture_ports, playback_ports, - 0, "from_master_", "to_master_", 0, 0 ) == 0 ) - { - return driver; - } - else - { - delete driver; - return NULL; - } + } + } - } - catch ( ... ) - { - return NULL; - } + try { + Jack::JackDriverClientInterface* driver = + new Jack::JackWaitThreadedDriver ( + new Jack::JackNetOneDriver ( "system", "net_pcm", engine, table, listen_port, mtu, + capture_ports_midi, playback_ports_midi, capture_ports, playback_ports, + sample_rate, period_size, resample_factor, + "net_pcm", handle_transport_sync, bitdepth, use_autoconfig, latency, redundancy, + dont_htonl_floats, always_deadline, jitter_val ) ); + + if ( driver->Open ( period_size, sample_rate, 1, 1, capture_ports, playback_ports, + 0, "from_master_", "to_master_", 0, 0 ) == 0 ) { + return driver; + } else { + delete driver; + return NULL; } - #ifdef __cplusplus + } catch ( ... ) { + return NULL; } - #endif + } + +#ifdef __cplusplus +} +#endif } diff --git a/common/JackNetOneDriver.h b/common/JackNetOneDriver.h index 348b4628..577c2f6f 100644 --- a/common/JackNetOneDriver.h +++ b/common/JackNetOneDriver.h @@ -27,72 +27,69 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. namespace Jack { - /** - \Brief This class describes the Net Backend - */ - - class JackNetOneDriver : public JackAudioDriver - { - private: - - netjack_driver_state_t netj; - - void - render_payload_to_jack_ports_float ( void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); - void - render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ); - #ifdef HAVE_CELT - void - render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes); - void - render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up); - #endif - void - render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); - void - render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats); - - public: - - JackNetOneDriver ( const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, - int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, - int sample_rate, int period_size, int resample_factor, - const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, - int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val ); - ~JackNetOneDriver(); - - int Open ( jack_nframes_t frames_per_cycle, jack_nframes_t rate, 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 Close(); - int Attach(); - int Detach(); - - int Read(); - int Write(); - - bool Initialize(); - int AllocPorts(); - void FreePorts(); - - // BufferSize can't be changed - bool IsFixedBufferSize() - { - return true; - } - - int SetBufferSize ( jack_nframes_t buffer_size ) - { - return -1; - } - - int SetSampleRate ( jack_nframes_t sample_rate ) - { - return -1; - } - - }; +/** +\Brief This class describes the Net Backend +*/ + +class JackNetOneDriver : public JackAudioDriver +{ + private: + + netjack_driver_state_t netj; + + void + render_payload_to_jack_ports_float(void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); + void + render_jack_ports_to_payload_float(JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats ); +#ifdef HAVE_CELT + void + render_payload_to_jack_ports_celt(void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes); + void + render_jack_ports_to_payload_celt(JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up); +#endif + void + render_payload_to_jack_ports(int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats); + void + render_jack_ports_to_payload(int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats); + + public: + + JackNetOneDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, + int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, + int sample_rate, int period_size, int resample_factor, + const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, + int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val); + ~JackNetOneDriver(); + + int Open(jack_nframes_t frames_per_cycle, jack_nframes_t rate, 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 Close(); + int Attach(); + int Detach(); + + int Read(); + int Write(); + + bool Initialize(); + int AllocPorts(); + void FreePorts(); + + // BufferSize can't be changed + bool IsFixedBufferSize() { + return true; + } + + int SetBufferSize(jack_nframes_t buffer_size) { + return -1; + } + + int SetSampleRate(jack_nframes_t sample_rate) { + return -1; + } + +}; } #endif diff --git a/common/JackNetTool.cpp b/common/JackNetTool.cpp index d44658df..0f527876 100644 --- a/common/JackNetTool.cpp +++ b/common/JackNetTool.cpp @@ -374,11 +374,13 @@ namespace Jack void NetCeltAudioBuffer::SetBuffer(int index, sample_t* buffer) { + assert(fPortBuffer); fPortBuffer[index] = buffer; } sample_t* NetCeltAudioBuffer::GetBuffer(int index) { + assert(fPortBuffer); return fPortBuffer[index]; } diff --git a/common/JackNetTool.h b/common/JackNetTool.h index 63138f51..8466253d 100644 --- a/common/JackNetTool.h +++ b/common/JackNetTool.h @@ -88,10 +88,10 @@ namespace Jack uint32_t fMtu; //connection mtu uint32_t fID; //slave's ID uint32_t fTransportSync; //is the transport synced ? - uint32_t fSendAudioChannels; //number of master->slave channels - uint32_t fReturnAudioChannels; //number of slave->master channels - uint32_t fSendMidiChannels; //number of master->slave midi channels - uint32_t fReturnMidiChannels; //number of slave->master midi channels + int32_t fSendAudioChannels; //number of master->slave channels + int32_t fReturnAudioChannels; //number of slave->master channels + int32_t fSendMidiChannels; //number of master->slave midi channels + int32_t fReturnMidiChannels; //number of slave->master midi channels uint32_t fSampleRate; //session sample rate uint32_t fPeriodSize; //period size uint32_t fSampleEncoder; //samples encoder diff --git a/common/JackPhysicalMidiInput.cpp b/common/JackPhysicalMidiInput.cpp deleted file mode 100644 index 311dad0b..00000000 --- a/common/JackPhysicalMidiInput.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* -Copyright (C) 2009 Devin Anderson - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include -#include -#include - -#include "JackError.h" -#include "JackPhysicalMidiInput.h" - -namespace Jack { - -JackPhysicalMidiInput::JackPhysicalMidiInput(size_t buffer_size) -{ - size_t datum_size = sizeof(jack_midi_data_t); - assert(buffer_size > 0); - input_ring = jack_ringbuffer_create((buffer_size + 1) * datum_size); - if (! input_ring) { - throw std::bad_alloc(); - } - jack_ringbuffer_mlock(input_ring); - Clear(); - expected_data_bytes = 0; - status_byte = 0; -} - -JackPhysicalMidiInput::~JackPhysicalMidiInput() -{ - jack_ringbuffer_free(input_ring); -} - -void -JackPhysicalMidiInput::Clear() -{ - jack_ringbuffer_reset(input_ring); - buffered_bytes = 0; - unbuffered_bytes = 0; -} - -void -JackPhysicalMidiInput::HandleBufferFailure(size_t unbuffered_bytes, - size_t total_bytes) -{ - jack_error("%d MIDI byte(s) of a %d byte message could not be buffered - " - "message dropped", unbuffered_bytes, total_bytes); -} - -void -JackPhysicalMidiInput::HandleIncompleteMessage(size_t bytes) -{ - jack_error("Discarding %d MIDI byte(s) - incomplete message (cable " - "unplugged?)", bytes); -} - -void -JackPhysicalMidiInput::HandleInvalidStatusByte(jack_midi_data_t status) -{ - jack_error("Dropping invalid MIDI status byte '%x'", - (unsigned int) status); -} - -void -JackPhysicalMidiInput::HandleUnexpectedSysexEnd(size_t bytes) -{ - jack_error("Discarding %d MIDI byte(s) - received sysex end without sysex " - "start (cable unplugged?)", bytes); -} - -void -JackPhysicalMidiInput::HandleWriteFailure(size_t bytes) -{ - jack_error("Failed to write a %d byte MIDI message to the port buffer", - bytes); -} - -void -JackPhysicalMidiInput::Process(jack_nframes_t frames) -{ - assert(port_buffer); - port_buffer->Reset(frames); - jack_nframes_t current_frame = 0; - size_t datum_size = sizeof(jack_midi_data_t); - for (;;) { - jack_midi_data_t datum; - current_frame = Receive(&datum, current_frame, frames); - if (current_frame >= frames) { - break; - } - - jack_log("JackPhysicalMidiInput::Process (%d) - Received '%x' byte", - current_frame, (unsigned int) datum); - - if (datum >= 0xf8) { - // Realtime - if (datum == 0xfd) { - HandleInvalidStatusByte(datum); - } else { - - jack_log("JackPhysicalMidiInput::Process - Writing realtime " - "event."); - - WriteByteEvent(current_frame, datum); - } - continue; - } - if (datum == 0xf7) { - // Sysex end - if (status_byte != 0xf0) { - HandleUnexpectedSysexEnd(buffered_bytes + unbuffered_bytes); - Clear(); - expected_data_bytes = 0; - status_byte = 0; - } else { - - jack_log("JackPhysicalMidiInput::Process - Writing sysex " - "event."); - - WriteBufferedSysexEvent(current_frame); - } - continue; - } - if (datum >= 0x80) { - - // We're handling a non-realtime status byte - - jack_log("JackPhysicalMidiInput::Process - Handling non-realtime " - "status byte."); - - if (buffered_bytes || unbuffered_bytes) { - HandleIncompleteMessage(buffered_bytes + unbuffered_bytes + 1); - Clear(); - } - status_byte = datum; - switch (datum & 0xf0) { - case 0x80: - case 0x90: - case 0xa0: - case 0xb0: - case 0xe0: - // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel - expected_data_bytes = 2; - break; - case 0xc0: - case 0xd0: - // Program Change, Channel Pressure - expected_data_bytes = 1; - break; - case 0xf0: - switch (datum) { - case 0xf0: - // Sysex message - expected_data_bytes = 0; - break; - case 0xf1: - case 0xf3: - // MTC Quarter frame, Song Select - expected_data_bytes = 1; - break; - case 0xf2: - // Song Position - expected_data_bytes = 2; - break; - case 0xf4: - case 0xf5: - // Undefined - HandleInvalidStatusByte(datum); - expected_data_bytes = 0; - status_byte = 0; - break; - case 0xf6: - // Tune Request - WriteByteEvent(current_frame, datum); - expected_data_bytes = 0; - status_byte = 0; - } - break; - } - continue; - } - - // We're handling a data byte - - jack_log("JackPhysicalMidiInput::Process - Buffering data byte."); - - if (jack_ringbuffer_write(input_ring, (const char *) &datum, - datum_size) == datum_size) { - buffered_bytes++; - } else { - unbuffered_bytes++; - } - unsigned long total_bytes = buffered_bytes + unbuffered_bytes; - assert((! expected_data_bytes) || - (total_bytes <= expected_data_bytes)); - if (total_bytes == expected_data_bytes) { - if (! unbuffered_bytes) { - - jack_log("JackPhysicalMidiInput::Process - Writing buffered " - "event."); - - WriteBufferedEvent(current_frame); - } else { - HandleBufferFailure(unbuffered_bytes, total_bytes); - Clear(); - } - if (status_byte >= 0xf0) { - expected_data_bytes = 0; - status_byte = 0; - } - } - } -} - -void -JackPhysicalMidiInput::WriteBufferedEvent(jack_nframes_t frame) -{ - assert(port_buffer && port_buffer->IsValid()); - size_t space = jack_ringbuffer_read_space(input_ring); - jack_midi_data_t *event = port_buffer->ReserveEvent(frame, space + 1); - if (event) { - jack_ringbuffer_data_t vector[2]; - jack_ringbuffer_get_read_vector(input_ring, vector); - event[0] = status_byte; - size_t data_length_1 = vector[0].len; - memcpy(event + 1, vector[0].buf, data_length_1); - size_t data_length_2 = vector[1].len; - if (data_length_2) { - memcpy(event + data_length_1 + 1, vector[1].buf, data_length_2); - } - } else { - HandleWriteFailure(space + 1); - } - Clear(); -} - -void -JackPhysicalMidiInput::WriteBufferedSysexEvent(jack_nframes_t frame) -{ - assert(port_buffer && port_buffer->IsValid()); - size_t space = jack_ringbuffer_read_space(input_ring); - jack_midi_data_t *event = port_buffer->ReserveEvent(frame, space + 2); - if (event) { - jack_ringbuffer_data_t vector[2]; - jack_ringbuffer_get_read_vector(input_ring, vector); - event[0] = status_byte; - size_t data_length_1 = vector[0].len; - memcpy(event + 1, vector[0].buf, data_length_1); - size_t data_length_2 = vector[1].len; - if (data_length_2) { - memcpy(event + data_length_1 + 1, vector[1].buf, data_length_2); - } - event[data_length_1 + data_length_2 + 1] = 0xf7; - } else { - HandleWriteFailure(space + 2); - } - Clear(); -} - -void -JackPhysicalMidiInput::WriteByteEvent(jack_nframes_t frame, - jack_midi_data_t datum) -{ - assert(port_buffer && port_buffer->IsValid()); - jack_midi_data_t *event = port_buffer->ReserveEvent(frame, 1); - if (event) { - event[0] = datum; - } else { - HandleWriteFailure(1); - } -} - -} diff --git a/common/JackPhysicalMidiInput.h b/common/JackPhysicalMidiInput.h deleted file mode 100644 index a05de6d0..00000000 --- a/common/JackPhysicalMidiInput.h +++ /dev/null @@ -1,146 +0,0 @@ -/* -Copyright (C) 2009 Devin Anderson - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef __JackPhysicalMidiInput__ -#define __JackPhysicalMidiInput__ - -#include "JackMidiPort.h" -#include "ringbuffer.h" - -namespace Jack { - - class JackPhysicalMidiInput { - - private: - - size_t buffered_bytes; - size_t expected_data_bytes; - jack_ringbuffer_t *input_ring; - JackMidiBuffer *port_buffer; - jack_midi_data_t status_byte; - size_t unbuffered_bytes; - - void - Clear(); - - void - WriteBufferedEvent(jack_nframes_t); - - void - WriteBufferedSysexEvent(jack_nframes_t); - - void - WriteByteEvent(jack_nframes_t, jack_midi_data_t); - - protected: - - /** - * Override to specify how to react when 1 or more bytes of a MIDI - * message are lost because there wasn't enough room in the input - * buffer. The first argument is the amount of bytes that couldn't be - * buffered, and the second argument is the total amount of bytes in - * the MIDI message. The default implementation calls 'jack_error' - * with a basic error message. - */ - - virtual void - HandleBufferFailure(size_t, size_t); - - /** - * Override to specify how to react when a new status byte is received - * before all of the data bytes in a message are received. The - * argument is the number of bytes being discarded. The default - * implementation calls 'jack_error' with a basic error message. - */ - - virtual void - HandleIncompleteMessage(size_t); - - /** - * Override to specify how to react when an invalid status byte (0xf4, - * 0xf5, 0xfd) is received. The argument contains the invalid status - * byte. The default implementation calls 'jack_error' with a basic - * error message. - */ - - virtual void - HandleInvalidStatusByte(jack_midi_data_t); - - /** - * Override to specify how to react when a sysex end byte (0xf7) is - * received without first receiving a sysex start byte (0xf0). The - * argument contains the amount of bytes that will be discarded. The - * default implementation calls 'jack_error' with a basic error - * message. - */ - - virtual void - HandleUnexpectedSysexEnd(size_t); - - /** - * Override to specify how to react when a MIDI message can not be - * written to the port buffer. The argument specifies the length of - * the MIDI message. The default implementation calls 'jack_error' - * with a basic error message. - */ - - virtual void - HandleWriteFailure(size_t); - - /** - * This method *must* be overridden to handle receiving MIDI bytes. - * The first argument is a pointer to the memory location at which the - * MIDI byte should be stored. The second argument is the last frame - * at which a MIDI byte was received, except at the beginning of the - * period when the value is 0. The third argument is the total number - * of frames in the period. The return value is the frame at which the - * MIDI byte is received at, or the value of the third argument is no - * more MIDI bytes can be received in this period. - */ - - virtual jack_nframes_t - Receive(jack_midi_data_t *, jack_nframes_t, jack_nframes_t) = 0; - - public: - - JackPhysicalMidiInput(size_t buffer_size=1024); - virtual ~JackPhysicalMidiInput(); - - /** - * Called to process MIDI data during a period. - */ - - void - Process(jack_nframes_t); - - /** - * Set the MIDI buffer that will receive incoming messages. - */ - - inline void - SetPortBuffer(JackMidiBuffer *port_buffer) - { - this->port_buffer = port_buffer; - } - - }; - -} - -#endif diff --git a/common/JackPhysicalMidiOutput.cpp b/common/JackPhysicalMidiOutput.cpp deleted file mode 100644 index 8f41d443..00000000 --- a/common/JackPhysicalMidiOutput.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* -Copyright (C) 2009 Devin Anderson - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include - -#include "JackError.h" -#include "JackPhysicalMidiOutput.h" - -namespace Jack { - -JackPhysicalMidiOutput::JackPhysicalMidiOutput(size_t non_rt_buffer_size, - size_t rt_buffer_size) -{ - size_t datum_size = sizeof(jack_midi_data_t); - assert(non_rt_buffer_size > 0); - assert(rt_buffer_size > 0); - output_ring = jack_ringbuffer_create((non_rt_buffer_size + 1) * - datum_size); - if (! output_ring) { - throw std::bad_alloc(); - } - rt_output_ring = jack_ringbuffer_create((rt_buffer_size + 1) * - datum_size); - if (! rt_output_ring) { - jack_ringbuffer_free(output_ring); - throw std::bad_alloc(); - } - jack_ringbuffer_mlock(output_ring); - jack_ringbuffer_mlock(rt_output_ring); - running_status = 0; -} - -JackPhysicalMidiOutput::~JackPhysicalMidiOutput() -{ - jack_ringbuffer_free(output_ring); - jack_ringbuffer_free(rt_output_ring); -} - -jack_nframes_t -JackPhysicalMidiOutput::Advance(jack_nframes_t frame) -{ - return frame; -} - -inline jack_midi_data_t -JackPhysicalMidiOutput::ApplyRunningStatus(jack_midi_data_t **buffer, - size_t *size) -{ - - // Stolen and modified from alsa/midi_pack.h - - jack_midi_data_t status = (*buffer)[0]; - if ((status >= 0x80) && (status < 0xf0)) { - if (status == running_status) { - (*buffer)++; - (*size)--; - } else { - running_status = status; - } - } else if (status < 0xf8) { - running_status = 0; - } - return status; -} - -void -JackPhysicalMidiOutput::HandleEventLoss(JackMidiEvent *event) -{ - jack_error("%d byte MIDI event lost", event->size); -} - -void -JackPhysicalMidiOutput::Process(jack_nframes_t frames) -{ - assert(port_buffer); - jack_nframes_t current_frame = Advance(0); - jack_nframes_t current_midi_event = 0; - jack_midi_data_t datum; - size_t datum_size = sizeof(jack_midi_data_t); - JackMidiEvent *midi_event; - jack_midi_data_t *midi_event_buffer; - size_t midi_event_size; - jack_nframes_t midi_events = port_buffer->event_count; - - // First, send any realtime MIDI data that's left from last cycle. - - if ((current_frame < frames) && - jack_ringbuffer_read_space(rt_output_ring)) { - - jack_log("JackPhysicalMidiOutput::Process (%d) - Sending buffered " - "realtime data from last period.", current_frame); - - current_frame = SendBufferedData(rt_output_ring, current_frame, - frames); - - jack_log("JackPhysicalMidiOutput::Process (%d) - Sent", current_frame); - - } - - // Iterate through the events in this cycle. - - for (; (current_midi_event < midi_events) && (current_frame < frames); - current_midi_event++) { - - // Once we're inside this loop, we know that the realtime buffer - // is empty. As long as we don't find a realtime message, we can - // concentrate on sending non-realtime data. - - midi_event = &(port_buffer->events[current_midi_event]); - jack_nframes_t midi_event_time = midi_event->time; - midi_event_buffer = midi_event->GetData(port_buffer); - midi_event_size = midi_event->size; - datum = ApplyRunningStatus(&midi_event_buffer, &midi_event_size); - if (current_frame < midi_event_time) { - - // We have time before this event is scheduled to be sent. - // Send data in the non-realtime buffer. - - if (jack_ringbuffer_read_space(output_ring)) { - - jack_log("JackPhysicalMidiOutput::Process (%d) - Sending " - "buffered non-realtime data from last period.", - current_frame); - - current_frame = SendBufferedData(output_ring, current_frame, - midi_event_time); - - jack_log("JackPhysicalMidiOutput::Process (%d) - Sent", - current_frame); - - } - if (current_frame < midi_event_time) { - - // We _still_ have time before this event is scheduled to - // be sent. Let's send as much of this event as we can - // (save for one byte, which will need to be sent at or - // after its scheduled time). First though, we need to - // make sure that we can buffer this data if we need to. - // Otherwise, we might start sending a message that we - // can't finish. - - if (midi_event_size > 1) { - if (jack_ringbuffer_write_space(output_ring) < - ((midi_event_size - 1) * datum_size)) { - HandleEventLoss(midi_event); - continue; - } - - // Send as much of the event as possible (save for one - // byte). - - do { - - jack_log("JackPhysicalMidiOutput::Process (%d) - " - "Sending unbuffered event byte early.", - current_frame); - - current_frame = Send(current_frame, - *midi_event_buffer); - - jack_log("JackPhysicalMidiOutput::Process (%d) - " - "Sent.", current_frame); - - midi_event_buffer++; - midi_event_size--; - if (current_frame >= midi_event_time) { - - // The event we're processing must be a - // non-realtime event. It has more than one - // byte. - - goto buffer_non_realtime_data; - } - } while (midi_event_size > 1); - } - - jack_log("JackPhysicalMidiOutput::Process (%d) - Advancing to " - ">= %d", current_frame, midi_event_time); - - current_frame = Advance(midi_event_time); - - jack_log("JackPhysicalMidiOutput::Process (%d) - Advanced.", - current_frame); - - } - } - - // If the event is realtime, then we'll send the event now. - // Otherwise, we attempt to put the rest of the event bytes in the - // non-realtime buffer. - - if (datum >= 0xf8) { - - jack_log("JackPhysicalMidiOutput::Process (%d) - Sending " - "unbuffered realtime event.", current_frame); - - current_frame = Send(current_frame, datum); - - jack_log("JackPhysicalMidiOutput::Process (%d) - Sent.", - current_frame); - - } else if (jack_ringbuffer_write_space(output_ring) >= - (midi_event_size * datum_size)) { - buffer_non_realtime_data: - - jack_log("JackPhysicalMidiOutput::Process (%d) - Buffering %d " - "byte(s) of non-realtime data.", current_frame, - midi_event_size); - - jack_ringbuffer_write(output_ring, - (const char *) midi_event_buffer, - midi_event_size); - } else { - HandleEventLoss(midi_event); - } - } - - if (current_frame < frames) { - - // If we have time left to send data, then we know that all of the - // data in the realtime buffer has been sent, and that all of the - // non-realtime messages have either been sent, or buffered. We - // use whatever time is left to send data in the non-realtime - // buffer. - - if (jack_ringbuffer_read_space(output_ring)) { - - jack_log("JackPhysicalMidiOutput::Process (%d) - All events " - "processed. Sending buffered non-realtime data.", - current_frame); - - current_frame = SendBufferedData(output_ring, current_frame, - frames); - - jack_log("JackPhysicalMidiOutput::Process (%d) - Sent.", - current_frame); - - } - } else { - - // Since we have no time left, we need to put all remaining midi - // events in their appropriate buffers, and send them next period. - - for (; current_midi_event < midi_events; current_midi_event++) { - midi_event = &(port_buffer->events[current_midi_event]); - midi_event_buffer = midi_event->GetData(port_buffer); - midi_event_size = midi_event->size; - datum = ApplyRunningStatus(&midi_event_buffer, &midi_event_size); - if (datum >= 0xf8) { - - // Realtime. - - if (jack_ringbuffer_write_space(rt_output_ring) >= - datum_size) { - - jack_log("JackPhysicalMidiOutput::Process - Buffering " - "realtime event for next period."); - - jack_ringbuffer_write(rt_output_ring, - (const char *) &datum, datum_size); - continue; - } - } else { - - // Non-realtime. - - if (jack_ringbuffer_write_space(output_ring) >= - (midi_event_size * datum_size)) { - - jack_log("JackPhysicalMidiOutput::Process - Buffering " - "non-realtime event for next period."); - - jack_ringbuffer_write(output_ring, - (const char *) midi_event_buffer, - midi_event_size * datum_size); - continue; - } - } - HandleEventLoss(midi_event); - } - } -} - -jack_nframes_t -JackPhysicalMidiOutput::SendBufferedData(jack_ringbuffer_t *buffer, - jack_nframes_t current_frame, - jack_nframes_t boundary) -{ - assert(buffer); - assert(current_frame < boundary); - size_t datum_size = sizeof(jack_midi_data_t); - size_t data_length = jack_ringbuffer_read_space(buffer) / datum_size; - for (size_t i = 0; i < data_length; i++) { - jack_midi_data_t datum; - jack_ringbuffer_read(buffer, (char *) &datum, datum_size); - current_frame = Send(current_frame, datum); - if (current_frame >= boundary) { - break; - } - } - return current_frame; -} - -} diff --git a/common/JackPhysicalMidiOutput.h b/common/JackPhysicalMidiOutput.h deleted file mode 100644 index 9b4804b7..00000000 --- a/common/JackPhysicalMidiOutput.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -Copyright (C) 2009 Devin Anderson - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#ifndef __JackPhysicalMidiOutput__ -#define __JackPhysicalMidiOutput__ - -#include "JackMidiPort.h" -#include "ringbuffer.h" - -namespace Jack { - - class JackPhysicalMidiOutput { - - private: - - jack_midi_data_t - ApplyRunningStatus(jack_midi_data_t **, size_t *); - - jack_ringbuffer_t *output_ring; - JackMidiBuffer *port_buffer; - jack_ringbuffer_t *rt_output_ring; - jack_midi_data_t running_status; - - protected: - - /** - * Override to specify the next frame at which a midi byte can be sent. - * The returned frame must be greater than or equal to the frame - * argument. The default returns the frame passed to it. - */ - - virtual jack_nframes_t - Advance(jack_nframes_t); - - /** - * Override to customize how to react when a MIDI event can't be - * buffered and can't be sent immediately. The default calls - * 'jack_error' and specifies the number of bytes lost. - */ - - virtual void - HandleEventLoss(JackMidiEvent *); - - /** - * This method *must* be overridden to specify what happens when a MIDI - * byte is sent at the specfied frame. The frame argument specifies - * the frame at which the MIDI byte should be sent, and the second - * argument specifies the byte itself. The return value is the next - * frame at which a MIDI byte can be sent, and must be greater than or - * equal to the frame argument. - */ - - virtual jack_nframes_t - Send(jack_nframes_t, jack_midi_data_t) = 0; - - /** - * Override to optimize behavior when sending MIDI data that's in the - * ringbuffer. The first frame argument is the current frame, and the - * second frame argument is the boundary frame. The function returns - * the next frame at which MIDI data can be sent, regardless of whether - * or not the boundary is reached. The default implementation calls - * 'Send' with each byte in the ringbuffer until either the ringbuffer - * is empty, or a frame beyond the boundary frame is returned by - * 'Send'. - */ - - virtual jack_nframes_t - SendBufferedData(jack_ringbuffer_t *, jack_nframes_t, jack_nframes_t); - - public: - - /** - * The non-realtime buffer size and the realtime buffer size are both - * optional arguments. - */ - - JackPhysicalMidiOutput(size_t non_rt_buffer_size=1024, - size_t rt_buffer_size=64); - virtual ~JackPhysicalMidiOutput(); - - /** - * Called to process MIDI data during a period. - */ - - void - Process(jack_nframes_t); - - /** - * Set the MIDI buffer that will contain the outgoing MIDI messages. - */ - - inline void - SetPortBuffer(JackMidiBuffer *port_buffer) - { - this->port_buffer = port_buffer; - } - - }; - -} - -#endif diff --git a/common/JackPort.h b/common/JackPort.h index 8e8c1667..88edf1ba 100644 --- a/common/JackPort.h +++ b/common/JackPort.h @@ -107,7 +107,7 @@ class SERVER_EXPORT JackPort // Since we are in shared memory, the resulting pointer cannot be cached, so align it here... jack_default_audio_sample_t* GetBuffer() { - return (jack_default_audio_sample_t*)((long)fBuffer & ~15L) + 4; + return (jack_default_audio_sample_t*)((uintptr_t)fBuffer & ~15L) + 4; } int GetRefNum() const; diff --git a/common/JackServer.cpp b/common/JackServer.cpp index cd1915fb..22027c9c 100644 --- a/common/JackServer.cpp +++ b/common/JackServer.cpp @@ -58,7 +58,7 @@ JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int prio new JackFreewheelDriver(fEngine, GetSynchroTable()); fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver); - fFreewheelDriver = freewheelDriver; + fFreewheelDriver = freewheelDriver; fDriverInfo = new JackDriverInfo(); fAudioDriver = NULL; fFreewheel = false; @@ -223,13 +223,11 @@ int JackServer::SetBufferSize(jack_nframes_t buffer_size) } if (fAudioDriver->SetBufferSize(buffer_size) == 0) { - fFreewheelDriver->SetBufferSize(buffer_size); fEngine->NotifyBufferSize(buffer_size); return fAudioDriver->Start(); } else { // Failure: try to restore current value jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size); fAudioDriver->SetBufferSize(current_buffer_size); - fFreewheelDriver->SetBufferSize(current_buffer_size); fAudioDriver->Start(); // SetBufferSize actually failed, so return an error... return -1; diff --git a/common/JackSession.h b/common/JackSession.h new file mode 100644 index 00000000..af78978a --- /dev/null +++ b/common/JackSession.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2001 Paul Davis + Copyright (C) 2004 Jack O'Quin + Copyright (C) 2010 Torben Hohn + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __jack_session_int_h__ +#define __jack_session_int_h__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum JackSessionEventType { + JackSessionSave = 1, + JackSessionSaveAndQuit = 2, + JackSessionSaveTemplate = 3 +}; + +typedef enum JackSessionEventType jack_session_event_type_t; + +enum JackSessionFlags { + JackSessionSaveError = 0x01, + JackSessionNeedTerminal = 0x02 +}; + +typedef enum JackSessionFlags jack_session_flags_t; + +struct _jack_session_event { + jack_session_event_type_t type; + const char *session_dir; + const char *client_uuid; + char *command_line; + jack_session_flags_t flags; + uint32_t future; +}; + +typedef struct _jack_session_event jack_session_event_t; + +typedef void (*JackSessionCallback)(jack_session_event_t *event, + void *arg); + +typedef struct { + const char *uuid; + const char *client_name; + const char *command; + jack_session_flags_t flags; +} jack_session_command_t; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/common/JackThreadedDriver.cpp b/common/JackThreadedDriver.cpp index 88323fe5..d11eb13e 100644 --- a/common/JackThreadedDriver.cpp +++ b/common/JackThreadedDriver.cpp @@ -127,9 +127,24 @@ void JackThreadedDriver::RemoveSlave(JackDriverInterface* slave) fDriver->RemoveSlave(slave); } -int JackThreadedDriver::ProcessSlaves() +int JackThreadedDriver::ProcessReadSlaves() { - return fDriver->ProcessSlaves(); + return fDriver->ProcessReadSlaves(); +} + +int JackThreadedDriver::ProcessWriteSlaves() +{ + return fDriver->ProcessWriteSlaves(); +} + +int JackThreadedDriver::ProcessRead() +{ + return fDriver->ProcessRead(); +} + +int JackThreadedDriver::ProcessWrite() +{ + return fDriver->ProcessWrite(); } std::list JackThreadedDriver::GetSlaves() @@ -184,7 +199,6 @@ int JackThreadedDriver::Stop() case JackThread::kIniting: if (fThread.Kill() < 0) { jack_error("Cannot kill thread"); - return -1; } break; @@ -192,7 +206,6 @@ int JackThreadedDriver::Stop() case JackThread::kRunning: if (fThread.Stop() < 0) { jack_error("Cannot stop thread"); - return -1; } break; diff --git a/common/JackThreadedDriver.h b/common/JackThreadedDriver.h index 92ec1d26..9d4876b1 100644 --- a/common/JackThreadedDriver.h +++ b/common/JackThreadedDriver.h @@ -89,10 +89,17 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi virtual void SetMaster(bool onoff); virtual bool GetMaster(); + virtual void AddSlave(JackDriverInterface* slave); virtual void RemoveSlave(JackDriverInterface* slave); + virtual std::list GetSlaves(); - virtual int ProcessSlaves(); + + virtual int ProcessReadSlaves(); + virtual int ProcessWriteSlaves(); + + virtual int ProcessRead(); + virtual int ProcessWrite(); virtual int ClientNotify(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2); virtual JackClientControl* GetClientControl() const; diff --git a/common/JackWaitThreadedDriver.h b/common/JackWaitThreadedDriver.h index 1448572b..eb772eb3 100644 --- a/common/JackWaitThreadedDriver.h +++ b/common/JackWaitThreadedDriver.h @@ -22,15 +22,15 @@ #define __JackWaitThreadedDriver__ #include "JackThreadedDriver.h" -#include "JackAudioDriver.h" +#include "JackDriver.h" namespace Jack { - + /*! -\brief To be used as a wrapper of JackNetDriver. +\brief To be used as a wrapper of JackNetDriver. -The idea is to behave as the "dummy" driver, until the network connection is really started and processing starts. +The idea is to behave as the "dummy" driver, until the network connection is really started and processing starts. The Execute method will call the ProcessNull method until the decorated driver Init method returns. A helper JackDriverStarter thread is used for that purpose. */ @@ -38,54 +38,58 @@ A helper JackDriverStarter thread is used for that purpose. class SERVER_EXPORT JackWaitThreadedDriver : public JackThreadedDriver { private: - - struct SERVER_EXPORT JackDriverStarter : public JackRunnableInterface + + struct SERVER_EXPORT JackDriverStarter : public JackRunnableInterface { - + JackDriver* fDriver; JackThread fThread; - bool fRunning; - + volatile bool fRunning; + JackDriverStarter(JackDriver* driver) :fDriver(driver),fThread(this),fRunning(false) {} - + ~JackDriverStarter() { fThread.Kill(); } - + int Start() { fRunning = false; return fThread.Start(); } - + // JackRunnableInterface interface bool Execute() { - // Blocks until decorated driver is started (that is when it's Initialize method returns true). - while (!fDriver->Initialize()) {} - fRunning = true; + // Blocks until decorated driver is started (that is when it's Initialize method returns). + if (fDriver->Initialize()) { + fRunning = true; + } else { + jack_error("Initing net driver fails..."); + } + return false; } - + }; - + JackDriverStarter fStarter; - + public: - JackWaitThreadedDriver(JackDriver* netdriver) - :JackThreadedDriver(netdriver),fStarter(netdriver) + JackWaitThreadedDriver(JackDriver* net_driver) + :JackThreadedDriver(net_driver), fStarter(net_driver) {} virtual ~JackWaitThreadedDriver() {} - + // JackRunnableInterface interface bool Init(); bool Execute(); -}; +}; } // end of namespace diff --git a/common/JackWeakAPI.cpp b/common/JackWeakAPI.cpp index 6ff5af85..146de360 100644 --- a/common/JackWeakAPI.cpp +++ b/common/JackWeakAPI.cpp @@ -235,7 +235,7 @@ DECL_FUNCTION(jack_time_t, jack_frames_to_time, (const jack_client_t *client, ja DECL_FUNCTION(jack_nframes_t, jack_frame_time, (const jack_client_t *client), (client)); DECL_FUNCTION(jack_nframes_t, jack_last_frame_time, (const jack_client_t *client), (client)); DECL_FUNCTION(float, jack_cpu_load, (jack_client_t *client), (client)); -DECL_FUNCTION_NULL(pthread_t, jack_client_thread_id, (jack_client_t *client), (client)); +DECL_FUNCTION_NULL(jack_native_thread_t, jack_client_thread_id, (jack_client_t *client), (client)); DECL_VOID_FUNCTION(jack_set_error_function, (print_function fun), (fun)); DECL_VOID_FUNCTION(jack_set_info_function, (print_function fun), (fun)); @@ -261,17 +261,17 @@ DECL_VOID_FUNCTION(jack_set_transport_info, (jack_client_t *client, jack_transpo DECL_FUNCTION(int, jack_client_real_time_priority, (jack_client_t* client), (client)); DECL_FUNCTION(int, jack_client_max_real_time_priority, (jack_client_t* client), (client)); -DECL_FUNCTION(int, jack_acquire_real_time_scheduling, (pthread_t thread, int priority), (thread, priority)); +DECL_FUNCTION(int, jack_acquire_real_time_scheduling, (jack_native_thread_t thread, int priority), (thread, priority)); DECL_FUNCTION(int, jack_client_create_thread, (jack_client_t* client, - pthread_t *thread, + jack_native_thread_t *thread, int priority, int realtime, // boolean thread_routine routine, void *arg), (client, thread, priority, realtime, routine, arg)); -DECL_FUNCTION(int, jack_drop_real_time_scheduling, (pthread_t thread), (thread)); +DECL_FUNCTION(int, jack_drop_real_time_scheduling, (jack_native_thread_t thread), (thread)); -DECL_FUNCTION(int, jack_client_stop_thread, (jack_client_t* client, pthread_t thread), (client, thread)); -DECL_FUNCTION(int, jack_client_kill_thread, (jack_client_t* client, pthread_t thread), (client, thread)); +DECL_FUNCTION(int, jack_client_stop_thread, (jack_client_t* client, jack_native_thread_t thread), (client, thread)); +DECL_FUNCTION(int, jack_client_kill_thread, (jack_client_t* client, jack_native_thread_t thread), (client, thread)); #ifndef WIN32 DECL_VOID_FUNCTION(jack_set_thread_creator, (jack_thread_creator_t jtc), (jtc)); #endif diff --git a/common/Jackdmp.cpp b/common/Jackdmp.cpp index 602aca31..f2edfe5b 100644 --- a/common/Jackdmp.cpp +++ b/common/Jackdmp.cpp @@ -191,7 +191,7 @@ int main(int argc, char* argv[]) const JSList * server_parameters; const char* server_name = "default"; jackctl_driver_t * master_driver_ctl; - jackctl_driver_t * loopback_driver_ctl; + jackctl_driver_t * loopback_driver_ctl = NULL; int replace_registry = 0; const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:" @@ -476,14 +476,16 @@ int main(int argc, char* argv[]) fprintf(stderr, "Unknown driver \"%s\"\n", *it); goto close_server; } - jackctl_server_add_slave(server_ctl, slave_driver_ctl); + if (!jackctl_server_add_slave(server_ctl, slave_driver_ctl)) { + fprintf(stderr, "Driver \"%s\" cannot be loaded\n", *it); + goto close_server; + } } // Loopback driver if (loopback > 0) { loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback"); - // XX: What if this fails? if (loopback_driver_ctl != NULL) { const JSList * loopback_parameters = jackctl_driver_get_parameters(loopback_driver_ctl); param = jackctl_get_parameter(loopback_parameters, "channels"); @@ -491,9 +493,14 @@ int main(int argc, char* argv[]) value.ui = loopback; jackctl_parameter_set_value(param, &value); } - jackctl_server_add_slave(server_ctl, loopback_driver_ctl); + if (!jackctl_server_add_slave(server_ctl, loopback_driver_ctl)) { + fprintf(stderr, "Driver \"loopback\" cannot be loaded\n"); + goto close_server; + } + } else { + fprintf(stderr, "Driver \"loopback\" not found\n"); + goto close_server; } - } // Start the server @@ -509,7 +516,10 @@ int main(int argc, char* argv[]) fprintf(stderr, "Unknown internal \"%s\"\n", *it); goto stop_server; } - jackctl_server_load_internal(server_ctl, internal_driver_ctl); + if (!jackctl_server_load_internal(server_ctl, internal_driver_ctl)) { + fprintf(stderr, "Internal client \"%s\" cannot be loaded\n", *it); + goto stop_server; + } } notify_server_start(server_name); @@ -523,12 +533,25 @@ int main(int argc, char* argv[]) if (! jackctl_server_stop(server_ctl)) { fprintf(stderr, "Cannot stop server...\n"); } - if (notify_sent) { - notify_server_stop(server_name); - } close_server: + if (loopback > 0 && loopback_driver_ctl) { + jackctl_server_remove_slave(server_ctl, loopback_driver_ctl); + } + // Slave drivers + for (it = slaves_list.begin(); it != slaves_list.end(); it++) { + jackctl_driver_t * slave_driver_ctl = jackctl_server_get_driver(server_ctl, *it); + jackctl_server_remove_slave(server_ctl, slave_driver_ctl); + } + // Internal clients + for (it = internals_list.begin(); it != internals_list.end(); it++) { + jackctl_internal_t * internal_driver_ctl = jackctl_server_get_internal(server_ctl, *it); + jackctl_server_unload_internal(server_ctl, internal_driver_ctl); + } jackctl_server_close(server_ctl); destroy_server: jackctl_server_destroy(server_ctl); + if (notify_sent) { + notify_server_stop(server_name); + } return return_value; } diff --git a/common/jack/jack.h b/common/jack/jack.h index 40f06ddd..03d601b0 100644 --- a/common/jack/jack.h +++ b/common/jack/jack.h @@ -233,7 +233,7 @@ jack_nframes_t jack_thread_wait (jack_client_t*, int status) JACK_OPTIONAL_WEAK_ * * @return the number of frames of data to process */ - jack_nframes_t jack_cycle_wait (jack_client_t* client) JACK_OPTIONAL_WEAK_EXPORT; +jack_nframes_t jack_cycle_wait (jack_client_t* client) JACK_OPTIONAL_WEAK_EXPORT; /** * Signal next clients in the graph. @@ -310,7 +310,7 @@ int jack_set_thread_init_callback (jack_client_t *client, * jack_on_info_shutdown() will. */ void jack_on_shutdown (jack_client_t *client, - JackShutdownCallback shutdown_callback, void *arg) JACK_WEAK_EXPORT; + JackShutdownCallback shutdown_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; /** * @param client pointer to JACK client structure. @@ -336,7 +336,7 @@ void jack_on_shutdown (jack_client_t *client, * jack_on_info_shutdown() will. */ void jack_on_info_shutdown (jack_client_t *client, - JackInfoShutdownCallback shutdown_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; + JackInfoShutdownCallback shutdown_callback, void *arg) JACK_WEAK_EXPORT; /** * Tell the Jack server to call @a process_callback whenever there is diff --git a/common/jack/weakmacros.h b/common/jack/weakmacros.h index d5818b34..e7bc57a9 100644 --- a/common/jack/weakmacros.h +++ b/common/jack/weakmacros.h @@ -40,13 +40,23 @@ the symbol it used with. For this to work full may require linker arguments in the client as well. */ -#define JACK_WEAK_EXPORT __attribute__((weak)) + +#ifdef WIN32 + /* + Not working with __declspec(dllexport) so normal linking + Linking with JackWeakAPI.cpp will be the preferred way. + */ + #define JACK_WEAK_EXPORT #else -/* Add other things here for non-gcc platforms */ - -#ifdef WIN32 -#define JACK_WEAK_EXPORT -#endif + #define JACK_WEAK_EXPORT __attribute__((weak)) +#endif + +#else +/* Add other things here for non-gcc platforms */ + +#ifdef WIN32 +#define JACK_WEAK_EXPORT +#endif #endif #endif @@ -59,13 +69,14 @@ #ifdef __GNUC__ #define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT __attribute__((__deprecated__)) #else -/* Add other things here for non-gcc platforms */ - -#ifdef WIN32 -#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT -#endif +/* Add other things here for non-gcc platforms */ + +#ifdef WIN32 +#define JACK_OPTIONAL_WEAK_DEPRECATED_EXPORT +#endif #endif /* __GNUC__ */ #endif #endif /* __weakmacros_h__ */ + diff --git a/common/netjack.c b/common/netjack.c index e3ec0c33..2b7eeb0d 100644 --- a/common/netjack.c +++ b/common/netjack.c @@ -55,12 +55,11 @@ $Id: net_driver.c,v 1.17 2006/04/16 20:16:10 torbenh Exp $ #include #endif +#include "JackError.h" + #include "netjack.h" #include "netjack_packet.h" -// JACK2 -#include "control.h" - #define MIN(x,y) ((x)<(y) ? (x) : (y)) static int sync_state = 1; diff --git a/common/netjack_packet.c b/common/netjack_packet.c index 638e3d82..21457798 100644 --- a/common/netjack_packet.c +++ b/common/netjack_packet.c @@ -68,15 +68,14 @@ #include #endif +#include "JackError.h" + #if HAVE_CELT #include #endif #include "netjack_packet.h" -// JACK2 specific. -#include "control.h" - #ifdef NO_JACK_ERROR #define jack_error printf #endif diff --git a/common/wscript b/common/wscript index a3935904..84e4a6b7 100644 --- a/common/wscript +++ b/common/wscript @@ -130,8 +130,21 @@ def build(bld): 'JackNetTool.cpp', 'JackNetInterface.cpp', 'JackArgParser.cpp', - 'JackPhysicalMidiInput.cpp', - 'JackPhysicalMidiOutput.cpp', + + #'JackPhysicalMidiInput.cpp', + #'JackPhysicalMidiOutput.cpp', + + 'JackMidiAsyncQueue.cpp', + 'JackMidiAsyncWaitQueue.cpp', + 'JackMidiBufferReadQueue.cpp', + 'JackMidiBufferWriteQueue.cpp', + 'JackMidiRawInputWriteQueue.cpp', + 'JackMidiRawOutputWriteQueue.cpp', + 'JackMidiReadQueue.cpp', + 'JackMidiReceiveQueue.cpp', + 'JackMidiSendQueue.cpp', + 'JackMidiUtil.cpp', + 'JackMidiWriteQueue.cpp' ] if bld.env['IS_LINUX']: diff --git a/dbus/controller.c b/dbus/controller.c index 77acef39..e0abd258 100644 --- a/dbus/controller.c +++ b/dbus/controller.c @@ -64,6 +64,56 @@ jack_controller_find_driver( return NULL; } +bool +jack_controller_add_slave_drivers( + struct jack_controller * controller_ptr) +{ + struct list_head * node_ptr; + struct jack_controller_slave_driver * driver_ptr; + + list_for_each(node_ptr, &controller_ptr->slave_drivers) + { + driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings); + driver_ptr->handle = jack_controller_find_driver(controller_ptr->server, driver_ptr->name); + + if (driver_ptr->handle == NULL) + { + jack_error("Unknown driver \"%s\"", driver_ptr->name); + goto fail; + } + + if (!jackctl_server_add_slave(controller_ptr->server, driver_ptr->handle)) + { + jack_error("Driver \"%s\" cannot be loaded", driver_ptr->name); + goto fail; + } + } + + return true; + +fail: + driver_ptr->handle = NULL; + return false; +} + +void +jack_controller_remove_slave_drivers( + struct jack_controller * controller_ptr) +{ + struct list_head * node_ptr; + struct jack_controller_slave_driver * driver_ptr; + + list_for_each(node_ptr, &controller_ptr->slave_drivers) + { + driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings); + if (driver_ptr->handle != NULL) + { + jackctl_server_remove_slave(controller_ptr->server, driver_ptr->handle); + driver_ptr->handle = NULL; + } + } +} + jackctl_internal_t * jack_controller_find_internal( jackctl_server_t *server, @@ -161,6 +211,8 @@ jack_controller_start_server( goto fail; } + jack_controller_add_slave_drivers(controller_ptr); + if (!jackctl_server_start( controller_ptr->server)) { @@ -221,6 +273,8 @@ fail_stop_server: } fail_close_server: + jack_controller_remove_slave_drivers(controller_ptr); + if (!jackctl_server_close(controller_ptr->server)) { jack_error("failed to close jack server"); @@ -263,6 +317,8 @@ jack_controller_stop_server( return FALSE; } + jack_controller_remove_slave_drivers(controller_ptr); + if (!jackctl_server_close(controller_ptr->server)) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to close server"); @@ -387,6 +443,7 @@ jack_controller_create( controller_ptr->started = false; controller_ptr->driver = NULL; controller_ptr->driver_set = false; + INIT_LIST_HEAD(&controller_ptr->slave_drivers); drivers = (JSList *)jackctl_server_get_drivers_list(controller_ptr->server); controller_ptr->drivers_count = jack_slist_length(drivers); @@ -465,41 +522,58 @@ fail: } bool -jack_controller_add_slave( - struct jack_controller *controller_ptr, +jack_controller_add_slave_driver( + struct jack_controller * controller_ptr, const char * driver_name) { - jackctl_driver_t *driver; + struct jack_controller_slave_driver * driver_ptr; - driver = jack_controller_find_driver(controller_ptr->server, driver_name); - - if (driver == NULL) + driver_ptr = malloc(sizeof(struct jack_controller_slave_driver)); + if (driver_ptr == NULL) { + jack_error("malloc() failed to allocate jack_controller_slave_driver struct"); return false; } - jack_info("driver \"%s\" selected", driver_name); + driver_ptr->name = strdup(driver_name); + if (driver_ptr->name == NULL) + { + jack_error("strdup() failed for slave driver name \"%s\"", driver_name); + free(driver_ptr); + return false; + } + + driver_ptr->handle = NULL; - return jackctl_server_add_slave(controller_ptr->server, driver); + jack_info("slave driver \"%s\" added", driver_name); + + list_add_tail(&driver_ptr->siblings, &controller_ptr->slave_drivers); + + return true; } bool -jack_controller_remove_slave( - struct jack_controller *controller_ptr, +jack_controller_remove_slave_driver( + struct jack_controller * controller_ptr, const char * driver_name) { - jackctl_driver_t *driver; + struct list_head * node_ptr; + struct jack_controller_slave_driver * driver_ptr; - driver = jack_controller_find_driver(controller_ptr->server, driver_name); - - if (driver == NULL) + list_for_each(node_ptr, &controller_ptr->slave_drivers) { - return false; + driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings); + if (strcmp(driver_ptr->name, driver_name) == 0) + { + jack_info("slave driver \"%s\" removed", driver_name); + list_del(&driver_ptr->siblings); + free(driver_ptr->name); + free(driver_ptr); + return true; + } } - jack_info("driver \"%s\" selected", driver_name); - - return jackctl_server_remove_slave(controller_ptr->server, driver); + return false; } bool diff --git a/dbus/controller_iface_configure.c b/dbus/controller_iface_configure.c index dfa56703..f4b6d46f 100644 --- a/dbus/controller_iface_configure.c +++ b/dbus/controller_iface_configure.c @@ -603,6 +603,73 @@ oom: jack_error ("Ran out of memory trying to construct method return"); } +static +void +jack_controller_fill_parameter_info( + jackctl_parameter_t * parameter, + struct parameter_info * info_ptr) +{ + info_ptr->type = jackctl_parameter_get_type(parameter); + info_ptr->name = jackctl_parameter_get_name(parameter); + info_ptr->short_decr = jackctl_parameter_get_short_description(parameter); + info_ptr->long_descr = jackctl_parameter_get_long_description(parameter); +} + +static +bool +jack_controller_append_parameter_info_struct( + DBusMessageIter * iter_ptr, + struct parameter_info * info_ptr) +{ + DBusMessageIter struct_iter; + unsigned char type; + + /* Open the struct. */ + if (!dbus_message_iter_open_container(iter_ptr, DBUS_TYPE_STRUCT, NULL, &struct_iter)) + { + goto fail; + } + + /* Append parameter type. */ + type = PARAM_TYPE_JACK_TO_DBUS(info_ptr->type); + if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_BYTE, &type)) + { + goto fail_close; + } + + /* Append parameter name. */ + if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->name)) + { + goto fail_close; + } + + /* Append parameter short description. */ + if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->short_decr)) + { + goto fail_close; + } + + /* Append parameter long description. */ + if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->long_descr)) + { + goto fail_close; + } + + /* Close the struct. */ + if (!dbus_message_iter_close_container(iter_ptr, &struct_iter)) + { + goto fail; + } + + return true; + +fail_close: + dbus_message_iter_close_container(iter_ptr, &struct_iter); + +fail: + return false; +} + static void jack_controller_get_parameters_info( @@ -610,9 +677,8 @@ jack_controller_get_parameters_info( struct parameter_info * special_parameter_info_ptr, const JSList * parameters_list) { - DBusMessageIter iter, array_iter, struct_iter; - unsigned char type; - const char *str; + DBusMessageIter iter, array_iter; + struct parameter_info info; call->reply = dbus_message_new_method_return (call->message); if (!call->reply) @@ -630,39 +696,7 @@ jack_controller_get_parameters_info( if (special_parameter_info_ptr != NULL) { - /* Open the struct. */ - if (!dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter)) - { - goto fail_close_unref; - } - - /* Append parameter type. */ - type = PARAM_TYPE_JACK_TO_DBUS(special_parameter_info_ptr->type); - if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_BYTE, &type)) - { - goto fail_close2_unref; - } - - /* Append parameter name. */ - if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &special_parameter_info_ptr->name)) - { - goto fail_close2_unref; - } - - /* Append parameter short description. */ - if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &special_parameter_info_ptr->short_decr)) - { - goto fail_close2_unref; - } - - /* Append parameter long description. */ - if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &special_parameter_info_ptr->long_descr)) - { - goto fail_close2_unref; - } - - /* Close the struct. */ - if (!dbus_message_iter_close_container (&array_iter, &struct_iter)) + if (!jack_controller_append_parameter_info_struct(&array_iter, special_parameter_info_ptr)) { goto fail_close_unref; } @@ -671,42 +705,8 @@ jack_controller_get_parameters_info( /* Append parameter descriptions to the array. */ while (parameters_list != NULL) { - /* Open the struct. */ - if (!dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter)) - { - goto fail_close_unref; - } - - /* Append parameter type. */ - type = PARAM_TYPE_JACK_TO_DBUS(jackctl_parameter_get_type(parameters_list->data)); - if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_BYTE, &type)) - { - goto fail_close2_unref; - } - - /* Append parameter name. */ - str = jackctl_parameter_get_name(parameters_list->data); - if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &str)) - { - goto fail_close2_unref; - } - - /* Append parameter short description. */ - str = jackctl_parameter_get_short_description(parameters_list->data); - if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &str)) - { - goto fail_close2_unref; - } - - /* Append parameter long description. */ - str = jackctl_parameter_get_long_description(parameters_list->data); - if (!dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &str)) - { - goto fail_close2_unref; - } - - /* Close the struct. */ - if (!dbus_message_iter_close_container (&array_iter, &struct_iter)) + jack_controller_fill_parameter_info(parameters_list->data, &info); + if (!jack_controller_append_parameter_info_struct(&array_iter, &info)) { goto fail_close_unref; } @@ -722,9 +722,6 @@ jack_controller_get_parameters_info( return; -fail_close2_unref: - dbus_message_iter_close_container (&iter, &struct_iter); - fail_close_unref: dbus_message_iter_close_container (&iter, &array_iter); @@ -851,8 +848,7 @@ jack_controller_get_parameter_info_ex( struct jack_dbus_method_call * call, struct parameter_info * info_ptr) { - DBusMessageIter iter, struct_iter; - unsigned char type; + DBusMessageIter iter; call->reply = dbus_message_new_method_return(call->message); if (!call->reply) @@ -862,48 +858,13 @@ jack_controller_get_parameter_info_ex( dbus_message_iter_init_append(call->reply, &iter); - /* Open the struct. */ - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &struct_iter)) - { - goto fail_unref; - } - - /* Append parameter type. */ - type = PARAM_TYPE_JACK_TO_DBUS(info_ptr->type); - if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_BYTE, &type)) - { - goto fail_close_unref; - } - - /* Append parameter name. */ - if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->name)) - { - goto fail_close_unref; - } - - /* Append parameter short description. */ - if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->short_decr)) - { - goto fail_close_unref; - } - - /* Append parameter long description. */ - if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &info_ptr->long_descr)) - { - goto fail_close_unref; - } - - /* Close the struct. */ - if (!dbus_message_iter_close_container(&iter, &struct_iter)) + if (!jack_controller_append_parameter_info_struct(&iter, info_ptr)) { goto fail_unref; } return; -fail_close_unref: - dbus_message_iter_close_container(&iter, &struct_iter); - fail_unref: dbus_message_unref(call->reply); call->reply = NULL; @@ -920,11 +881,7 @@ jack_controller_get_parameter_info( { struct parameter_info info; - info.type = jackctl_parameter_get_type(parameter); - info.name = jackctl_parameter_get_name(parameter); - info.short_decr = jackctl_parameter_get_short_description(parameter); - info.long_descr = jackctl_parameter_get_long_description(parameter); - + jack_controller_fill_parameter_info(parameter, &info); jack_controller_get_parameter_info_ex(call, &info); } diff --git a/dbus/controller_iface_control.c b/dbus/controller_iface_control.c index cd0187da..53daba7e 100644 --- a/dbus/controller_iface_control.c +++ b/dbus/controller_iface_control.c @@ -229,10 +229,15 @@ jack_control_run_method( "jack_controller_load_internal failed for internal (%s)", internal_name); } } - else if (strcmp (call->method_name, "AddSlave") == 0) + else if (strcmp (call->method_name, "AddSlaveDriver") == 0) { const char *driver_name; + if (controller_ptr->started) + { + goto fail_started; + } + if (!jack_dbus_get_method_args(call, DBUS_TYPE_STRING, &driver_name, DBUS_TYPE_INVALID)) { /* The method call had invalid arguments meaning that @@ -241,17 +246,22 @@ jack_control_run_method( goto exit; } - if (!jack_controller_add_slave(controller_ptr, driver_name)) { + if (!jack_controller_add_slave_driver(controller_ptr, driver_name)) { jack_dbus_error( call, JACK_DBUS_ERROR_GENERIC, - "jack_controller_add_slave failed for driver (%s)", driver_name); + "jack_controller_add_slave_driver failed for driver (%s)", driver_name); } } - else if (strcmp (call->method_name, "RemoveSlave") == 0) + else if (strcmp (call->method_name, "RemoveSlaveDriver") == 0) { const char *driver_name; + if (controller_ptr->started) + { + goto fail_started; + } + if (!jack_dbus_get_method_args(call, DBUS_TYPE_STRING, &driver_name, DBUS_TYPE_INVALID)) { /* The method call had invalid arguments meaning that @@ -260,11 +270,11 @@ jack_control_run_method( goto exit; } - if (!jack_controller_remove_slave(controller_ptr, driver_name)) { + if (!jack_controller_remove_slave_driver(controller_ptr, driver_name)) { jack_dbus_error( call, JACK_DBUS_ERROR_GENERIC, - "jack_controller_remove_slave failed for driver (%s)", driver_name); + "jack_controller_remove_slave_driver failed for driver (%s)", driver_name); } } else if (strcmp (call->method_name, "UnloadInternal") == 0) @@ -293,8 +303,7 @@ jack_control_run_method( } jack_dbus_construct_method_return_single(call, type, arg); - - return true; + goto exit; not_started: jack_dbus_only_error( @@ -302,6 +311,15 @@ not_started: JACK_DBUS_ERROR_SERVER_NOT_RUNNING, "Can't execute method '%s' with stopped JACK server", call->method_name); + goto exit; + +fail_started: + jack_dbus_only_error( + call, + JACK_DBUS_ERROR_SERVER_RUNNING, + "Can't execute method '%s' with started JACK server", + call->method_name); + goto exit; exit: return true; @@ -361,12 +379,12 @@ JACK_DBUS_METHOD_ARGUMENTS_BEGIN(UnloadInternal) JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) JACK_DBUS_METHOD_ARGUMENTS_END -JACK_DBUS_METHOD_ARGUMENTS_BEGIN(AddSlave) - JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(AddSlaveDriver) + JACK_DBUS_METHOD_ARGUMENT("driver_name", "s", false) JACK_DBUS_METHOD_ARGUMENTS_END -JACK_DBUS_METHOD_ARGUMENTS_BEGIN(RemoveSlave) - JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(RemoveSlaveDriver) + JACK_DBUS_METHOD_ARGUMENT("driver_name", "s", false) JACK_DBUS_METHOD_ARGUMENTS_END JACK_DBUS_METHODS_BEGIN @@ -384,8 +402,8 @@ JACK_DBUS_METHODS_BEGIN JACK_DBUS_METHOD_DESCRIBE(ResetXruns, NULL) JACK_DBUS_METHOD_DESCRIBE(LoadInternal, NULL) JACK_DBUS_METHOD_DESCRIBE(UnloadInternal, NULL) - JACK_DBUS_METHOD_DESCRIBE(AddSlave, NULL) - JACK_DBUS_METHOD_DESCRIBE(RemoveSlave, NULL) + JACK_DBUS_METHOD_DESCRIBE(AddSlaveDriver, NULL) + JACK_DBUS_METHOD_DESCRIBE(RemoveSlaveDriver, NULL) JACK_DBUS_METHODS_END JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ServerStarted) diff --git a/dbus/controller_internal.h b/dbus/controller_internal.h index a7711a8d..6bb223a8 100644 --- a/dbus/controller_internal.h +++ b/dbus/controller_internal.h @@ -26,6 +26,14 @@ #include "jack/control.h" #include "jack/jack.h" #include "jackdbus.h" +#include "list.h" + +struct jack_controller_slave_driver +{ + struct list_head siblings; + char * name; + jackctl_driver_t * handle; +}; struct jack_controller { @@ -45,6 +53,7 @@ struct jack_controller jackctl_driver_t *driver; bool driver_set; /* whether driver is manually set, if false - DEFAULT_DRIVER is auto set */ + struct list_head slave_drivers; struct jack_dbus_object_descriptor dbus_descriptor; }; @@ -87,12 +96,12 @@ jack_controller_switch_master( void *dbus_call_context_ptr); bool -jack_controller_add_slave( +jack_controller_add_slave_driver( struct jack_controller *controller_ptr, const char * driver_name); bool -jack_controller_remove_slave( +jack_controller_remove_slave_driver( struct jack_controller *controller_ptr, const char * driver_name); diff --git a/dbus/jackdbus.h b/dbus/jackdbus.h index d920cf06..c0ab8861 100644 --- a/dbus/jackdbus.h +++ b/dbus/jackdbus.h @@ -46,6 +46,7 @@ jack_controller_settings_uninit(); #define JACK_DBUS_ERROR_UNKNOWN_METHOD "org.jackaudio.Error.UnknownMethod" #define JACK_DBUS_ERROR_SERVER_NOT_RUNNING "org.jackaudio.Error.ServerNotRunning" +#define JACK_DBUS_ERROR_SERVER_RUNNING "org.jackaudio.Error.ServerRunning" #define JACK_DBUS_ERROR_UNKNOWN_DRIVER "org.jackaudio.Error.UnknownDriver" #define JACK_DBUS_ERROR_UNKNOWN_INTERNAL "org.jackaudio.Error.UnknownInternal" #define JACK_DBUS_ERROR_UNKNOWN_PARAMETER "org.jackaudio.Error.UnknownParameter" diff --git a/doxyfile b/doxyfile index 45b36fda..084836cd 100644 --- a/doxyfile +++ b/doxyfile @@ -31,7 +31,7 @@ PROJECT_NAME = "Jack2" # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 1.9.7 +PROJECT_NUMBER = 1.9.8 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/example-clients/jack_control b/example-clients/jack_control index 1d06436b..b90bfd5c 100755 --- a/example-clients/jack_control +++ b/example-clients/jack_control @@ -116,6 +116,8 @@ def main(): print " dp - get parameters of currently selected driver" print " dpd - get long description for driver parameter" print " dps - set driver parameter" + print " asd - add slave driver" + print " rsd - remove slave driver" print " il - get list of available internals" print " ip - get parameters of given internal" print " ipd - get long description for internal parameter" @@ -305,6 +307,26 @@ def main(): name = sys.argv[index] index += 1 result = control_iface.UnloadInternal(name) + elif arg == 'asd': + print "--- add slave driver" + + if index >= len(sys.argv): + print "add slave driver command requires driver name argument" + sys.exit() + + name = sys.argv[index] + index += 1 + result = control_iface.AddSlaveDriver(name) + elif arg == 'rsd': + print "--- remove slave driver" + + if index >= len(sys.argv): + print "remove slave driver command requires driver name argument" + sys.exit() + + name = sys.argv[index] + index += 1 + result = control_iface.RemoveSlaveDriver(name) else: print "Unknown command '%s'" % arg except dbus.DBusException, e: diff --git a/example-clients/latent_client.c b/example-clients/latent_client.c index 67217832..9384d98a 100644 --- a/example-clients/latent_client.c +++ b/example-clients/latent_client.c @@ -1,4 +1,4 @@ -/** @file simple_client.c +/** @file latent_client.c * * @brief This simple client demonstrates the most basic features of JACK * as they would be used by many applications. @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -19,12 +19,12 @@ jack_client_t *client; jack_default_audio_sample_t *delay_line; jack_nframes_t delay_index; -jack_nframes_t latency = 1024; - -#ifdef WIN32 -#define jack_sleep(val) Sleep((val)) -#else -#define jack_sleep(val) usleep((val) * 1000) +jack_nframes_t latency = 1024; + +#ifdef WIN32 +#define jack_sleep(val) Sleep((val)) +#else +#define jack_sleep(val) usleep((val) * 1000) #endif /** @@ -213,3 +213,4 @@ main (int argc, char *argv[]) jack_client_close (client); exit (0); } + diff --git a/example-clients/midi_latency_test.c b/example-clients/midi_latency_test.c new file mode 100644 index 00000000..60d13882 --- /dev/null +++ b/example-clients/midi_latency_test.c @@ -0,0 +1,777 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/* + * This program is used to measure MIDI latency and jitter. It writes MIDI + * messages to one port and calculates how long it takes before it reads the + * same MIDI message over another port. It was written to calculate the + * latency and jitter of hardware and JACK hardware drivers, but might have + * other practical applications. + * + * The latency results of the program include the latency introduced by the + * JACK system. Because JACK has sample accurate MIDI, the same latency + * imposed on audio is also imposed on MIDI going through the system. Make + * sure you take this into account before complaining to me or (*especially*) + * other JACK developers about reported MIDI latency. + * + * The jitter results are a little more interesting. The program attempts to + * calculate 'average jitter' and 'peak jitter', as defined here: + * + * http://openmuse.org/transport/fidelity.html + * + * It also outputs a jitter plot, which gives you a more specific idea about + * the MIDI jitter for the ports you're testing. This is useful for catching + * extreme jitter values, and for analyzing the amount of truth in the + * technical specifications for your MIDI interface(s). :) + * + * This program is loosely based on 'alsa-midi-latency-test' in the ALSA test + * suite. + * + * To port this program to non-POSIX platforms, you'll have to include + * implementations for semaphores and command-line argument handling. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#ifdef WIN32 +#include +#include +#else +#include +#endif + +#include + +#define ABS(x) (((x) >= 0) ? (x) : (-(x))) + +#ifdef WIN32 +typedef HANDLE semaphore_t; +#else +typedef sem_t *semaphore_t; +#endif + +const char *ERROR_RESERVE = "could not reserve MIDI event on port buffer"; +const char *ERROR_SHUTDOWN = "the JACK server has been shutdown"; +const char *ERROR_TIMEOUT1 = "timed out while waiting for MIDI message"; + +const char *SOURCE_EVENT_RESERVE = "jack_midi_event_reserve"; +const char *SOURCE_PROCESS = "handle_process"; +const char *SOURCE_SHUTDOWN = "handle_shutdown"; +const char *SOURCE_SIGNAL_SEMAPHORE = "signal_semaphore"; +const char *SOURCE_WAIT_SEMAPHORE = "wait_semaphore"; + +jack_client_t *client; +const char *error_message; +const char *error_source; +jack_nframes_t highest_latency; +jack_time_t highest_latency_time; +jack_latency_range_t in_latency_range; +jack_port_t *in_port; +semaphore_t init_semaphore; +jack_nframes_t last_activity; +jack_time_t last_activity_time; +jack_time_t *latency_time_values; +jack_nframes_t *latency_values; +jack_nframes_t lowest_latency; +jack_time_t lowest_latency_time; +jack_midi_data_t *message_1; +jack_midi_data_t *message_2; +size_t messages_received; +size_t messages_sent; +size_t message_size; +jack_latency_range_t out_latency_range; +jack_port_t *out_port; +semaphore_t process_semaphore; +int process_state; +char *program_name; +jack_port_t *remote_in_port; +jack_port_t *remote_out_port; +size_t samples; +int timeout; +jack_nframes_t total_latency; +jack_time_t total_latency_time; +size_t unexpected_messages; +size_t xrun_count; + +static void signal_handler(int sig) +{ + jack_client_close(client); + fprintf(stderr, "signal received, exiting ...\n"); + exit(0); +} + +#ifdef WIN32 +char semaphore_error_msg[1024]; +#endif + +static void +output_error(const char *source, const char *message); + +static void +output_usage(); + +static void +set_process_error(const char *source, const char *message); + +static int +signal_semaphore(semaphore_t semaphore); + +static int +wait_semaphore(semaphore_t semaphore, int block); + +static semaphore_t +create_semaphore(int id) +{ + semaphore_t semaphore; + +#ifdef WIN32 + semaphore = CreateSemaphore(NULL, 0, 1, NULL); +#elif defined (__APPLE__) + char name[128]; + sprintf(name, "midi_sem_%d", id); + semaphore = sem_open(name, O_CREAT, 0777, 0); + if (semaphore == (sem_t *) SEM_FAILED) { + semaphore = NULL; + } +#else + semaphore = malloc(sizeof(semaphore_t)); + if (semaphore != NULL) { + if (sem_init(semaphore, 0, 0)) { + free(semaphore); + semaphore = NULL; + } + } +#endif + + return semaphore; +} + +static void +destroy_semaphore(semaphore_t semaphore, int id) +{ + +#ifdef WIN32 + CloseHandle(semaphore); +#else + sem_destroy(semaphore); +#ifdef __APPLE__ + { + char name[128]; + sprintf(name, "midi_sem_%d", id); + sem_unlink(name); + } +#else + free(semaphore); +#endif +#endif + +} + +static void +die(const char *source, const char *error_message) +{ + output_error(source, error_message); + output_usage(); + exit(EXIT_FAILURE); +} + +static const char * +get_semaphore_error() +{ + +#ifdef WIN32 + DWORD error = GetLastError(); + if (! FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + semaphore_error_msg, 1024, NULL)) { + snprintf(semaphore_error_msg, 1023, "Unknown OS error code '%d'", + error); + } + return semaphore_error_msg; +#else + return strerror(errno); +#endif + +} + +static void +handle_info(const char *message) +{ + /* Suppress info */ +} + +static int +handle_process(jack_nframes_t frames, void *arg) +{ + jack_midi_data_t *buffer; + jack_midi_event_t event; + jack_nframes_t event_count; + jack_nframes_t event_time; + jack_nframes_t frame; + size_t i; + jack_nframes_t last_frame_time; + jack_midi_data_t *message; + jack_time_t microseconds; + void *port_buffer; + jack_time_t time; + jack_midi_clear_buffer(jack_port_get_buffer(out_port, frames)); + switch (process_state) { + + case 0: + /* State: initializing */ + switch (wait_semaphore(init_semaphore, 0)) { + case -1: + set_process_error(SOURCE_WAIT_SEMAPHORE, get_semaphore_error()); + // Fallthrough on purpose + case 0: + return 0; + } + highest_latency = 0; + lowest_latency = 0; + messages_received = 0; + messages_sent = 0; + process_state = 1; + total_latency = 0; + total_latency_time = 0; + unexpected_messages = 0; + xrun_count = 0; + jack_port_get_latency_range(remote_in_port, JackCaptureLatency, + &in_latency_range); + jack_port_get_latency_range(remote_out_port, JackPlaybackLatency, + &out_latency_range); + goto send_message; + + case 1: + /* State: processing */ + port_buffer = jack_port_get_buffer(in_port, frames); + event_count = jack_midi_get_event_count(port_buffer); + last_frame_time = jack_last_frame_time(client); + for (i = 0; i < event_count; i++) { + jack_midi_event_get(&event, port_buffer, i); + message = (messages_received % 2) ? message_2 : message_1; + if ((event.size == message_size) && + (! memcmp(message, event.buffer, + message_size * sizeof(jack_midi_data_t)))) { + goto found_message; + } + unexpected_messages++; + } + microseconds = jack_frames_to_time(client, last_frame_time) - + last_activity_time; + if ((microseconds / 1000000) >= timeout) { + set_process_error(SOURCE_PROCESS, ERROR_TIMEOUT1); + } + break; + found_message: + event_time = last_frame_time + event.time; + frame = event_time - last_activity; + time = jack_frames_to_time(client, event_time) - last_activity_time; + if ((! highest_latency) || (frame > highest_latency)) { + highest_latency = frame; + highest_latency_time = time; + } + if ((! lowest_latency) || (frame < lowest_latency)) { + lowest_latency = frame; + lowest_latency_time = time; + } + latency_time_values[messages_received] = time; + latency_values[messages_received] = frame; + total_latency += frame; + total_latency_time += time; + messages_received++; + if (messages_received == samples) { + process_state = 2; + if (! signal_semaphore(process_semaphore)) { + // Sigh ... + die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error()); + } + break; + } + send_message: + frame = (jack_nframes_t) ((((double) rand()) / RAND_MAX) * frames); + if (frame >= frames) { + frame = frames - 1; + } + port_buffer = jack_port_get_buffer(out_port, frames); + buffer = jack_midi_event_reserve(port_buffer, frame, message_size); + if (buffer == NULL) { + set_process_error(SOURCE_EVENT_RESERVE, ERROR_RESERVE); + break; + } + message = (messages_sent % 2) ? message_2 : message_1; + memcpy(buffer, message, message_size * sizeof(jack_midi_data_t)); + last_activity = jack_last_frame_time(client) + frame; + last_activity_time = jack_frames_to_time(client, last_activity); + messages_sent++; + + case 2: + /* State: finished - do nothing */ + + case -1: + /* State: error - do nothing */ + ; + + } + return 0; +} + +static void +handle_shutdown(void *arg) +{ + set_process_error(SOURCE_SHUTDOWN, ERROR_SHUTDOWN); +} + +static int +handle_xrun(void *arg) +{ + xrun_count++; + return 0; +} + +static void +output_error(const char *source, const char *message) +{ + fprintf(stderr, "%s: %s: %s\n", program_name, source, message); +} + +static void +output_usage() +{ + fprintf(stderr, "Usage: %s [options] out-port-name in-port-name\n\n" + "\t-h, --help print program usage\n" + "\t-m, --message-size=size set size of MIDI messages to send\n" + "\t-s, --samples=n number of MIDI messages to send\n" + "\t-t, --timeout=seconds wait time before giving up on message\n" + "\n", program_name); +} + +static unsigned long +parse_positive_number_arg(char *s, char *name) +{ + char *end_ptr; + unsigned long result; + errno = 0; + result = strtoul(s, &end_ptr, 10); + if (errno) { + die(name, strerror(errno)); + } + if (*s == '\0') { + die(name, "argument value cannot be empty"); + } + if (*end_ptr != '\0') { + die(name, "invalid value"); + } + if (! result) { + die(name, "must be a positive number"); + } + return result; +} + +static void +set_process_error(const char *source, const char *message) +{ + error_source = source; + error_message = message; + process_state = -1; + if (! signal_semaphore(process_semaphore)) { + // Sigh + output_error(source, message); + die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error()); + } +} + +static int +signal_semaphore(semaphore_t semaphore) +{ + +#ifdef WIN32 + return ReleaseSemaphore(semaphore, 1, NULL); +#else + return ! sem_post(semaphore); +#endif + +} + +static int +wait_semaphore(semaphore_t semaphore, int block) +{ + +#ifdef WIN32 + DWORD result = WaitForSingleObject(semaphore, block ? INFINITE : 0); + switch (result) { + case WAIT_OBJECT_0: + return 1; + case WAIT_TIMEOUT: + return 0; + } + return -1; +#else + if (block) { + while (sem_wait(semaphore)) { + if (errno != EINTR) { + return -1; + } + } + } else { + while (sem_trywait(semaphore)) { + switch (errno) { + case EAGAIN: + return 0; + case EINTR: + continue; + default: + return -1; + } + } + } + return 1; +#endif + +} + +int +main(int argc, char **argv) +{ + size_t jitter_plot[101]; + size_t latency_plot[101]; + int long_index = 0; + struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"message-size", 1, NULL, 'm'}, + {"samples", 1, NULL, 's'}, + {"timeout", 1, NULL, 't'} + }; + char *option_string = "hm:s:t:"; + int show_usage = 0; + error_message = NULL; + message_size = 3; + program_name = argv[0]; + samples = 1024; + timeout = 5; + + for (;;) { + char c = getopt_long(argc, argv, option_string, long_options, + &long_index); + switch (c) { + case 'h': + show_usage = 1; + break; + case 'm': + message_size = parse_positive_number_arg(optarg, "message-size"); + break; + case 's': + samples = parse_positive_number_arg(optarg, "samples"); + break; + case 't': + timeout = parse_positive_number_arg(optarg, "timeout"); + break; + default: + { + char *s = "'- '"; + s[2] = c; + die(s, "invalid switch"); + } + case -1: + if (show_usage) { + output_usage(); + exit(EXIT_SUCCESS); + } + goto parse_port_names; + case 1: + /* end of switch :) */ + ; + } + } + parse_port_names: + if ((argc - optind) != 2) { + output_usage(); + return EXIT_FAILURE; + } + latency_values = malloc(sizeof(jack_nframes_t) * samples); + if (latency_values == NULL) { + error_message = strerror(errno); + error_source = "malloc"; + goto show_error; + } + latency_time_values = malloc(sizeof(jack_time_t) * samples); + if (latency_time_values == NULL) { + error_message = strerror(errno); + error_source = "malloc"; + goto free_latency_values; + } + message_1 = malloc(message_size * sizeof(jack_midi_data_t)); + if (message_1 == NULL) { + error_message = strerror(errno); + error_source = "malloc"; + goto free_latency_time_values; + } + message_2 = malloc(message_size * sizeof(jack_midi_data_t)); + if (message_2 == NULL) { + error_message = strerror(errno); + error_source = "malloc"; + goto free_message_1; + } + switch (message_size) { + case 1: + message_1[0] = 0xf6; + message_2[0] = 0xfe; + break; + case 2: + message_1[0] = 0xc0; + message_1[1] = 0x00; + message_2[0] = 0xd0; + message_2[1] = 0x7f; + break; + case 3: + message_1[0] = 0x80; + message_1[1] = 0x00; + message_1[2] = 0x00; + message_2[0] = 0x90; + message_2[1] = 0x7f; + message_2[2] = 0x7f; + break; + default: + message_1[0] = 0xf0; + memset(message_1 + 1, 0, + (message_size - 2) * sizeof(jack_midi_data_t)); + message_1[message_size - 1] = 0xf7; + message_2[0] = 0xf0; + memset(message_2 + 1, 0x7f, + (message_size - 2) * sizeof(jack_midi_data_t)); + message_2[message_size - 1] = 0xf7; + } + + /* install a signal handler to properly quits jack client */ +#ifdef WIN32 + signal(SIGINT, signal_handler); + signal(SIGABRT, signal_handler); + signal(SIGTERM, signal_handler); +#else + signal(SIGQUIT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGHUP, signal_handler); + signal(SIGINT, signal_handler); +#endif + + client = jack_client_open(program_name, JackNullOption, NULL); + if (client == NULL) { + error_message = "failed to open JACK client"; + error_source = "jack_client_open"; + goto free_message_2; + } + remote_in_port = jack_port_by_name(client, argv[optind + 1]); + if (remote_in_port == NULL) { + error_message = "invalid port name"; + error_source = argv[optind + 1]; + goto close_client; + } + remote_out_port = jack_port_by_name(client, argv[optind]); + if (remote_out_port == NULL) { + error_message = "invalid port name"; + error_source = argv[optind]; + goto close_client; + } + in_port = jack_port_register(client, "in", JACK_DEFAULT_MIDI_TYPE, + JackPortIsInput, 0); + if (in_port == NULL) { + error_message = "failed to register MIDI-in port"; + error_source = "jack_port_register"; + goto close_client; + } + out_port = jack_port_register(client, "out", JACK_DEFAULT_MIDI_TYPE, + JackPortIsOutput, 0); + if (out_port == NULL) { + error_message = "failed to register MIDI-out port"; + error_source = "jack_port_register"; + goto unregister_in_port; + } + if (jack_set_process_callback(client, handle_process, NULL)) { + error_message = "failed to set process callback"; + error_source = "jack_set_process_callback"; + goto unregister_out_port; + } + if (jack_set_xrun_callback(client, handle_xrun, NULL)) { + error_message = "failed to set xrun callback"; + error_source = "jack_set_xrun_callback"; + goto unregister_out_port; + } + jack_on_shutdown(client, handle_shutdown, NULL); + jack_set_info_function(handle_info); + process_state = 0; + init_semaphore = create_semaphore(0); + if (init_semaphore == NULL) { + error_message = get_semaphore_error(); + error_source = "create_semaphore"; + goto unregister_out_port; + } + process_semaphore = create_semaphore(1); + if (process_semaphore == NULL) { + error_message = get_semaphore_error(); + error_source = "create_semaphore"; + goto destroy_init_semaphore; + } + if (jack_activate(client)) { + error_message = "could not activate client"; + error_source = "jack_activate"; + goto destroy_process_semaphore; + } + if (jack_connect(client, jack_port_name(out_port), + jack_port_name(remote_out_port))) { + error_message = "could not connect MIDI out port"; + error_source = "jack_connect"; + goto deactivate_client; + } + if (jack_connect(client, jack_port_name(remote_in_port), + jack_port_name(in_port))) { + error_message = "could not connect MIDI in port"; + error_source = "jack_connect"; + goto deactivate_client; + } + if (! signal_semaphore(init_semaphore)) { + error_message = get_semaphore_error(); + error_source = "post_semaphore"; + goto deactivate_client; + } + if (wait_semaphore(process_semaphore, 1) == -1) { + error_message = get_semaphore_error(); + error_source = "wait_semaphore"; + goto deactivate_client; + } + if (process_state == 2) { + double average_latency = ((double) total_latency) / samples; + double average_latency_time = total_latency_time / samples; + size_t i; + double latency_plot_offset = + floor(((double) lowest_latency_time) / 100.0) / 10.0; + double sample_rate = (double) jack_get_sample_rate(client); + jack_nframes_t total_jitter = 0; + jack_time_t total_jitter_time = 0; + for (i = 0; i <= 100; i++) { + jitter_plot[i] = 0; + latency_plot[i] = 0; + } + for (i = 0; i < samples; i++) { + double latency_time_value = (double) latency_time_values[i]; + double latency_plot_time = + (latency_time_value / 1000.0) - latency_plot_offset; + double jitter_time = ABS(average_latency_time - + latency_time_value); + if (latency_plot_time >= 10.0) { + (latency_plot[100])++; + } else { + (latency_plot[(int) (latency_plot_time * 10.0)])++; + } + if (jitter_time >= 10000.0) { + (jitter_plot[100])++; + } else { + (jitter_plot[(int) (jitter_time / 100.0)])++; + } + total_jitter += ABS(average_latency - + ((double) latency_values[i])); + total_jitter_time += jitter_time; + } + printf("Reported out-port latency: %.2f-%.2f ms (%u-%u frames)\n" + "Reported in-port latency: %.2f-%.2f ms (%u-%u frames)\n" + "Average latency: %.2f ms (%.2f frames)\n" + "Lowest latency: %.2f ms (%u frames)\n" + "Highest latency: %.2f ms (%u frames)\n" + "Peak MIDI jitter: %.2f ms (%u frames)\n" + "Average MIDI jitter: %.2f ms (%.2f frames)\n", + (out_latency_range.min / sample_rate) * 1000.0, + (out_latency_range.max / sample_rate) * 1000.0, + out_latency_range.min, out_latency_range.max, + (in_latency_range.min / sample_rate) * 1000.0, + (in_latency_range.max / sample_rate) * 1000.0, + in_latency_range.min, in_latency_range.max, + average_latency_time / 1000.0, average_latency, + lowest_latency_time / 1000.0, lowest_latency, + highest_latency_time / 1000.0, highest_latency, + (highest_latency_time - lowest_latency_time) / 1000.0, + highest_latency - lowest_latency, + (total_jitter_time / 1000.0) / samples, + ((double) total_jitter) / samples); + printf("\nJitter Plot:\n"); + for (i = 0; i < 100; i++) { + if (jitter_plot[i]) { + printf("%.1f - %.1f ms: %u\n", ((float) i) / 10.0, + ((float) (i + 1)) / 10.0, jitter_plot[i]); + } + } + if (jitter_plot[100]) { + printf(" > 10 ms: %u\n", jitter_plot[100]); + } + printf("\nLatency Plot:\n"); + for (i = 0; i < 100; i++) { + if (latency_plot[i]) { + printf("%.1f - %.1f ms: %u\n", + latency_plot_offset + (((float) i) / 10.0), + latency_plot_offset + (((float) (i + 1)) / 10.0), + latency_plot[i]); + } + } + if (latency_plot[100]) { + printf(" > %.1f ms: %u\n", latency_plot_offset + 10.0, + latency_plot[100]); + } + } + printf("\nMessages sent: %d\n" + "Messages received: %d\n", + messages_sent, messages_received); + if (unexpected_messages) { + printf("Unexpected messages received: %d\n", unexpected_messages); + } + if (xrun_count) { + printf("Xruns: %d (messages may have been lost)\n", xrun_count); + } + deactivate_client: + jack_deactivate(client); + destroy_process_semaphore: + destroy_semaphore(process_semaphore, 1); + destroy_init_semaphore: + destroy_semaphore(init_semaphore, 0); + unregister_out_port: + jack_port_unregister(client, out_port); + unregister_in_port: + jack_port_unregister(client, in_port); + close_client: + jack_client_close(client); + free_message_2: + free(message_2); + free_message_1: + free(message_1); + free_latency_time_values: + free(latency_time_values); + free_latency_values: + free(latency_values); + if (error_message != NULL) { + show_error: + output_error(error_source, error_message); + exit(EXIT_FAILURE); + } + return EXIT_SUCCESS; +} diff --git a/example-clients/showtime.c b/example-clients/showtime.c index af413e89..b40589fc 100644 --- a/example-clients/showtime.c +++ b/example-clients/showtime.c @@ -35,7 +35,7 @@ showtime () transport_state = jack_transport_query (client, ¤t); frame_time = jack_frame_time (client); - printf ("frame = %u frame_time = %u usecs = %lld \t", current.frame, frame_time, current.usecs); + printf ("frame = %u frame_time = %u usecs = %ld \t", current.frame, frame_time, current.usecs); switch (transport_state) { case JackTransportStopped: diff --git a/example-clients/thru_client.c b/example-clients/thru_client.c index 426fa6bc..d47fbe15 100644 --- a/example-clients/thru_client.c +++ b/example-clients/thru_client.c @@ -1,4 +1,4 @@ -/** @file simple_client.c +/** @file thru_client.c * * @brief This simple through client demonstrates the basic features of JACK * as they would be used by many applications. diff --git a/example-clients/tw.c b/example-clients/tw.c index b583720e..339f1c37 100644 --- a/example-clients/tw.c +++ b/example-clients/tw.c @@ -1,4 +1,4 @@ -/** @file simple_client.c +/** @file tw.c * * @brief This simple client demonstrates the basic features of JACK * as they would be used by many applications. @@ -42,56 +42,56 @@ _process (jack_nframes_t nframes) { jack_default_audio_sample_t *in, *out; jack_transport_state_t ts = jack_transport_query(client, NULL); - + if (ts == JackTransportRolling) { - + if (client_state == Init) client_state = Run; - + in = jack_port_get_buffer (input_port, nframes); out = jack_port_get_buffer (output_port, nframes); memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); - + } else if (ts == JackTransportStopped) { - + if (client_state == Run) { client_state = Exit; return -1; // to stop the thread } } - return 0; + return 0; } -static void* jack_thread(void *arg) +static void* jack_thread(void *arg) { jack_client_t* client = (jack_client_t*) arg; - + while (1) { - + jack_nframes_t frames = jack_cycle_wait (client); int status = _process(frames); jack_cycle_signal (client, status); - + /* Possibly do something else after signaling next clients in the graph */ - + /* End condition */ if (status != 0) - return 0; + return 0; } - + /* not reached*/ return 0; } /* -static void* jack_thread(void *arg) +static void* jack_thread(void *arg) { jack_client_t* client = (jack_client_t*) arg; - + while (1) { jack_nframes_t frames; int status; @@ -103,7 +103,7 @@ static void* jack_thread(void *arg) frames = jack_cycle_wait (client); status = _process(frames); jack_cycle_signal (client, status); - // cycle 3 + // cycle 3 frames = jack_cycle_wait (client); status = _process(frames); jack_cycle_signal (client, status); @@ -112,7 +112,7 @@ static void* jack_thread(void *arg) status = _process(frames); jack_cycle_signal (client, status); } - + return 0; } */ @@ -172,8 +172,8 @@ main (int argc, char *argv[]) /* tell the JACK server to call `process()' whenever there is work to be done. - */ - if (jack_set_process_thread(client, jack_thread, client) < 0) + */ + if (jack_set_process_thread(client, jack_thread, client) < 0) exit(1); /* tell the JACK server to call `jack_shutdown()' if @@ -183,7 +183,7 @@ main (int argc, char *argv[]) jack_on_shutdown (client, jack_shutdown, 0); - /* display the current sample rate. + /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", @@ -231,7 +231,7 @@ main (int argc, char *argv[]) } free (ports); - + ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); if (ports == NULL) { @@ -244,7 +244,7 @@ main (int argc, char *argv[]) } free (ports); - + /* install a signal handler to properly quits jack client */ signal(SIGQUIT, signal_handler); signal(SIGTERM, signal_handler); diff --git a/example-clients/wait.c b/example-clients/wait.c index 81870321..9150bb63 100644 --- a/example-clients/wait.c +++ b/example-clients/wait.c @@ -40,7 +40,7 @@ main (int argc, char *argv[]) int wait_timeout = 0; time_t start_timestamp; - + struct option long_options[] = { { "server", 1, 0, 's' }, { "wait", 0, 0, 'w' }, diff --git a/example-clients/wscript b/example-clients/wscript index d32c1f75..9c70e27a 100644 --- a/example-clients/wscript +++ b/example-clients/wscript @@ -29,6 +29,7 @@ example_programs = { 'jack_net_master' : 'netmaster.c', 'jack_latent_client' : 'latent_client.c', 'jack_midi_dump' : 'midi_dump.c', + 'jack_midi_latency_test' : 'midi_latency_test.c' } example_libs = { diff --git a/example-clients/zombie.c b/example-clients/zombie.c index a3a2dadd..fb3cd24e 100644 --- a/example-clients/zombie.c +++ b/example-clients/zombie.c @@ -1,6 +1,6 @@ /* Copyright (C) 2002 Jeremy Hall - + 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 @@ -30,18 +30,18 @@ int count = 0; jack_port_t* output_port; static int -process(jack_nframes_t nframes, void* arg) +process(jack_nframes_t nframes, void* arg) { if (count++ == 1000) { printf("process block\n"); //while (1) {} sleep(1); } - + return 0; } -static void +static void shutdown (void *arg) { printf("shutdown \n"); @@ -57,7 +57,7 @@ main (int argc, char *argv[]) fprintf (stderr, "jack server not running?\n"); goto error; } - + jack_set_process_callback (client, process, NULL); jack_on_shutdown(client, shutdown, NULL); output_port = jack_port_register (client, "port1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); @@ -67,9 +67,9 @@ main (int argc, char *argv[]) fprintf (stderr, "cannot activate client"); goto error; } - + jack_connect(client, jack_port_name(output_port), "coreaudio:Built-in Audio:in2"); - + while (running) { sleep(1); printf ("run\n"); @@ -78,9 +78,9 @@ main (int argc, char *argv[]) jack_deactivate (client); jack_client_close (client); return 0; - + error: - if (client) + if (client) jack_client_close (client); return 1; } diff --git a/linux/alsa/JackAlsaAdapter.cpp b/linux/alsa/JackAlsaAdapter.cpp index ba847851..070dacd4 100644 --- a/linux/alsa/JackAlsaAdapter.cpp +++ b/linux/alsa/JackAlsaAdapter.cpp @@ -259,7 +259,7 @@ extern "C" i++; strcpy ( desc->params[i].name, "inchannels" ); desc->params[i].character = 'i'; - desc->params[i].type = JackDriverParamUInt; + desc->params[i].type = JackDriverParamInt; desc->params[i].value.i = 0; strcpy ( desc->params[i].short_desc, "Number of capture channels (defaults to hardware max)" ); @@ -268,7 +268,7 @@ extern "C" i++; strcpy ( desc->params[i].name, "outchannels" ); desc->params[i].character = 'o'; - desc->params[i].type = JackDriverParamUInt; + desc->params[i].type = JackDriverParamInt; desc->params[i].value.i = 0; strcpy ( desc->params[i].short_desc, "Number of playback channels (defaults to hardware max)" ); @@ -277,7 +277,7 @@ extern "C" i++; strcpy(desc->params[i].name, "quality"); desc->params[i].character = 'q'; - desc->params[i].type = JackDriverParamInt; + desc->params[i].type = JackDriverParamUInt; desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Resample algorithm quality (0 - 4)"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -285,7 +285,7 @@ extern "C" i++; strcpy(desc->params[i].name, "ring-buffer"); desc->params[i].character = 'g'; - desc->params[i].type = JackDriverParamInt; + desc->params[i].type = JackDriverParamUInt; desc->params[i].value.ui = 32768; strcpy(desc->params[i].short_desc, "Fixed ringbuffer size"); strcpy(desc->params[i].long_desc, "Fixed ringbuffer size (if not set => automatic adaptative)"); diff --git a/linux/alsa/JackAlsaDriver.cpp b/linux/alsa/JackAlsaDriver.cpp index b42e9693..470d46df 100644 --- a/linux/alsa/JackAlsaDriver.cpp +++ b/linux/alsa/JackAlsaDriver.cpp @@ -55,8 +55,11 @@ int JackAlsaDriver::SetBufferSize(jack_nframes_t buffer_size) ((alsa_driver_t *)fDriver)->frame_rate); if (res == 0) { // update fEngineControl and fGraphManager - JackAudioDriver::SetBufferSize(buffer_size); // never fails + JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails + // ALSA specific + UpdateLatencies(); } else { + // Restore old values alsa_driver_reset_parameters((alsa_driver_t *)fDriver, fEngineControl->fBufferSize, ((alsa_driver_t *)fDriver)->user_nperiods, ((alsa_driver_t *)fDriver)->frame_rate); @@ -65,6 +68,29 @@ int JackAlsaDriver::SetBufferSize(jack_nframes_t buffer_size) return res; } +void JackAlsaDriver::UpdateLatencies() +{ + jack_latency_range_t range; + alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver; + + for (int i = 0; i < fCaptureChannels; i++) { + range.min = range.max = alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency; + fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &range); + } + + for (int i = 0; i < fPlaybackChannels; i++) { + // Add one buffer more latency if "async" mode is used... + range.min = range.max = (alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency; + fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &range); + // Monitor port + if (fWithMonitorPorts) { + range.min = range.max = alsa_driver->frames_per_cycle; + fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &range); + } + } +} + int JackAlsaDriver::Attach() { JackPort* port; @@ -72,7 +98,6 @@ int JackAlsaDriver::Attach() unsigned long port_flags = (unsigned long)CaptureDriverFlags; char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; - jack_latency_range_t range; assert(fCaptureChannels < DRIVER_PORT_NUM); assert(fPlaybackChannels < DRIVER_PORT_NUM); @@ -97,8 +122,6 @@ int JackAlsaDriver::Attach() } port = fGraphManager->GetPort(port_index); port->SetAlias(alias); - range.min = range.max = alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency; - port->SetLatencyRange(JackCaptureLatency, &range); fCapturePortList[i] = port_index; jack_log("JackAlsaDriver::Attach fCapturePortList[i] %ld ", port_index); } @@ -114,11 +137,6 @@ int JackAlsaDriver::Attach() } port = fGraphManager->GetPort(port_index); port->SetAlias(alias); - // Add one buffer more latency if "async" mode is used... - range.min = range.max = (alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + - ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency; - - port->SetLatencyRange(JackPlaybackLatency, &range); fPlaybackPortList[i] = port_index; jack_log("JackAlsaDriver::Attach fPlaybackPortList[i] %ld ", port_index); @@ -129,14 +147,13 @@ int JackAlsaDriver::Attach() if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { jack_error ("ALSA: cannot register monitor port for %s", name); } else { - port = fGraphManager->GetPort(port_index); - range.min = range.max = alsa_driver->frames_per_cycle; - port->SetLatencyRange(JackCaptureLatency, &range); fMonitorPortList[i] = port_index; } } } + UpdateLatencies(); + if (alsa_driver->midi) { int err = (alsa_driver->midi->attach)(alsa_driver->midi); if (err) @@ -275,7 +292,7 @@ int JackAlsaDriver::Open(jack_nframes_t nframes, } } - fDriver = alsa_driver_new ("alsa_pcm", (char*)playback_driver_name, (char*)capture_driver_name, + fDriver = alsa_driver_new ((char*)"alsa_pcm", (char*)playback_driver_name, (char*)capture_driver_name, NULL, nframes, user_nperiods, @@ -828,7 +845,7 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () i++; strcpy (params[i].name, "inchannels"); params[i].character = 'i'; - params[i].type = JackDriverParamUInt; + params[i].type = JackDriverParamInt; params[i].value.i = 0; strcpy (params[i].short_desc, "Number of capture channels (defaults to hardware max)"); @@ -837,7 +854,7 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () i++; strcpy (params[i].name, "outchannels"); params[i].character = 'o'; - params[i].type = JackDriverParamUInt; + params[i].type = JackDriverParamInt; params[i].value.i = 0; strcpy (params[i].short_desc, "Number of playback channels (defaults to hardware max)"); @@ -855,7 +872,7 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () strcpy (params[i].name, "input-latency"); params[i].character = 'I'; params[i].type = JackDriverParamUInt; - params[i].value.i = 0; + params[i].value.ui = 0; strcpy (params[i].short_desc, "Extra input latency (frames)"); strcpy (params[i].long_desc, params[i].short_desc); @@ -863,7 +880,7 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () strcpy (params[i].name, "output-latency"); params[i].character = 'O'; params[i].type = JackDriverParamUInt; - params[i].value.i = 0; + params[i].value.ui = 0; strcpy (params[i].short_desc, "Extra output latency (frames)"); strcpy (params[i].long_desc, params[i].short_desc); diff --git a/linux/alsa/JackAlsaDriver.h b/linux/alsa/JackAlsaDriver.h index 6d42b91a..a88d4a01 100644 --- a/linux/alsa/JackAlsaDriver.h +++ b/linux/alsa/JackAlsaDriver.h @@ -42,6 +42,8 @@ class JackAlsaDriver : public JackAudioDriver int fReservedCaptureDevice; int fReservedPlaybackDevice; + void UpdateLatencies(); + public: JackAlsaDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) diff --git a/linux/alsa/alsa_driver.c b/linux/alsa/alsa_driver.c index 536cfb6c..5fe3635c 100644 --- a/linux/alsa/alsa_driver.c +++ b/linux/alsa/alsa_driver.c @@ -204,8 +204,8 @@ alsa_driver_ice1712_hardware (alsa_driver_t *driver) static int alsa_driver_usx2y_hardware (alsa_driver_t *driver) { - driver->hw = jack_alsa_usx2y_hw_new (driver); - return 0; + driver->hw = jack_alsa_usx2y_hw_new (driver); + return 0; } */ diff --git a/linux/alsarawmidi/JackALSARawMidiDriver.cpp b/linux/alsarawmidi/JackALSARawMidiDriver.cpp new file mode 100755 index 00000000..42771357 --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiDriver.cpp @@ -0,0 +1,614 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include + +#include + +#include "JackALSARawMidiDriver.h" +#include "JackEngineControl.h" +#include "JackError.h" +#include "JackMidiUtil.h" + +using Jack::JackALSARawMidiDriver; + +JackALSARawMidiDriver::JackALSARawMidiDriver(const char *name, + const char *alias, + JackLockedEngine *engine, + JackSynchro *table): + JackMidiDriver(name, alias, engine, table) +{ + thread = new JackThread(this); + fCaptureChannels = 0; + fds[0] = -1; + fds[1] = -1; + fPlaybackChannels = 0; + input_ports = 0; + output_ports = 0; + poll_fds = 0; +} + +JackALSARawMidiDriver::~JackALSARawMidiDriver() +{ + delete thread; +} + +int +JackALSARawMidiDriver::Attach() +{ + const char *alias; + 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; + for (int i = 0; i < fCaptureChannels; i++) { + JackALSARawMidiInputPort *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("JackALSARawMidiDriver::Attach - cannot register input " + "port with name '%s'.", name); + // X: Do we need to deallocate ports? + return -1; + } + alias = input_port->GetAlias(); + port = fGraphManager->GetPort(index); + port->SetAlias(alias); + port->SetLatencyRange(JackCaptureLatency, &latency_range); + fCapturePortList[i] = index; + + jack_info("JackALSARawMidiDriver::Attach - input port registered " + "(name='%s', alias='%s').", name, alias); + + } + if (! fEngineControl->fSyncMode) { + latency += buffer_size; + latency_range.max = latency; + latency_range.min = latency; + } + for (int i = 0; i < fPlaybackChannels; i++) { + JackALSARawMidiOutputPort *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("JackALSARawMidiDriver::Attach - cannot register " + "output port with name '%s'.", name); + // X: Do we need to deallocate ports? + return -1; + } + alias = output_port->GetAlias(); + port = fGraphManager->GetPort(index); + port->SetAlias(alias); + port->SetLatencyRange(JackPlaybackLatency, &latency_range); + fPlaybackPortList[i] = index; + + jack_info("JackALSARawMidiDriver::Attach - output port registered " + "(name='%s', alias='%s').", name, alias); + + } + return 0; +} + +int +JackALSARawMidiDriver::Close() +{ + // Generic MIDI driver close + int result = JackMidiDriver::Close(); + + if (input_ports) { + for (int i = 0; i < fCaptureChannels; i++) { + delete input_ports[i]; + } + delete[] input_ports; + input_ports = 0; + } + if (output_ports) { + for (int i = 0; i < fPlaybackChannels; i++) { + delete output_ports[i]; + } + delete[] output_ports; + output_ports = 0; + } + return result; +} + +bool +JackALSARawMidiDriver::Execute() +{ + jack_nframes_t timeout_frame = 0; + for (;;) { + jack_nframes_t process_frame; + unsigned short revents; + jack_nframes_t *timeout_frame_ptr; + if (! timeout_frame) { + timeout_frame_ptr = 0; + } else { + timeout_frame_ptr = &timeout_frame; + } + if (Poll(timeout_frame_ptr) == -1) { + if (errno == EINTR) { + continue; + } + jack_error("JackALSARawMidiDriver::Execute - poll error: %s", + strerror(errno)); + break; + } + revents = poll_fds[0].revents; + if (revents & POLLHUP) { + // Driver is being stopped. + break; + } + if (revents & (~ POLLIN)) { + jack_error("JackALSARawMidiDriver::Execute - unexpected poll " + "event on pipe file descriptor."); + break; + } + timeout_frame = 0; + for (int i = 0; i < fCaptureChannels; i++) { + if (! input_ports[i]->ProcessALSA(&process_frame)) { + jack_error("JackALSARawMidiDriver::Execute - a fatal error " + "occurred while processing ALSA input events."); + goto cleanup; + } + if (process_frame && ((! timeout_frame) || + (process_frame < timeout_frame))) { + timeout_frame = process_frame; + } + } + for (int i = 0; i < fPlaybackChannels; i++) { + if (! output_ports[i]->ProcessALSA(fds[0], &process_frame)) { + jack_error("JackALSARawMidiDriver::Execute - a fatal error " + "occurred while processing ALSA output events."); + goto cleanup; + } + if (process_frame && ((! timeout_frame) || + (process_frame < timeout_frame))) { + timeout_frame = process_frame; + } + } + } + cleanup: + close(fds[0]); + fds[0] = -1; + + jack_info("JackALSARawMidiDriver::Execute - ALSA thread exiting."); + + return false; +} + +void +JackALSARawMidiDriver:: +GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info, + std::vector *info_list) +{ + snd_rawmidi_info_set_subdevice(info, 0); + int code = snd_ctl_rawmidi_info(control, info); + if (code) { + if (code != -ENOENT) { + HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code); + } + return; + } + unsigned int count = snd_rawmidi_info_get_subdevices_count(info); + for (unsigned int i = 0; i < count; i++) { + snd_rawmidi_info_set_subdevice(info, i); + int code = snd_ctl_rawmidi_info(control, info); + if (code) { + HandleALSAError("GetDeviceInfo", "snd_ctl_rawmidi_info", code); + continue; + } + snd_rawmidi_info_t *info_copy; + code = snd_rawmidi_info_malloc(&info_copy); + if (code) { + HandleALSAError("GetDeviceInfo", "snd_rawmidi_info_malloc", code); + continue; + } + snd_rawmidi_info_copy(info_copy, info); + try { + info_list->push_back(info_copy); + } catch (std::bad_alloc &e) { + snd_rawmidi_info_free(info_copy); + jack_error("JackALSARawMidiDriver::GetDeviceInfo - " + "std::vector::push_back: %s", e.what()); + } + } +} + +void +JackALSARawMidiDriver::HandleALSAError(const char *driver_func, + const char *alsa_func, int code) +{ + jack_error("JackALSARawMidiDriver::%s - %s: %s", driver_func, alsa_func, + snd_strerror(code)); +} + +bool +JackALSARawMidiDriver::Init() +{ + set_threaded_log_function(); + if (thread->AcquireSelfRealTime(fEngineControl->fServerPriority + 1)) { + jack_error("JackALSARawMidiDriver::Init - could not acquire realtime " + "scheduling. Continuing anyway."); + } + return true; +} + +int +JackALSARawMidiDriver::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) +{ + snd_rawmidi_info_t *info; + int code = snd_rawmidi_info_malloc(&info); + if (code) { + HandleALSAError("Open", "snd_rawmidi_info_malloc", code); + return -1; + } + std::vector in_info_list; + std::vector out_info_list; + for (int card = -1;;) { + int code = snd_card_next(&card); + if (code) { + HandleALSAError("Open", "snd_card_next", code); + continue; + } + if (card == -1) { + break; + } + char name[32]; + snprintf(name, sizeof(name), "hw:%d", card); + snd_ctl_t *control; + code = snd_ctl_open(&control, name, SND_CTL_NONBLOCK); + if (code) { + HandleALSAError("Open", "snd_ctl_open", code); + continue; + } + for (int device = -1;;) { + code = snd_ctl_rawmidi_next_device(control, &device); + if (code) { + HandleALSAError("Open", "snd_ctl_rawmidi_next_device", code); + continue; + } + if (device == -1) { + break; + } + snd_rawmidi_info_set_device(info, device); + snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); + GetDeviceInfo(control, info, &in_info_list); + snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT); + GetDeviceInfo(control, info, &out_info_list); + } + snd_ctl_close(control); + } + snd_rawmidi_info_free(info); + size_t potential_inputs = in_info_list.size(); + size_t potential_outputs = out_info_list.size(); + if (! (potential_inputs || potential_outputs)) { + jack_error("JackALSARawMidiDriver::Open - no ALSA raw MIDI input or " + "output ports found."); + return -1; + } + + // XXX: Can't use auto_ptr here. These are arrays, and require the + // delete[] operator. + std::auto_ptr input_ptr; + if (potential_inputs) { + input_ports = new JackALSARawMidiInputPort *[potential_inputs]; + input_ptr.reset(input_ports); + } + std::auto_ptr output_ptr; + if (potential_outputs) { + output_ports = new JackALSARawMidiOutputPort *[potential_outputs]; + output_ptr.reset(output_ports); + } + + size_t num_inputs = 0; + size_t num_outputs = 0; + for (size_t i = 0; i < potential_inputs; i++) { + snd_rawmidi_info_t *info = in_info_list.at(i); + try { + input_ports[num_inputs] = new JackALSARawMidiInputPort(info, i); + + jack_info("JackALSARawMidiDriver::Open - Input port: card=%d, " + "device=%d, subdevice=%d, id=%s, name=%s, subdevice " + "name=%s", + snd_rawmidi_info_get_card(info), + snd_rawmidi_info_get_device(info), + snd_rawmidi_info_get_subdevice(info), + snd_rawmidi_info_get_id(info), + snd_rawmidi_info_get_name(info), + snd_rawmidi_info_get_subdevice_name(info)); + + num_inputs++; + } catch (std::exception e) { + jack_error("JackALSARawMidiDriver::Open - while creating new " + "JackALSARawMidiInputPort: %s", e.what()); + } + snd_rawmidi_info_free(info); + } + for (size_t i = 0; i < potential_outputs; i++) { + snd_rawmidi_info_t *info = out_info_list.at(i); + try { + output_ports[num_outputs] = new JackALSARawMidiOutputPort(info, i); + + jack_info("JackALSARawMidiDriver::Open - Output port: card=%d, " + "device=%d, subdevice=%d, id=%s, name=%s, subdevice " + "name=%s", + snd_rawmidi_info_get_card(info), + snd_rawmidi_info_get_device(info), + snd_rawmidi_info_get_subdevice(info), + snd_rawmidi_info_get_id(info), + snd_rawmidi_info_get_name(info), + snd_rawmidi_info_get_subdevice_name(info)); + + num_outputs++; + } catch (std::exception e) { + jack_error("JackALSARawMidiDriver::Open - while creating new " + "JackALSARawMidiOutputPort: %s", e.what()); + } + snd_rawmidi_info_free(info); + } + if (num_inputs || num_outputs) { + if (! JackMidiDriver::Open(capturing, playing, num_inputs, num_outputs, + monitor, capture_driver_name, + playback_driver_name, capture_latency, + playback_latency)) { + if (potential_inputs) { + input_ptr.release(); + } + if (potential_outputs) { + output_ptr.release(); + } + return 0; + } + jack_error("JackALSARawMidiDriver::Open - JackMidiDriver::Open error"); + } else { + jack_error("JackALSARawMidiDriver::Open - none of the potential " + "inputs or outputs were successfully opened."); + } + Close(); + return -1; +} + +int +JackALSARawMidiDriver::Poll(const jack_nframes_t *wakeup_frame) +{ + struct timespec timeout; + struct timespec *timeout_ptr; + if (! wakeup_frame) { + timeout_ptr = 0; + } else { + timeout_ptr = &timeout; + jack_time_t next_time = GetTimeFromFrames(*wakeup_frame); + jack_time_t now = GetMicroSeconds(); + if (next_time <= now) { + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + } else { + jack_time_t wait_time = next_time - now; + timeout.tv_sec = wait_time / 1000000; + timeout.tv_nsec = (wait_time % 1000000) * 1000; + } + } + return ppoll(poll_fds, poll_fd_count, timeout_ptr, 0); +} + +int +JackALSARawMidiDriver::Read() +{ + jack_nframes_t buffer_size = fEngineControl->fBufferSize; + for (int i = 0; i < fCaptureChannels; i++) { + if (! input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size)) { + return -1; + } + } + return 0; +} + +int +JackALSARawMidiDriver::Start() +{ + + jack_info("JackALSARawMidiDriver::Start - Starting 'alsarawmidi' driver."); + + JackMidiDriver::Start(); + poll_fd_count = 1; + for (int i = 0; i < fCaptureChannels; i++) { + poll_fd_count += input_ports[i]->GetPollDescriptorCount(); + } + for (int i = 0; i < fPlaybackChannels; i++) { + poll_fd_count += output_ports[i]->GetPollDescriptorCount(); + } + try { + poll_fds = new pollfd[poll_fd_count]; + } catch (std::bad_alloc e) { + jack_error("JackALSARawMidiDriver::Start - creating poll descriptor " + "structures failed: %s", e.what()); + return -1; + } + int flags; + struct pollfd *poll_fd_iter; + if (pipe(fds) == -1) { + jack_error("JackALSARawMidiDriver::Start - while creating wake pipe: " + "%s", strerror(errno)); + goto free_poll_descriptors; + } + flags = fcntl(fds[0], F_GETFL); + if (flags == -1) { + jack_error("JackALSARawMidiDriver::Start = while getting flags for " + "read file descriptor: %s", strerror(errno)); + goto close_fds; + } + if (fcntl(fds[0], F_SETFL, flags | O_NONBLOCK) == -1) { + jack_error("JackALSARawMidiDriver::Start - while setting non-blocking " + "mode for read file descriptor: %s", strerror(errno)); + goto close_fds; + } + flags = fcntl(fds[1], F_GETFL); + if (flags == -1) { + jack_error("JackALSARawMidiDriver::Start = while getting flags for " + "write file descriptor: %s", strerror(errno)); + goto close_fds; + } + if (fcntl(fds[1], F_SETFL, flags | O_NONBLOCK) == -1) { + jack_error("JackALSARawMidiDriver::Start - while setting non-blocking " + "mode for write file descriptor: %s", strerror(errno)); + goto close_fds; + } + poll_fds[0].events = POLLERR | POLLIN | POLLNVAL; + poll_fds[0].fd = fds[0]; + poll_fd_iter = poll_fds + 1; + for (int i = 0; i < fCaptureChannels; i++) { + JackALSARawMidiInputPort *input_port = input_ports[i]; + input_port->PopulatePollDescriptors(poll_fd_iter); + poll_fd_iter += input_port->GetPollDescriptorCount(); + } + for (int i = 0; i < fPlaybackChannels; i++) { + JackALSARawMidiOutputPort *output_port = output_ports[i]; + output_port->PopulatePollDescriptors(poll_fd_iter); + poll_fd_iter += output_port->GetPollDescriptorCount(); + } + + jack_info("JackALSARawMidiDriver::Start - starting ALSA thread ..."); + + if (! thread->StartSync()) { + + jack_info("JackALSARawMidiDriver::Start - started ALSA thread."); + + return 0; + } + jack_error("JackALSARawMidiDriver::Start - failed to start MIDI " + "processing thread."); + close_fds: + close(fds[1]); + fds[1] = -1; + close(fds[0]); + fds[0] = -1; + free_poll_descriptors: + delete[] poll_fds; + poll_fds = 0; + return -1; +} + +int +JackALSARawMidiDriver::Stop() +{ + jack_info("JackALSARawMidiDriver::Stop - stopping 'alsarawmidi' driver."); + + if (fds[1] != -1) { + close(fds[1]); + fds[1] = -1; + } + int result; + const char *verb; + switch (thread->GetStatus()) { + case JackThread::kIniting: + case JackThread::kStarting: + result = thread->Kill(); + verb = "kill"; + break; + case JackThread::kRunning: + result = thread->Stop(); + verb = "stop"; + break; + default: + result = 0; + verb = 0; + } + if (fds[0] != -1) { + close(fds[0]); + fds[0] = -1; + } + if (poll_fds) { + delete[] poll_fds; + poll_fds = 0; + } + if (result) { + jack_error("JackALSARawMidiDriver::Stop - could not %s MIDI " + "processing thread.", verb); + } + return result; +} + +int +JackALSARawMidiDriver::Write() +{ + jack_nframes_t buffer_size = fEngineControl->fBufferSize; + int write_fd = fds[1]; + for (int i = 0; i < fPlaybackChannels; i++) { + if (! output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size, + write_fd)) { + return -1; + } + } + return 0; +} + +#ifdef __cplusplus +extern "C" { +#endif + + SERVER_EXPORT jack_driver_desc_t * + driver_get_descriptor() + { + jack_driver_desc_t *desc = + (jack_driver_desc_t *) malloc(sizeof(jack_driver_desc_t)); + if (desc) { + strcpy(desc->desc, "Alternative ALSA raw MIDI backend."); + strcpy(desc->name, "alsarawmidi"); + + // X: There could be parameters here regarding setting I/O buffer + // sizes. I don't think MIDI drivers can accept parameters right + // now without being set as the main driver. + desc->nparams = 0; + desc->params = 0; + } + return desc; + } + + SERVER_EXPORT Jack::JackDriverClientInterface * + driver_initialize(Jack::JackLockedEngine *engine, Jack::JackSynchro *table, + const JSList *params) + { + Jack::JackDriverClientInterface *driver = + new Jack::JackALSARawMidiDriver("system_midi", "alsarawmidi", + engine, table); + if (driver->Open(1, 1, 0, 0, false, "midi in", "midi out", 0, 0)) { + delete driver; + driver = 0; + } + return driver; + } + +#ifdef __cplusplus +} +#endif diff --git a/linux/alsarawmidi/JackALSARawMidiDriver.h b/linux/alsarawmidi/JackALSARawMidiDriver.h new file mode 100755 index 00000000..4dfa05bc --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiDriver.h @@ -0,0 +1,98 @@ +/* +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 __JackALSARawMidiDriver__ +#define __JackALSARawMidiDriver__ + +#include + +#include +#include + +#include "JackALSARawMidiInputPort.h" +#include "JackALSARawMidiOutputPort.h" +#include "JackMidiDriver.h" +#include "JackThread.h" + +namespace Jack { + + class JackALSARawMidiDriver: + public JackMidiDriver, public JackRunnableInterface { + + private: + + int fds[2]; + JackALSARawMidiInputPort **input_ports; + JackALSARawMidiOutputPort **output_ports; + nfds_t poll_fd_count; + struct pollfd *poll_fds; + JackThread *thread; + + void + GetDeviceInfo(snd_ctl_t *control, snd_rawmidi_info_t *info, + std::vector *info_list); + + void + HandleALSAError(const char *driver_func, const char *alsa_func, + int code); + + int + Poll(const jack_nframes_t *wakeup_frame); + + public: + + JackALSARawMidiDriver(const char *name, const char *alias, + JackLockedEngine *engine, JackSynchro *table); + ~JackALSARawMidiDriver(); + + int + Attach(); + + int + Close(); + + bool + Execute(); + + bool + Init(); + + int + Open(bool capturing, bool playing, int in_channels, int out_channels, + bool monitoring, const char *capture_driver_name, + const char *playback_driver_name, jack_nframes_t capture_latency, + jack_nframes_t playback_latency); + + int + Read(); + + int + Start(); + + int + Stop(); + + int + Write(); + + }; + +} + +#endif diff --git a/linux/alsarawmidi/JackALSARawMidiInputPort.cpp b/linux/alsarawmidi/JackALSARawMidiInputPort.cpp new file mode 100755 index 00000000..b81c5783 --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiInputPort.cpp @@ -0,0 +1,143 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +#include "JackALSARawMidiInputPort.h" +#include "JackMidiUtil.h" + +using Jack::JackALSARawMidiInputPort; + +JackALSARawMidiInputPort::JackALSARawMidiInputPort(snd_rawmidi_info_t *info, + size_t index, + size_t max_bytes, + size_t max_messages): + JackALSARawMidiPort(info, index) +{ + alsa_event = 0; + jack_event = 0; + receive_queue = new JackALSARawMidiReceiveQueue(rawmidi, max_bytes); + std::auto_ptr receive_ptr(receive_queue); + thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages); + std::auto_ptr thread_ptr(thread_queue); + write_queue = new JackMidiBufferWriteQueue(); + std::auto_ptr write_ptr(write_queue); + raw_queue = new JackMidiRawInputWriteQueue(thread_queue, max_bytes, + max_messages); + write_ptr.release(); + thread_ptr.release(); + receive_ptr.release(); +} + +JackALSARawMidiInputPort::~JackALSARawMidiInputPort() +{ + delete raw_queue; + delete receive_queue; + delete thread_queue; + delete write_queue; +} + +jack_nframes_t +JackALSARawMidiInputPort::EnqueueALSAEvent() +{ + switch (raw_queue->EnqueueEvent(alsa_event)) { + case JackMidiWriteQueue::BUFFER_FULL: + // Processing events early might free up some space in the raw queue. + raw_queue->Process(); + switch (raw_queue->EnqueueEvent(alsa_event)) { + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackALSARawMidiInputPort::Process - **BUG** " + "JackMidiRawInputWriteQueue::EnqueueEvent returned " + "`BUFFER_FULL` and then returned `BUFFER_TOO_SMALL` " + "after a `Process()` call."); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + return 0; + default: + ; + } + break; + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackALSARawMidiInputPort::Execute - The thread queue " + "couldn't enqueue a %d-byte packet. Dropping event.", + alsa_event->size); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + return 0; + default: + ; + } + jack_nframes_t alsa_time = alsa_event->time; + jack_nframes_t next_time = raw_queue->Process(); + return (next_time < alsa_time) ? next_time : alsa_time; +} + +bool +JackALSARawMidiInputPort::ProcessALSA(jack_nframes_t *frame) +{ + unsigned short revents; + if (! ProcessPollEvents(&revents)) { + return false; + } + if (alsa_event) { + *frame = EnqueueALSAEvent(); + if (*frame) { + return true; + } + } + if (revents & POLLIN) { + for (alsa_event = receive_queue->DequeueEvent(); alsa_event; + alsa_event = receive_queue->DequeueEvent()) { + *frame = EnqueueALSAEvent(); + if (*frame) { + return true; + } + } + } + *frame = raw_queue->Process(); + return true; +} + +bool +JackALSARawMidiInputPort::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()) { + + // We add `frames` so that MIDI events align with audio as closely as + // possible. + switch (write_queue->EnqueueEvent(jack_event, frames)) { + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackALSARawMidiInputPort::ProcessJack - The write " + "queue couldn't enqueue a %d-byte event. Dropping " + "event.", jack_event->size); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + continue; + default: + ; + } + break; + } + return true; +} diff --git a/linux/alsarawmidi/JackALSARawMidiInputPort.h b/linux/alsarawmidi/JackALSARawMidiInputPort.h new file mode 100755 index 00000000..55ad2278 --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiInputPort.h @@ -0,0 +1,62 @@ +/* +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 __JackALSARawMidiInputPort__ +#define __JackALSARawMidiInputPort__ + +#include "JackALSARawMidiPort.h" +#include "JackALSARawMidiReceiveQueue.h" +#include "JackMidiAsyncQueue.h" +#include "JackMidiBufferWriteQueue.h" +#include "JackMidiRawInputWriteQueue.h" + +namespace Jack { + + class JackALSARawMidiInputPort: public JackALSARawMidiPort { + + private: + + jack_midi_event_t *alsa_event; + jack_midi_event_t *jack_event; + JackMidiRawInputWriteQueue *raw_queue; + JackALSARawMidiReceiveQueue *receive_queue; + JackMidiAsyncQueue *thread_queue; + JackMidiBufferWriteQueue *write_queue; + + jack_nframes_t + EnqueueALSAEvent(); + + public: + + JackALSARawMidiInputPort(snd_rawmidi_info_t *info, size_t index, + size_t max_bytes=4096, + size_t max_messages=1024); + ~JackALSARawMidiInputPort(); + + bool + ProcessALSA(jack_nframes_t *frame); + + bool + ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames); + + }; + +} + +#endif diff --git a/linux/alsarawmidi/JackALSARawMidiOutputPort.cpp b/linux/alsarawmidi/JackALSARawMidiOutputPort.cpp new file mode 100755 index 00000000..1b9a19bb --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiOutputPort.cpp @@ -0,0 +1,172 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +#include "JackALSARawMidiOutputPort.h" + +using Jack::JackALSARawMidiOutputPort; + +JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info, + size_t index, + size_t max_bytes, + size_t max_messages): + JackALSARawMidiPort(info, index) +{ + alsa_event = 0; + blocked = false; + read_queue = new JackMidiBufferReadQueue(); + std::auto_ptr read_ptr(read_queue); + send_queue = new JackALSARawMidiSendQueue(rawmidi); + std::auto_ptr send_ptr(send_queue); + thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages); + std::auto_ptr thread_ptr(thread_queue); + raw_queue = new JackMidiRawOutputWriteQueue(send_queue, max_bytes, + max_messages, max_messages); + thread_ptr.release(); + send_ptr.release(); + read_ptr.release(); +} + +JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort() +{ + delete raw_queue; + delete read_queue; + delete send_queue; + delete thread_queue; +} + +jack_midi_event_t * +JackALSARawMidiOutputPort::DequeueALSAEvent(int read_fd) +{ + jack_midi_event_t *event = thread_queue->DequeueEvent(); + if (event) { + char c; + ssize_t result = read(read_fd, &c, 1); + if (! result) { + jack_error("JackALSARawMidiOutputPort::DequeueALSAEvent - **BUG** " + "An event was dequeued from the thread queue, but no " + "byte was available for reading from the pipe file " + "descriptor."); + } else if (result < 0) { + jack_error("JackALSARawMidiOutputPort::DequeueALSAEvent - error " + "reading a byte from the pipe file descriptor: %s", + strerror(errno)); + } + } + return event; +} + +bool +JackALSARawMidiOutputPort::ProcessALSA(int read_fd, jack_nframes_t *frame) +{ + unsigned short revents; + if (! ProcessPollEvents(&revents)) { + return false; + } + if (blocked) { + if (! (revents & POLLOUT)) { + *frame = 0; + return true; + } + blocked = false; + } + if (! alsa_event) { + alsa_event = DequeueALSAEvent(read_fd); + } + for (; alsa_event; alsa_event = DequeueALSAEvent(read_fd)) { + switch (raw_queue->EnqueueEvent(alsa_event)) { + case JackMidiWriteQueue::BUFFER_FULL: + // Try to free up some space by processing events early. + raw_queue->Process(); + switch (raw_queue->EnqueueEvent(alsa_event)) { + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackALSARawMidiOutputPort::ProcessALSA - **BUG** " + "JackMidiRawOutputWriteQueue::EnqueueEvent " + "returned `BUFFER_FULL`, and then returned " + "`BUFFER_TOO_SMALL` after a Process() call."); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + continue; + default: + ; + } + goto process_events; + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackALSARawMidiOutputPort::ProcessALSA - The raw " + "output queue couldn't enqueue a %d-byte event. " + "Dropping event.", alsa_event->size); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + continue; + default: + ; + } + break; + } + process_events: + *frame = raw_queue->Process(); + blocked = send_queue->IsBlocked(); + if (blocked) { + + jack_info("JackALSARawMidiOutputPort::ProcessALSA - MIDI port is " + "blocked"); + + SetPollEventMask(POLLERR | POLLNVAL | POLLOUT); + *frame = 0; + } else { + SetPollEventMask(POLLERR | POLLNVAL); + } + return true; +} + +bool +JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer, + jack_nframes_t frames, int write_fd) +{ + read_queue->ResetMidiBuffer(port_buffer); + for (jack_midi_event_t *event = read_queue->DequeueEvent(); event; + event = read_queue->DequeueEvent()) { + if (event->size > thread_queue->GetAvailableSpace()) { + jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread " + "queue doesn't have enough room to enqueue a %d-byte " + "event. Dropping event.", event->size); + continue; + } + char c = 1; + ssize_t result = write(write_fd, &c, 1); + assert(result <= 1); + if (result < 0) { + jack_error("JackALSARawMidiOutputPort::ProcessJack - error " + "writing a byte to the pipe file descriptor: %s", + strerror(errno)); + return false; + } + if (! result) { + // Recoverable. + jack_error("JackALSARawMidiOutputPort::ProcessJack - Couldn't " + "write a byte to the pipe file descriptor. Dropping " + "event."); + } else { + assert(thread_queue->EnqueueEvent(event, frames) == + JackMidiWriteQueue::OK); + } + } + return true; +} diff --git a/linux/alsarawmidi/JackALSARawMidiOutputPort.h b/linux/alsarawmidi/JackALSARawMidiOutputPort.h new file mode 100755 index 00000000..6707e381 --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiOutputPort.h @@ -0,0 +1,63 @@ +/* +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 __JackALSARawMidiOutputPort__ +#define __JackALSARawMidiOutputPort__ + +#include "JackALSARawMidiPort.h" +#include "JackALSARawMidiSendQueue.h" +#include "JackMidiAsyncQueue.h" +#include "JackMidiBufferReadQueue.h" +#include "JackMidiRawOutputWriteQueue.h" + +namespace Jack { + + class JackALSARawMidiOutputPort: public JackALSARawMidiPort { + + private: + + jack_midi_event_t *alsa_event; + bool blocked; + JackMidiRawOutputWriteQueue *raw_queue; + JackMidiBufferReadQueue *read_queue; + JackALSARawMidiSendQueue *send_queue; + JackMidiAsyncQueue *thread_queue; + + jack_midi_event_t * + DequeueALSAEvent(int read_fd); + + public: + + JackALSARawMidiOutputPort(snd_rawmidi_info_t *info, size_t index, + size_t max_bytes=4096, + size_t max_messages=1024); + ~JackALSARawMidiOutputPort(); + + bool + ProcessALSA(int read_fd, jack_nframes_t *frame); + + bool + ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames, + int write_fd); + + }; + +} + +#endif diff --git a/linux/alsarawmidi/JackALSARawMidiPort.cpp b/linux/alsarawmidi/JackALSARawMidiPort.cpp new file mode 100755 index 00000000..021241cf --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiPort.cpp @@ -0,0 +1,191 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "JackALSARawMidiPort.h" +#include "JackError.h" + +using Jack::JackALSARawMidiPort; + +JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info, + size_t index) +{ + int card = snd_rawmidi_info_get_card(info); + unsigned int device = snd_rawmidi_info_get_device(info); + unsigned int subdevice = snd_rawmidi_info_get_subdevice(info); + char device_id[32]; + snprintf(device_id, sizeof(device_id), "hw:%d,%d,%d", card, device, + subdevice); + const char *alias_prefix; + const char *error_message; + snd_rawmidi_t **in; + snd_rawmidi_t **out; + const char *name_suffix; + if (snd_rawmidi_info_get_stream(info) == SND_RAWMIDI_STREAM_OUTPUT) { + alias_prefix = "system:midi_playback_"; + in = 0; + name_suffix = "out"; + out = &rawmidi; + } else { + alias_prefix = "system:midi_capture_"; + in = &rawmidi; + name_suffix = "in"; + out = 0; + } + const char *device_name; + const char *func; + int code = snd_rawmidi_open(in, out, device_id, SND_RAWMIDI_NONBLOCK); + if (code) { + error_message = snd_strerror(code); + func = "snd_rawmidi_open"; + goto handle_error; + } + snd_rawmidi_params_t *params; + code = snd_rawmidi_params_malloc(¶ms); + if (code) { + error_message = snd_strerror(code); + func = "snd_rawmidi_params_malloc"; + goto close; + } + code = snd_rawmidi_params_current(rawmidi, params); + if (code) { + error_message = snd_strerror(code); + func = "snd_rawmidi_params_current"; + goto free_params; + } + code = snd_rawmidi_params_set_avail_min(rawmidi, params, 1); + if (code) { + error_message = snd_strerror(code); + func = "snd_rawmidi_params_set_avail_min"; + goto free_params; + } + + // Smallest valid buffer size. + code = snd_rawmidi_params_set_buffer_size(rawmidi, params, 32); + if (code) { + error_message = snd_strerror(code); + func = "snd_rawmidi_params_set_buffer_size"; + goto free_params; + } + + code = snd_rawmidi_params_set_no_active_sensing(rawmidi, params, 1); + if (code) { + error_message = snd_strerror(code); + func = "snd_rawmidi_params_set_no_active_sensing"; + goto free_params; + } + code = snd_rawmidi_params(rawmidi, params); + if (code) { + error_message = snd_strerror(code); + func = "snd_rawmidi_params"; + goto free_params; + } + snd_rawmidi_params_free(params); + num_fds = snd_rawmidi_poll_descriptors_count(rawmidi); + if (! num_fds) { + error_message = "returned '0' count for poll descriptors"; + func = "snd_rawmidi_poll_descriptors_count"; + goto close; + } + snprintf(alias, sizeof(alias), "%s%d", alias_prefix, index + 1); + snprintf(name, sizeof(name), "system:%d-%d %s %d %s", card + 1, device + 1, + snd_rawmidi_info_get_name(info), subdevice + 1, name_suffix); + return; + free_params: + snd_rawmidi_params_free(params); + close: + snd_rawmidi_close(rawmidi); + handle_error: + throw std::runtime_error(std::string(func) + ": " + error_message); +} + +JackALSARawMidiPort::~JackALSARawMidiPort() +{ + if (rawmidi) { + int code = snd_rawmidi_close(rawmidi); + if (code) { + jack_error("JackALSARawMidiPort::~JackALSARawMidiPort - " + "snd_rawmidi_close: %s", snd_strerror(code)); + } + rawmidi = 0; + } +} + +const char * +JackALSARawMidiPort::GetAlias() +{ + return alias; +} + +const char * +JackALSARawMidiPort::GetName() +{ + return name; +} + +int +JackALSARawMidiPort::GetPollDescriptorCount() +{ + return num_fds; +} + +bool +JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd) +{ + bool result = snd_rawmidi_poll_descriptors(rawmidi, poll_fd, num_fds) == + num_fds; + if (result) { + poll_fds = poll_fd; + } + return result; +} + +bool +JackALSARawMidiPort::ProcessPollEvents(unsigned short *revents) +{ + int code = snd_rawmidi_poll_descriptors_revents(rawmidi, poll_fds, num_fds, + revents); + if (code) { + jack_error("JackALSARawMidiPort::ProcessPollEvents - " + "snd_rawmidi_poll_descriptors_revents: %s", + snd_strerror(code)); + return false; + } + if ((*revents) & POLLNVAL) { + jack_error("JackALSARawMidiPort::ProcessPollEvents - the file " + "descriptor is invalid."); + return false; + } + if ((*revents) & POLLERR) { + jack_error("JackALSARawMidiPort::ProcessPollEvents - an error has " + "occurred on the device or stream."); + return false; + } + return true; +} + +void +JackALSARawMidiPort::SetPollEventMask(unsigned short events) +{ + for (int i = 0; i < num_fds; i++) { + (poll_fds + i)->events = events; + } +} diff --git a/linux/alsarawmidi/JackALSARawMidiPort.h b/linux/alsarawmidi/JackALSARawMidiPort.h new file mode 100755 index 00000000..16d1a006 --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiPort.h @@ -0,0 +1,72 @@ +/* +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 __JackALSARawMidiPort__ +#define __JackALSARawMidiPort__ + +#include +#include + +#include "JackConstants.h" + +namespace Jack { + + class JackALSARawMidiPort { + + private: + + char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; + char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; + int num_fds; + struct pollfd *poll_fds; + + protected: + + snd_rawmidi_t *rawmidi; + + bool + ProcessPollEvents(unsigned short *revents); + + void + SetPollEventMask(unsigned short events); + + public: + + JackALSARawMidiPort(snd_rawmidi_info_t *info, size_t index); + + virtual + ~JackALSARawMidiPort(); + + const char * + GetAlias(); + + const char * + GetName(); + + int + GetPollDescriptorCount(); + + bool + PopulatePollDescriptors(struct pollfd *poll_fd); + + }; + +} + +#endif diff --git a/linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp b/linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp new file mode 100755 index 00000000..61af8e91 --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp @@ -0,0 +1,54 @@ +/* +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 "JackALSARawMidiReceiveQueue.h" +#include "JackError.h" +#include "JackMidiUtil.h" + +using Jack::JackALSARawMidiReceiveQueue; + +JackALSARawMidiReceiveQueue:: +JackALSARawMidiReceiveQueue(snd_rawmidi_t *rawmidi, size_t buffer_size) +{ + buffer = new jack_midi_data_t[buffer_size]; + this->buffer_size = buffer_size; + this->rawmidi = rawmidi; +} + +JackALSARawMidiReceiveQueue::~JackALSARawMidiReceiveQueue() +{ + delete[] buffer; +} + +jack_midi_event_t * +JackALSARawMidiReceiveQueue::DequeueEvent() +{ + ssize_t result = snd_rawmidi_read(rawmidi, buffer, buffer_size); + if (result > 0) { + event.buffer = buffer; + event.size = (size_t) result; + event.time = GetCurrentFrame(); + return &event; + } + if (result && (result != -EWOULDBLOCK)) { + jack_error("JackALSARawMidiReceiveQueue::DequeueEvent - " + "snd_rawmidi_read: %s", snd_strerror(result)); + } + return 0; +} diff --git a/linux/alsarawmidi/JackALSARawMidiReceiveQueue.h b/linux/alsarawmidi/JackALSARawMidiReceiveQueue.h new file mode 100755 index 00000000..ffe4ea5f --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiReceiveQueue.h @@ -0,0 +1,51 @@ +/* +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 __JackALSARawMidiReceiveQueue__ +#define __JackALSARawMidiReceiveQueue__ + +#include + +#include "JackMidiReceiveQueue.h" + +namespace Jack { + + class JackALSARawMidiReceiveQueue: public JackMidiReceiveQueue { + + private: + + jack_midi_data_t *buffer; + size_t buffer_size; + jack_midi_event_t event; + snd_rawmidi_t *rawmidi; + + public: + + JackALSARawMidiReceiveQueue(snd_rawmidi_t *rawmidi, + size_t buffer_size=4096); + ~JackALSARawMidiReceiveQueue(); + + jack_midi_event_t * + DequeueEvent(); + + }; + +} + +#endif diff --git a/linux/alsarawmidi/JackALSARawMidiSendQueue.cpp b/linux/alsarawmidi/JackALSARawMidiSendQueue.cpp new file mode 100755 index 00000000..156986a7 --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiSendQueue.cpp @@ -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. + +*/ + +#include + +#include "JackALSARawMidiSendQueue.h" +#include "JackMidiUtil.h" + +using Jack::JackALSARawMidiSendQueue; + +JackALSARawMidiSendQueue::JackALSARawMidiSendQueue(snd_rawmidi_t *rawmidi) +{ + this->rawmidi = rawmidi; + blocked = false; +} + +Jack::JackMidiWriteQueue::EnqueueResult +JackALSARawMidiSendQueue::EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer) +{ + assert(size == 1); + if (time > GetCurrentFrame()) { + return EVENT_EARLY; + } + ssize_t result = snd_rawmidi_write(rawmidi, buffer, 1); + switch (result) { + case 1: + blocked = false; + return OK; + case -EWOULDBLOCK: + blocked = true; + return BUFFER_FULL; + } + jack_error("JackALSARawMidiSendQueue::EnqueueEvent - snd_rawmidi_write: " + "%s", snd_strerror(result)); + return EN_ERROR; +} + +bool +JackALSARawMidiSendQueue::IsBlocked() +{ + return blocked; +} diff --git a/linux/alsarawmidi/JackALSARawMidiSendQueue.h b/linux/alsarawmidi/JackALSARawMidiSendQueue.h new file mode 100755 index 00000000..2d904b3a --- /dev/null +++ b/linux/alsarawmidi/JackALSARawMidiSendQueue.h @@ -0,0 +1,51 @@ +/* +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 __JackALSARawMidiSendQueue__ +#define __JackALSARawMidiSendQueue__ + +#include + +#include "JackMidiSendQueue.h" + +namespace Jack { + + class JackALSARawMidiSendQueue: public JackMidiSendQueue { + + private: + + bool blocked; + snd_rawmidi_t *rawmidi; + + public: + + JackALSARawMidiSendQueue(snd_rawmidi_t *rawmidi); + + JackMidiWriteQueue::EnqueueResult + EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer); + + bool + IsBlocked(); + + }; + +} + +#endif diff --git a/linux/firewire/JackFFADODriver.cpp b/linux/firewire/JackFFADODriver.cpp index 2f855f37..62f10ad1 100644 --- a/linux/firewire/JackFFADODriver.cpp +++ b/linux/firewire/JackFFADODriver.cpp @@ -36,8 +36,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include #include "JackFFADODriver.h" -#include "JackFFADOMidiInput.h" -#include "JackFFADOMidiOutput.h" +#include "JackFFADOMidiInputPort.h" +#include "JackFFADOMidiOutputPort.h" #include "JackEngineControl.h" #include "JackClientControl.h" #include "JackPort.h" @@ -94,14 +94,9 @@ JackFFADODriver::ffado_driver_read (ffado_driver_t * driver, jack_nframes_t nfra /* process the midi data */ for (chn = 0; chn < driver->capture_nchannels; chn++) { if (driver->capture_channels[chn].stream_type == ffado_stream_type_midi) { - JackFFADOMidiInput *midi_input = (JackFFADOMidiInput *) driver->capture_channels[chn].midi_input; + JackFFADOMidiInputPort *midi_input = (JackFFADOMidiInputPort *) driver->capture_channels[chn].midi_input; JackMidiBuffer *buffer = (JackMidiBuffer *) fGraphManager->GetBuffer(fCapturePortList[chn], nframes); - if (! buffer) { - continue; - } - midi_input->SetInputBuffer(driver->capture_channels[chn].midi_buffer); - midi_input->SetPortBuffer(buffer); - midi_input->Process(nframes); + midi_input->Process(buffer, driver->capture_channels[chn].midi_buffer, nframes); } } @@ -138,16 +133,9 @@ JackFFADODriver::ffado_driver_write (ffado_driver_t * driver, jack_nframes_t nfr memset(midi_buffer, 0, nframes * sizeof(uint32_t)); buf = (jack_default_audio_sample_t *) fGraphManager->GetBuffer(fPlaybackPortList[chn], nframes); ffado_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(midi_buffer)); - /* if the returned buffer is invalid, continue */ - if (!buf) { - ffado_streaming_playback_stream_onoff(driver->dev, chn, 0); - continue; - } - ffado_streaming_playback_stream_onoff(driver->dev, chn, 1); - JackFFADOMidiOutput *midi_output = (JackFFADOMidiOutput *) driver->playback_channels[chn].midi_output; - midi_output->SetPortBuffer((JackMidiBuffer *) buf); - midi_output->SetOutputBuffer(midi_buffer); - midi_output->Process(nframes); + ffado_streaming_playback_stream_onoff(driver->dev, chn, buf ? 1 : 0); + JackFFADOMidiOutputPort *midi_output = (JackFFADOMidiOutputPort *) driver->playback_channels[chn].midi_output; + midi_output->Process((JackMidiBuffer *) buf, midi_buffer, nframes); } else { // always have a valid buffer ffado_streaming_set_playback_stream_buffer(driver->dev, chn, (char *)(driver->nullbuffer)); @@ -155,9 +143,7 @@ JackFFADODriver::ffado_driver_write (ffado_driver_t * driver, jack_nframes_t nfr } } } - ffado_streaming_transfer_playback_buffers(driver->dev); - printExit(); return 0; } @@ -476,7 +462,7 @@ int JackFFADODriver::Attach() printError(" cannot enable port %s", buf); } - driver->capture_channels[chn].midi_input = new JackFFADOMidiInput(); + driver->capture_channels[chn].midi_input = new JackFFADOMidiInputPort(); // setup the midi buffer driver->capture_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); @@ -557,12 +543,12 @@ int JackFFADODriver::Attach() // This constructor optionally accepts arguments for the // non-realtime buffer size and the realtime buffer size. Ideally, // these would become command-line options for the FFADO driver. - driver->playback_channels[chn].midi_output = new JackFFADOMidiOutput(); + driver->playback_channels[chn].midi_output = new JackFFADOMidiOutputPort(); driver->playback_channels[chn].midi_buffer = (uint32_t *)calloc(driver->period_size, sizeof(uint32_t)); port = fGraphManager->GetPort(port_index); - range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + driver->playback_frame_latency; + range.min = range.max = (driver->period_size * (driver->device_options.nb_buffers - 1)) + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + driver->playback_frame_latency; port->SetLatencyRange(JackPlaybackLatency, &range); fPlaybackPortList[chn] = port_index; jack_log("JackFFADODriver::Attach fPlaybackPortList[i] %ld ", port_index); @@ -600,7 +586,7 @@ int JackFFADODriver::Detach() if (driver->capture_channels[chn].midi_buffer) free(driver->capture_channels[chn].midi_buffer); if (driver->capture_channels[chn].midi_input) - delete ((JackFFADOMidiInput *) (driver->capture_channels[chn].midi_input)); + delete ((JackFFADOMidiInputPort *) (driver->capture_channels[chn].midi_input)); } free(driver->capture_channels); @@ -608,7 +594,7 @@ int JackFFADODriver::Detach() if (driver->playback_channels[chn].midi_buffer) free(driver->playback_channels[chn].midi_buffer); if (driver->playback_channels[chn].midi_output) - delete ((JackFFADOMidiOutput *) (driver->playback_channels[chn].midi_output)); + delete ((JackFFADOMidiOutputPort *) (driver->playback_channels[chn].midi_output)); } free(driver->playback_channels); diff --git a/linux/firewire/JackFFADOMidiInput.cpp b/linux/firewire/JackFFADOMidiInput.cpp deleted file mode 100644 index 38ed539b..00000000 --- a/linux/firewire/JackFFADOMidiInput.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright (C) 2009 Devin Anderson - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include - -#include "JackFFADOMidiInput.h" - -namespace Jack { - -JackFFADOMidiInput::JackFFADOMidiInput(size_t buffer_size): - JackPhysicalMidiInput(buffer_size) -{ - new_period = true; -} - -JackFFADOMidiInput::~JackFFADOMidiInput() -{ - // Empty -} - -jack_nframes_t -JackFFADOMidiInput::Receive(jack_midi_data_t *datum, - jack_nframes_t current_frame, - jack_nframes_t total_frames) -{ - assert(input_buffer); - if (! new_period) { - current_frame += 8; - } else { - new_period = false; - } - for (; current_frame < total_frames; current_frame += 8) { - uint32_t data = input_buffer[current_frame]; - if (data & 0xff000000) { - *datum = (jack_midi_data_t) (data & 0xff); - return current_frame; - } - } - new_period = true; - return total_frames; -} - -} diff --git a/linux/firewire/JackFFADOMidiInputPort.cpp b/linux/firewire/JackFFADOMidiInputPort.cpp new file mode 100644 index 00000000..3923bbe0 --- /dev/null +++ b/linux/firewire/JackFFADOMidiInputPort.cpp @@ -0,0 +1,94 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include "JackFFADOMidiInputPort.h" +#include "JackMidiUtil.h" + +using Jack::JackFFADOMidiInputPort; + +JackFFADOMidiInputPort::JackFFADOMidiInputPort(size_t max_bytes) +{ + event = 0; + receive_queue = new JackFFADOMidiReceiveQueue(); + std::auto_ptr receive_queue_ptr(receive_queue); + write_queue = new JackMidiBufferWriteQueue(); + std::auto_ptr write_queue_ptr(write_queue); + raw_queue = new JackMidiRawInputWriteQueue(write_queue, max_bytes, + max_bytes); + write_queue_ptr.release(); + receive_queue_ptr.release(); +} + +JackFFADOMidiInputPort::~JackFFADOMidiInputPort() +{ + delete raw_queue; + delete receive_queue; + delete write_queue; +} + +void +JackFFADOMidiInputPort::Process(JackMidiBuffer *port_buffer, + uint32_t *input_buffer, jack_nframes_t frames) +{ + receive_queue->ResetInputBuffer(input_buffer, frames); + write_queue->ResetMidiBuffer(port_buffer, frames); + jack_nframes_t boundary_frame = GetLastFrame() + frames; + if (! event) { + event = receive_queue->DequeueEvent(); + } + for (; event; event = receive_queue->DequeueEvent()) { + switch (raw_queue->EnqueueEvent(event)) { + case JackMidiWriteQueue::BUFFER_FULL: + + // Processing events early might free up some space in the raw + // input queue. + + raw_queue->Process(boundary_frame); + switch (raw_queue->EnqueueEvent(event)) { + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + // This shouldn't really happen. It indicates a bug if it + // does. + jack_error("JackFFADOMidiInputPort::Process - **BUG** " + "JackMidiRawInputWriteQueue::EnqueueEvent returned " + "`BUFFER_FULL`, and then returned " + "`BUFFER_TOO_SMALL` after a `Process()` call."); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + continue; + default: + return; + } + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackFFADOMidiInputPort::Process - The write queue " + "couldn't enqueue a %d-byte event. Dropping event.", + event->size); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + continue; + default: + // This is here to stop compliers from warning us about not + // handling enumeration values. + ; + } + break; + } + raw_queue->Process(boundary_frame); +} diff --git a/linux/firewire/JackFFADOMidiInputPort.h b/linux/firewire/JackFFADOMidiInputPort.h new file mode 100644 index 00000000..f4c70a80 --- /dev/null +++ b/linux/firewire/JackFFADOMidiInputPort.h @@ -0,0 +1,51 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackFFADOMidiInputPort__ +#define __JackFFADOMidiInputPort__ + +#include "JackFFADOMidiReceiveQueue.h" +#include "JackMidiBufferWriteQueue.h" +#include "JackMidiRawInputWriteQueue.h" + +namespace Jack { + + class JackFFADOMidiInputPort { + + private: + + jack_midi_event_t *event; + JackMidiRawInputWriteQueue *raw_queue; + JackFFADOMidiReceiveQueue *receive_queue; + JackMidiBufferWriteQueue *write_queue; + + public: + + JackFFADOMidiInputPort(size_t max_bytes=4096); + ~JackFFADOMidiInputPort(); + + void + Process(JackMidiBuffer *port_buffer, uint32_t *input_buffer, + jack_nframes_t frames); + + }; + +} + +#endif diff --git a/linux/firewire/JackFFADOMidiOutput.cpp b/linux/firewire/JackFFADOMidiOutput.cpp deleted file mode 100644 index 995f2d28..00000000 --- a/linux/firewire/JackFFADOMidiOutput.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright (C) 2009 Devin Anderson - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include - -#include "JackError.h" -#include "JackFFADOMidiOutput.h" - -namespace Jack { - -JackFFADOMidiOutput::JackFFADOMidiOutput(size_t non_rt_buffer_size, - size_t rt_buffer_size): - JackPhysicalMidiOutput(non_rt_buffer_size, rt_buffer_size) -{ - // Empty -} - -JackFFADOMidiOutput::~JackFFADOMidiOutput() -{ - // Empty -} - -jack_nframes_t -JackFFADOMidiOutput::Advance(jack_nframes_t current_frame) -{ - if (current_frame % 8) { - current_frame = (current_frame & (~ ((jack_nframes_t) 7))) + 8; - } - return current_frame; -} - -jack_nframes_t -JackFFADOMidiOutput::Send(jack_nframes_t current_frame, jack_midi_data_t datum) -{ - assert(output_buffer); - - jack_log("JackFFADOMidiOutput::Send (%d) - Sending '%x' byte.", - current_frame, (unsigned int) datum); - - output_buffer[current_frame] = 0x01000000 | ((uint32_t) datum); - return current_frame + 8; -} - -} diff --git a/linux/firewire/JackFFADOMidiOutputPort.cpp b/linux/firewire/JackFFADOMidiOutputPort.cpp new file mode 100644 index 00000000..b916c8c5 --- /dev/null +++ b/linux/firewire/JackFFADOMidiOutputPort.cpp @@ -0,0 +1,98 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include "JackFFADOMidiOutputPort.h" +#include "JackMidiUtil.h" + +using Jack::JackFFADOMidiOutputPort; + +JackFFADOMidiOutputPort::JackFFADOMidiOutputPort(size_t non_rt_size, + size_t max_non_rt_messages, + size_t max_rt_messages) +{ + event = 0; + read_queue = new JackMidiBufferReadQueue(); + std::auto_ptr read_queue_ptr(read_queue); + send_queue = new JackFFADOMidiSendQueue(); + std::auto_ptr send_queue_ptr(send_queue); + raw_queue = new JackMidiRawOutputWriteQueue(send_queue, non_rt_size, + max_non_rt_messages, + max_rt_messages); + send_queue_ptr.release(); + read_queue_ptr.release(); +} + +JackFFADOMidiOutputPort::~JackFFADOMidiOutputPort() +{ + delete raw_queue; + delete read_queue; + delete send_queue; +} + +void +JackFFADOMidiOutputPort::Process(JackMidiBuffer *port_buffer, + uint32_t *output_buffer, + jack_nframes_t frames) +{ + read_queue->ResetMidiBuffer(port_buffer); + send_queue->ResetOutputBuffer(output_buffer, frames); + jack_nframes_t boundary_frame = GetLastFrame() + frames; + if (! event) { + event = read_queue->DequeueEvent(); + } + for (; event; event = read_queue->DequeueEvent()) { + switch (raw_queue->EnqueueEvent(event)) { + case JackMidiWriteQueue::BUFFER_FULL: + + // Processing events early might free up some space in the raw + // output queue. + + raw_queue->Process(boundary_frame); + switch (raw_queue->EnqueueEvent(event)) { + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + // This shouldn't really happen. It indicates a bug if it + // does. + jack_error("JackFFADOMidiOutputPort::Process - **BUG** " + "JackMidiRawOutputWriteQueue::EnqueueEvent " + "returned `BUFFER_FULL`, and then returned " + "`BUFFER_TOO_SMALL` after a `Process()` call."); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + continue; + default: + return; + } + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackFFADOMidiOutputPort::Process - The write queue " + "couldn't enqueue a %d-byte event. Dropping event.", + event->size); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + continue; + default: + // This is here to stop compliers from warning us about not + // handling enumeration values. + ; + } + break; + } + raw_queue->Process(boundary_frame); +} diff --git a/linux/firewire/JackFFADOMidiOutputPort.h b/linux/firewire/JackFFADOMidiOutputPort.h new file mode 100644 index 00000000..4ca309bb --- /dev/null +++ b/linux/firewire/JackFFADOMidiOutputPort.h @@ -0,0 +1,53 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __JackFFADOMidiOutputPort__ +#define __JackFFADOMidiOutputPort__ + +#include "JackFFADOMidiSendQueue.h" +#include "JackMidiBufferReadQueue.h" +#include "JackMidiRawOutputWriteQueue.h" + +namespace Jack { + + class JackFFADOMidiOutputPort { + + private: + + jack_midi_event_t *event; + JackMidiRawOutputWriteQueue *raw_queue; + JackMidiBufferReadQueue *read_queue; + JackFFADOMidiSendQueue *send_queue; + + public: + + JackFFADOMidiOutputPort(size_t non_rt_size=4096, + size_t max_non_rt_messages=1024, + size_t max_rt_messages=128); + ~JackFFADOMidiOutputPort(); + + void + Process(JackMidiBuffer *port_buffer, uint32_t *output_buffer, + jack_nframes_t frames); + + }; + +} + +#endif diff --git a/linux/firewire/JackFFADOMidiReceiveQueue.cpp b/linux/firewire/JackFFADOMidiReceiveQueue.cpp new file mode 100644 index 00000000..4b67f329 --- /dev/null +++ b/linux/firewire/JackFFADOMidiReceiveQueue.cpp @@ -0,0 +1,55 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "JackFFADOMidiReceiveQueue.h" +#include "JackMidiUtil.h" + +using Jack::JackFFADOMidiReceiveQueue; + +JackFFADOMidiReceiveQueue::JackFFADOMidiReceiveQueue() +{ + // Empty +} + +jack_midi_event_t * +JackFFADOMidiReceiveQueue::DequeueEvent() +{ + for (; index < length; index += 8) { + uint32_t data = input_buffer[index]; + if (data & 0xff000000) { + byte = (jack_midi_data_t) (data & 0xff); + event.buffer = &byte; + event.size = 1; + event.time = last_frame + index; + index += 8; + return &event; + } + } + return 0; +} + +void +JackFFADOMidiReceiveQueue::ResetInputBuffer(uint32_t *input_buffer, + jack_nframes_t length) +{ + this->input_buffer = input_buffer; + index = 0; + last_frame = GetLastFrame(); + this->length = length; +} diff --git a/linux/firewire/JackFFADOMidiInput.h b/linux/firewire/JackFFADOMidiReceiveQueue.h similarity index 59% rename from linux/firewire/JackFFADOMidiInput.h rename to linux/firewire/JackFFADOMidiReceiveQueue.h index 12dc043c..7647869d 100644 --- a/linux/firewire/JackFFADOMidiInput.h +++ b/linux/firewire/JackFFADOMidiReceiveQueue.h @@ -1,5 +1,5 @@ /* -Copyright (C) 2009 Devin Anderson +Copyright (C) 2010 Devin Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -17,35 +17,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __JackFFADOMidiInput__ -#define __JackFFADOMidiInput__ +#ifndef __JackFFADOMidiReceiveQueue__ +#define __JackFFADOMidiReceiveQueue__ -#include "JackPhysicalMidiInput.h" +#include "JackMidiReceiveQueue.h" namespace Jack { - class JackFFADOMidiInput: public JackPhysicalMidiInput { + class JackFFADOMidiReceiveQueue: public JackMidiReceiveQueue { private: + jack_midi_data_t byte; + jack_midi_event_t event; + jack_nframes_t index; uint32_t *input_buffer; - bool new_period; - - protected: - - jack_nframes_t - Receive(jack_midi_data_t *, jack_nframes_t, jack_nframes_t); + jack_nframes_t last_frame; + jack_nframes_t length; public: - JackFFADOMidiInput(size_t buffer_size=1024); - ~JackFFADOMidiInput(); + JackFFADOMidiReceiveQueue(); + + jack_midi_event_t * + DequeueEvent(); - inline void - SetInputBuffer(uint32_t *input_buffer) - { - this->input_buffer = input_buffer; - } + void + ResetInputBuffer(uint32_t *input_buffer, jack_nframes_t length); }; diff --git a/linux/firewire/JackFFADOMidiSendQueue.cpp b/linux/firewire/JackFFADOMidiSendQueue.cpp new file mode 100644 index 00000000..97fdf17d --- /dev/null +++ b/linux/firewire/JackFFADOMidiSendQueue.cpp @@ -0,0 +1,64 @@ +/* +Copyright (C) 2010 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include + +#include "JackFFADOMidiSendQueue.h" +#include "JackMidiUtil.h" + +using Jack::JackFFADOMidiSendQueue; + +JackFFADOMidiSendQueue::JackFFADOMidiSendQueue() +{ + // Empty +} + +Jack::JackMidiWriteQueue::EnqueueResult +JackFFADOMidiSendQueue::EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer) +{ + assert(size == 1); + jack_nframes_t relative_time = (time < last_frame) ? 0 : time - last_frame; + if (index < relative_time) { + index = (relative_time % 8) ? + (relative_time & (~ ((jack_nframes_t) 7))) + 8 : relative_time; + } + if (index >= length) { + return BUFFER_FULL; + } + output_buffer[index] = 0x01000000 | ((uint32_t) *buffer); + index += 8; + return OK; +} + +jack_nframes_t +JackFFADOMidiSendQueue::GetNextScheduleFrame() +{ + return last_frame + index; +} + +void +JackFFADOMidiSendQueue::ResetOutputBuffer(uint32_t *output_buffer, + jack_nframes_t length) +{ + index = 0; + last_frame = GetLastFrame(); + this->length = length; + this->output_buffer = output_buffer; +} diff --git a/linux/firewire/JackFFADOMidiOutput.h b/linux/firewire/JackFFADOMidiSendQueue.h similarity index 58% rename from linux/firewire/JackFFADOMidiOutput.h rename to linux/firewire/JackFFADOMidiSendQueue.h index 309e7f61..f395f13d 100644 --- a/linux/firewire/JackFFADOMidiOutput.h +++ b/linux/firewire/JackFFADOMidiSendQueue.h @@ -1,5 +1,5 @@ /* -Copyright (C) 2009 Devin Anderson +Copyright (C) 2010 Devin Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -17,38 +17,35 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __JackFFADOMidiOutput__ -#define __JackFFADOMidiOutput__ +#ifndef __JackFFADOMidiSendQueue__ +#define __JackFFADOMidiSendQueue__ -#include "JackPhysicalMidiOutput.h" +#include "JackMidiSendQueue.h" namespace Jack { - class JackFFADOMidiOutput: public JackPhysicalMidiOutput { + class JackFFADOMidiSendQueue: public JackMidiSendQueue { private: + jack_nframes_t index; + jack_nframes_t last_frame; + jack_nframes_t length; uint32_t *output_buffer; - protected: - - jack_nframes_t - Advance(jack_nframes_t); + public: - jack_nframes_t - Send(jack_nframes_t, jack_midi_data_t); + JackFFADOMidiSendQueue(); - public: + EnqueueResult + EnqueueEvent(jack_nframes_t time, size_t size, + jack_midi_data_t *buffer); - JackFFADOMidiOutput(size_t non_rt_buffer_size=1024, - size_t rt_buffer_size=64); - ~JackFFADOMidiOutput(); + jack_nframes_t + GetNextScheduleFrame(); - inline void - SetOutputBuffer(uint32_t *output_buffer) - { - this->output_buffer = output_buffer; - } + void + ResetOutputBuffer(uint32_t *output_buffer, jack_nframes_t length); }; diff --git a/linux/wscript b/linux/wscript index 5675c3dc..3306b880 100644 --- a/linux/wscript +++ b/linux/wscript @@ -57,15 +57,25 @@ def build(bld): 'alsa/ice1712.c' ] + alsarawmidi_driver_src = ['alsarawmidi/JackALSARawMidiDriver.cpp', + 'alsarawmidi/JackALSARawMidiInputPort.cpp', + 'alsarawmidi/JackALSARawMidiOutputPort.cpp', + 'alsarawmidi/JackALSARawMidiPort.cpp', + 'alsarawmidi/JackALSARawMidiReceiveQueue.cpp', + 'alsarawmidi/JackALSARawMidiSendQueue.cpp' + ] + ffado_driver_src = ['firewire/JackFFADODriver.cpp', - 'firewire/JackFFADOMidiInput.cpp', - 'firewire/JackFFADOMidiOutput.cpp', - '../common/JackPhysicalMidiInput.cpp', - '../common/JackPhysicalMidiOutput.cpp' + 'firewire/JackFFADOMidiInputPort.cpp', + 'firewire/JackFFADOMidiOutputPort.cpp', + 'firewire/JackFFADOMidiReceiveQueue.cpp', + 'firewire/JackFFADOMidiSendQueue.cpp' ] if bld.env['BUILD_DRIVER_ALSA'] == True: create_jack_driver_obj(bld, 'alsa', alsa_driver_src, "ALSA") + create_jack_driver_obj(bld, 'alsarawmidi', alsarawmidi_driver_src, + "ALSA") if bld.env['BUILD_DRIVER_FREEBOB'] == True: create_jack_driver_obj(bld, 'freebob', 'freebob/JackFreebobDriver.cpp', "LIBFREEBOB") diff --git a/macosx/Jack-Info.plist b/macosx/Jack-Info.plist index 0d714313..ef6c3bfa 100644 --- a/macosx/Jack-Info.plist +++ b/macosx/Jack-Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable Jackservermp CFBundleGetInfoString - Jackdmp 1.9.7, @03-11 Paul Davis, Grame + Jackdmp 1.9.8, @03-11 Paul Davis, Grame CFBundleIdentifier com.grame.Jackmp CFBundleInfoDictionaryVersion @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.9.7 + 1.9.8 diff --git a/macosx/JackMachThread.h b/macosx/JackMachThread.h index eae474f2..bb9e18f0 100644 --- a/macosx/JackMachThread.h +++ b/macosx/JackMachThread.h @@ -70,7 +70,7 @@ typedef unsigned char Boolean; #include "JackPosixThread.h" #ifndef MY_TARGET_OS_IPHONE -#import +#include #endif #include diff --git a/macosx/Jackdmp.xcodeproj/project.pbxproj b/macosx/Jackdmp.xcodeproj/project.pbxproj index dbcdbe05..5961dd82 100644 --- a/macosx/Jackdmp.xcodeproj/project.pbxproj +++ b/macosx/Jackdmp.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ 4B66550E127C356E00753A79 /* PBXTargetDependency */, 4B38120313269CCB00C61B14 /* PBXTargetDependency */, 4B8F16FC1329169F0002AD73 /* PBXTargetDependency */, + 4B20220C133A9C370019E213 /* PBXTargetDependency */, ); name = "All Universal 32/64 bits"; productName = All; @@ -107,6 +108,12 @@ /* 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 */; }; + 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 */; }; + 4B193994133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; }; + 4B193995133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; }; + 4B193996133F321500547810 /* JackFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B193990133F321500547810 /* JackFilters.h */; }; 4B19B3130E2362E800DD4A82 /* JackAudioAdapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19B3060E2362E700DD4A82 /* JackAudioAdapter.cpp */; }; 4B19B3140E2362E800DD4A82 /* JackAudioAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19B3070E2362E700DD4A82 /* JackAudioAdapter.h */; }; 4B19B3150E2362E800DD4A82 /* JackAudioAdapterInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19B3080E2362E700DD4A82 /* JackAudioAdapterInterface.cpp */; }; @@ -114,6 +121,7 @@ 4B19B31B0E2362E800DD4A82 /* JackLibSampleRateResampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19B30E0E2362E700DD4A82 /* JackLibSampleRateResampler.cpp */; }; 4B19B31C0E2362E800DD4A82 /* JackLibSampleRateResampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B19B30F0E2362E700DD4A82 /* JackLibSampleRateResampler.h */; }; 4B19B31F0E2362E800DD4A82 /* JackResampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B19B3120E2362E700DD4A82 /* JackResampler.cpp */; }; + 4B20220A133A9C1C0019E213 /* midi_latency_test.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B202209133A9C1C0019E213 /* midi_latency_test.c */; }; 4B2209E112F6BBF300E5DC26 /* JackSocketServerChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3B6B30E703B8D0066E42F /* JackSocketServerChannel.cpp */; }; 4B2209E212F6BBF400E5DC26 /* JackSocketServerChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC3B6B40E703B8D0066E42F /* JackSocketServerChannel.h */; }; 4B2209E312F6BBF500E5DC26 /* JackSocketServerNotifyChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3B6B50E703B8D0066E42F /* JackSocketServerNotifyChannel.cpp */; }; @@ -317,6 +325,38 @@ 4B363F230DEB0AB0001F72D9 /* monitor_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B363F220DEB0AB0001F72D9 /* monitor_client.c */; }; 4B363F3E0DEB0C31001F72D9 /* showtime.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B363F3D0DEB0C31001F72D9 /* showtime.c */; }; 4B363F760DEB0D7D001F72D9 /* impulse_grabber.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B363F750DEB0D7D001F72D9 /* impulse_grabber.c */; }; + 4B370A24133DD7E300237B68 /* JackCoreMidiInputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A14133DD7E200237B68 /* JackCoreMidiInputPort.cpp */; }; + 4B370A25133DD7E300237B68 /* JackCoreMidiInputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A15133DD7E200237B68 /* JackCoreMidiInputPort.h */; }; + 4B370A26133DD7E300237B68 /* JackCoreMidiOutputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A16133DD7E200237B68 /* JackCoreMidiOutputPort.cpp */; }; + 4B370A27133DD7E300237B68 /* JackCoreMidiOutputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A17133DD7E200237B68 /* JackCoreMidiOutputPort.h */; }; + 4B370A28133DD7E300237B68 /* JackCoreMidiPhysicalInputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A18133DD7E200237B68 /* JackCoreMidiPhysicalInputPort.cpp */; }; + 4B370A29133DD7E300237B68 /* JackCoreMidiPhysicalInputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A19133DD7E200237B68 /* JackCoreMidiPhysicalInputPort.h */; }; + 4B370A2A133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A1A133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.cpp */; }; + 4B370A2B133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A1B133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.h */; }; + 4B370A2C133DD7E300237B68 /* JackCoreMidiPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A1C133DD7E300237B68 /* JackCoreMidiPort.cpp */; }; + 4B370A2D133DD7E300237B68 /* JackCoreMidiPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A1D133DD7E300237B68 /* JackCoreMidiPort.h */; }; + 4B370A2E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A1E133DD7E300237B68 /* JackCoreMidiUtil.cpp */; }; + 4B370A2F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A1F133DD7E300237B68 /* JackCoreMidiUtil.h */; }; + 4B370A30133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A20133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp */; }; + 4B370A31133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A21133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h */; }; + 4B370A32133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A22133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp */; }; + 4B370A33133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A23133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h */; }; + 4B370A34133DD7E300237B68 /* JackCoreMidiInputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A14133DD7E200237B68 /* JackCoreMidiInputPort.cpp */; }; + 4B370A35133DD7E300237B68 /* JackCoreMidiInputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A15133DD7E200237B68 /* JackCoreMidiInputPort.h */; }; + 4B370A36133DD7E300237B68 /* JackCoreMidiOutputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A16133DD7E200237B68 /* JackCoreMidiOutputPort.cpp */; }; + 4B370A37133DD7E300237B68 /* JackCoreMidiOutputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A17133DD7E200237B68 /* JackCoreMidiOutputPort.h */; }; + 4B370A38133DD7E300237B68 /* JackCoreMidiPhysicalInputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A18133DD7E200237B68 /* JackCoreMidiPhysicalInputPort.cpp */; }; + 4B370A39133DD7E300237B68 /* JackCoreMidiPhysicalInputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A19133DD7E200237B68 /* JackCoreMidiPhysicalInputPort.h */; }; + 4B370A3A133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A1A133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.cpp */; }; + 4B370A3B133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A1B133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.h */; }; + 4B370A3C133DD7E300237B68 /* JackCoreMidiPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A1C133DD7E300237B68 /* JackCoreMidiPort.cpp */; }; + 4B370A3D133DD7E300237B68 /* JackCoreMidiPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A1D133DD7E300237B68 /* JackCoreMidiPort.h */; }; + 4B370A3E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A1E133DD7E300237B68 /* JackCoreMidiUtil.cpp */; }; + 4B370A3F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A1F133DD7E300237B68 /* JackCoreMidiUtil.h */; }; + 4B370A40133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A20133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp */; }; + 4B370A41133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A21133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h */; }; + 4B370A42133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B370A22133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp */; }; + 4B370A43133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B370A23133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h */; }; 4B3811FB13269C8300C61B14 /* latent_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3811FA13269C8300C61B14 /* latent_client.c */; }; 4B3811FC13269C8300C61B14 /* latent_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3811FA13269C8300C61B14 /* latent_client.c */; }; 4B3814201327AA6800C61B14 /* iodelay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B38141F1327AA6800C61B14 /* iodelay.cpp */; }; @@ -595,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, ); }; }; @@ -754,18 +830,6 @@ 4BC3B6A50E703B2E0066E42F /* JackPosixThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC3B6A30E703B2E0066E42F /* JackPosixThread.h */; }; 4BC3B6A60E703B2E0066E42F /* JackPosixThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3B6A20E703B2E0066E42F /* JackPosixThread.cpp */; }; 4BC3B6A70E703B2E0066E42F /* JackPosixThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BC3B6A30E703B2E0066E42F /* JackPosixThread.h */; }; - 4BCBCE5D10C4FE3F00450FFE /* JackPhysicalMidiInput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCBCE5910C4FE3F00450FFE /* JackPhysicalMidiInput.cpp */; }; - 4BCBCE5E10C4FE3F00450FFE /* JackPhysicalMidiInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCBCE5A10C4FE3F00450FFE /* JackPhysicalMidiInput.h */; }; - 4BCBCE5F10C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCBCE5B10C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp */; }; - 4BCBCE6010C4FE3F00450FFE /* JackPhysicalMidiOutput.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCBCE5C10C4FE3F00450FFE /* JackPhysicalMidiOutput.h */; }; - 4BCBCE6110C4FE3F00450FFE /* JackPhysicalMidiInput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCBCE5910C4FE3F00450FFE /* JackPhysicalMidiInput.cpp */; }; - 4BCBCE6210C4FE3F00450FFE /* JackPhysicalMidiInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCBCE5A10C4FE3F00450FFE /* JackPhysicalMidiInput.h */; }; - 4BCBCE6310C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCBCE5B10C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp */; }; - 4BCBCE6410C4FE3F00450FFE /* JackPhysicalMidiOutput.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCBCE5C10C4FE3F00450FFE /* JackPhysicalMidiOutput.h */; }; - 4BCBCE6510C4FE3F00450FFE /* JackPhysicalMidiInput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCBCE5910C4FE3F00450FFE /* JackPhysicalMidiInput.cpp */; }; - 4BCBCE6610C4FE3F00450FFE /* JackPhysicalMidiInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCBCE5A10C4FE3F00450FFE /* JackPhysicalMidiInput.h */; }; - 4BCBCE6710C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCBCE5B10C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp */; }; - 4BCBCE6810C4FE3F00450FFE /* JackPhysicalMidiOutput.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCBCE5C10C4FE3F00450FFE /* JackPhysicalMidiOutput.h */; }; 4BCC87960D57168300A7FEB1 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BCC87950D57168300A7FEB1 /* Accelerate.framework */; }; 4BCC87970D57168300A7FEB1 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BCC87950D57168300A7FEB1 /* Accelerate.framework */; }; 4BCC87980D57168300A7FEB1 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BCC87950D57168300A7FEB1 /* Accelerate.framework */; }; @@ -877,6 +941,13 @@ remoteGlobalIDString = 4B19B2F60E23620F00DD4A82; remoteInfo = audioadapter; }; + 4B20220B133A9C370019E213 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4B2021DC133A9BA40019E213; + remoteInfo = "jack_midi_latency 64 bits"; + }; 4B224B330E65BA330066BE5B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; @@ -1430,9 +1501,6 @@ 4B05A0640DF72BC000840F4C /* usx2y.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = usx2y.c; path = ../linux/alsa/usx2y.c; sourceTree = SOURCE_ROOT; }; 4B05A0650DF72BC000840F4C /* usx2y.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = usx2y.h; path = ../linux/alsa/usx2y.h; sourceTree = SOURCE_ROOT; }; 4B05A07D0DF72BC000840F4C /* driver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = driver.h; path = ../linux/driver.h; sourceTree = SOURCE_ROOT; }; - 4B05A07F0DF72BC000840F4C /* ffado_driver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ffado_driver.h; path = ../linux/firewire/ffado_driver.h; sourceTree = SOURCE_ROOT; }; - 4B05A0800DF72BC000840F4C /* JackFFADODriver.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackFFADODriver.cpp; path = ../linux/firewire/JackFFADODriver.cpp; sourceTree = SOURCE_ROOT; }; - 4B05A0810DF72BC000840F4C /* JackFFADODriver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackFFADODriver.h; path = ../linux/firewire/JackFFADODriver.h; sourceTree = SOURCE_ROOT; }; 4B05A0830DF72BC000840F4C /* freebob_driver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = freebob_driver.h; path = ../linux/freebob/freebob_driver.h; sourceTree = SOURCE_ROOT; }; 4B05A0840DF72BC000840F4C /* JackFreebobDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackFreebobDriver.cpp; path = ../linux/freebob/JackFreebobDriver.cpp; sourceTree = SOURCE_ROOT; }; 4B05A0850DF72BC000840F4C /* JackFreebobDriver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackFreebobDriver.h; path = ../linux/freebob/JackFreebobDriver.h; sourceTree = SOURCE_ROOT; }; @@ -1457,6 +1525,25 @@ 4B0A28E60D52073D002EFF74 /* jack_thread_wait */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_thread_wait; sourceTree = BUILT_PRODUCTS_DIR; }; 4B0A28EC0D520852002EFF74 /* tw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tw.c; path = "../example-clients/tw.c"; sourceTree = SOURCE_ROOT; }; 4B0A292D0D52108E002EFF74 /* jack_thread_wait */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_thread_wait; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiAsyncQueue.cpp; path = ../common/JackMidiAsyncQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B193932133F311400547810 /* JackMidiAsyncQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiAsyncQueue.h; path = ../common/JackMidiAsyncQueue.h; sourceTree = SOURCE_ROOT; }; + 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiAsyncWaitQueue.cpp; path = ../common/JackMidiAsyncWaitQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiAsyncWaitQueue.h; path = ../common/JackMidiAsyncWaitQueue.h; sourceTree = SOURCE_ROOT; }; + 4B193945133F315200547810 /* JackMidiReadQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiReadQueue.cpp; path = ../common/JackMidiReadQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B193946133F315200547810 /* JackMidiReadQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiReadQueue.h; path = ../common/JackMidiReadQueue.h; sourceTree = SOURCE_ROOT; }; + 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiBufferReadQueue.cpp; path = ../common/JackMidiBufferReadQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiBufferReadQueue.h; path = ../common/JackMidiBufferReadQueue.h; sourceTree = SOURCE_ROOT; }; + 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiBufferWriteQueue.cpp; path = ../common/JackMidiBufferWriteQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiBufferWriteQueue.h; path = ../common/JackMidiBufferWriteQueue.h; sourceTree = SOURCE_ROOT; }; + 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiReceiveQueue.cpp; path = ../common/JackMidiReceiveQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiReceiveQueue.h; path = ../common/JackMidiReceiveQueue.h; sourceTree = SOURCE_ROOT; }; + 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiSendQueue.cpp; path = ../common/JackMidiSendQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B193976133F31CB00547810 /* JackMidiSendQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiSendQueue.h; path = ../common/JackMidiSendQueue.h; sourceTree = SOURCE_ROOT; }; + 4B193977133F31CB00547810 /* JackMidiUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiUtil.cpp; path = ../common/JackMidiUtil.cpp; sourceTree = SOURCE_ROOT; }; + 4B193978133F31CB00547810 /* JackMidiUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiUtil.h; path = ../common/JackMidiUtil.h; sourceTree = SOURCE_ROOT; }; + 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiWriteQueue.cpp; path = ../common/JackMidiWriteQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiWriteQueue.h; path = ../common/JackMidiWriteQueue.h; sourceTree = SOURCE_ROOT; }; + 4B193990133F321500547810 /* JackFilters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackFilters.h; path = ../common/JackFilters.h; sourceTree = SOURCE_ROOT; }; 4B19B3000E23620F00DD4A82 /* audioadapter.so */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = audioadapter.so; sourceTree = BUILT_PRODUCTS_DIR; }; 4B19B3060E2362E700DD4A82 /* JackAudioAdapter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackAudioAdapter.cpp; path = ../common/JackAudioAdapter.cpp; sourceTree = SOURCE_ROOT; }; 4B19B3070E2362E700DD4A82 /* JackAudioAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackAudioAdapter.h; path = ../common/JackAudioAdapter.h; sourceTree = SOURCE_ROOT; }; @@ -1466,6 +1553,8 @@ 4B19B30E0E2362E700DD4A82 /* JackLibSampleRateResampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackLibSampleRateResampler.cpp; path = ../common/JackLibSampleRateResampler.cpp; sourceTree = SOURCE_ROOT; }; 4B19B30F0E2362E700DD4A82 /* JackLibSampleRateResampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackLibSampleRateResampler.h; path = ../common/JackLibSampleRateResampler.h; sourceTree = SOURCE_ROOT; }; 4B19B3120E2362E700DD4A82 /* JackResampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackResampler.cpp; path = ../common/JackResampler.cpp; sourceTree = SOURCE_ROOT; }; + 4B2021E6133A9BA40019E213 /* jack_midi_latency_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_midi_latency_test; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B202209133A9C1C0019E213 /* midi_latency_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = midi_latency_test.c; path = "../example-clients/midi_latency_test.c"; sourceTree = SOURCE_ROOT; }; 4B2C28F908DAD01E00249230 /* JackGlobals.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackGlobals.cpp; path = ../common/JackGlobals.cpp; sourceTree = SOURCE_ROOT; }; 4B3224E510A3156800838A8E /* jack_netone.so */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = jack_netone.so; sourceTree = BUILT_PRODUCTS_DIR; }; 4B3224E810A315B100838A8E /* JackNetOneDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackNetOneDriver.cpp; path = ../common/JackNetOneDriver.cpp; sourceTree = SOURCE_ROOT; }; @@ -1478,6 +1567,29 @@ 4B32256110A3187800838A8E /* jack_netsource */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_netsource; sourceTree = BUILT_PRODUCTS_DIR; }; 4B32256310A318E300838A8E /* netsource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = netsource.c; path = "../example-clients/netsource.c"; sourceTree = SOURCE_ROOT; }; 4B32257B10A3190C00838A8E /* jack_netsource */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_netsource; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B349826133A6AF500D130AB /* JackALSARawMidiDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackALSARawMidiDriver.cpp; path = ../linux/alsarawmidi/JackALSARawMidiDriver.cpp; sourceTree = SOURCE_ROOT; }; + 4B349827133A6AF500D130AB /* JackALSARawMidiDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackALSARawMidiDriver.h; path = ../linux/alsarawmidi/JackALSARawMidiDriver.h; sourceTree = SOURCE_ROOT; }; + 4B349828133A6AF500D130AB /* JackALSARawMidiInputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackALSARawMidiInputPort.cpp; path = ../linux/alsarawmidi/JackALSARawMidiInputPort.cpp; sourceTree = SOURCE_ROOT; }; + 4B349829133A6AF500D130AB /* JackALSARawMidiInputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackALSARawMidiInputPort.h; path = ../linux/alsarawmidi/JackALSARawMidiInputPort.h; sourceTree = SOURCE_ROOT; }; + 4B34982A133A6AF500D130AB /* JackALSARawMidiOutputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackALSARawMidiOutputPort.cpp; path = ../linux/alsarawmidi/JackALSARawMidiOutputPort.cpp; sourceTree = SOURCE_ROOT; }; + 4B34982B133A6AF500D130AB /* JackALSARawMidiOutputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackALSARawMidiOutputPort.h; path = ../linux/alsarawmidi/JackALSARawMidiOutputPort.h; sourceTree = SOURCE_ROOT; }; + 4B34982C133A6AF500D130AB /* JackALSARawMidiPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackALSARawMidiPort.cpp; path = ../linux/alsarawmidi/JackALSARawMidiPort.cpp; sourceTree = SOURCE_ROOT; }; + 4B34982D133A6AF500D130AB /* JackALSARawMidiPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackALSARawMidiPort.h; path = ../linux/alsarawmidi/JackALSARawMidiPort.h; sourceTree = SOURCE_ROOT; }; + 4B34982E133A6AF500D130AB /* JackALSARawMidiReceiveQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackALSARawMidiReceiveQueue.cpp; path = ../linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B34982F133A6AF500D130AB /* JackALSARawMidiReceiveQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackALSARawMidiReceiveQueue.h; path = ../linux/alsarawmidi/JackALSARawMidiReceiveQueue.h; sourceTree = SOURCE_ROOT; }; + 4B349830133A6AF500D130AB /* JackALSARawMidiSendQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackALSARawMidiSendQueue.cpp; path = ../linux/alsarawmidi/JackALSARawMidiSendQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B349831133A6AF500D130AB /* JackALSARawMidiSendQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackALSARawMidiSendQueue.h; path = ../linux/alsarawmidi/JackALSARawMidiSendQueue.h; sourceTree = SOURCE_ROOT; }; + 4B349838133A6B6F00D130AB /* ffado_driver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ffado_driver.h; path = ../linux/firewire/ffado_driver.h; sourceTree = SOURCE_ROOT; }; + 4B349839133A6B6F00D130AB /* JackFFADODriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackFFADODriver.cpp; path = ../linux/firewire/JackFFADODriver.cpp; sourceTree = SOURCE_ROOT; }; + 4B34983A133A6B6F00D130AB /* JackFFADODriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackFFADODriver.h; path = ../linux/firewire/JackFFADODriver.h; sourceTree = SOURCE_ROOT; }; + 4B34983B133A6B6F00D130AB /* JackFFADOMidiInputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackFFADOMidiInputPort.cpp; path = ../linux/firewire/JackFFADOMidiInputPort.cpp; sourceTree = SOURCE_ROOT; }; + 4B34983C133A6B6F00D130AB /* JackFFADOMidiInputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackFFADOMidiInputPort.h; path = ../linux/firewire/JackFFADOMidiInputPort.h; sourceTree = SOURCE_ROOT; }; + 4B34983D133A6B6F00D130AB /* JackFFADOMidiOutputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackFFADOMidiOutputPort.cpp; path = ../linux/firewire/JackFFADOMidiOutputPort.cpp; sourceTree = SOURCE_ROOT; }; + 4B34983E133A6B6F00D130AB /* JackFFADOMidiOutputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackFFADOMidiOutputPort.h; path = ../linux/firewire/JackFFADOMidiOutputPort.h; sourceTree = SOURCE_ROOT; }; + 4B34983F133A6B6F00D130AB /* JackFFADOMidiReceiveQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackFFADOMidiReceiveQueue.cpp; path = ../linux/firewire/JackFFADOMidiReceiveQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B349840133A6B6F00D130AB /* JackFFADOMidiReceiveQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackFFADOMidiReceiveQueue.h; path = ../linux/firewire/JackFFADOMidiReceiveQueue.h; sourceTree = SOURCE_ROOT; }; + 4B349841133A6B6F00D130AB /* JackFFADOMidiSendQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackFFADOMidiSendQueue.cpp; path = ../linux/firewire/JackFFADOMidiSendQueue.cpp; sourceTree = SOURCE_ROOT; }; + 4B349842133A6B6F00D130AB /* JackFFADOMidiSendQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackFFADOMidiSendQueue.h; path = ../linux/firewire/JackFFADOMidiSendQueue.h; sourceTree = SOURCE_ROOT; }; 4B35C4250D4731D1000DE7AE /* jackdmp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jackdmp; sourceTree = BUILT_PRODUCTS_DIR; }; 4B35C4830D4731D1000DE7AE /* Jackmp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Jackmp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4B35C4FC0D4731D1000DE7AE /* Jackservermp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Jackservermp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1518,6 +1630,22 @@ 4B363F3D0DEB0C31001F72D9 /* showtime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = showtime.c; path = "../example-clients/showtime.c"; sourceTree = SOURCE_ROOT; }; 4B363F720DEB0D4E001F72D9 /* jack_impulse_grabber */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_impulse_grabber; sourceTree = BUILT_PRODUCTS_DIR; }; 4B363F750DEB0D7D001F72D9 /* impulse_grabber.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = impulse_grabber.c; path = "../example-clients/impulse_grabber.c"; sourceTree = SOURCE_ROOT; }; + 4B370A14133DD7E200237B68 /* JackCoreMidiInputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiInputPort.cpp; path = ../../coremidi/JackCoreMidiInputPort.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A15133DD7E200237B68 /* JackCoreMidiInputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiInputPort.h; path = ../../coremidi/JackCoreMidiInputPort.h; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A16133DD7E200237B68 /* JackCoreMidiOutputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiOutputPort.cpp; path = ../../coremidi/JackCoreMidiOutputPort.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A17133DD7E200237B68 /* JackCoreMidiOutputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiOutputPort.h; path = ../../coremidi/JackCoreMidiOutputPort.h; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A18133DD7E200237B68 /* JackCoreMidiPhysicalInputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiPhysicalInputPort.cpp; path = ../../coremidi/JackCoreMidiPhysicalInputPort.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A19133DD7E200237B68 /* JackCoreMidiPhysicalInputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiPhysicalInputPort.h; path = ../../coremidi/JackCoreMidiPhysicalInputPort.h; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A1A133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiPhysicalOutputPort.cpp; path = ../../coremidi/JackCoreMidiPhysicalOutputPort.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A1B133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiPhysicalOutputPort.h; path = ../../coremidi/JackCoreMidiPhysicalOutputPort.h; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A1C133DD7E300237B68 /* JackCoreMidiPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiPort.cpp; path = ../../coremidi/JackCoreMidiPort.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A1D133DD7E300237B68 /* JackCoreMidiPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiPort.h; path = ../../coremidi/JackCoreMidiPort.h; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A1E133DD7E300237B68 /* JackCoreMidiUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiUtil.cpp; path = ../../coremidi/JackCoreMidiUtil.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A1F133DD7E300237B68 /* JackCoreMidiUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiUtil.h; path = ../../coremidi/JackCoreMidiUtil.h; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A20133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiVirtualInputPort.cpp; path = ../../coremidi/JackCoreMidiVirtualInputPort.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A21133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiVirtualInputPort.h; path = ../../coremidi/JackCoreMidiVirtualInputPort.h; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A22133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiVirtualOutputPort.cpp; path = ../../coremidi/JackCoreMidiVirtualOutputPort.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B370A23133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiVirtualOutputPort.h; path = ../../coremidi/JackCoreMidiVirtualOutputPort.h; sourceTree = BUILT_PRODUCTS_DIR; }; 4B37C20306DF1FBE0016E567 /* CALatencyLog.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CALatencyLog.cpp; path = /Developer/Examples/CoreAudio/PublicUtility/CALatencyLog.cpp; sourceTree = ""; }; 4B37C20406DF1FBE0016E567 /* CALatencyLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CALatencyLog.h; path = /Developer/Examples/CoreAudio/PublicUtility/CALatencyLog.h; sourceTree = ""; }; 4B37C20906DF1FE20016E567 /* latency.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = latency.c; path = /Developer/Examples/CoreAudio/PublicUtility/latency.c; sourceTree = ""; }; @@ -1642,10 +1770,6 @@ 4BC3B6B90E703BCC0066E42F /* JackNetUnixSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackNetUnixSocket.cpp; path = ../posix/JackNetUnixSocket.cpp; sourceTree = SOURCE_ROOT; }; 4BC3B6BA0E703BCC0066E42F /* JackNetUnixSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackNetUnixSocket.h; path = ../posix/JackNetUnixSocket.h; sourceTree = SOURCE_ROOT; }; 4BC8326D0DF42C7D00DD1C93 /* JackMutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMutex.h; path = ../common/JackMutex.h; sourceTree = SOURCE_ROOT; }; - 4BCBCE5910C4FE3F00450FFE /* JackPhysicalMidiInput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackPhysicalMidiInput.cpp; path = ../common/JackPhysicalMidiInput.cpp; sourceTree = SOURCE_ROOT; }; - 4BCBCE5A10C4FE3F00450FFE /* JackPhysicalMidiInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackPhysicalMidiInput.h; path = ../common/JackPhysicalMidiInput.h; sourceTree = SOURCE_ROOT; }; - 4BCBCE5B10C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackPhysicalMidiOutput.cpp; path = ../common/JackPhysicalMidiOutput.cpp; sourceTree = SOURCE_ROOT; }; - 4BCBCE5C10C4FE3F00450FFE /* JackPhysicalMidiOutput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackPhysicalMidiOutput.h; path = ../common/JackPhysicalMidiOutput.h; sourceTree = SOURCE_ROOT; }; 4BCC87950D57168300A7FEB1 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = /System/Library/Frameworks/Accelerate.framework; sourceTree = ""; }; 4BD4B4D409BACD9600750C0F /* JackTransportEngine.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackTransportEngine.h; path = ../common/JackTransportEngine.h; sourceTree = SOURCE_ROOT; }; 4BD4B4D509BACD9600750C0F /* JackTransportEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackTransportEngine.cpp; path = ../common/JackTransportEngine.cpp; sourceTree = SOURCE_ROOT; }; @@ -1783,6 +1907,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4B2021E0133A9BA40019E213 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4B3224E010A3156800838A8E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2559,6 +2690,7 @@ 4B3811971326884E00C61B14 /* jack_latent_client */, 4B8F16E513290DC80002AD73 /* jack_midi_dump */, 4B8F16F213290E0E0002AD73 /* jack_midi_dump */, + 4B2021E6133A9BA40019E213 /* jack_midi_latency_test */, ); name = Products; sourceTree = ""; @@ -2566,6 +2698,7 @@ 4B03383E0797E19900686131 /* Simple clients */ = { isa = PBXGroup; children = ( + 4B202209133A9C1C0019E213 /* midi_latency_test.c */, 4B8F16F41329161E0002AD73 /* midi_dump.c */, 4B3811FA13269C8300C61B14 /* latent_client.c */, 4B6654FB127C350100753A79 /* server_control.cpp */, @@ -2595,9 +2728,10 @@ 4B05A0420DF72B8500840F4C /* Linux */ = { isa = PBXGroup; children = ( + 4B349837133A6B6F00D130AB /* firewire */, + 4B349825133A6AF500D130AB /* alsarawmidi */, 4B05A04C0DF72BC000840F4C /* alsa */, 4B05A07D0DF72BC000840F4C /* driver.h */, - 4B05A07E0DF72BC000840F4C /* firewire */, 4B05A0820DF72BC000840F4C /* freebob */, ); name = Linux; @@ -2634,17 +2768,6 @@ path = ../linux/alsa; sourceTree = SOURCE_ROOT; }; - 4B05A07E0DF72BC000840F4C /* firewire */ = { - isa = PBXGroup; - children = ( - 4B05A07F0DF72BC000840F4C /* ffado_driver.h */, - 4B05A0800DF72BC000840F4C /* JackFFADODriver.cpp */, - 4B05A0810DF72BC000840F4C /* JackFFADODriver.h */, - ); - name = firewire; - path = ../linux/firewire; - sourceTree = SOURCE_ROOT; - }; 4B05A0820DF72BC000840F4C /* freebob */ = { isa = PBXGroup; children = ( @@ -2709,6 +2832,45 @@ name = Adapter; sourceTree = ""; }; + 4B349825133A6AF500D130AB /* alsarawmidi */ = { + isa = PBXGroup; + children = ( + 4B349826133A6AF500D130AB /* JackALSARawMidiDriver.cpp */, + 4B349827133A6AF500D130AB /* JackALSARawMidiDriver.h */, + 4B349828133A6AF500D130AB /* JackALSARawMidiInputPort.cpp */, + 4B349829133A6AF500D130AB /* JackALSARawMidiInputPort.h */, + 4B34982A133A6AF500D130AB /* JackALSARawMidiOutputPort.cpp */, + 4B34982B133A6AF500D130AB /* JackALSARawMidiOutputPort.h */, + 4B34982C133A6AF500D130AB /* JackALSARawMidiPort.cpp */, + 4B34982D133A6AF500D130AB /* JackALSARawMidiPort.h */, + 4B34982E133A6AF500D130AB /* JackALSARawMidiReceiveQueue.cpp */, + 4B34982F133A6AF500D130AB /* JackALSARawMidiReceiveQueue.h */, + 4B349830133A6AF500D130AB /* JackALSARawMidiSendQueue.cpp */, + 4B349831133A6AF500D130AB /* JackALSARawMidiSendQueue.h */, + ); + name = alsarawmidi; + path = ../linux/alsarawmidi; + sourceTree = SOURCE_ROOT; + }; + 4B349837133A6B6F00D130AB /* firewire */ = { + isa = PBXGroup; + children = ( + 4B349838133A6B6F00D130AB /* ffado_driver.h */, + 4B349839133A6B6F00D130AB /* JackFFADODriver.cpp */, + 4B34983A133A6B6F00D130AB /* JackFFADODriver.h */, + 4B34983B133A6B6F00D130AB /* JackFFADOMidiInputPort.cpp */, + 4B34983C133A6B6F00D130AB /* JackFFADOMidiInputPort.h */, + 4B34983D133A6B6F00D130AB /* JackFFADOMidiOutputPort.cpp */, + 4B34983E133A6B6F00D130AB /* JackFFADOMidiOutputPort.h */, + 4B34983F133A6B6F00D130AB /* JackFFADOMidiReceiveQueue.cpp */, + 4B349840133A6B6F00D130AB /* JackFFADOMidiReceiveQueue.h */, + 4B349841133A6B6F00D130AB /* JackFFADOMidiSendQueue.cpp */, + 4B349842133A6B6F00D130AB /* JackFFADOMidiSendQueue.h */, + ); + name = firewire; + path = ../linux/firewire; + sourceTree = SOURCE_ROOT; + }; 4B37C20006DF1F900016E567 /* Latency */ = { isa = PBXGroup; children = ( @@ -2889,6 +3051,7 @@ 4BA550FB05E2420000569492 /* Engine */ = { isa = PBXGroup; children = ( + 4B193990133F321500547810 /* JackFilters.h */, 4B5F253D0DEE9B8F0041E486 /* JackLockedEngine.h */, 4BF8D2130834F02800C94B91 /* JackEngine.h */, 4BF8D2140834F02800C94B91 /* JackEngine.cpp */, @@ -2994,10 +3157,40 @@ 4BF3390D0F8B86AF0080FB5B /* MIDI */ = { isa = PBXGroup; children = ( - 4BCBCE5910C4FE3F00450FFE /* JackPhysicalMidiInput.cpp */, - 4BCBCE5A10C4FE3F00450FFE /* JackPhysicalMidiInput.h */, - 4BCBCE5B10C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp */, - 4BCBCE5C10C4FE3F00450FFE /* JackPhysicalMidiOutput.h */, + 4B193973133F31CB00547810 /* JackMidiReceiveQueue.cpp */, + 4B193974133F31CB00547810 /* JackMidiReceiveQueue.h */, + 4B193975133F31CB00547810 /* JackMidiSendQueue.cpp */, + 4B193976133F31CB00547810 /* JackMidiSendQueue.h */, + 4B193977133F31CB00547810 /* JackMidiUtil.cpp */, + 4B193978133F31CB00547810 /* JackMidiUtil.h */, + 4B193979133F31CB00547810 /* JackMidiWriteQueue.cpp */, + 4B19397A133F31CB00547810 /* JackMidiWriteQueue.h */, + 4B193968133F319000547810 /* JackMidiBufferWriteQueue.cpp */, + 4B193969133F319000547810 /* JackMidiBufferWriteQueue.h */, + 4B19395D133F317300547810 /* JackMidiBufferReadQueue.cpp */, + 4B19395E133F317300547810 /* JackMidiBufferReadQueue.h */, + 4B193945133F315200547810 /* JackMidiReadQueue.cpp */, + 4B193946133F315200547810 /* JackMidiReadQueue.h */, + 4B19393B133F313000547810 /* JackMidiAsyncWaitQueue.cpp */, + 4B19393C133F313000547810 /* JackMidiAsyncWaitQueue.h */, + 4B193931133F311400547810 /* JackMidiAsyncQueue.cpp */, + 4B193932133F311400547810 /* JackMidiAsyncQueue.h */, + 4B370A14133DD7E200237B68 /* JackCoreMidiInputPort.cpp */, + 4B370A15133DD7E200237B68 /* JackCoreMidiInputPort.h */, + 4B370A16133DD7E200237B68 /* JackCoreMidiOutputPort.cpp */, + 4B370A17133DD7E200237B68 /* JackCoreMidiOutputPort.h */, + 4B370A18133DD7E200237B68 /* JackCoreMidiPhysicalInputPort.cpp */, + 4B370A19133DD7E200237B68 /* JackCoreMidiPhysicalInputPort.h */, + 4B370A1A133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.cpp */, + 4B370A1B133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.h */, + 4B370A1C133DD7E300237B68 /* JackCoreMidiPort.cpp */, + 4B370A1D133DD7E300237B68 /* JackCoreMidiPort.h */, + 4B370A1E133DD7E300237B68 /* JackCoreMidiUtil.cpp */, + 4B370A1F133DD7E300237B68 /* JackCoreMidiUtil.h */, + 4B370A20133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp */, + 4B370A21133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h */, + 4B370A22133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp */, + 4B370A23133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h */, 4BF3391F0F8B873E0080FB5B /* JackMidiDriver.cpp */, 4BF339200F8B873E0080FB5B /* JackMidiDriver.h */, 4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */, @@ -3086,6 +3279,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4B2021DD133A9BA40019E213 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4B3224D810A3156800838A8E /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -3181,6 +3381,7 @@ 4B8A38F0117B827900664E07 /* JackSocket.h in Headers */, 4B8A38F7117B82B200664E07 /* JackSocketClientChannel.h in Headers */, 4B5160A813215E8B00BB7DCB /* systemdeps.h in Headers */, + 4B193993133F321500547810 /* JackFilters.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3243,8 +3444,6 @@ 4BF339220F8B873E0080FB5B /* JackMidiDriver.h in Headers */, 4BDCDBD21001FD0200B15929 /* JackWaitThreadedDriver.h in Headers */, 4BDCDC0A1001FDA800B15929 /* JackArgParser.h in Headers */, - 4BCBCE6210C4FE3F00450FFE /* JackPhysicalMidiInput.h in Headers */, - 4BCBCE6410C4FE3F00450FFE /* JackPhysicalMidiOutput.h in Headers */, 4B88D04311298BEE007A87C1 /* weakjack.h in Headers */, 4B88D04411298BEE007A87C1 /* weakmacros.h in Headers */, 4BC2CA5A113C6CB80076717C /* JackNetInterface.h in Headers */, @@ -3254,6 +3453,16 @@ 4B8A38B0117B812500664E07 /* JackSocketServerChannel.h in Headers */, 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; }; @@ -3549,6 +3758,7 @@ 4B88D04111298BEE007A87C1 /* weakjack.h in Headers */, 4B88D04211298BEE007A87C1 /* weakmacros.h in Headers */, 4B5160A913215EBF00BB7DCB /* systemdeps.h in Headers */, + 4B193994133F321500547810 /* JackFilters.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3640,6 +3850,7 @@ 4B88D03C11298BEE007A87C1 /* weakmacros.h in Headers */, 4B2209ED12F6BC2200E5DC26 /* JackSocket.h in Headers */, 4B2209EF12F6BC2500E5DC26 /* JackSocketClientChannel.h in Headers */, + 4B193991133F321500547810 /* JackFilters.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3706,8 +3917,6 @@ 4BECB2F60F4451C10091B70A /* JackProcessSync.h in Headers */, 4BF339240F8B873E0080FB5B /* JackMidiDriver.h in Headers */, 4B94334B10A5E666002A187F /* systemdeps.h in Headers */, - 4BCBCE5E10C4FE3F00450FFE /* JackPhysicalMidiInput.h in Headers */, - 4BCBCE6010C4FE3F00450FFE /* JackPhysicalMidiOutput.h in Headers */, 4B88D03D11298BEE007A87C1 /* weakjack.h in Headers */, 4B88D03E11298BEE007A87C1 /* weakmacros.h in Headers */, 4BC2CA56113C6C940076717C /* JackNetInterface.h in Headers */, @@ -3716,6 +3925,16 @@ 4B2209E412F6BBF600E5DC26 /* JackSocketServerNotifyChannel.h in Headers */, 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; }; @@ -3901,13 +4120,12 @@ 4BA3396D10B2E36800190E3B /* JackMidiDriver.h in Headers */, 4BA3396E10B2E36800190E3B /* JackWaitThreadedDriver.h in Headers */, 4BA3396F10B2E36800190E3B /* JackArgParser.h in Headers */, - 4BCBCE6610C4FE3F00450FFE /* JackPhysicalMidiInput.h in Headers */, - 4BCBCE6810C4FE3F00450FFE /* JackPhysicalMidiOutput.h in Headers */, 4B88D04511298BEE007A87C1 /* weakjack.h in Headers */, 4B88D04611298BEE007A87C1 /* weakmacros.h in Headers */, 4BC2CA5E113C6CCA0076717C /* JackNetInterface.h in Headers */, 4BC2CA60113C6CD20076717C /* JackNetUnixSocket.h in Headers */, 4B5160AE13215EF900BB7DCB /* systemdeps.h in Headers */, + 4B193996133F321500547810 /* JackFilters.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3944,6 +4162,14 @@ buildActionMask = 2147483647; files = ( 4BDCDB951001FB9C00B15929 /* JackCoreMidiDriver.h in Headers */, + 4B370A35133DD7E300237B68 /* JackCoreMidiInputPort.h in Headers */, + 4B370A37133DD7E300237B68 /* JackCoreMidiOutputPort.h in Headers */, + 4B370A39133DD7E300237B68 /* JackCoreMidiPhysicalInputPort.h in Headers */, + 4B370A3B133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.h in Headers */, + 4B370A3D133DD7E300237B68 /* JackCoreMidiPort.h in Headers */, + 4B370A3F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */, + 4B370A41133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */, + 4B370A43133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4004,6 +4230,14 @@ buildActionMask = 2147483647; files = ( 4BF3391A0F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */, + 4B370A25133DD7E300237B68 /* JackCoreMidiInputPort.h in Headers */, + 4B370A27133DD7E300237B68 /* JackCoreMidiOutputPort.h in Headers */, + 4B370A29133DD7E300237B68 /* JackCoreMidiPhysicalInputPort.h in Headers */, + 4B370A2B133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.h in Headers */, + 4B370A2D133DD7E300237B68 /* JackCoreMidiPort.h in Headers */, + 4B370A2F133DD7E300237B68 /* JackCoreMidiUtil.h in Headers */, + 4B370A31133DD7E300237B68 /* JackCoreMidiVirtualInputPort.h in Headers */, + 4B370A33133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4137,6 +4371,25 @@ productReference = 4B19B3000E23620F00DD4A82 /* audioadapter.so */; productType = "com.apple.product-type.library.dynamic"; }; + 4B2021DC133A9BA40019E213 /* jack_midi_latency 64 bits */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4B2021E2133A9BA40019E213 /* Build configuration list for PBXNativeTarget "jack_midi_latency 64 bits" */; + buildPhases = ( + 4B2021DD133A9BA40019E213 /* Headers */, + 4B2021DE133A9BA40019E213 /* Sources */, + 4B2021E0133A9BA40019E213 /* Frameworks */, + 4B2021E1133A9BA40019E213 /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "jack_midi_latency 64 bits"; + productInstallPath = /usr/local/bin; + productName = jack_metro; + productReference = 4B2021E6133A9BA40019E213 /* jack_midi_latency_test */; + productType = "com.apple.product-type.tool"; + }; 4B3224D710A3156800838A8E /* jack_netone Universal */ = { isa = PBXNativeTarget; buildConfigurationList = 4B3224E110A3156800838A8E /* Build configuration list for PBXNativeTarget "jack_netone Universal" */; @@ -5864,6 +6117,7 @@ 4B35C50A0D4731D1000DE7AE /* jack_midiseq 64 bits */, 4B35C5160D4731D1000DE7AE /* jack_midisine 64 bits */, 4B8F16E813290E0E0002AD73 /* jack_midi_dump 64 bits */, + 4B2021DC133A9BA40019E213 /* jack_midi_latency 64 bits */, 4B35C5220D4731D1000DE7AE /* jack_metro 64 bits */, 4B35C52E0D4731D1000DE7AE /* jack_lsp 64 bits */, 4B35C53A0D4731D1000DE7AE /* jack_connect 64 bits */, @@ -5966,6 +6220,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4B2021E1133A9BA40019E213 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4B32255C10A3187800838A8E /* Rez */ = { isa = PBXRezBuildPhase; buildActionMask = 2147483647; @@ -6474,6 +6735,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4B2021DE133A9BA40019E213 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4B20220A133A9C1C0019E213 /* midi_latency_test.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4B3224DC10A3156800838A8E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -6610,14 +6879,21 @@ 4BF339210F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */, 4BDCDBD11001FD0100B15929 /* JackWaitThreadedDriver.cpp in Sources */, 4BDCDC091001FDA800B15929 /* JackArgParser.cpp in Sources */, - 4BCBCE6110C4FE3F00450FFE /* JackPhysicalMidiInput.cpp in Sources */, - 4BCBCE6310C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp in Sources */, 4BC2CA59113C6CB60076717C /* JackNetInterface.cpp in Sources */, 4BC2CA5B113C6CBE0076717C /* JackNetUnixSocket.cpp in Sources */, 4B8A38A7117B80D300664E07 /* JackSocket.cpp in Sources */, 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; }; @@ -7064,14 +7340,21 @@ 4BBAE4110F42FA6100B8BD3F /* JackEngineProfiling.cpp in Sources */, 4BECB2F50F4451C10091B70A /* JackProcessSync.cpp in Sources */, 4BF339230F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */, - 4BCBCE5D10C4FE3F00450FFE /* JackPhysicalMidiInput.cpp in Sources */, - 4BCBCE5F10C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp in Sources */, 4BC2CA55113C6C930076717C /* JackNetInterface.cpp in Sources */, 4BC2CA57113C6C9B0076717C /* JackNetUnixSocket.cpp in Sources */, 4B2209E112F6BBF300E5DC26 /* JackSocketServerChannel.cpp in Sources */, 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; }; @@ -7260,8 +7543,6 @@ 4BA339A210B2E36800190E3B /* JackMidiDriver.cpp in Sources */, 4BA339A310B2E36800190E3B /* JackWaitThreadedDriver.cpp in Sources */, 4BA339A410B2E36800190E3B /* JackArgParser.cpp in Sources */, - 4BCBCE6510C4FE3F00450FFE /* JackPhysicalMidiInput.cpp in Sources */, - 4BCBCE6710C4FE3F00450FFE /* JackPhysicalMidiOutput.cpp in Sources */, 4BC2CA5D113C6CC90076717C /* JackNetInterface.cpp in Sources */, 4BC2CA5F113C6CD10076717C /* JackNetUnixSocket.cpp in Sources */, ); @@ -7304,6 +7585,14 @@ buildActionMask = 2147483647; files = ( 4BDCDB971001FB9C00B15929 /* JackCoreMidiDriver.cpp in Sources */, + 4B370A34133DD7E300237B68 /* JackCoreMidiInputPort.cpp in Sources */, + 4B370A36133DD7E300237B68 /* JackCoreMidiOutputPort.cpp in Sources */, + 4B370A38133DD7E300237B68 /* JackCoreMidiPhysicalInputPort.cpp in Sources */, + 4B370A3A133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.cpp in Sources */, + 4B370A3C133DD7E300237B68 /* JackCoreMidiPort.cpp in Sources */, + 4B370A3E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */, + 4B370A40133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */, + 4B370A42133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -7369,6 +7658,14 @@ buildActionMask = 2147483647; files = ( 4BF3391B0F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */, + 4B370A24133DD7E300237B68 /* JackCoreMidiInputPort.cpp in Sources */, + 4B370A26133DD7E300237B68 /* JackCoreMidiOutputPort.cpp in Sources */, + 4B370A28133DD7E300237B68 /* JackCoreMidiPhysicalInputPort.cpp in Sources */, + 4B370A2A133DD7E300237B68 /* JackCoreMidiPhysicalOutputPort.cpp in Sources */, + 4B370A2C133DD7E300237B68 /* JackCoreMidiPort.cpp in Sources */, + 4B370A2E133DD7E300237B68 /* JackCoreMidiUtil.cpp in Sources */, + 4B370A30133DD7E300237B68 /* JackCoreMidiVirtualInputPort.cpp in Sources */, + 4B370A32133DD7E300237B68 /* JackCoreMidiVirtualOutputPort.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -7470,6 +7767,11 @@ target = 4B19B2F60E23620F00DD4A82 /* audioadapter Universal */; targetProxy = 4B19B32B0E23636E00DD4A82 /* PBXContainerItemProxy */; }; + 4B20220C133A9C370019E213 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4B2021DC133A9BA40019E213 /* jack_midi_latency 64 bits */; + targetProxy = 4B20220B133A9C370019E213 /* PBXContainerItemProxy */; + }; 4B224B340E65BA330066BE5B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4B5E08BF0E5B66EE00BEE4E0 /* netadapter Universal */; @@ -8054,7 +8356,7 @@ OTHER_CFLAGS = ""; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; OTHER_LDFLAGS = ( - /usr/local/lib/libsamplerate.a, + /opt/local/lib/libsamplerate.a, "-framework", Jackservermp, "-framework", @@ -8173,6 +8475,101 @@ }; name = Default; }; + 4B2021E3133A9BA40019E213 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + HEADER_SEARCH_PATHS = ../common; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Jackmp, + "-framework", + CoreFoundation, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = jack_midi_latency_test; + REZ_EXECUTABLE = YES; + SDKROOT = ""; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = YES; + }; + name = Development; + }; + 4B2021E4133A9BA40019E213 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + COPY_PHASE_STRIP = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + HEADER_SEARCH_PATHS = ../common; + MACOSX_DEPLOYMENT_TARGET = 10.4; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Jackmp, + "-framework", + CoreFoundation, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = jack_midi_latency_test; + REZ_EXECUTABLE = YES; + SDKROOT = ""; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = NO; + }; + name = Deployment; + }; + 4B2021E5133A9BA40019E213 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc64, + ppc, + i386, + x86_64, + ); + FRAMEWORK_SEARCH_PATHS = ""; + HEADER_SEARCH_PATHS = ../common; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Jackmp, + "-framework", + CoreFoundation, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = jack_midisine; + REZ_EXECUTABLE = YES; + SDKROOT = ""; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Default; + }; 4B3224E210A3156800838A8E /* Development */ = { isa = XCBuildConfiguration; buildSettings = { @@ -8734,7 +9131,7 @@ ); OTHER_LDFLAGS = ( "-framework", - Jackdmp, + Jackservermp, "-framework", CoreAudio, "-framework", @@ -9105,6 +9502,7 @@ "-D__SMP__", "-DMACH_RPC_MACH_SEMA", "$(OTHER_CPLUSPLUSFLAGS_QUOTED_FOR_TARGET_1)", + "$(OTHER_CPLUSPLUSFLAGS_QUOTED_FOR_TARGET_2)", ); OTHER_CPLUSPLUSFLAGS_QUOTED_FOR_TARGET_1 = "-DADDON_DIR=\\\"/usr/local/lib/jackmp\\\""; OTHER_LDFLAGS = ( @@ -9115,7 +9513,7 @@ CoreAudio, ); OTHER_REZFLAGS = ""; - PRODUCT_NAME = Jackdmp; + PRODUCT_NAME = Jackservermp; REZ_EXECUTABLE = NO; SDKROOT = ""; SECTORDER_FLAGS = ""; @@ -11113,7 +11511,7 @@ OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA"; OTHER_LDFLAGS = ( "-framework", - Jackdmp, + Jackservermp, "-framework", CoreAudio, "-framework", @@ -11263,7 +11661,7 @@ OTHER_LDFLAGS = ( libportaudio.a, "-framework", - Jackdmp, + Jackservermp, "-framework", AudioToolbox, "-framework", @@ -11412,7 +11810,7 @@ OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA"; OTHER_LDFLAGS = ( "-framework", - Jackdmp, + Jackservermp, "-framework", CoreAudio, "-framework", @@ -11550,7 +11948,7 @@ OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; OTHER_LDFLAGS = ( "-framework", - Jackdmp, + Jackservermp, "-framework", CoreAudio, "-framework", @@ -16062,7 +16460,7 @@ CoreAudio, ); OTHER_REZFLAGS = ""; - PRODUCT_NAME = Jackdmp; + PRODUCT_NAME = Jackservermp; REZ_EXECUTABLE = NO; SDKROOT = ""; SECTORDER_FLAGS = ""; @@ -17073,7 +17471,7 @@ OTHER_CFLAGS = ""; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; OTHER_LDFLAGS = ( - /usr/local/lib/libsamplerate.a, + /opt/local/lib/libsamplerate.a, "-framework", Jackservermp, "-framework", @@ -17222,7 +17620,7 @@ OTHER_CFLAGS = ""; OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA"; OTHER_LDFLAGS = ( - /usr/local/lib/libsamplerate.a, + /opt/local/lib/libsamplerate.a, "-framework", Jackservermp, "-framework", @@ -18769,6 +19167,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; + 4B2021E2133A9BA40019E213 /* Build configuration list for PBXNativeTarget "jack_midi_latency 64 bits" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4B2021E3133A9BA40019E213 /* Development */, + 4B2021E4133A9BA40019E213 /* Deployment */, + 4B2021E5133A9BA40019E213 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; 4B3224E110A3156800838A8E /* Build configuration list for PBXNativeTarget "jack_netone Universal" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/macosx/coreaudio/JackCoreAudioAdapter.cpp b/macosx/coreaudio/JackCoreAudioAdapter.cpp index c1e9dc5e..f77a5e3a 100644 --- a/macosx/coreaudio/JackCoreAudioAdapter.cpp +++ b/macosx/coreaudio/JackCoreAudioAdapter.cpp @@ -168,7 +168,7 @@ OSStatus JackCoreAudioAdapter::SRNotificationCallback(AudioDeviceID inDevice, switch (inPropertyID) { case kAudioDevicePropertyNominalSampleRate: { - jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate"); + jack_log("JackCoreAudioAdapter::SRNotificationCallback kAudioDevicePropertyNominalSampleRate"); driver->fState = true; break; } @@ -430,12 +430,15 @@ OSStatus JackCoreAudioAdapter::GetDefaultDevice(AudioDeviceID* id) jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault); // Get the device only if default input and output are the same - if (inDefault == outDefault) { - *id = inDefault; - return noErr; - } else { + if (inDefault != outDefault) { jack_error("Default input and output devices are not the same !!"); return kAudioHardwareBadDeviceError; + } else if (inDefault == 0) { + jack_error("Default input and output devices are null !!"); + return kAudioHardwareBadDeviceError; + } else { + *id = inDefault; + return noErr; } } @@ -444,20 +447,16 @@ OSStatus JackCoreAudioAdapter::GetTotalChannels(AudioDeviceID device, int& chann OSStatus err = noErr; UInt32 outSize; Boolean outWritable; - AudioBufferList* bufferList = 0; channelCount = 0; err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable); if (err == noErr) { - bufferList = (AudioBufferList*)malloc(outSize); + AudioBufferList bufferList[outSize]; err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList); if (err == noErr) { for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++) channelCount += bufferList->mBuffers[i].mNumberChannels; } - - if (bufferList) - free(bufferList); } return err; @@ -604,7 +603,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, // Use default driver in duplex mode } else { - jack_log("JackCoreAudioDriver::Open default driver"); + jack_log("JackCoreAudioAdapter::Open default driver"); if (GetDefaultDevice(&fDeviceID) != noErr) { jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); @@ -1030,14 +1029,14 @@ OSStatus JackCoreAudioAdapter::DestroyAggregateDevice() osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); + jack_error("JackCoreAudioAdapter::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); printError(osErr); return osErr; } osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); + jack_error("JackCoreAudioAdapter::DestroyAggregateDevice : AudioObjectGetPropertyData error"); printError(osErr); return osErr; } @@ -1115,18 +1114,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca for (UInt32 i = 0; i < captureDeviceID.size(); i++) { if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : cannot set SR of input device"); } else { // Check clock domain osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); if (osErr != 0) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); printError(osErr); } else { keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; - jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); + jack_log("JackCoreAudioAdapter::CreateAggregateDevice : input clockdomain = %d", clockdomain); if (clockdomain != 0 && clockdomain != keptclockdomain) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); need_clock_drift_compensation = true; } } @@ -1135,18 +1134,18 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : cannot set SR of output device"); } else { // Check clock domain osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); if (osErr != 0) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); printError(osErr); } else { keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; - jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); + jack_log("JackCoreAudioAdapter::CreateAggregateDevice : output clockdomain = %d", clockdomain); if (clockdomain != 0 && clockdomain != keptclockdomain) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); need_clock_drift_compensation = true; } } @@ -1175,7 +1174,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); printError(osErr); return osErr; } @@ -1191,7 +1190,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); printError(osErr); return osErr; } @@ -1218,13 +1217,13 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca SInt32 system; Gestalt(gestaltSystemVersion, &system); - jack_log("JackCoreAudioDriver::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); + jack_log("JackCoreAudioAdapter::CreateAggregateDevice : system version = %x limit = %x", system, 0x00001054); // Starting with 10.5.4 systems, the AD can be internal... (better) if (system < 0x00001054) { - jack_log("JackCoreAudioDriver::CreateAggregateDevice : public aggregate device...."); + jack_log("JackCoreAudioAdapter::CreateAggregateDevice : public aggregate device...."); } else { - jack_log("JackCoreAudioDriver::CreateAggregateDevice : private aggregate device...."); + jack_log("JackCoreAudioAdapter::CreateAggregateDevice : private aggregate device...."); CFDictionaryAddValue(aggDeviceDict, CFSTR(kAudioAggregateDeviceIsPrivateKey), AggregateDeviceNumberRef); } @@ -1306,14 +1305,14 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); printError(osErr); goto error; } osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectGetPropertyData error"); printError(osErr); goto error; } @@ -1332,7 +1331,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca outDataSize = sizeof(CFMutableArrayRef); osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error"); printError(osErr); goto error; } @@ -1352,7 +1351,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca outDataSize = sizeof(CFStringRef); osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]); // First apture is master... if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for master device error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice : AudioObjectSetPropertyData for master device error"); printError(osErr); goto error; } @@ -1370,19 +1369,19 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca // Get the property data size osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); printError(osErr); } // Calculate the number of object IDs subDevicesNum = outSize / sizeof(AudioObjectID); - jack_info("JackCoreAudioDriver::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); + jack_info("JackCoreAudioAdapter::CreateAggregateDevice clock drift compensation, number of sub-devices = %d", subDevicesNum); AudioObjectID subDevices[subDevicesNum]; outSize = sizeof(subDevices); osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); printError(osErr); } @@ -1391,7 +1390,7 @@ OSStatus JackCoreAudioAdapter::CreateAggregateDeviceAux(vector ca UInt32 theDriftCompensationValue = 1; osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue); if (osErr != noErr) { - jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error"); + jack_error("JackCoreAudioAdapter::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error"); printError(osErr); } } @@ -1512,7 +1511,7 @@ extern "C" strcpy(desc->params[i].name, "channels"); desc->params[i].character = 'c'; desc->params[i].type = JackDriverParamInt; - desc->params[i].value.ui = -1; + desc->params[i].value.i = -1; strcpy(desc->params[i].short_desc, "Maximum number of channels"); strcpy(desc->params[i].long_desc, "Maximum number of channels. If -1, max possible number of channels will be used"); @@ -1520,7 +1519,7 @@ extern "C" strcpy(desc->params[i].name, "inchannels"); desc->params[i].character = 'i'; desc->params[i].type = JackDriverParamInt; - desc->params[i].value.ui = -1; + desc->params[i].value.i = -1; strcpy(desc->params[i].short_desc, "Maximum number of input channels"); strcpy(desc->params[i].long_desc, "Maximum number of input channels. If -1, max possible number of input channels will be used"); @@ -1528,7 +1527,7 @@ extern "C" strcpy(desc->params[i].name, "outchannels"); desc->params[i].character = 'o'; desc->params[i].type = JackDriverParamInt; - desc->params[i].value.ui = -1; + desc->params[i].value.i = -1; strcpy(desc->params[i].short_desc, "Maximum number of output channels"); strcpy(desc->params[i].long_desc, "Maximum number of output channels. If -1, max possible number of output channels will be used"); diff --git a/macosx/coreaudio/JackCoreAudioDriver.cpp b/macosx/coreaudio/JackCoreAudioDriver.cpp index 83806646..1c26ce65 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.cpp +++ b/macosx/coreaudio/JackCoreAudioDriver.cpp @@ -195,7 +195,7 @@ OSStatus JackCoreAudioDriver::Render(void *inRefCon, driver->fCurrentTime = (AudioTimeStamp *)inTimeStamp; driver->fDriverOutputData = ioData; - // Setup threadded based log function once... + // Setup threaded based log function et get RT thread parameters once... if (set_threaded_log_function()) { jack_log("set_threaded_log_function"); @@ -216,8 +216,11 @@ OSStatus JackCoreAudioDriver::Render(void *inRefCon, int JackCoreAudioDriver::Read() { - OSStatus err = AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData); - return (err == noErr) ? 0 : -1; + if (fCaptureChannels > 0) { // Calling AudioUnitRender with no input returns a '????' error (callback setting issue ??), so hack to avoid it here... + return (AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData) == noErr) ? 0 : -1; + } else { + return 0; + } } int JackCoreAudioDriver::Write() @@ -386,12 +389,15 @@ OSStatus JackCoreAudioDriver::GetDefaultDevice(AudioDeviceID* id) jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault); // Get the device only if default input and output are the same - if (inDefault == outDefault) { - *id = inDefault; - return noErr; - } else { + if (inDefault != outDefault) { jack_error("Default input and output devices are not the same !!"); return kAudioHardwareBadDeviceError; + } else if (inDefault == 0) { + jack_error("Default input and output devices are null !!"); + return kAudioHardwareBadDeviceError; + } else { + *id = inDefault; + return noErr; } } @@ -1549,7 +1555,6 @@ error: int JackCoreAudioDriver::Close() { jack_log("JackCoreAudioDriver::Close"); - Stop(); // Generic audio driver close int res = JackAudioDriver::Close(); @@ -1561,6 +1566,53 @@ int JackCoreAudioDriver::Close() return res; } +void JackCoreAudioDriver::UpdateLatencies() +{ + UInt32 size; + OSStatus err; + jack_latency_range_t range; + range.max = fEngineControl->fBufferSize; + range.min = fEngineControl->fBufferSize; + + for (int i = 0; i < fCaptureChannels; i++) { + size = sizeof(UInt32); + UInt32 value1 = 0; + UInt32 value2 = 0; + err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1); + if (err != noErr) + jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error"); + err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2); + if (err != noErr) + jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error"); + + range.min = range.max = fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency; + fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &range); + } + + for (int i = 0; i < fPlaybackChannels; i++) { + size = sizeof(UInt32); + UInt32 value1 = 0; + UInt32 value2 = 0; + err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyLatency, &size, &value1); + if (err != noErr) + jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error"); + err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2); + if (err != noErr) + jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error"); + + // Add more latency if "async" mode is used... + range.min = range.max + = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize * fIOUsage) + value1 + value2 + fPlaybackLatency; + fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &range); + + // Monitor port + if (fWithMonitorPorts) { + range.min = range.max = fEngineControl->fBufferSize; + fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &range); + } + } +} + int JackCoreAudioDriver::Attach() { OSStatus err; @@ -1571,7 +1623,6 @@ int JackCoreAudioDriver::Attach() char channel_name[64]; char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; - jack_latency_range_t range; jack_log("JackCoreAudioDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); @@ -1596,20 +1647,8 @@ int JackCoreAudioDriver::Attach() return -1; } - size = sizeof(UInt32); - UInt32 value1 = 0; - UInt32 value2 = 0; - err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertyLatency, &size, &value1); - if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error"); - err = AudioDeviceGetProperty(fDeviceID, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2); - if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error"); - port = fGraphManager->GetPort(port_index); port->SetAlias(alias); - range.min = range.max = fEngineControl->fBufferSize + value1 + value2 + fCaptureLatency; - port->SetLatencyRange(JackCaptureLatency, &range); fCapturePortList[i] = port_index; } @@ -1634,21 +1673,8 @@ int JackCoreAudioDriver::Attach() return -1; } - size = sizeof(UInt32); - UInt32 value1 = 0; - UInt32 value2 = 0; - err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertyLatency, &size, &value1); - if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertyLatency error"); - err = AudioDeviceGetProperty(fDeviceID, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2); - if (err != noErr) - jack_log("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error"); - port = fGraphManager->GetPort(port_index); port->SetAlias(alias); - // Add more latency if "async" mode is used... - range.min = range.max = fEngineControl->fBufferSize + ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize * fIOUsage) + value1 + value2 + fPlaybackLatency; - port->SetLatencyRange(JackPlaybackLatency, &range); fPlaybackPortList[i] = port_index; // Monitor ports @@ -1659,14 +1685,13 @@ int JackCoreAudioDriver::Attach() jack_error("Cannot register monitor port for %s", name); return -1; } else { - port = fGraphManager->GetPort(port_index); - range.min = range.max = fEngineControl->fBufferSize; - port->SetLatencyRange(JackCaptureLatency, &range); fMonitorPortList[i] = port_index; } } } + UpdateLatencies(); + // Input buffers do no change : prepare them only once for (int i = 0; i < fCaptureChannels; i++) { fJackInputData->mBuffers[i].mData = GetInputBuffer(i); @@ -1714,17 +1739,19 @@ int JackCoreAudioDriver::Stop() int JackCoreAudioDriver::SetBufferSize(jack_nframes_t buffer_size) { - OSStatus err; UInt32 outSize = sizeof(UInt32); - err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size); + OSStatus err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &buffer_size); if (err != noErr) { jack_error("Cannot set buffer size %ld", buffer_size); printError(err); return -1; } - JackAudioDriver::SetBufferSize(buffer_size); // never fails + JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails + + // CoreAudio specific + UpdateLatencies(); // Input buffers do no change : prepare them only once for (int i = 0; i < fCaptureChannels; i++) { @@ -1820,7 +1847,7 @@ extern "C" strcpy(desc->params[i].name, "channels"); desc->params[i].character = 'c'; desc->params[i].type = JackDriverParamInt; - desc->params[i].value.ui = -1; + desc->params[i].value.i = -1; strcpy(desc->params[i].short_desc, "Maximum number of channels"); strcpy(desc->params[i].long_desc, "Maximum number of channels. If -1, max possible number of channels will be used"); @@ -1828,7 +1855,7 @@ extern "C" strcpy(desc->params[i].name, "inchannels"); desc->params[i].character = 'i'; desc->params[i].type = JackDriverParamInt; - desc->params[i].value.ui = -1; + desc->params[i].value.i = -1; strcpy(desc->params[i].short_desc, "Maximum number of input channels"); strcpy(desc->params[i].long_desc, "Maximum number of input channels. If -1, max possible number of input channels will be used"); @@ -1836,7 +1863,7 @@ extern "C" strcpy(desc->params[i].name, "outchannels"); desc->params[i].character = 'o'; desc->params[i].type = JackDriverParamInt; - desc->params[i].value.ui = -1; + desc->params[i].value.i = -1; strcpy(desc->params[i].short_desc, "Maximum number of output channels"); strcpy(desc->params[i].long_desc, "Maximum number of output channels. If -1, max possible number of output channels will be used"); @@ -1897,7 +1924,7 @@ extern "C" strcpy(desc->params[i].name, "input-latency"); desc->params[i].character = 'I'; desc->params[i].type = JackDriverParamUInt; - desc->params[i].value.i = 0; + desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Extra input latency (frames)"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -1905,7 +1932,7 @@ extern "C" strcpy(desc->params[i].name, "output-latency"); desc->params[i].character = 'O'; desc->params[i].type = JackDriverParamUInt; - desc->params[i].value.i = 0; + desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Extra output latency (frames)"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -1929,7 +1956,7 @@ extern "C" strcpy(desc->params[i].name, "async-latency"); desc->params[i].character = 'L'; desc->params[i].type = JackDriverParamUInt; - desc->params[i].value.i = 100; + desc->params[i].value.ui = 100; strcpy(desc->params[i].short_desc, "Extra output latency in asynchronous mode (percent)"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -1937,7 +1964,7 @@ extern "C" strcpy(desc->params[i].name, "grain"); desc->params[i].character = 'G'; desc->params[i].type = JackDriverParamUInt; - desc->params[i].value.i = 100; + desc->params[i].value.ui = 100; strcpy(desc->params[i].short_desc, "Computation grain in RT thread (percent)"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); diff --git a/macosx/coreaudio/JackCoreAudioDriver.h b/macosx/coreaudio/JackCoreAudioDriver.h index b0ccbe10..c0513609 100644 --- a/macosx/coreaudio/JackCoreAudioDriver.h +++ b/macosx/coreaudio/JackCoreAudioDriver.h @@ -40,7 +40,7 @@ typedef UInt8 CAAudioHardwareDeviceSectionID; #define kAudioDeviceSectionOutput ((CAAudioHardwareDeviceSectionID)0x00) #define kAudioDeviceSectionGlobal ((CAAudioHardwareDeviceSectionID)0x00) #define kAudioDeviceSectionWildcard ((CAAudioHardwareDeviceSectionID)0xFF) - + #define WAIT_COUNTER 60 /*! @@ -74,13 +74,13 @@ class JackCoreAudioDriver : public JackAudioDriver float fIOUsage; float fComputationGrain; bool fClockDriftCompensate; - - /* + + /* #ifdef MAC_OS_X_VERSION_10_5 AudioDeviceIOProcID fMesureCallbackID; #endif */ - + static OSStatus Render(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, @@ -106,13 +106,13 @@ class JackCoreAudioDriver : public JackAudioDriver OSStatus GetDefaultOutputDevice(AudioDeviceID* id); OSStatus GetDeviceNameFromID(AudioDeviceID id, char* name); OSStatus GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput); - + // Setup OSStatus CreateAggregateDevice(AudioDeviceID captureDeviceID, AudioDeviceID playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice); OSStatus CreateAggregateDeviceAux(vector captureDeviceID, vector playbackDeviceID, jack_nframes_t samplerate, AudioDeviceID* outAggregateDevice); OSStatus DestroyAggregateDevice(); bool IsAggregateDevice(AudioDeviceID device); - + int SetupDevices(const char* capture_driver_uid, const char* playback_driver_uid, char* capture_driver_name, @@ -146,10 +146,12 @@ class JackCoreAudioDriver : public JackAudioDriver int AddListeners(); void RemoveListeners(); - + bool TakeHogAux(AudioDeviceID deviceID, bool isInput); bool TakeHog(); + void UpdateLatencies(); + public: JackCoreAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); diff --git a/macosx/coremidi/JackCoreMidiDriver.cpp b/macosx/coremidi/JackCoreMidiDriver.cpp index 1cb7176b..292e771f 100644 --- a/macosx/coremidi/JackCoreMidiDriver.cpp +++ b/macosx/coremidi/JackCoreMidiDriver.cpp @@ -1,5 +1,6 @@ /* Copyright (C) 2009 Grame +Copyright (C) 2011 Devin Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,345 +18,620 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + +#include + #include "JackCoreMidiDriver.h" -#include "JackGraphManager.h" -#include "JackServer.h" +#include "JackCoreMidiUtil.h" #include "JackEngineControl.h" -#include "JackDriverLoader.h" -#include -#include -#include -#include -#include +using Jack::JackCoreMidiDriver; + +/////////////////////////////////////////////////////////////////////////////// +// Static callbacks +/////////////////////////////////////////////////////////////////////////////// -namespace Jack +void +JackCoreMidiDriver::HandleInputEvent(const MIDIPacketList *packet_list, + void *driver, void *port) { + ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list); +} -static MIDITimeStamp MIDIGetCurrentHostTime() +void +JackCoreMidiDriver::HandleNotificationEvent(const MIDINotification *message, + void *driver) { - return mach_absolute_time(); + ((JackCoreMidiDriver *) driver)->HandleNotification(message); } -void JackCoreMidiDriver::ReadProcAux(const MIDIPacketList *pktlist, jack_ringbuffer_t* ringbuffer) +/////////////////////////////////////////////////////////////////////////////// +// Class +/////////////////////////////////////////////////////////////////////////////// + +JackCoreMidiDriver::JackCoreMidiDriver(const char *name, const char *alias, + JackLockedEngine *engine, + JackSynchro *table): + JackMidiDriver(name, alias, engine, table) { - // Write the number of packets - size_t size = jack_ringbuffer_write_space(ringbuffer); - if (size < sizeof(UInt32)) { - jack_error("ReadProc : ring buffer is full, skip events..."); - return; + mach_timebase_info_data_t info; + kern_return_t result = mach_timebase_info(&info); + if (result != KERN_SUCCESS) { + throw std::runtime_error(mach_error_string(result)); } + client = 0; + fCaptureChannels = 0; + fPlaybackChannels = 0; + num_physical_inputs = 0; + num_physical_outputs = 0; + num_virtual_inputs = 0; + num_virtual_outputs = 0; + physical_input_ports = 0; + physical_output_ports = 0; + time_ratio = (((double) info.numer) / info.denom) / 1000.0; + virtual_input_ports = 0; + virtual_output_ports = 0; +} - jack_ringbuffer_write(ringbuffer, (char*)&pktlist->numPackets, sizeof(UInt32)); +JackCoreMidiDriver::~JackCoreMidiDriver() +{} - for (unsigned int i = 0; i < pktlist->numPackets; ++i) { +int +JackCoreMidiDriver::Attach() +{ + 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; + JackCoreMidiPort *port_obj; + latency_range.max = latency; + latency_range.min = latency; + + // Physical inputs + for (int i = 0; i < num_physical_inputs; i++) { + port_obj = physical_input_ports[i]; + name = port_obj->GetName(); + index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, + JACK_DEFAULT_MIDI_TYPE, + CaptureDriverFlags, buffer_size); + if (index == NO_PORT) { + jack_error("JackCoreMidiDriver::Attach - cannot register physical " + "input port with name '%s'.", name); + // X: Do we need to deallocate ports? + return -1; + } + port = fGraphManager->GetPort(index); + port->SetAlias(port_obj->GetAlias()); + port->SetLatencyRange(JackCaptureLatency, &latency_range); + fCapturePortList[i] = index; + } - MIDIPacket *packet = (MIDIPacket *)pktlist->packet; + // Virtual inputs + for (int i = 0; i < num_virtual_inputs; i++) { + port_obj = virtual_input_ports[i]; + name = port_obj->GetName(); + index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, + JACK_DEFAULT_MIDI_TYPE, + CaptureDriverFlags, buffer_size); + if (index == NO_PORT) { + jack_error("JackCoreMidiDriver::Attach - cannot register virtual " + "input port with name '%s'.", name); + // X: Do we need to deallocate ports? + return -1; + } + port = fGraphManager->GetPort(index); + port->SetAlias(port_obj->GetAlias()); + port->SetLatencyRange(JackCaptureLatency, &latency_range); + fCapturePortList[num_physical_inputs + i] = index; + } - // TODO : use timestamp + if (! fEngineControl->fSyncMode) { + latency += buffer_size; + latency_range.max = latency; + latency_range.min = latency; + } - // Check available size first.. - size = jack_ringbuffer_write_space(ringbuffer); - if (size < (sizeof(UInt16) + packet->length)) { - jack_error("ReadProc : ring buffer is full, skip events..."); - return; + // Physical outputs + for (int i = 0; i < num_physical_outputs; i++) { + port_obj = physical_output_ports[i]; + name = port_obj->GetName(); + index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, + JACK_DEFAULT_MIDI_TYPE, + PlaybackDriverFlags, buffer_size); + if (index == NO_PORT) { + jack_error("JackCoreMidiDriver::Attach - cannot register physical " + "output port with name '%s'.", name); + // X: Do we need to deallocate ports? + return -1; } - // Write length of each packet first - jack_ringbuffer_write(ringbuffer, (char*)&packet->length, sizeof(UInt16)); - // Write event actual data - jack_ringbuffer_write(ringbuffer, (char*)packet->data, packet->length); + port = fGraphManager->GetPort(index); + port->SetAlias(port_obj->GetAlias()); + port->SetLatencyRange(JackPlaybackLatency, &latency_range); + fPlaybackPortList[i] = index; + } - packet = MIDIPacketNext(packet); + // Virtual outputs + for (int i = 0; i < num_virtual_outputs; i++) { + port_obj = virtual_output_ports[i]; + name = port_obj->GetName(); + index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, + JACK_DEFAULT_MIDI_TYPE, + PlaybackDriverFlags, buffer_size); + if (index == NO_PORT) { + jack_error("JackCoreMidiDriver::Attach - cannot register virtual " + "output port with name '%s'.", name); + // X: Do we need to deallocate ports? + return -1; + } + port = fGraphManager->GetPort(index); + port->SetAlias(port_obj->GetAlias()); + port->SetLatencyRange(JackPlaybackLatency, &latency_range); + fPlaybackPortList[num_physical_outputs + i] = index; } -} -void JackCoreMidiDriver::ReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) -{ - jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)connRefCon; - ReadProcAux(pktlist, ringbuffer); + return 0; } -void JackCoreMidiDriver::ReadVirtualProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) +int +JackCoreMidiDriver::Close() { - jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)refCon; - ReadProcAux(pktlist, ringbuffer); + // Generic MIDI driver close + int result = JackMidiDriver::Close(); + + OSStatus status; + if (physical_input_ports) { + for (int i = 0; i < num_physical_inputs; i++) { + delete physical_input_ports[i]; + } + delete[] physical_input_ports; + num_physical_inputs = 0; + physical_input_ports = 0; + status = MIDIPortDispose(internal_input); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose", + status); + result = -1; + } + } + if (physical_output_ports) { + for (int i = 0; i < num_physical_outputs; i++) { + delete physical_output_ports[i]; + } + delete[] physical_output_ports; + num_physical_outputs = 0; + physical_output_ports = 0; + status = MIDIPortDispose(internal_output); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose", + status); + result = -1; + } + } + if (virtual_input_ports) { + for (int i = 0; i < num_virtual_inputs; i++) { + delete virtual_input_ports[i]; + } + delete[] virtual_input_ports; + num_virtual_inputs = 0; + virtual_input_ports = 0; + } + if (virtual_output_ports) { + for (int i = 0; i < num_virtual_outputs; i++) { + delete virtual_output_ports[i]; + } + delete[] virtual_output_ports; + num_virtual_outputs = 0; + virtual_output_ports = 0; + } + if (client) { + status = MIDIClientDispose(client); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientDispose", + status); + result = -1; + } + client = 0; + } + return result; } -void JackCoreMidiDriver::NotifyProc(const MIDINotification *message, void *refCon) +void +JackCoreMidiDriver::HandleNotification(const MIDINotification *message) { - jack_log("NotifyProc %d", message->messageID); + // Empty } -JackCoreMidiDriver::JackCoreMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) - : JackMidiDriver(name, alias, engine, table), fMidiClient(NULL), fInputPort(NULL), fOutputPort(NULL), fRealCaptureChannels(0), fRealPlaybackChannels(0) -{} - -JackCoreMidiDriver::~JackCoreMidiDriver() -{} - -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; - - // Get real input/output number - fRealCaptureChannels = MIDIGetNumberOfSources(); - fRealPlaybackChannels = MIDIGetNumberOfDestinations(); - - // Generic JackMidiDriver Open - if (JackMidiDriver::Open(capturing, playing, inchannels + fRealCaptureChannels, outchannels + fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) +int +JackCoreMidiDriver::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) +{ + int pi_count = 0; + int po_count = 0; + int vi_count = 0; + int vo_count = 0; + ItemCount potential_po_count; + ItemCount potential_pi_count; + + CFStringRef name = CFStringCreateWithCString(0, "JackMidi", + CFStringGetSystemEncoding()); + if (! name) { + jack_error("JackCoreMidiDriver::Open - failed to allocate memory for " + "client name string"); return -1; + } - coutputStr = CFStringCreateWithCString(0, "JackMidi", CFStringGetSystemEncoding()); - err = MIDIClientCreate(coutputStr, NotifyProc, this, &fMidiClient); - CFRelease(coutputStr); - if (!fMidiClient) { - jack_error("Cannot create CoreMidi client"); - goto error; - } - - err = MIDIInputPortCreate(fMidiClient, CFSTR("Input port"), ReadProc, this, &fInputPort); - if (!fInputPort) { - jack_error("Cannot open CoreMidi in port\n"); - goto error; - } + OSStatus status = MIDIClientCreate(name, HandleNotificationEvent, this, + &client); - err = MIDIOutputPortCreate(fMidiClient, CFSTR("Output port"), &fOutputPort); - if (!fOutputPort) { - jack_error("Cannot open CoreMidi out port\n"); - goto error; - } + CFRelease(name); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientCreate", + status); + return -1; + } + char *client_name = fClientControl.fName; + + // Allocate and connect physical inputs + potential_pi_count = MIDIGetNumberOfSources(); + if (potential_pi_count) { + status = MIDIInputPortCreate(client, CFSTR("Physical Input Port"), + HandleInputEvent, this, &internal_input); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Open", "MIDIInputPortCreate", + status); + goto destroy_virtual_output_ports; + } + try { + physical_input_ports = + new JackCoreMidiPhysicalInputPort*[potential_pi_count]; + } catch (std::exception e) { + jack_error("JackCoreMidiDriver::Open - while creating physical " + "input port array: %s", e.what()); + goto destroy_internal_input_port; + } + for (ItemCount i = 0; i < potential_pi_count; i++) { + try { + physical_input_ports[pi_count] = + new JackCoreMidiPhysicalInputPort(fAliasName, client_name, + capture_driver_name, i, + client, internal_input, + time_ratio); + } catch (std::exception e) { + jack_error("JackCoreMidiDriver::Open - while creating " + "physical input port: %s", e.what()); + goto destroy_internal_input_port; + } + pi_count++; + } + } - fMidiDestination = new MIDIEndpointRef[inchannels + fRealCaptureChannels]; - assert(fMidiDestination); + // Allocate and connect physical outputs + potential_po_count = MIDIGetNumberOfDestinations(); + if (potential_po_count) { + status = MIDIOutputPortCreate(client, CFSTR("Physical Output Port"), + &internal_output); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Open", "MIDIOutputPortCreate", + status); + goto destroy_physical_input_ports; + } + try { + physical_output_ports = + new JackCoreMidiPhysicalOutputPort*[potential_po_count]; + } catch (std::exception e) { + jack_error("JackCoreMidiDriver::Open - while creating physical " + "output port array: %s", e.what()); + goto destroy_internal_output_port; + } + for (ItemCount i = 0; i < potential_po_count; i++) { + try { + physical_output_ports[po_count] = + new JackCoreMidiPhysicalOutputPort(fAliasName, client_name, + playback_driver_name, i, + client, internal_output, + time_ratio); + } catch (std::exception e) { + jack_error("JackCoreMidiDriver::Open - while creating " + "physical output port: %s", e.what()); + goto destroy_internal_output_port; + } + po_count++; + } + } - // Virtual input - for (int i = 0; i < inchannels; i++) { - std::stringstream num; - num << i; - str = "JackMidi" + num.str(); - coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding()); - err = MIDIDestinationCreate(fMidiClient, coutputStr, ReadVirtualProc, fRingBuffer[i], &fMidiDestination[i]); - CFRelease(coutputStr); - if (!fMidiDestination[i]) { - jack_error("Cannot create CoreMidi destination"); - goto error; + // Allocate and connect virtual inputs + if (in_channels) { + try { + virtual_input_ports = + new JackCoreMidiVirtualInputPort*[in_channels]; + } catch (std::exception e) { + jack_error("JackCoreMidiDriver::Open - while creating virtual " + "input port array: %s", e.what()); + goto destroy_client; + } + for (vi_count = 0; vi_count < in_channels; vi_count++) { + try { + virtual_input_ports[vi_count] = + new JackCoreMidiVirtualInputPort(fAliasName, client_name, + capture_driver_name, + vi_count + pi_count, client, + time_ratio); + } catch (std::exception e) { + jack_error("JackCoreMidiDriver::Open - while creating virtual " + "input port: %s", e.what()); + goto destroy_virtual_input_ports; + } } } - // Real input - for (int i = 0; i < fRealCaptureChannels; i++) { - fMidiDestination[i + inchannels] = MIDIGetSource(i); - MIDIPortConnectSource(fInputPort, fMidiDestination[i + inchannels], fRingBuffer[i + inchannels]); + // Allocate and connect virtual outputs + if (out_channels) { + try { + virtual_output_ports = + new JackCoreMidiVirtualOutputPort*[out_channels]; + } catch (std::exception e) { + jack_error("JackCoreMidiDriver::Open - while creating virtual " + "output port array: %s", e.what()); + goto destroy_virtual_input_ports; + } + for (vo_count = 0; vo_count < out_channels; vo_count++) { + try { + virtual_output_ports[vo_count] = + new JackCoreMidiVirtualOutputPort(fAliasName, client_name, + playback_driver_name, + vo_count + po_count, client, + time_ratio); + } catch (std::exception e) { + jack_error("JackCoreMidiDriver::Open - while creating virtual " + "output port: %s", e.what()); + goto destroy_virtual_output_ports; + } + } } - fMidiSource = new MIDIEndpointRef[outchannels + fRealPlaybackChannels]; - assert(fMidiSource); - // Virtual output - for (int i = 0; i < outchannels; i++) { - std::stringstream num; - num << i; - str = "JackMidi" + num.str(); - coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding()); - err = MIDISourceCreate(fMidiClient, coutputStr, &fMidiSource[i]); - CFRelease(coutputStr); - if (!fMidiSource[i]) { - jack_error("Cannot create CoreMidi source"); - goto error; - } + if (! (pi_count || po_count || in_channels || out_channels)) { + jack_error("JackCoreMidiDriver::Open - no CoreMIDI inputs or outputs " + "found, and no virtual ports allocated."); + } else if (! JackMidiDriver::Open(capturing, playing, + in_channels + pi_count, + out_channels + po_count, monitor, + capture_driver_name, + playback_driver_name, capture_latency, + playback_latency)) { + num_physical_inputs = pi_count; + num_physical_outputs = po_count; + num_virtual_inputs = in_channels; + num_virtual_outputs = out_channels; + return 0; } - // Real output - for (int i = 0; i < fRealPlaybackChannels; i++) { - fMidiSource[i + outchannels] = MIDIGetDestination(i); + // Cleanup + if (physical_output_ports) { + for (int i = 0; i < po_count; i++) { + delete physical_output_ports[i]; + } + delete[] physical_output_ports; + physical_output_ports = 0; } + destroy_internal_output_port: + status = MIDIPortDispose(internal_output); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status); + } + destroy_physical_input_ports: + if (physical_input_ports) { + for (int i = 0; i < pi_count; i++) { + delete physical_input_ports[i]; + } + delete[] physical_input_ports; + physical_input_ports = 0; + } + destroy_internal_input_port: + status = MIDIPortDispose(internal_input); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status); + } + destroy_virtual_output_ports: + if (virtual_output_ports) { + for (int i = 0; i < vo_count; i++) { + delete virtual_output_ports[i]; + } + delete[] virtual_output_ports; + virtual_output_ports = 0; + } + destroy_virtual_input_ports: + if (virtual_input_ports) { + for (int i = 0; i < vi_count; i++) { + delete virtual_input_ports[i]; + } + delete[] virtual_input_ports; + virtual_input_ports = 0; + } + destroy_client: + status = MIDIClientDispose(client); + if (status != noErr) { + WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientDispose", + status); + } + client = 0; + return -1; +} +int +JackCoreMidiDriver::Read() +{ + jack_nframes_t buffer_size = fEngineControl->fBufferSize; + for (int i = 0; i < num_physical_inputs; i++) { + physical_input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size); + } + for (int i = 0; i < num_virtual_inputs; i++) { + virtual_input_ports[i]-> + ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size); + } return 0; - -error: - Close(); - return -1; } -int JackCoreMidiDriver::Close() +int +JackCoreMidiDriver::Start() { - // Generic midi driver close - int res = JackMidiDriver::Close(); + jack_info("JackCoreMidiDriver::Start - Starting driver."); - if (fInputPort) - MIDIPortDispose(fInputPort); + JackMidiDriver::Start(); - if (fOutputPort) - MIDIPortDispose(fOutputPort); + int pi_count = 0; + int po_count = 0; + int vi_count = 0; + int vo_count = 0; - // Only dispose "virtual" endpoints - for (int i = 0; i < fCaptureChannels - fRealCaptureChannels; i++) { - if (fMidiDestination) - MIDIEndpointDispose(fMidiDestination[i]); - } - delete[] fMidiDestination; + jack_info("JackCoreMidiDriver::Start - Enabling physical input ports."); - // Only dispose "virtual" endpoints - for (int i = 0; i < fPlaybackChannels - fRealPlaybackChannels; i++) { - if (fMidiSource[i]) - MIDIEndpointDispose(fMidiSource[i]); + for (; pi_count < num_physical_inputs; pi_count++) { + if (physical_input_ports[pi_count]->Start() < 0) { + jack_error("JackCoreMidiDriver::Start - Failed to enable physical " + "input port."); + goto stop_physical_input_ports; + } } - delete[] fMidiSource; - if (fMidiClient) - MIDIClientDispose(fMidiClient); + jack_info("JackCoreMidiDriver::Start - Enabling physical output ports."); - return res; -} - -int JackCoreMidiDriver::Attach() -{ - OSStatus err; - JackPort* port; - CFStringRef pname; - jack_port_id_t port_index; - char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; - char endpoint_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; - char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; - int i; - - jack_log("JackCoreMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); - - for (i = 0; i < fCaptureChannels; i++) { - - err = MIDIObjectGetStringProperty(fMidiDestination[i], kMIDIPropertyName, &pname); - if (err == noErr) { - CFStringGetCString(pname, endpoint_name, sizeof(endpoint_name), 0); - CFRelease(pname); - snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, endpoint_name, i + 1); - } else { - snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1); + for (; po_count < num_physical_outputs; po_count++) { + if (physical_output_ports[po_count]->Start() < 0) { + jack_error("JackCoreMidiDriver::Start - Failed to enable physical " + "output port."); + goto stop_physical_output_ports; } - - 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("JackCoreMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index); } - for (i = 0; i < fPlaybackChannels; i++) { + jack_info("JackCoreMidiDriver::Start - Enabling virtual input ports."); - err = MIDIObjectGetStringProperty(fMidiSource[i], kMIDIPropertyName, &pname); - if (err == noErr) { - CFStringGetCString(pname, endpoint_name, sizeof(endpoint_name), 0); - CFRelease(pname); - snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, endpoint_name, i + 1); - } else { - snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1); + for (; vi_count < num_virtual_inputs; vi_count++) { + if (virtual_input_ports[vi_count]->Start() < 0) { + jack_error("JackCoreMidiDriver::Start - Failed to enable virtual " + "input port."); + goto stop_virtual_input_ports; } + } - 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; + jack_info("JackCoreMidiDriver::Start - Enabling virtual output ports."); + + for (; vo_count < num_virtual_outputs; vo_count++) { + if (virtual_output_ports[vo_count]->Start() < 0) { + jack_error("JackCoreMidiDriver::Start - Failed to enable virtual " + "output port."); + goto stop_virtual_output_ports; } - port = fGraphManager->GetPort(port_index); - port->SetAlias(alias); - fPlaybackPortList[i] = port_index; - jack_log("JackCoreMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index); } - return 0; -} -int JackCoreMidiDriver::Read() -{ - for (int chan = 0; chan < fCaptureChannels; chan++) { - - if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) { + jack_info("JackCoreMidiDriver::Start - Driver started."); - // Get JACK port - JackMidiBuffer* midi_buffer = GetInputBuffer(chan); + return 0; - if (jack_ringbuffer_read_space(fRingBuffer[chan]) == 0) { - // Reset buffer - midi_buffer->Reset(midi_buffer->nframes); - } else { + stop_virtual_output_ports: + for (int i = 0; i < vo_count; i++) { + if (virtual_output_ports[i]->Stop() < 0) { + jack_error("JackCoreMidiDriver::Start - Failed to disable virtual " + "output port."); + } + } + stop_virtual_input_ports: + for (int i = 0; i < vi_count; i++) { + if (virtual_input_ports[i]->Stop() < 0) { + jack_error("JackCoreMidiDriver::Start - Failed to disable virtual " + "input port."); + } + } + stop_physical_output_ports: + for (int i = 0; i < po_count; i++) { + if (physical_output_ports[i]->Stop() < 0) { + jack_error("JackCoreMidiDriver::Start - Failed to disable " + "physical output port."); + } + } + stop_physical_input_ports: + for (int i = 0; i < pi_count; i++) { + if (physical_input_ports[i]->Stop() < 0) { + jack_error("JackCoreMidiDriver::Start - Failed to disable " + "physical input port."); + } + } - while (jack_ringbuffer_read_space(fRingBuffer[chan]) > 0) { + return -1; +} - // Read event number - int ev_count = 0; - jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int)); +int +JackCoreMidiDriver::Stop() +{ + int result = 0; - for (int j = 0; j < ev_count; j++) { - // Read event length - UInt16 event_len; - jack_ringbuffer_read(fRingBuffer[chan], (char*)&event_len, sizeof(UInt16)); - // Read event actual data - jack_midi_data_t* dest = midi_buffer->ReserveEvent(0, event_len); - jack_ringbuffer_read(fRingBuffer[chan], (char*)dest, event_len); - } - } - } + jack_info("JackCoreMidiDriver::Stop - disabling physical input ports."); - } else { - // Consume ring buffer - jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan])); + for (int i = 0; i < num_physical_inputs; i++) { + if (physical_input_ports[i]->Stop() < 0) { + jack_error("JackCoreMidiDriver::Stop - Failed to disable physical " + "input port."); + result = -1; } } - return 0; -} - -int JackCoreMidiDriver::Write() -{ - MIDIPacketList* pktlist = (MIDIPacketList*)fMIDIBuffer; - for (int chan = 0; chan < fPlaybackChannels; chan++) { + jack_info("JackCoreMidiDriver::Stop - disabling physical output ports."); - if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) { + for (int i = 0; i < num_physical_outputs; i++) { + if (physical_output_ports[i]->Stop() < 0) { + jack_error("JackCoreMidiDriver::Stop - Failed to disable physical " + "output port."); + result = -1; + } + } - MIDIPacket* packet = MIDIPacketListInit(pktlist); - JackMidiBuffer* midi_buffer = GetOutputBuffer(chan); + jack_info("JackCoreMidiDriver::Stop - disabling virtual input ports."); - // TODO : use timestamp + for (int i = 0; i < num_virtual_inputs; i++) { + if (virtual_input_ports[i]->Stop() < 0) { + jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual " + "input port."); + result = -1; + } + } - for (unsigned int j = 0; j < midi_buffer->event_count; j++) { - JackMidiEvent* ev = &midi_buffer->events[j]; - packet = MIDIPacketListAdd(pktlist, sizeof(fMIDIBuffer), packet, MIDIGetCurrentHostTime(), ev->size, ev->GetData(midi_buffer)); - } + jack_info("JackCoreMidiDriver::Stop - disabling virtual output ports."); - if (packet) { - if (chan < fPlaybackChannels - fRealPlaybackChannels) { - OSStatus err = MIDIReceived(fMidiSource[chan], pktlist); - if (err != noErr) - jack_error("MIDIReceived error"); - } else { - OSStatus err = MIDISend(fOutputPort, fMidiSource[chan], pktlist); - if (err != noErr) - jack_error("MIDISend error"); - } - } + for (int i = 0; i < num_virtual_outputs; i++) { + if (virtual_output_ports[i]->Stop() < 0) { + jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual " + "output port."); + result = -1; } } - return 0; + return result; } -} // end of namespace +int +JackCoreMidiDriver::Write() +{ + jack_nframes_t buffer_size = fEngineControl->fBufferSize; + for (int i = 0; i < num_physical_outputs; i++) { + physical_output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size); + } + for (int i = 0; i < num_virtual_outputs; i++) { + virtual_output_ports[i]-> + ProcessJack(GetOutputBuffer(num_physical_outputs + i), + buffer_size); + } + return 0; +} #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor() @@ -373,7 +649,7 @@ extern "C" i = 0; strcpy(desc->params[i].name, "inchannels"); desc->params[i].character = 'i'; - desc->params[i].type = JackDriverParamInt; + desc->params[i].type = JackDriverParamUInt; 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); @@ -381,7 +657,7 @@ extern "C" i++; strcpy(desc->params[i].name, "outchannels"); desc->params[i].character = 'o'; - desc->params[i].type = JackDriverParamInt; + desc->params[i].type = JackDriverParamUInt; 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); @@ -423,4 +699,3 @@ extern "C" #ifdef __cplusplus } #endif - diff --git a/macosx/coremidi/JackCoreMidiDriver.h b/macosx/coremidi/JackCoreMidiDriver.h index a99b35a0..c5a26f5b 100644 --- a/macosx/coremidi/JackCoreMidiDriver.h +++ b/macosx/coremidi/JackCoreMidiDriver.h @@ -1,5 +1,6 @@ /* Copyright (C) 2009 Grame +Copyright (C) 2011 Devin Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,61 +21,74 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #ifndef __JackCoreMidiDriver__ #define __JackCoreMidiDriver__ -#include +#include "JackCoreMidiPhysicalInputPort.h" +#include "JackCoreMidiPhysicalOutputPort.h" +#include "JackCoreMidiVirtualInputPort.h" +#include "JackCoreMidiVirtualOutputPort.h" #include "JackMidiDriver.h" -#include "JackTime.h" -namespace Jack -{ +namespace Jack { -/*! -\brief The CoreMidi driver. -*/ - -class JackCoreMidiDriver : public JackMidiDriver -{ + class JackCoreMidiDriver: public JackMidiDriver { private: - MIDIClientRef fMidiClient; - MIDIPortRef fInputPort; - MIDIPortRef fOutputPort; - MIDIEndpointRef* fMidiDestination; - MIDIEndpointRef* fMidiSource; + static void + HandleInputEvent(const MIDIPacketList *packet_list, void *driver, + void *port); + + static void + HandleNotificationEvent(const MIDINotification *message, void *driver); + + void + HandleNotification(const MIDINotification *message); + + MIDIClientRef client; + MIDIPortRef internal_input; + MIDIPortRef internal_output; + int num_physical_inputs; + int num_physical_outputs; + int num_virtual_inputs; + int num_virtual_outputs; + JackCoreMidiPhysicalInputPort **physical_input_ports; + JackCoreMidiPhysicalOutputPort **physical_output_ports; + double time_ratio; + JackCoreMidiVirtualInputPort **virtual_input_ports; + JackCoreMidiVirtualOutputPort **virtual_output_ports; + + public: - char fMIDIBuffer[BUFFER_SIZE_MAX * sizeof(jack_default_audio_sample_t)]; + JackCoreMidiDriver(const char* name, const char* alias, + JackLockedEngine* engine, JackSynchro* table); - int fRealCaptureChannels; - int fRealPlaybackChannels; + ~JackCoreMidiDriver(); - static void ReadProcAux(const MIDIPacketList *pktlist, jack_ringbuffer_t* ringbuffer); - static void ReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon); - static void ReadVirtualProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon); - static void NotifyProc(const MIDINotification *message, void *refCon); + int + Attach(); - public: + int + Close(); + + 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); - JackCoreMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table); - virtual ~JackCoreMidiDriver(); + int + Read(); - int Open( bool capturing, - bool playing, - int chan_in, - int chan_out, - bool monitor, - const char* capture_driver_name, - const char* playback_driver_name, - jack_nframes_t capture_latency, - jack_nframes_t playback_latency); - int Close(); + int + Start(); - int Attach(); + int + Stop(); - int Read(); - int Write(); + int + Write(); -}; + }; -} // end of namespace +} #endif diff --git a/macosx/coremidi/JackCoreMidiInputPort.cpp b/macosx/coremidi/JackCoreMidiInputPort.cpp new file mode 100644 index 00000000..fb4bc961 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiInputPort.cpp @@ -0,0 +1,184 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "JackCoreMidiInputPort.h" +#include "JackMidiUtil.h" +//#include "types.h" + +using Jack::JackCoreMidiInputPort; + +JackCoreMidiInputPort::JackCoreMidiInputPort(double time_ratio, + size_t max_bytes, + size_t max_messages): + JackCoreMidiPort(time_ratio) +{ + thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages); + std::auto_ptr thread_queue_ptr(thread_queue); + write_queue = new JackMidiBufferWriteQueue(); + std::auto_ptr write_queue_ptr(write_queue); + sysex_buffer = new jack_midi_data_t[max_bytes]; + write_queue_ptr.release(); + thread_queue_ptr.release(); + jack_event = 0; +} + +JackCoreMidiInputPort::~JackCoreMidiInputPort() +{ + delete thread_queue; + delete write_queue; + delete[] sysex_buffer; +} + +jack_nframes_t +JackCoreMidiInputPort::GetFramesFromTimeStamp(MIDITimeStamp timestamp) +{ + return GetFramesFromTime((jack_time_t) (timestamp * time_ratio)); +} + +void +JackCoreMidiInputPort::Initialize(const char *alias_name, + const char *client_name, + const char *driver_name, int index, + MIDIEndpointRef endpoint) +{ + JackCoreMidiPort::Initialize(alias_name, client_name, driver_name, index, endpoint, false); +} + +void +JackCoreMidiInputPort::ProcessCoreMidi(const MIDIPacketList *packet_list) +{ + set_threaded_log_function(); + + unsigned int packet_count = packet_list->numPackets; + assert(packet_count); + MIDIPacket *packet = (MIDIPacket *) packet_list->packet; + for (unsigned int i = 0; i < packet_count; i++) { + jack_midi_data_t *data = packet->data; + size_t size = packet->length; + assert(size); + jack_midi_event_t event; + + // XX: There might be dragons in my spaghetti. This code is begging + // for a rewrite. + + if (sysex_bytes_sent) { + if (data[0] & 0x80) { + jack_error("JackCoreMidiInputPort::ProcessCoreMidi - System " + "exclusive message aborted."); + sysex_bytes_sent = 0; + goto parse_event; + } + buffer_sysex_bytes: + if ((sysex_bytes_sent + size) <= sizeof(sysex_buffer)) { + memcpy(sysex_buffer + sysex_bytes_sent, packet, + size * sizeof(jack_midi_data_t)); + } + sysex_bytes_sent += size; + if (data[size - 1] == 0xf7) { + if (sysex_bytes_sent > sizeof(sysex_buffer)) { + jack_error("JackCoreMidiInputPort::ProcessCoreMidi - " + "Could not buffer a %d-byte system exclusive " + "message. Discarding message.", + sysex_bytes_sent); + sysex_bytes_sent = 0; + goto get_next_packet; + } + event.buffer = sysex_buffer; + event.size = sysex_bytes_sent; + sysex_bytes_sent = 0; + goto send_event; + } + goto get_next_packet; + } + + parse_event: + if (data[0] == 0xf0) { + if (data[size - 1] != 0xf7) { + goto buffer_sysex_bytes; + } + } + event.buffer = data; + event.size = size; + + send_event: + event.time = GetFramesFromTimeStamp(packet->timeStamp); + switch (thread_queue->EnqueueEvent(&event)) { + case JackMidiWriteQueue::BUFFER_FULL: + jack_error("JackCoreMidiInputPort::ProcessCoreMidi - The thread " + "queue buffer is full. Dropping event."); + break; + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackCoreMidiInputPort::ProcessCoreMidi - The thread " + "queue couldn't enqueue a %d-byte packet. Dropping " + "event.", event.size); + break; + default: + ; + } + + get_next_packet: + packet = MIDIPacketNext(packet); + assert(packet); + } +} + +void +JackCoreMidiInputPort::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()) { + // Add 'frames' to MIDI events to align with audio. + switch (write_queue->EnqueueEvent(jack_event, frames)) { + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackCoreMidiInputPort::ProcessJack - The write queue " + "couldn't enqueue a %d-byte event. Dropping event.", + jack_event->size); + // Fallthrough on purpose + case JackMidiWriteQueue::OK: + continue; + default: + ; + } + break; + } +} + +bool +JackCoreMidiInputPort::Start() +{ + // Hack: Get rid of any messages that might have come in before starting + // the engine. + while (thread_queue->DequeueEvent()); + sysex_bytes_sent = 0; + return true; +} + +bool +JackCoreMidiInputPort::Stop() +{ + return true; +} diff --git a/macosx/coremidi/JackCoreMidiInputPort.h b/macosx/coremidi/JackCoreMidiInputPort.h new file mode 100644 index 00000000..3950c70c --- /dev/null +++ b/macosx/coremidi/JackCoreMidiInputPort.h @@ -0,0 +1,73 @@ +/* +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 __JackCoreMidiInputPort__ +#define __JackCoreMidiInputPort__ + +#include "JackCoreMidiPort.h" +#include "JackMidiAsyncQueue.h" +#include "JackMidiBufferWriteQueue.h" + +namespace Jack { + + class JackCoreMidiInputPort: public JackCoreMidiPort { + + private: + + jack_nframes_t + GetFramesFromTimeStamp(MIDITimeStamp timestamp); + + jack_midi_event_t *jack_event; + jack_midi_data_t *sysex_buffer; + size_t sysex_bytes_sent; + JackMidiAsyncQueue *thread_queue; + JackMidiBufferWriteQueue *write_queue; + + protected: + + void + Initialize(const char *alias_name, const char *client_name, + const char *driver_name, int index, + MIDIEndpointRef endpoint); + + public: + + JackCoreMidiInputPort(double time_ratio, size_t max_bytes=4096, + size_t max_messages=1024); + + virtual + ~JackCoreMidiInputPort(); + + void + ProcessCoreMidi(const MIDIPacketList *packet_list); + + void + ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames); + + bool + Start(); + + bool + Stop(); + + }; + +} + +#endif diff --git a/macosx/coremidi/JackCoreMidiOutputPort.cpp b/macosx/coremidi/JackCoreMidiOutputPort.cpp new file mode 100644 index 00000000..9a66b88d --- /dev/null +++ b/macosx/coremidi/JackCoreMidiOutputPort.cpp @@ -0,0 +1,249 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include + +#include "JackCoreMidiOutputPort.h" +#include "JackMidiUtil.h" +#include "JackTime.h" + +using Jack::JackCoreMidiOutputPort; + +JackCoreMidiOutputPort::JackCoreMidiOutputPort(double time_ratio, + size_t max_bytes, + size_t max_messages): + JackCoreMidiPort(time_ratio) +{ + read_queue = new JackMidiBufferReadQueue(); + std::auto_ptr read_queue_ptr(read_queue); + thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages); + std::auto_ptr thread_queue_ptr(thread_queue); + thread = new JackThread(this); + std::auto_ptr thread_ptr(thread); + sprintf(semaphore_name, "coremidi_%p", this); + thread_queue_semaphore = sem_open(semaphore_name, O_CREAT, 0777, 0); + if (thread_queue_semaphore == (sem_t *) SEM_FAILED) { + throw std::runtime_error(strerror(errno)); + } + advance_schedule_time = 0; + thread_ptr.release(); + thread_queue_ptr.release(); + read_queue_ptr.release(); +} + +JackCoreMidiOutputPort::~JackCoreMidiOutputPort() +{ + delete thread; + sem_destroy(thread_queue_semaphore); + sem_unlink(semaphore_name); + delete read_queue; + delete thread_queue; +} + +bool +JackCoreMidiOutputPort::Execute() +{ + jack_midi_event_t *event = 0; + MIDIPacketList *packet_list = (MIDIPacketList *) packet_buffer; + for (;;) { + MIDIPacket *packet = MIDIPacketListInit(packet_list); + assert(packet); + if (! event) { + event = GetCoreMidiEvent(true); + } + jack_midi_data_t *data = event->buffer; + jack_nframes_t send_frame = event->time; + jack_time_t send_time = + GetTimeFromFrames(send_frame) - advance_schedule_time; + size_t size = event->size; + MIDITimeStamp timestamp = GetTimeStampFromFrames(send_frame); + packet = MIDIPacketListAdd(packet_list, PACKET_BUFFER_SIZE, packet, + timestamp, size, data); + if (packet) { + while (GetMicroSeconds() < send_time) { + event = GetCoreMidiEvent(false); + if (! event) { + break; + } + packet = MIDIPacketListAdd(packet_list, sizeof(packet_buffer), + packet, + GetTimeStampFromFrames(event->time), + event->size, event->buffer); + if (! packet) { + break; + } + } + SendPacketList(packet_list); + } else { + + // We have a large system exclusive event. We'll have to send it + // out in multiple packets. + size_t bytes_sent = 0; + do { + packet = MIDIPacketListInit(packet_list); + assert(packet); + size_t num_bytes = 0; + for (; bytes_sent < size; bytes_sent += num_bytes) { + size_t num_bytes = size - bytes_sent; + + // We use 256 because the MIDIPacket struct defines the + // size of the 'data' member to be 256 bytes. I believe + // this prevents packets from being dynamically allocated + // by 'MIDIPacketListAdd', but I might be wrong. + if (num_bytes > 256) { + num_bytes = 256; + } + packet = MIDIPacketListAdd(packet_list, + sizeof(packet_buffer), packet, + timestamp, num_bytes, + data + bytes_sent); + if (! packet) { + break; + } + } + if (! SendPacketList(packet_list)) { + // An error occurred. The error message has already been + // output. We lick our wounds and move along. + break; + } + } while (bytes_sent < size); + event = 0; + } + } + return false; +} + +jack_midi_event_t * +JackCoreMidiOutputPort::GetCoreMidiEvent(bool block) +{ + if (! block) { + if (sem_trywait(thread_queue_semaphore)) { + if (errno != EAGAIN) { + jack_error("JackCoreMidiOutputPort::Execute - sem_trywait: %s", + strerror(errno)); + } + return 0; + } + } else { + while (sem_wait(thread_queue_semaphore)) { + if (errno != EINTR) { + jack_error("JackCoreMidiOutputPort::Execute - sem_wait: %s", + strerror(errno)); + return 0; + } + } + } + return thread_queue->DequeueEvent(); +} + +MIDITimeStamp +JackCoreMidiOutputPort::GetTimeStampFromFrames(jack_nframes_t frames) +{ + return GetTimeFromFrames(frames) / time_ratio; +} + +bool +JackCoreMidiOutputPort::Init() +{ + set_threaded_log_function(); + + // OSX only, values read in RT CoreMidi thread + UInt64 period = 0; + UInt64 computation = 250 * 1000; + UInt64 constraint = 500 * 1000; + thread->SetParams(period, computation, constraint); + + if (thread->AcquireSelfRealTime()) { + jack_error("JackCoreMidiOutputPort::Init - could not acquire realtime " + "scheduling. Continuing anyway."); + } + return true; +} + +void +JackCoreMidiOutputPort::Initialize(const char *alias_name, + const char *client_name, + const char *driver_name, int index, + MIDIEndpointRef endpoint, + SInt32 advance_schedule_time) +{ + JackCoreMidiPort::Initialize(alias_name, client_name, driver_name, index, + endpoint, true); + assert(advance_schedule_time >= 0); + this->advance_schedule_time = advance_schedule_time; +} + +void +JackCoreMidiOutputPort::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("JackCoreMidiOutputPort::ProcessJack - The thread " + "queue buffer is full. Dropping event."); + break; + case JackMidiWriteQueue::BUFFER_TOO_SMALL: + jack_error("JackCoreMidiOutputPort::ProcessJack - The thread " + "queue couldn't enqueue a %d-byte event. Dropping " + "event.", event->size); + break; + default: + if (sem_post(thread_queue_semaphore)) { + jack_error("JackCoreMidiOutputPort::ProcessJack - unexpected " + "error while posting to thread queue semaphore: %s", + strerror(errno)); + } + } + } +} + +bool +JackCoreMidiOutputPort::Start() +{ + bool result = thread->GetStatus() != JackThread::kIdle; + if (! result) { + result = ! thread->StartSync(); + if (! result) { + jack_error("JackCoreMidiOutputPort::Start - failed to start MIDI " + "processing thread."); + } + } + return result; +} + +bool +JackCoreMidiOutputPort::Stop() +{ + bool result = thread->GetStatus() == JackThread::kIdle; + if (! result) { + result = ! thread->Kill(); + if (! result) { + jack_error("JackCoreMidiOutputPort::Stop - failed to stop MIDI " + "processing thread."); + } + } + return result; +} diff --git a/macosx/coremidi/JackCoreMidiOutputPort.h b/macosx/coremidi/JackCoreMidiOutputPort.h new file mode 100644 index 00000000..a04d98b3 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiOutputPort.h @@ -0,0 +1,90 @@ +/* +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 __JackCoreMidiOutputPort__ +#define __JackCoreMidiOutputPort__ + +#include + +#include "JackCoreMidiPort.h" +#include "JackMidiAsyncQueue.h" +#include "JackMidiBufferReadQueue.h" +#include "JackThread.h" + +namespace Jack { + + class JackCoreMidiOutputPort: + public JackCoreMidiPort, public JackRunnableInterface { + + private: + + jack_midi_event_t * + GetCoreMidiEvent(bool block); + + MIDITimeStamp + GetTimeStampFromFrames(jack_nframes_t frames); + + static const size_t PACKET_BUFFER_SIZE = 65536; + + SInt32 advance_schedule_time; + char packet_buffer[PACKET_BUFFER_SIZE]; + JackMidiBufferReadQueue *read_queue; + char semaphore_name[128]; + JackThread *thread; + JackMidiAsyncQueue *thread_queue; + sem_t *thread_queue_semaphore; + + protected: + + virtual bool + SendPacketList(MIDIPacketList *packet_list) = 0; + + void + Initialize(const char *alias_name, const char *client_name, + const char *driver_name, int index, + MIDIEndpointRef endpoint, SInt32 advance_schedule_time); + + public: + + JackCoreMidiOutputPort(double time_ratio, size_t max_bytes=4096, + size_t max_messages=1024); + + virtual + ~JackCoreMidiOutputPort(); + + bool + Execute(); + + bool + Init(); + + void + ProcessJack(JackMidiBuffer *port_buffer, jack_nframes_t frames); + + bool + Start(); + + bool + Stop(); + + }; + +} + +#endif diff --git a/macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp b/macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp new file mode 100644 index 00000000..748dbc17 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp @@ -0,0 +1,53 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "JackCoreMidiPhysicalInputPort.h" +#include "JackCoreMidiUtil.h" + +using Jack::JackCoreMidiPhysicalInputPort; + +JackCoreMidiPhysicalInputPort:: +JackCoreMidiPhysicalInputPort(const char *alias_name, const char *client_name, + const char *driver_name, int index, + MIDIClientRef client, MIDIPortRef internal_input, + double time_ratio, size_t max_bytes, + size_t max_messages): + JackCoreMidiInputPort(time_ratio, max_bytes, max_messages) +{ + MIDIEndpointRef source = MIDIGetSource(index); + if (! source) { + // X: Is there a way to get a better error message? + std::stringstream stream; + stream << "The source at index '" << index << "' is not available"; + throw std::runtime_error(stream.str().c_str()); + } + OSStatus status = MIDIPortConnectSource(internal_input, source, this); + if (status != noErr) { + throw std::runtime_error(GetMacOSErrorString(status)); + } + Initialize(alias_name, client_name, driver_name, index, source); +} + +JackCoreMidiPhysicalInputPort::~JackCoreMidiPhysicalInputPort() +{ + // Empty +} diff --git a/macosx/coremidi/JackCoreMidiPhysicalInputPort.h b/macosx/coremidi/JackCoreMidiPhysicalInputPort.h new file mode 100644 index 00000000..83f0f2dd --- /dev/null +++ b/macosx/coremidi/JackCoreMidiPhysicalInputPort.h @@ -0,0 +1,45 @@ +/* +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 __JackCoreMidiPhysicalInputPort__ +#define __JackCoreMidiPhysicalInputPort__ + +#include "JackCoreMidiInputPort.h" + +namespace Jack { + + class JackCoreMidiPhysicalInputPort: public JackCoreMidiInputPort { + + public: + + JackCoreMidiPhysicalInputPort(const char *alias_name, + const char *client_name, + const char *driver_name, int index, + MIDIClientRef client, + MIDIPortRef internal_input, + double time_ratio, size_t max_bytes=4096, + size_t max_messages=1024); + + ~JackCoreMidiPhysicalInputPort(); + + }; + +} + +#endif diff --git a/macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp b/macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp new file mode 100644 index 00000000..d8a4af25 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp @@ -0,0 +1,78 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "JackCoreMidiPhysicalOutputPort.h" +#include "JackCoreMidiUtil.h" + +using Jack::JackCoreMidiPhysicalOutputPort; + +JackCoreMidiPhysicalOutputPort:: +JackCoreMidiPhysicalOutputPort(const char *alias_name, const char *client_name, + const char *driver_name, int index, + MIDIClientRef client, + MIDIPortRef internal_output, double time_ratio, + size_t max_bytes, + size_t max_messages): + JackCoreMidiOutputPort(time_ratio, max_bytes, + max_messages) +{ + MIDIEndpointRef destination = MIDIGetDestination(index); + if (! destination) { + // X: Can we get a better error message? + std::stringstream stream; + stream << "The destination at index '" << index + << "' is not available"; + throw std::runtime_error(stream.str().c_str()); + } + SInt32 advance_schedule_time; + OSStatus status = + MIDIObjectGetIntegerProperty(destination, + kMIDIPropertyAdvanceScheduleTimeMuSec, + &advance_schedule_time); + if (status != noErr) { + WriteMacOSError("JackCoreMidiPhysicalOutputPort [constructor]", + "MIDIObjectGetIntegerProperty", status); + advance_schedule_time = 0; + } else if (advance_schedule_time < 0) { + advance_schedule_time = 0; + } + Initialize(alias_name, client_name, driver_name, index, destination, + advance_schedule_time); + this->internal_output = internal_output; +} + +JackCoreMidiPhysicalOutputPort::~JackCoreMidiPhysicalOutputPort() +{ + // Empty +} + +bool +JackCoreMidiPhysicalOutputPort::SendPacketList(MIDIPacketList *packet_list) +{ + OSStatus status = MIDISend(internal_output, endpoint, packet_list); + bool result = status == noErr; + if (! result) { + WriteMacOSError("JackCoreMidiPhysicalOutputPort::SendPacketList", + "MIDISend", status); + } + return result; +} diff --git a/macosx/coremidi/JackCoreMidiPhysicalOutputPort.h b/macosx/coremidi/JackCoreMidiPhysicalOutputPort.h new file mode 100644 index 00000000..9d641180 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiPhysicalOutputPort.h @@ -0,0 +1,55 @@ +/* +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 __JackCoreMidiPhysicalOutputPort__ +#define __JackCoreMidiPhysicalOutputPort__ + +#include "JackCoreMidiOutputPort.h" + +namespace Jack { + + class JackCoreMidiPhysicalOutputPort: public JackCoreMidiOutputPort { + + private: + + MIDIPortRef internal_output; + + protected: + + bool + SendPacketList(MIDIPacketList *packet_list); + + public: + + JackCoreMidiPhysicalOutputPort(const char *alias_name, + const char *client_name, + const char *driver_name, int index, + MIDIClientRef client, + MIDIPortRef internal_output, + double time_ratio, + size_t max_bytes=4096, + size_t max_messages=1024); + + ~JackCoreMidiPhysicalOutputPort(); + + }; + +} + +#endif diff --git a/macosx/coremidi/JackCoreMidiPort.cpp b/macosx/coremidi/JackCoreMidiPort.cpp new file mode 100644 index 00000000..7b2fd6db --- /dev/null +++ b/macosx/coremidi/JackCoreMidiPort.cpp @@ -0,0 +1,93 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +#include "JackCoreMidiPort.h" +#include "JackCoreMidiUtil.h" +#include "JackError.h" + +using Jack::JackCoreMidiPort; + +JackCoreMidiPort::JackCoreMidiPort(double time_ratio) +{ + initialized = false; + this->time_ratio = time_ratio; +} + +JackCoreMidiPort::~JackCoreMidiPort() +{ + // Empty +} + +const char * +JackCoreMidiPort::GetAlias() +{ + assert(initialized); + return alias; +} + +MIDIEndpointRef +JackCoreMidiPort::GetEndpoint() +{ + assert(initialized); + return endpoint; +} + +const char * +JackCoreMidiPort::GetName() +{ + assert(initialized); + return name; +} + +void +JackCoreMidiPort::Initialize(const char *alias_name, const char *client_name, + const char *driver_name, int index, + MIDIEndpointRef endpoint, bool is_output) +{ + char endpoint_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; + CFStringRef endpoint_name_ref; + int num = index + 1; + Boolean res; + OSStatus result = MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, + &endpoint_name_ref); + if (result != noErr) { + WriteMacOSError("JackCoreMidiPort::Initialize", + "MIDIObjectGetStringProperty", result); + goto get_basic_alias; + } + res = CFStringGetCString(endpoint_name_ref, endpoint_name, + sizeof(endpoint_name), 0); + CFRelease(endpoint_name_ref); + if (!res) { + jack_error("JackCoreMidiPort::Initialize - failed to allocate memory " + "for endpoint name."); + get_basic_alias: + snprintf(alias, sizeof(alias) - 1, "%s:%s:%s%d", alias_name, + driver_name, is_output ? "in" : "out", num); + } else { + snprintf(alias, sizeof(alias) - 1, "%s:%s:%s%d", alias_name, + endpoint_name, is_output ? "in" : "out", num); + } + snprintf(name, sizeof(name) - 1, "%s:%s_%d", client_name, + is_output ? "playback" : "capture", num); + this->endpoint = endpoint; + initialized = true; +} diff --git a/macosx/coremidi/JackCoreMidiPort.h b/macosx/coremidi/JackCoreMidiPort.h new file mode 100644 index 00000000..21055c31 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiPort.h @@ -0,0 +1,67 @@ +/* +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 __JackCoreMidiPort__ +#define __JackCoreMidiPort__ + +#include + +#include "JackConstants.h" + +namespace Jack { + + class JackCoreMidiPort { + + private: + + char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; + bool initialized; + char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; + + protected: + + MIDIEndpointRef + GetEndpoint(); + + void + Initialize(const char *alias_name, const char *client_name, + const char *driver_name, int index, + MIDIEndpointRef endpoint, bool is_output); + + double time_ratio; + MIDIEndpointRef endpoint; + + public: + + JackCoreMidiPort(double time_ratio); + + virtual + ~JackCoreMidiPort(); + + const char * + GetAlias(); + + const char * + GetName(); + + }; + +} + +#endif diff --git a/macosx/coremidi/JackCoreMidiUtil.cpp b/macosx/coremidi/JackCoreMidiUtil.cpp new file mode 100644 index 00000000..d976e936 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiUtil.cpp @@ -0,0 +1,43 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +#include "JackError.h" +#include "JackCoreMidiUtil.h" + +std::string +Jack::GetMacOSErrorString(OSStatus status) +{ + const char *message = GetMacOSStatusErrorString(status); + if (! message) { + std::stringstream stream; + stream << "error (code: '" << status << "')"; + return stream.str(); + } + return std::string(message); +} + +void +Jack::WriteMacOSError(const char *jack_function, const char *mac_function, + OSStatus status) +{ + jack_error("%s - %s: %s", jack_function, mac_function, + GetMacOSErrorString(status).c_str()); +} diff --git a/macosx/coremidi/JackCoreMidiUtil.h b/macosx/coremidi/JackCoreMidiUtil.h new file mode 100644 index 00000000..4f24fc5b --- /dev/null +++ b/macosx/coremidi/JackCoreMidiUtil.h @@ -0,0 +1,39 @@ +/* +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 __JackCoreMidiUtil__ +#define __JackCoreMidiUtil__ + +#include + +#include +#include + +namespace Jack { + + std::string + GetMacOSErrorString(OSStatus status); + + void + WriteMacOSError(const char *jack_function, const char *mac_function, + OSStatus status); + +} + +#endif diff --git a/macosx/coremidi/JackCoreMidiVirtualInputPort.cpp b/macosx/coremidi/JackCoreMidiVirtualInputPort.cpp new file mode 100644 index 00000000..874a644d --- /dev/null +++ b/macosx/coremidi/JackCoreMidiVirtualInputPort.cpp @@ -0,0 +1,75 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "JackCoreMidiUtil.h" +#include "JackCoreMidiVirtualInputPort.h" + +using Jack::JackCoreMidiVirtualInputPort; + +/////////////////////////////////////////////////////////////////////////////// +// Static callbacks +/////////////////////////////////////////////////////////////////////////////// + +void +JackCoreMidiVirtualInputPort:: +HandleInputEvent(const MIDIPacketList *packet_list, void *port, + void */*src_ref*/) +{ + ((JackCoreMidiVirtualInputPort *) port)->ProcessCoreMidi(packet_list); +} + +/////////////////////////////////////////////////////////////////////////////// +// Class +/////////////////////////////////////////////////////////////////////////////// + +JackCoreMidiVirtualInputPort:: +JackCoreMidiVirtualInputPort(const char *alias_name, const char *client_name, + const char *driver_name, int index, + MIDIClientRef client, double time_ratio, + size_t max_bytes, size_t max_messages): + JackCoreMidiInputPort(time_ratio, max_bytes, max_messages) +{ + std::stringstream stream; + stream << "virtual" << (index + 1); + CFStringRef name = CFStringCreateWithCString(0, stream.str().c_str(), + CFStringGetSystemEncoding()); + if (! name) { + throw std::bad_alloc(); + } + MIDIEndpointRef destination; + OSStatus status = MIDIDestinationCreate(client, name, HandleInputEvent, + this, &destination); + CFRelease(name); + if (status != noErr) { + throw std::runtime_error(GetMacOSErrorString(status)); + } + Initialize(alias_name, client_name, driver_name, index, destination); +} + +JackCoreMidiVirtualInputPort::~JackCoreMidiVirtualInputPort() +{ + OSStatus status = MIDIEndpointDispose(GetEndpoint()); + if (status != noErr) { + WriteMacOSError("JackCoreMidiVirtualInputPort [destructor]", + "MIDIEndpointDispose", status); + } +} diff --git a/macosx/coremidi/JackCoreMidiVirtualInputPort.h b/macosx/coremidi/JackCoreMidiVirtualInputPort.h new file mode 100644 index 00000000..e48126c4 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiVirtualInputPort.h @@ -0,0 +1,50 @@ +/* +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 __JackCoreMidiVirtualInputPort__ +#define __JackCoreMidiVirtualInputPort__ + +#include "JackCoreMidiInputPort.h" + +namespace Jack { + + class JackCoreMidiVirtualInputPort: public JackCoreMidiInputPort { + + private: + + static void + HandleInputEvent(const MIDIPacketList *packet_list, void *port, + void *src_ref); + + public: + + JackCoreMidiVirtualInputPort(const char *alias_name, + const char *client_name, + const char *driver_name, int index, + MIDIClientRef client, double time_ratio, + size_t max_bytes=4096, + size_t max_messages=1024); + + ~JackCoreMidiVirtualInputPort(); + + }; + +} + +#endif diff --git a/macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp b/macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp new file mode 100644 index 00000000..0d8bc173 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp @@ -0,0 +1,72 @@ +/* +Copyright (C) 2011 Devin Anderson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "JackCoreMidiUtil.h" +#include "JackCoreMidiVirtualOutputPort.h" + +using Jack::JackCoreMidiVirtualOutputPort; + +JackCoreMidiVirtualOutputPort:: +JackCoreMidiVirtualOutputPort(const char *alias_name, const char *client_name, + const char *driver_name, int index, + MIDIClientRef client, double time_ratio, + size_t max_bytes, + size_t max_messages): + JackCoreMidiOutputPort(time_ratio, max_bytes, + max_messages) +{ + std::stringstream stream; + stream << "virtual" << (index + 1); + CFStringRef name = CFStringCreateWithCString(0, stream.str().c_str(), + CFStringGetSystemEncoding()); + if (! name) { + throw std::bad_alloc(); + } + MIDIEndpointRef source; + OSStatus status = MIDISourceCreate(client, name, &source); + CFRelease(name); + if (status != noErr) { + throw std::runtime_error(GetMacOSErrorString(status)); + } + Initialize(alias_name, client_name, driver_name, index, source, 0); +} + +JackCoreMidiVirtualOutputPort::~JackCoreMidiVirtualOutputPort() +{ + OSStatus status = MIDIEndpointDispose(GetEndpoint()); + if (status != noErr) { + WriteMacOSError("JackCoreMidiVirtualOutputPort [destructor]", + "MIDIEndpointDispose", status); + } +} + +bool +JackCoreMidiVirtualOutputPort::SendPacketList(MIDIPacketList *packet_list) +{ + OSStatus status = MIDIReceived(endpoint, packet_list); + bool result = status == noErr; + if (! result) { + WriteMacOSError("JackCoreMidiVirtualOutputPort::SendPacketList", + "MIDIReceived", status); + } + return result; +} diff --git a/macosx/coremidi/JackCoreMidiVirtualOutputPort.h b/macosx/coremidi/JackCoreMidiVirtualOutputPort.h new file mode 100644 index 00000000..61529a98 --- /dev/null +++ b/macosx/coremidi/JackCoreMidiVirtualOutputPort.h @@ -0,0 +1,49 @@ +/* +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 __JackCoreMidiVirtualOutputPort__ +#define __JackCoreMidiVirtualOutputPort__ + +#include "JackCoreMidiOutputPort.h" + +namespace Jack { + + class JackCoreMidiVirtualOutputPort: public JackCoreMidiOutputPort { + + protected: + + bool + SendPacketList(MIDIPacketList *packet_list); + + public: + + JackCoreMidiVirtualOutputPort(const char *alias_name, + const char *client_name, + const char *driver_name, int index, + MIDIClientRef client, double time_ratio, + size_t max_bytes=4096, + size_t max_messages=1024); + + ~JackCoreMidiVirtualOutputPort(); + + }; + +} + +#endif diff --git a/posix/JackNetUnixSocket.h b/posix/JackNetUnixSocket.h index 34e69b05..10fc2331 100644 --- a/posix/JackNetUnixSocket.h +++ b/posix/JackNetUnixSocket.h @@ -40,6 +40,7 @@ namespace Jack class SERVER_EXPORT JackNetUnixSocket { private: + int fSockfd; int fPort; int fTimeOut; @@ -50,7 +51,9 @@ namespace Jack int WaitRead(); int WaitWrite(); #endif + public: + JackNetUnixSocket(); JackNetUnixSocket ( const char* ip, int port ); JackNetUnixSocket ( const JackNetUnixSocket& ); diff --git a/posix/JackPosixThread.cpp b/posix/JackPosixThread.cpp index aed3796b..cae2c493 100644 --- a/posix/JackPosixThread.cpp +++ b/posix/JackPosixThread.cpp @@ -232,6 +232,8 @@ int JackPosixThread::AcquireRealTimeImp(jack_native_thread_t thread, int priorit memset(&rtparam, 0, sizeof(rtparam)); rtparam.sched_priority = priority; + jack_log("JackPosixThread::AcquireRealTimeImp priority = %d", priority); + if ((res = pthread_setschedparam(thread, JACK_SCHED_POLICY, &rtparam)) != 0) { jack_error("Cannot use real-time scheduling (RR/%d)" "(%d: %s)", rtparam.sched_priority, res, diff --git a/posix/JackSocketServerChannel.cpp b/posix/JackSocketServerChannel.cpp index 3008e307..2c5f267e 100644 --- a/posix/JackSocketServerChannel.cpp +++ b/posix/JackSocketServerChannel.cpp @@ -571,7 +571,7 @@ bool JackSocketServerChannel::Execute() return true; } catch (JackQuitException& e) { - jack_log("JackMachServerChannel::Execute JackQuitException"); + jack_log("JackSocketServerChannel::Execute JackQuitException"); return false; } } diff --git a/solaris/oss/JackBoomerDriver.cpp b/solaris/oss/JackBoomerDriver.cpp index fc054541..63446f14 100644 --- a/solaris/oss/JackBoomerDriver.cpp +++ b/solaris/oss/JackBoomerDriver.cpp @@ -106,14 +106,14 @@ static inline void CopyAndConvertOut(void *dst, jack_sample_t *src, size_t nfram case 24: { signed int *s32dst = (signed int*)dst; s32dst += channel; - sample_move_d24_sS((char*)s32dst, src, nframes, byte_skip, NULL); + sample_move_d24_sS((char*)s32dst, src, nframes, byte_skip, NULL); break; - } + } case 32: { signed int *s32dst = (signed int*)dst; s32dst += channel; sample_move_d32u24_sS((char*)s32dst, src, nframes, byte_skip, NULL); - break; + break; } } } @@ -127,7 +127,7 @@ void JackBoomerDriver::SetSampleFormat() fSampleSize = 4; break; case 32: /* native-endian 32-bit integer */ - fSampleFormat = AFMT_S32_NE; + fSampleFormat = AFMT_S32_NE; fSampleSize = 4; break; case 16: /* native-endian 16-bit integer */ @@ -144,13 +144,13 @@ void JackBoomerDriver::DisplayDeviceInfo() oss_audioinfo ai_in, ai_out; memset(&info, 0, sizeof(audio_buf_info)); int cap = 0; - + // Duplex cards : http://manuals.opensound.com/developer/full_duplex.html jack_info("Audio Interface Description :"); jack_info("Sampling Frequency : %d, Sample Format : %d, Mode : %d", fEngineControl->fSampleRate, fSampleFormat, fRWMode); - + if (fRWMode & kWrite) { - + oss_sysinfo si; if (ioctl(fOutFD, OSS_SYSINFO, &si) == -1) { jack_error("JackBoomerDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -162,18 +162,18 @@ void JackBoomerDriver::DisplayDeviceInfo() jack_info("OSS numaudioengines %d", si.numaudioengines); jack_info("OSS numcards %d", si.numcards); } - + jack_info("Output capabilities - %d channels : ", fPlaybackChannels); jack_info("Output block size = %d", fOutputBufferSize); - + if (ioctl(fOutFD, SNDCTL_DSP_GETOSPACE, &info) == -1) { jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); } else { - jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", + jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", info.fragments, info.fragstotal, info.fragsize, info.bytes); fFragmentSize = info.fragsize; } - + if (ioctl(fOutFD, SNDCTL_DSP_GETCAPS, &cap) == -1) { jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); } else { @@ -186,10 +186,10 @@ void JackBoomerDriver::DisplayDeviceInfo() if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI"); if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); } - } - + } + if (fRWMode & kRead) { - + oss_sysinfo si; if (ioctl(fInFD, OSS_SYSINFO, &si) == -1) { jack_error("JackBoomerDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -201,14 +201,14 @@ void JackBoomerDriver::DisplayDeviceInfo() jack_info("OSS numaudioengines %d", si.numaudioengines); jack_info("OSS numcards %d", si.numcards); } - + jack_info("Input capabilities - %d channels : ", fCaptureChannels); jack_info("Input block size = %d", fInputBufferSize); - - if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1) { + + if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1) { jack_error("JackBoomerDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); } else { - jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", + jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", info.fragments, info.fragstotal, info.fragsize, info.bytes); } @@ -225,31 +225,30 @@ void JackBoomerDriver::DisplayDeviceInfo() if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); } } - + if (ai_in.rate_source != ai_out.rate_source) { jack_info("Warning : input and output are not necessarily driven by the same clock!"); } } JackBoomerDriver::JackBoomerDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) - : JackAudioDriver(name, alias, engine, table), - fInFD(-1), fOutFD(-1), fBits(0), - fSampleFormat(0), fNperiods(0), fSampleSize(0), fFragmentSize(0), - fRWMode(0), fExcl(false), fSyncIO(false), - fInputBufferSize(0), fOutputBufferSize(0), - fInputBuffer(NULL), fOutputBuffer(NULL), - fInputThread(&fInputHandler), fOutputThread(&fOutputHandler), - fInputHandler(this), fOutputHandler(this) - + : JackAudioDriver(name, alias, engine, table), + fInFD(-1), fOutFD(-1), fBits(0), + fSampleFormat(0), fNperiods(0), fSampleSize(0), fFragmentSize(0), + fRWMode(0), fExcl(false), fSyncIO(false), + fInputBufferSize(0), fOutputBufferSize(0), + fInputBuffer(NULL), fOutputBuffer(NULL), + fInputThread(&fInputHandler), fOutputThread(&fOutputHandler), + fInputHandler(this), fOutputHandler(this) { - sem_init(&fReadSema, 0, 0); - sem_init(&fWriteSema, 0, 0); + sem_init(&fReadSema, 0, 0); + sem_init(&fWriteSema, 0, 0); } JackBoomerDriver::~JackBoomerDriver() { - sem_destroy(&fReadSema); - sem_destroy(&fWriteSema); + sem_destroy(&fReadSema); + sem_destroy(&fWriteSema); } int JackBoomerDriver::OpenInput() @@ -260,8 +259,9 @@ int JackBoomerDriver::OpenInput() int cur_sample_format; jack_nframes_t cur_sample_rate; - if (fCaptureChannels == 0) fCaptureChannels = 2; - + if (fCaptureChannels == 0) + fCaptureChannels = 2; + if ((fInFD = open(fCaptureDriverName, O_RDONLY | ((fExcl) ? O_EXCL : 0))) < 0) { jack_error("JackBoomerDriver::OpenInput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno); return -1; @@ -276,7 +276,7 @@ int JackBoomerDriver::OpenInput() } } - gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fCaptureChannels); + gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fCaptureChannels); if (ioctl(fInFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) { jack_error("JackBoomerDriver::OpenInput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); goto error; @@ -290,7 +290,7 @@ int JackBoomerDriver::OpenInput() if (cur_sample_format != fSampleFormat) { jack_info("JackBoomerDriver::OpenInput driver forced the sample format %ld", fSampleFormat); } - + cur_capture_channels = fCaptureChannels; if (ioctl(fInFD, SNDCTL_DSP_CHANNELS, &fCaptureChannels) == -1) { jack_error("JackBoomerDriver::OpenInput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -299,7 +299,7 @@ int JackBoomerDriver::OpenInput() if (cur_capture_channels != fCaptureChannels) { jack_info("JackBoomerDriver::OpenInput driver forced the number of capture channels %ld", fCaptureChannels); } - + cur_sample_rate = fEngineControl->fSampleRate; if (ioctl(fInFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) { jack_error("JackBoomerDriver::OpenInput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -315,7 +315,7 @@ int JackBoomerDriver::OpenInput() fInputBuffer = (void*)calloc(fInputBufferSize, 1); assert(fInputBuffer); return 0; - + error: ::close(fInFD); return -1; @@ -329,28 +329,29 @@ int JackBoomerDriver::OpenOutput() int cur_playback_channels; jack_nframes_t cur_sample_rate; - if (fPlaybackChannels == 0) fPlaybackChannels = 2; - + if (fPlaybackChannels == 0) + fPlaybackChannels = 2; + if ((fOutFD = open(fPlaybackDriverName, O_WRONLY | ((fExcl) ? O_EXCL : 0))) < 0) { jack_error("JackBoomerDriver::OpenOutput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno); return -1; } jack_log("JackBoomerDriver::OpenOutput output fOutFD = %d", fOutFD); - + if (fExcl) { if (ioctl(fOutFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) { jack_error("JackBoomerDriver::OpenOutput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno); goto error; - } - } + } + } - gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels); + gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels); if (ioctl(fOutFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) { jack_error("JackBoomerDriver::OpenOutput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); goto error; } - + cur_sample_format = fSampleFormat; if (ioctl(fOutFD, SNDCTL_DSP_SETFMT, &fSampleFormat) == -1) { jack_error("JackBoomerDriver::OpenOutput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -359,7 +360,7 @@ int JackBoomerDriver::OpenOutput() if (cur_sample_format != fSampleFormat) { jack_info("JackBoomerDriver::OpenOutput driver forced the sample format %ld", fSampleFormat); } - + cur_playback_channels = fPlaybackChannels; if (ioctl(fOutFD, SNDCTL_DSP_CHANNELS, &fPlaybackChannels) == -1) { jack_error("JackBoomerDriver::OpenOutput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -380,33 +381,33 @@ int JackBoomerDriver::OpenOutput() // Just set the write size to the value we want... fOutputBufferSize = fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels; - + fOutputBuffer = (void*)calloc(fOutputBufferSize, 1); assert(fOutputBuffer); return 0; - + error: ::close(fOutFD); return -1; } int JackBoomerDriver::Open(jack_nframes_t nframes, - int user_nperiods, - jack_nframes_t samplerate, - bool capturing, - bool playing, - int inchannels, - int outchannels, - bool excl, - bool monitor, - const char* capture_driver_uid, - const char* playback_driver_uid, - jack_nframes_t capture_latency, - jack_nframes_t playback_latency, - int bits, bool syncio) + int user_nperiods, + jack_nframes_t samplerate, + bool capturing, + bool playing, + int inchannels, + int outchannels, + bool excl, + bool monitor, + const char* capture_driver_uid, + const char* playback_driver_uid, + jack_nframes_t capture_latency, + jack_nframes_t playback_latency, + int bits, bool syncio) { // Generic JackAudioDriver Open - if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, + if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) { return -1; } else { @@ -422,12 +423,12 @@ int JackBoomerDriver::Open(jack_nframes_t nframes, fExcl = excl; fNperiods = (user_nperiods == 0) ? 1 : user_nperiods ; fSyncIO = syncio; - + #ifdef JACK_MONITOR // Force memory page in memset(&gCycleTable, 0, sizeof(gCycleTable)); #endif - + if (OpenAux() < 0) { Close(); return -1; @@ -441,14 +442,14 @@ int JackBoomerDriver::Close() { #ifdef JACK_MONITOR FILE* file = fopen("OSSProfiling.log", "w"); - + if (file) { jack_info("Writing OSS driver timing data...."); for (int i = 1; i < std::min(gCycleReadCount, gCycleWriteCount); i++) { int d1 = gCycleTable.fTable[i].fAfterRead - gCycleTable.fTable[i].fBeforeRead; int d2 = gCycleTable.fTable[i].fAfterReadConvert - gCycleTable.fTable[i].fAfterRead; int d3 = gCycleTable.fTable[i].fAfterWrite - gCycleTable.fTable[i].fBeforeWrite; - int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert; + int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert; fprintf(file, "%d \t %d \t %d \t %d \t \n", d1, d2, d3, d4); } fclose(file); @@ -461,7 +462,7 @@ int JackBoomerDriver::Close() if (file == NULL) { jack_error("JackBoomerDriver::Close cannot open TimingOSS.plot file"); } else { - + fprintf(file, "set grid\n"); fprintf(file, "set title \"OSS audio driver timing\"\n"); fprintf(file, "set xlabel \"audio cycles\"\n"); @@ -470,10 +471,10 @@ int JackBoomerDriver::Close() \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \ \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \ \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n"); - + fprintf(file, "set output 'TimingOSS.pdf\n"); fprintf(file, "set terminal pdf\n"); - + fprintf(file, "set grid\n"); fprintf(file, "set title \"OSS audio driver timing\"\n"); fprintf(file, "set xlabel \"audio cycles\"\n"); @@ -482,12 +483,12 @@ int JackBoomerDriver::Close() \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \ \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \ \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n"); - + fclose(file); } #endif int res = JackAudioDriver::Close(); - CloseAux(); + CloseAux(); return res; } @@ -498,12 +499,12 @@ int JackBoomerDriver::OpenAux() if ((fRWMode & kRead) && (OpenInput() < 0)) { return -1; } - - if ((fRWMode & kWrite) && (OpenOutput() < 0)) { + + if ((fRWMode & kWrite) && (OpenOutput() < 0)) { return -1; } - - DisplayDeviceInfo(); + + DisplayDeviceInfo(); return 0; } @@ -513,16 +514,16 @@ void JackBoomerDriver::CloseAux() close(fInFD); fInFD = -1; } - + if (fRWMode & kWrite && fOutFD >= 0) { close(fOutFD); fOutFD = -1; } - + if (fInputBuffer) free(fInputBuffer); fInputBuffer = NULL; - + if (fOutputBuffer) free(fOutputBuffer); fOutputBuffer = NULL; @@ -533,29 +534,29 @@ int JackBoomerDriver::Start() jack_log("JackBoomerDriver::Start"); JackAudioDriver::Start(); - // Input/output synchronisation + // Input/output synchronisation if (fInFD >= 0 && fOutFD >= 0 && fSyncIO) { - jack_log("JackBoomerDriver::Start sync input/output"); + jack_log("JackBoomerDriver::Start sync input/output"); // Create and fill synch group int id; oss_syncgroup group; group.id = 0; - + group.mode = PCM_ENABLE_INPUT; - if (ioctl(fInFD, SNDCTL_DSP_SYNCGROUP, &group) == -1) + if (ioctl(fInFD, SNDCTL_DSP_SYNCGROUP, &group) == -1) jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCGROUP : %s@%i, errno = %d", __FILE__, __LINE__, errno); - + group.mode = PCM_ENABLE_OUTPUT; - if (ioctl(fOutFD, SNDCTL_DSP_SYNCGROUP, &group) == -1) + if (ioctl(fOutFD, SNDCTL_DSP_SYNCGROUP, &group) == -1) jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCGROUP : %s@%i, errno = %d", __FILE__, __LINE__, errno); // Prefill output buffer : 2 fragments of silence as described in http://manuals.opensound.com/developer/synctest.c.html#LOC6 char* silence_buf = (char*)malloc(fFragmentSize); memset(silence_buf, 0, fFragmentSize); - jack_log ("JackBoomerDriver::Start prefill size = %d", fFragmentSize); + jack_log ("JackBoomerDriver::Start prefill size = %d", fFragmentSize); for (int i = 0; i < 2; i++) { ssize_t count = ::write(fOutFD, silence_buf, fFragmentSize); @@ -569,12 +570,12 @@ int JackBoomerDriver::Start() // Start input/output in sync id = group.id; - if (ioctl(fInFD, SNDCTL_DSP_SYNCSTART, &id) == -1) + if (ioctl(fInFD, SNDCTL_DSP_SYNCSTART, &id) == -1) jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCSTART : %s@%i, errno = %d", __FILE__, __LINE__, errno); } else if (fOutFD >= 0) { - - // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html + + // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html memset(fOutputBuffer, 0, fOutputBufferSize); // Prefill ouput buffer @@ -584,8 +585,8 @@ int JackBoomerDriver::Start() jack_error("JackBoomerDriver::Start error bytes written = %ld", count); } } - } - + } + // Start input thread only when needed if (fInFD >= 0) { if (fInputThread.StartSync() < 0) { @@ -627,44 +628,44 @@ bool JackBoomerDriver::JackBoomerDriverInput::Init() if (fDriver->fInputThread.AcquireRealTime(GetEngineControl()->fServerPriority) < 0) { jack_error("AcquireRealTime error"); } else { - set_threaded_log_function(); + set_threaded_log_function(); } } - + return true; } // TODO : better error handling bool JackBoomerDriver::JackBoomerDriverInput::Execute() { - + #ifdef JACK_MONITOR gCycleTable.fTable[gCycleReadCount].fBeforeRead = GetMicroSeconds(); #endif audio_errinfo ei_in; - ssize_t count = ::read(fDriver->fInFD, fDriver->fInputBuffer, fDriver->fInputBufferSize); - + ssize_t count = ::read(fDriver->fInFD, fDriver->fInputBuffer, fDriver->fInputBufferSize); + #ifdef JACK_MONITOR if (count > 0 && count != (int)fDriver->fInputBufferSize) jack_log("JackBoomerDriverInput::Execute count = %ld", count / (fDriver->fSampleSize * fDriver->fCaptureChannels)); gCycleTable.fTable[gCycleReadCount].fAfterRead = GetMicroSeconds(); #endif - + // XRun detection if (ioctl(fDriver->fInFD, SNDCTL_DSP_GETERROR, &ei_in) == 0) { if (ei_in.rec_overruns > 0 ) { jack_error("JackBoomerDriverInput::Execute overruns"); jack_time_t cur_time = GetMicroSeconds(); - fDriver->NotifyXRun(cur_time, float(cur_time - fDriver->fBeginDateUst)); // Better this value than nothing... + fDriver->NotifyXRun(cur_time, float(cur_time - fDriver->fBeginDateUst)); // Better this value than nothing... } if (ei_in.rec_errorcount > 0 && ei_in.rec_lasterror != 0) { jack_error("%d OSS rec event(s), last=%05d:%d", ei_in.rec_errorcount, ei_in.rec_lasterror, ei_in.rec_errorparm); } - } - + } + if (count < 0) { jack_log("JackBoomerDriverInput::Execute error = %s", strerror(errno)); } else if (count < (int)fDriver->fInputBufferSize) { @@ -675,11 +676,11 @@ bool JackBoomerDriver::JackBoomerDriverInput::Execute() fDriver->CycleTakeBeginTime(); for (int i = 0; i < fDriver->fCaptureChannels; i++) { if (fDriver->fGraphManager->GetConnectionsNum(fDriver->fCapturePortList[i]) > 0) { - CopyAndConvertIn(fDriver->GetInputBuffer(i), - fDriver->fInputBuffer, - fDriver->fEngineControl->fBufferSize, - i, - fDriver->fCaptureChannels * fDriver->fSampleSize, + CopyAndConvertIn(fDriver->GetInputBuffer(i), + fDriver->fInputBuffer, + fDriver->fEngineControl->fBufferSize, + i, + fDriver->fCaptureChannels * fDriver->fSampleSize, fDriver->fBits); } } @@ -707,18 +708,18 @@ bool JackBoomerDriver::JackBoomerDriverOutput::Init() if (fDriver->fOutputThread.AcquireRealTime(GetEngineControl()->fServerPriority) < 0) { jack_error("AcquireRealTime error"); } else { - set_threaded_log_function(); + set_threaded_log_function(); } } - + int delay; if (ioctl(fDriver->fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) { jack_error("JackBoomerDriverOutput::Init error get out delay : %s@%i, errno = %d", __FILE__, __LINE__, errno); } - + delay /= fDriver->fSampleSize * fDriver->fPlaybackChannels; jack_info("JackBoomerDriverOutput::Init output latency frames = %ld", delay); - + return true; } @@ -730,21 +731,21 @@ bool JackBoomerDriver::JackBoomerDriverOutput::Execute() #ifdef JACK_MONITOR gCycleTable.fTable[gCycleWriteCount].fBeforeWriteConvert = GetMicroSeconds(); #endif - + for (int i = 0; i < fDriver->fPlaybackChannels; i++) { if (fDriver->fGraphManager->GetConnectionsNum(fDriver->fPlaybackPortList[i]) > 0) { - CopyAndConvertOut(fDriver->fOutputBuffer, - fDriver->GetOutputBuffer(i), - fDriver->fEngineControl->fBufferSize, - i, - fDriver->fPlaybackChannels * fDriver->fSampleSize, + CopyAndConvertOut(fDriver->fOutputBuffer, + fDriver->GetOutputBuffer(i), + fDriver->fEngineControl->fBufferSize, + i, + fDriver->fPlaybackChannels * fDriver->fSampleSize, fDriver->fBits); } } - + #ifdef JACK_MONITOR gCycleTable.fTable[gCycleWriteCount].fBeforeWrite = GetMicroSeconds(); -#endif +#endif ssize_t count = ::write(fDriver->fOutFD, fDriver->fOutputBuffer, fDriver->fOutputBufferSize); @@ -762,20 +763,20 @@ bool JackBoomerDriver::JackBoomerDriverOutput::Execute() if (ei_out.play_underruns > 0) { jack_error("JackBoomerDriverOutput::Execute underruns"); jack_time_t cur_time = GetMicroSeconds(); - fDriver->NotifyXRun(cur_time, float(cur_time - fDriver->fBeginDateUst)); // Better this value than nothing... + fDriver->NotifyXRun(cur_time, float(cur_time - fDriver->fBeginDateUst)); // Better this value than nothing... } if (ei_out.play_errorcount > 0 && ei_out.play_lasterror != 0) { jack_error("%d OSS play event(s), last=%05d:%d",ei_out.play_errorcount, ei_out.play_lasterror, ei_out.play_errorparm); } } - + if (count < 0) { jack_log("JackBoomerDriverOutput::Execute error = %s", strerror(errno)); } else if (count < (int)fDriver->fOutputBufferSize) { jack_error("JackBoomerDriverOutput::Execute error bytes written = %ld", count); } - + // Duplex : sync with read thread if (fDriver->fInFD >= 0 && fDriver->fOutFD >= 0) { fDriver->SynchronizeWrite(); @@ -802,12 +803,11 @@ void JackBoomerDriver::SynchronizeWrite() int JackBoomerDriver::SetBufferSize(jack_nframes_t buffer_size) { - CloseAux(); - JackAudioDriver::SetBufferSize(buffer_size); // never fails + CloseAux(); + JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails return OpenAux(); } - } // end of namespace #ifdef __cplusplus @@ -823,7 +823,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->name, "boomer"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 strcpy(desc->desc, "Boomer/OSS API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 - + desc->nparams = OSS_DRIVER_N_PARAMS; desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); @@ -866,7 +866,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() desc->params[i].value.ui = OSS_DRIVER_DEF_INS; strcpy(desc->params[i].short_desc, "Capture channels"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "outchannels"); desc->params[i].character = 'o'; @@ -874,7 +874,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() desc->params[i].value.ui = OSS_DRIVER_DEF_OUTS; strcpy(desc->params[i].short_desc, "Playback channels"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "excl"); desc->params[i].character = 'e'; @@ -890,7 +890,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->params[i].value.str, OSS_DRIVER_DEF_DEV); strcpy(desc->params[i].short_desc, "Input device"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "playback"); desc->params[i].character = 'P'; @@ -906,12 +906,12 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->params[i].value.str, OSS_DRIVER_DEF_DEV); strcpy(desc->params[i].short_desc, "OSS device name"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "input-latency"); desc->params[i].character = 'I'; desc->params[i].type = JackDriverParamUInt; - desc->params[i].value.i = 0; + desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Extra input latency"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -919,7 +919,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->params[i].name, "output-latency"); desc->params[i].character = 'O'; desc->params[i].type = JackDriverParamUInt; - desc->params[i].value.i = 0; + desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Extra output latency"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -953,13 +953,13 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine const jack_driver_param_t *param; jack_nframes_t systemic_input_latency = 0; jack_nframes_t systemic_output_latency = 0; - + for (node = params; node; node = jack_slist_next(node)) { - + param = (const jack_driver_param_t *)node->data; switch (param->character) { - + case 'r': srate = param->value.ui; break; @@ -983,7 +983,7 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine case 'o': chan_out = (int)param->value.ui; break; - + case 'C': capture = true; if (strcmp(param->value.str, "none") != 0) { @@ -1002,11 +1002,11 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine playback_pcm_name = param->value.str; capture_pcm_name = param->value.str; break; - + case 'e': excl = true; break; - + case 'I': systemic_input_latency = param->value.ui; break; @@ -1028,9 +1028,9 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine } Jack::JackBoomerDriver* boomer_driver = new Jack::JackBoomerDriver("system", "boomer", engine, table); - + // Special open for Boomer driver... - if (boomer_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out, excl, + if (boomer_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out, excl, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, syncio) == 0) { return boomer_driver; } else { diff --git a/solaris/oss/JackOSSDriver.cpp b/solaris/oss/JackOSSDriver.cpp index 3b66740a..444fce44 100644 --- a/solaris/oss/JackOSSDriver.cpp +++ b/solaris/oss/JackOSSDriver.cpp @@ -107,12 +107,12 @@ static inline void CopyAndConvertOut(void *dst, jack_sample_t *src, size_t nfram s32dst += channel; sample_move_d24_sS((char*)s32dst, src, nframes, chcount<<2, NULL); // No dithering for now... break; - } + } case 32: { signed int *s32dst = (signed int*)dst; s32dst += channel; sample_move_d32u24_sS((char*)s32dst, src, nframes, chcount<<2, NULL); - break; + break; } } } @@ -126,7 +126,7 @@ void JackOSSDriver::SetSampleFormat() fSampleSize = sizeof(int); break; case 32: /* native-endian 32-bit integer */ - fSampleFormat = AFMT_S32_NE; + fSampleFormat = AFMT_S32_NE; fSampleSize = sizeof(int); break; case 16: /* native-endian 16-bit integer */ @@ -143,13 +143,13 @@ void JackOSSDriver::DisplayDeviceInfo() oss_audioinfo ai_in, ai_out; memset(&info, 0, sizeof(audio_buf_info)); int cap = 0; - + // Duplex cards : http://manuals.opensound.com/developer/full_duplex.html jack_info("Audio Interface Description :"); jack_info("Sampling Frequency : %d, Sample Format : %d, Mode : %d", fEngineControl->fSampleRate, fSampleFormat, fRWMode); - + if (fRWMode & kWrite) { - + oss_sysinfo si; if (ioctl(fOutFD, OSS_SYSINFO, &si) == -1) { jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -161,17 +161,17 @@ void JackOSSDriver::DisplayDeviceInfo() jack_info("OSS numaudioengines %d", si.numaudioengines); jack_info("OSS numcards %d", si.numcards); } - + jack_info("Output capabilities - %d channels : ", fPlaybackChannels); jack_info("Output block size = %d", fOutputBufferSize); - + if (ioctl(fOutFD, SNDCTL_DSP_GETOSPACE, &info) == -1) { jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); } else { - jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", + jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", info.fragments, info.fragstotal, info.fragsize, info.bytes); } - + if (ioctl(fOutFD, SNDCTL_DSP_GETCAPS, &cap) == -1) { jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETCAPS failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); } else { @@ -184,10 +184,10 @@ void JackOSSDriver::DisplayDeviceInfo() if (cap & DSP_CAP_MULTI) jack_info(" DSP_CAP_MULTI"); if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); } - } - + } + if (fRWMode & kRead) { - + oss_sysinfo si; if (ioctl(fInFD, OSS_SYSINFO, &si) == -1) { jack_error("JackOSSDriver::DisplayDeviceInfo OSS_SYSINFO failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -199,14 +199,14 @@ void JackOSSDriver::DisplayDeviceInfo() jack_info("OSS numaudioengines %d", si.numaudioengines); jack_info("OSS numcards %d", si.numcards); } - + jack_info("Input capabilities - %d channels : ", fCaptureChannels); jack_info("Input block size = %d", fInputBufferSize); - - if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1) { + + if (ioctl(fInFD, SNDCTL_DSP_GETISPACE, &info) == -1) { jack_error("JackOSSDriver::DisplayDeviceInfo SNDCTL_DSP_GETOSPACE failed : %s@%i, errno = %d", __FILE__, __LINE__, errno); } else { - jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", + jack_info("input space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", info.fragments, info.fragstotal, info.fragsize, info.bytes); } @@ -223,7 +223,7 @@ void JackOSSDriver::DisplayDeviceInfo() if (cap & DSP_CAP_BIND) jack_info(" DSP_CAP_BIND"); } } - + if (ai_in.rate_source != ai_out.rate_source) { jack_info("Warning : input and output are not necessarily driven by the same clock!"); } @@ -238,7 +238,7 @@ int JackOSSDriver::OpenInput() jack_nframes_t cur_sample_rate; if (fCaptureChannels == 0) fCaptureChannels = 2; - + if ((fInFD = open(fCaptureDriverName, O_RDONLY | ((fExcl) ? O_EXCL : 0))) < 0) { jack_error("JackOSSDriver::OpenInput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno); return -1; @@ -253,7 +253,7 @@ int JackOSSDriver::OpenInput() } } - gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fCaptureChannels); + gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fCaptureChannels); if (ioctl(fInFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) { jack_error("JackOSSDriver::OpenInput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); goto error; @@ -267,7 +267,7 @@ int JackOSSDriver::OpenInput() if (cur_sample_format != fSampleFormat) { jack_info("JackOSSDriver::OpenInput driver forced the sample format %ld", fSampleFormat); } - + cur_capture_channels = fCaptureChannels; if (ioctl(fInFD, SNDCTL_DSP_CHANNELS, &fCaptureChannels) == -1) { jack_error("JackOSSDriver::OpenInput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -276,7 +276,7 @@ int JackOSSDriver::OpenInput() if (cur_capture_channels != fCaptureChannels) { jack_info("JackOSSDriver::OpenInput driver forced the number of capture channels %ld", fCaptureChannels); } - + cur_sample_rate = fEngineControl->fSampleRate; if (ioctl(fInFD, SNDCTL_DSP_SPEED, &fEngineControl->fSampleRate) == -1) { jack_error("JackOSSDriver::OpenInput failed to set sample rate : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -291,7 +291,7 @@ int JackOSSDriver::OpenInput() jack_error("JackOSSDriver::OpenInput failed to get fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); goto error; } - + if (fInputBufferSize != fEngineControl->fBufferSize * fSampleSize * fCaptureChannels) { if (fIgnoreHW) { int new_buffer_size = fInputBufferSize / (fSampleSize * fCaptureChannels); @@ -306,7 +306,7 @@ int JackOSSDriver::OpenInput() fInputBuffer = (void*)calloc(fInputBufferSize, 1); assert(fInputBuffer); return 0; - + error: ::close(fInFD); return -1; @@ -321,27 +321,27 @@ int JackOSSDriver::OpenOutput() jack_nframes_t cur_sample_rate; if (fPlaybackChannels == 0) fPlaybackChannels = 2; - + if ((fOutFD = open(fPlaybackDriverName, O_WRONLY | ((fExcl) ? O_EXCL : 0))) < 0) { jack_error("JackOSSDriver::OpenOutput failed to open device : %s@%i, errno = %d", __FILE__, __LINE__, errno); return -1; } jack_log("JackOSSDriver::OpenOutput output fOutFD = %d", fOutFD); - + if (fExcl) { if (ioctl(fOutFD, SNDCTL_DSP_COOKEDMODE, &flags) == -1) { jack_error("JackOSSDriver::OpenOutput failed to set cooked mode : %s@%i, errno = %d", __FILE__, __LINE__, errno); goto error; - } - } + } + } - gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels); + gFragFormat = (2 << 16) + int2pow2(fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels); if (ioctl(fOutFD, SNDCTL_DSP_SETFRAGMENT, &gFragFormat) == -1) { jack_error("JackOSSDriver::OpenOutput failed to set fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); goto error; } - + cur_sample_format = fSampleFormat; if (ioctl(fOutFD, SNDCTL_DSP_SETFMT, &fSampleFormat) == -1) { jack_error("JackOSSDriver::OpenOutput failed to set format : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -350,7 +350,7 @@ int JackOSSDriver::OpenOutput() if (cur_sample_format != fSampleFormat) { jack_info("JackOSSDriver::OpenOutput driver forced the sample format %ld", fSampleFormat); } - + cur_playback_channels = fPlaybackChannels; if (ioctl(fOutFD, SNDCTL_DSP_CHANNELS, &fPlaybackChannels) == -1) { jack_error("JackOSSDriver::OpenOutput failed to set channels : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -374,7 +374,7 @@ int JackOSSDriver::OpenOutput() jack_error("JackOSSDriver::OpenOutput failed to get fragments : %s@%i, errno = %d", __FILE__, __LINE__, errno); goto error; } - + if (fOutputBufferSize != fEngineControl->fBufferSize * fSampleSize * fPlaybackChannels) { if (fIgnoreHW) { int new_buffer_size = fOutputBufferSize / (fSampleSize * fPlaybackChannels); @@ -385,19 +385,19 @@ int JackOSSDriver::OpenOutput() goto error; } } - + fOutputBuffer = (void*)calloc(fOutputBufferSize, 1); fFirstCycle = true; assert(fOutputBuffer); return 0; - + error: ::close(fOutFD); return -1; } int JackOSSDriver::Open(jack_nframes_t nframes, - int user_nperiods, + int user_nperiods, jack_nframes_t samplerate, bool capturing, bool playing, @@ -413,7 +413,7 @@ int JackOSSDriver::Open(jack_nframes_t nframes, bool ignorehwbuf) { // Generic JackAudioDriver Open - if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, + if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) { return -1; } else { @@ -422,7 +422,7 @@ int JackOSSDriver::Open(jack_nframes_t nframes, jack_error("Cannot run in asynchronous mode, use the -S parameter for jackd"); return -1; } - + fRWMode |= ((capturing) ? kRead : 0); fRWMode |= ((playing) ? kWrite : 0); fBits = bits; @@ -434,7 +434,7 @@ int JackOSSDriver::Open(jack_nframes_t nframes, // Force memory page in memset(&gCycleTable, 0, sizeof(gCycleTable)); #endif - + if (OpenAux() < 0) { Close(); return -1; @@ -448,14 +448,14 @@ int JackOSSDriver::Close() { #ifdef JACK_MONITOR FILE* file = fopen("OSSProfiling.log", "w"); - + if (file) { jack_info("Writing OSS driver timing data...."); for (int i = 1; i < gCycleCount; i++) { int d1 = gCycleTable.fTable[i].fAfterRead - gCycleTable.fTable[i].fBeforeRead; int d2 = gCycleTable.fTable[i].fAfterReadConvert - gCycleTable.fTable[i].fAfterRead; int d3 = gCycleTable.fTable[i].fAfterWrite - gCycleTable.fTable[i].fBeforeWrite; - int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert; + int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert; fprintf(file, "%d \t %d \t %d \t %d \t \n", d1, d2, d3, d4); } fclose(file); @@ -468,7 +468,7 @@ int JackOSSDriver::Close() if (file == NULL) { jack_error("JackOSSDriver::Close cannot open TimingOSS.plot file"); } else { - + fprintf(file, "set grid\n"); fprintf(file, "set title \"OSS audio driver timing\"\n"); fprintf(file, "set xlabel \"audio cycles\"\n"); @@ -477,10 +477,10 @@ int JackOSSDriver::Close() \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \ \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \ \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n"); - + fprintf(file, "set output 'TimingOSS.pdf\n"); fprintf(file, "set terminal pdf\n"); - + fprintf(file, "set grid\n"); fprintf(file, "set title \"OSS audio driver timing\"\n"); fprintf(file, "set xlabel \"audio cycles\"\n"); @@ -489,12 +489,12 @@ int JackOSSDriver::Close() \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \ \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \ \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n"); - + fclose(file); } #endif int res = JackAudioDriver::Close(); - CloseAux(); + CloseAux(); return res; } @@ -506,8 +506,8 @@ int JackOSSDriver::OpenAux() if ((fRWMode & kRead) && (OpenInput() < 0)) { return -1; } - - if ((fRWMode & kWrite) && (OpenOutput() < 0)) { + + if ((fRWMode & kWrite) && (OpenOutput() < 0)) { return -1; } @@ -522,7 +522,7 @@ int JackOSSDriver::OpenAux() } */ - DisplayDeviceInfo(); + DisplayDeviceInfo(); return 0; } @@ -532,16 +532,16 @@ void JackOSSDriver::CloseAux() close(fInFD); fInFD = -1; } - + if (fRWMode & kWrite && fOutFD > 0) { close(fOutFD); fOutFD = -1; } - + if (fInputBuffer) free(fInputBuffer); fInputBuffer = NULL; - + if (fOutputBuffer) free(fOutputBuffer); fOutputBuffer = NULL; @@ -554,7 +554,7 @@ int JackOSSDriver::Read() JackDriver::CycleTakeBeginTime(); return 0; } - + ssize_t count; #ifdef JACK_MONITOR @@ -562,28 +562,28 @@ int JackOSSDriver::Read() #endif audio_errinfo ei_in; - count = ::read(fInFD, fInputBuffer, fInputBufferSize); - + count = ::read(fInFD, fInputBuffer, fInputBufferSize); + #ifdef JACK_MONITOR if (count > 0 && count != (int)fInputBufferSize) jack_log("JackOSSDriver::Read count = %ld", count / (fSampleSize * fCaptureChannels)); gCycleTable.fTable[gCycleCount].fAfterRead = GetMicroSeconds(); #endif - + // XRun detection if (ioctl(fInFD, SNDCTL_DSP_GETERROR, &ei_in) == 0) { if (ei_in.rec_overruns > 0 ) { jack_error("JackOSSDriver::Read overruns"); jack_time_t cur_time = GetMicroSeconds(); - NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... + NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... } if (ei_in.rec_errorcount > 0 && ei_in.rec_lasterror != 0) { jack_error("%d OSS rec event(s), last=%05d:%d", ei_in.rec_errorcount, ei_in.rec_lasterror, ei_in.rec_errorparm); } - } - + } + if (count < 0) { jack_log("JackOSSDriver::Read error = %s", strerror(errno)); return -1; @@ -603,7 +603,7 @@ int JackOSSDriver::Read() #ifdef JACK_MONITOR gCycleTable.fTable[gCycleCount].fAfterReadConvert = GetMicroSeconds(); #endif - + return 0; } } @@ -618,10 +618,10 @@ int JackOSSDriver::Write() ssize_t count; audio_errinfo ei_out; - - // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html + + // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html if (fFirstCycle) { - + fFirstCycle = false; memset(fOutputBuffer, 0, fOutputBufferSize); @@ -633,17 +633,17 @@ int JackOSSDriver::Write() return -1; } } - + int delay; if (ioctl(fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) { jack_error("JackOSSDriver::Write error get out delay : %s@%i, errno = %d", __FILE__, __LINE__, errno); return -1; } - + delay /= fSampleSize * fPlaybackChannels; jack_info("JackOSSDriver::Write output latency frames = %ld", delay); } - + #ifdef JACK_MONITOR gCycleTable.fTable[gCycleCount].fBeforeWriteConvert = GetMicroSeconds(); #endif @@ -657,7 +657,7 @@ int JackOSSDriver::Write() #ifdef JACK_MONITOR gCycleTable.fTable[gCycleCount].fBeforeWrite = GetMicroSeconds(); - #endif + #endif // Keep end cycle time JackDriver::CycleTakeEndTime(); @@ -676,14 +676,14 @@ int JackOSSDriver::Write() if (ei_out.play_underruns > 0) { jack_error("JackOSSDriver::Write underruns"); jack_time_t cur_time = GetMicroSeconds(); - NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... + NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... } if (ei_out.play_errorcount > 0 && ei_out.play_lasterror != 0) { jack_error("%d OSS play event(s), last=%05d:%d",ei_out.play_errorcount, ei_out.play_lasterror, ei_out.play_errorparm); } } - + if (count < 0) { jack_log("JackOSSDriver::Write error = %s", strerror(errno)); return -1; @@ -697,15 +697,15 @@ int JackOSSDriver::Write() int JackOSSDriver::SetBufferSize(jack_nframes_t buffer_size) { - CloseAux(); - JackAudioDriver::SetBufferSize(buffer_size); // never fails + CloseAux(); + JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails return OpenAux(); } int JackOSSDriver::ProcessSync() { // Read input buffers for the current cycle - if (Read() < 0) { + if (Read() < 0) { jack_error("ProcessSync: read error, skip cycle"); return 0; // Non fatal error here, skip cycle, but continue processing... } @@ -715,13 +715,13 @@ int JackOSSDriver::ProcessSync() } else { fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable); } - + // Write output buffers for the current cycle - if (Write() < 0) { + if (Write() < 0) { jack_error("JackAudioDriver::ProcessSync: write error, skip cycle"); return 0; // Non fatal error here, skip cycle, but continue processing... } - + return 0; } @@ -740,7 +740,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->name, "oss"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 strcpy(desc->desc, "OSS API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 - + desc->nparams = OSS_DRIVER_N_PARAMS; desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); @@ -783,7 +783,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() desc->params[i].value.ui = OSS_DRIVER_DEF_INS; strcpy(desc->params[i].short_desc, "Capture channels"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "outchannels"); desc->params[i].character = 'o'; @@ -807,7 +807,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->params[i].value.str, OSS_DRIVER_DEF_DEV); strcpy(desc->params[i].short_desc, "Input device"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "playback"); desc->params[i].character = 'P'; @@ -823,7 +823,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->params[i].value.str, OSS_DRIVER_DEF_DEV); strcpy(desc->params[i].short_desc, "OSS device name"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "ignorehwbuf"); desc->params[i].character = 'b'; @@ -831,12 +831,12 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() desc->params[i].value.i = false; strcpy(desc->params[i].short_desc, "Ignore hardware period size"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); - + i++; strcpy(desc->params[i].name, "input-latency"); desc->params[i].character = 'I'; desc->params[i].type = JackDriverParamUInt; - desc->params[i].value.i = 0; + desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Extra input latency"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -844,7 +844,7 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->params[i].name, "output-latency"); desc->params[i].character = 'O'; desc->params[i].type = JackDriverParamUInt; - desc->params[i].value.i = 0; + desc->params[i].value.ui = 0; strcpy(desc->params[i].short_desc, "Extra output latency"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); @@ -870,13 +870,13 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine bool ignorehwbuf = false; jack_nframes_t systemic_input_latency = 0; jack_nframes_t systemic_output_latency = 0; - + for (node = params; node; node = jack_slist_next(node)) { - + param = (const jack_driver_param_t *)node->data; switch (param->character) { - + case 'r': srate = param->value.ui; break; @@ -900,7 +900,7 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine case 'o': chan_out = (int)param->value.ui; break; - + case 'C': capture = true; if (strcmp(param->value.str, "none") != 0) { @@ -919,7 +919,7 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine playback_pcm_name = param->value.str; capture_pcm_name = param->value.str; break; - + case 'b': ignorehwbuf = true; break; @@ -927,7 +927,7 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine case 'e': excl = true; break; - + case 'I': systemic_input_latency = param->value.ui; break; @@ -946,9 +946,9 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine Jack::JackOSSDriver* oss_driver = new Jack::JackOSSDriver("system", "oss", engine, table); Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(oss_driver); - + // Special open for OSS driver... - if (oss_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out, + if (oss_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out, excl, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, ignorehwbuf) == 0) { return threaded_driver; } else { diff --git a/tests/test.cpp b/tests/test.cpp index 1a6e4a05..232be4ea 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -745,7 +745,9 @@ int main (int argc, char *argv[]) } jack_on_shutdown(client1, jack_shutdown, 0); - jack_on_info_shutdown(client1, jack_info_shutdown, 0); + + if (jack_on_info_shutdown) + jack_on_info_shutdown(client1, jack_info_shutdown, 0); if (jack_set_buffer_size_callback(client1, Jack_Update_Buffer_Size, 0) != 0) { printf("Error when calling buffer_size_callback !\n"); @@ -972,14 +974,14 @@ int main (int argc, char *argv[]) float factor = 0.5f; old_buffer_size = jack_get_buffer_size(client1); - Log("Testing BufferSize change & Callback...\n--> Current buffer size : %i.\n", old_buffer_size); + Log("Testing BufferSize change & Callback...\n--> Current buffer size : %d.\n", old_buffer_size); linebuf = linecount; if (jack_set_buffer_size(client1, (jack_nframes_t)(old_buffer_size * factor)) < 0) { printf("!!! ERROR !!! jack_set_buffer_size fails !\n"); } jack_sleep(1 * 1000); cur_buffer_size = jack_get_buffer_size(client1); - if ((old_buffer_size * factor) != cur_buffer_size) { + if (abs((old_buffer_size * factor) - cur_buffer_size) > 5) { // Tolerance needed for dummy driver... printf("!!! ERROR !!! Buffer size has not been changed !\n"); printf("!!! Maybe jack was compiled without the '--enable-resize' flag...\n"); } else { diff --git a/windows/JackNetWinSocket.h b/windows/JackNetWinSocket.h index bd303eff..1041fab8 100644 --- a/windows/JackNetWinSocket.h +++ b/windows/JackNetWinSocket.h @@ -1,20 +1,20 @@ /* Copyright (C) 2004-2008 Grame - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - + */ #ifndef __JackNetWinSocket__ @@ -23,7 +23,8 @@ #include "JackNetSocket.h" #ifdef __MINGW32__ #include -#include +#include +#include #endif @@ -31,9 +32,9 @@ namespace Jack { #define E(code, s) { code, s } #define NET_ERROR_CODE WSAGetLastError() -#define StrError PrintError +#define StrError PrintError - typedef uint32_t uint; + typedef uint32_t uint; typedef int SOCKLEN; typedef struct _win_net_error win_net_error_t; diff --git a/windows/JackRouter/JackRouter.cpp b/windows/JackRouter/JackRouter.cpp index e5086f8d..c5dbc495 100644 --- a/windows/JackRouter/JackRouter.cpp +++ b/windows/JackRouter/JackRouter.cpp @@ -29,13 +29,12 @@ Copyright (C) 2006 Grame #include "profport.h" /* - 08/07/2007 SL : USe jack_client_open instead of jack_client_new (automatic client renaming). 09/08/2007 SL : Add JackRouter.ini parameter file. 09/20/2007 SL : Better error report in DllRegisterServer (for Vista). 09/27/2007 SL : Add AUDO_CONNECT property in JackRouter.ini file. 10/10/2007 SL : Use ASIOSTInt32LSB instead of ASIOSTInt16LSB. - + 12/04/2011 SL : Compilation on Windows 64. */ //------------------------------------------------------------------------------------------ @@ -54,7 +53,13 @@ static const double twoRaisedTo32Reciprocal = 1. / twoRaisedTo32; #if WINDOWS #include "windows.h" #include "mmsystem.h" -#include "psapi.h" +#ifdef _WIN64 +#define JACK_ROUTER "JackRouter64.dll" +#include +#else +#define JACK_ROUTER "JackRouter.dll" +#include "./psapi.h" +#endif using namespace std; @@ -95,11 +100,11 @@ HRESULT _stdcall DllRegisterServer() LONG rc; char errstr[128]; - rc = RegisterAsioDriver (IID_ASIO_DRIVER,"JackRouter.dll","JackRouter","JackRouter","Apartment"); + rc = RegisterAsioDriver (IID_ASIO_DRIVER, JACK_ROUTER,"JackRouter","JackRouter","Apartment"); if (rc) { memset(errstr,0,128); - sprintf(errstr,"Register Server failed ! (%d)",rc); + sprintf(errstr,"Register Server failed ! (%d)", rc); MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"JackRouter",MB_OK); return -1; } @@ -115,7 +120,7 @@ HRESULT _stdcall DllUnregisterServer() LONG rc; char errstr[128]; - rc = UnregisterAsioDriver (IID_ASIO_DRIVER,"JackRouter.dll","JackRouter"); + rc = UnregisterAsioDriver (IID_ASIO_DRIVER,JACK_ROUTER,"JackRouter"); if (rc) { memset(errstr,0,128); @@ -175,7 +180,7 @@ JackRouter::JackRouter() : AsioDriver() printf("Constructor\n"); // Use "jackrouter.ini" parameters if available - HMODULE handle = LoadLibrary("JackRouter.dll"); + HMODULE handle = LoadLibrary(JACK_ROUTER); if (handle) { @@ -209,15 +214,11 @@ JackRouter::~JackRouter() { stop (); disposeBuffers (); - printf("Destructor\n"); jack_client_close(fClient); + printf("Destructor\n"); } //------------------------------------------------------------------------------------------ -#include -#include -#include -#include "psapi.h" static bool GetEXEName(DWORD dwProcessID, char* name) { diff --git a/windows/JackRouter/JackRouter.vcxproj b/windows/JackRouter/JackRouter.vcxproj new file mode 100644 index 00000000..bb9a751b --- /dev/null +++ b/windows/JackRouter/JackRouter.vcxproj @@ -0,0 +1,280 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + DynamicLibrary + false + + + DynamicLibrary + false + + + DynamicLibrary + false + + + DynamicLibrary + false + + + + + + + + + + + + + + + + + + + + + + + .\Debug\ + .\Debug\ + true + + + .\Debug\ + .\Debug\ + true + + + .\Release\ + .\Release\ + false + + + .\Release\ + .\Release\ + false + + + + MultiThreadedDebugDLL + Default + false + Disabled + true + Level3 + true + ..\..\..\..\..\ASIOSDK2\common;..\..\common;..\..\common\jack;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Debug\ + true + .\Debug\JackRouter.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\JackRouter.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\JackRouter.bsc + + + true + true + true + Windows + Debug/JackRouter_debug.dll + .\Debug\JackRouter_debug.lib + odbc32.lib;odbccp32.lib;winmm.lib;%(AdditionalDependencies) + .\JackRouter.def + + + + + MultiThreadedDebugDLL + Default + false + Disabled + true + Level3 + ..\..\..\..\..\ASIOSDK2\common;..\..\common;..\..\common\jack;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Debug\ + true + .\Debug\JackRouter.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\JackRouter.tlb + true + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\JackRouter.bsc + + + true + true + true + Windows + Debug/JackRouter_debug.dll + .\Debug\JackRouter_debug.lib + odbc32.lib;odbccp32.lib;winmm.lib;%(AdditionalDependencies) + .\JackRouter.def + + + + + MultiThreadedDLL + OnlyExplicitInline + true + true + MaxSpeed + true + Level3 + ..\..\..\..\..\ASIOSDK2\common;..\..\common;..\..\common\jack;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Release\ + true + .\Release\JackRouter.pch + .\Release\ + .\Release\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\JackRouter.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\JackRouter.bsc + + + true + true + Windows + .\Release\JackRouter.dll + .\Release\JackRouter.lib + odbc32.lib;odbccp32.lib;winmm.lib;%(AdditionalDependencies) + .\JackRouter.def + + + + + MultiThreadedDLL + OnlyExplicitInline + true + true + MaxSpeed + true + Level3 + ..\..\..\..\..\ASIOSDK2\common;..\..\common;..\..\common\jack;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;PSAPI_VERSION=2;%(PreprocessorDefinitions) + .\Release\ + true + .\Release\JackRouter.pch + .\Release\ + .\Release\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\JackRouter.tlb + true + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\JackRouter64.bsc + + + true + true + Windows + .\Release\JackRouter64.dll + .\Release\JackRouter64.lib + odbc32.lib;odbccp32.lib;winmm.lib;%(AdditionalDependencies) + .\JackRouter.def + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/windows/JackRouter/JackRouter.vcxproj.filters b/windows/JackRouter/JackRouter.vcxproj.filters new file mode 100644 index 00000000..899efbc8 --- /dev/null +++ b/windows/JackRouter/JackRouter.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + {72f2b2b0-dbea-4574-94fa-0c1ea89a3c8e} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {9590ca0b-94c8-4c22-88b2-66724eb0ea21} + h;hpp;hxx;hm;inl + + + {9742e150-2741-4bf4-9b81-bea4aab464af} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + + + + + Source Files + + + \ No newline at end of file diff --git a/windows/JackRouter/JackRouter.vcxproj.user b/windows/JackRouter/JackRouter.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/windows/JackRouter/JackRouter.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/windows/JackRouter/README b/windows/JackRouter/README index 5f2bce1d..0f59b441 100644 --- a/windows/JackRouter/README +++ b/windows/JackRouter/README @@ -1,3 +1,7 @@ This folder contains the sources for ASIO/JACK bridge ASIO driver called "JackRouter". The included project is a Microsoft VC++ 6 one. It requires some files (combase.cpp, dllentry.cpp, register.cpp) that are part on the ASIO driver SDK. The produced "JackRouter.dll" file -has to be registered in the system using the "regsvr32" tool. \ No newline at end of file +has to be registered in the system using the "regsvr32" tool. + +64 bits compilation +==================== +A Visual Studio 10 project has been added to compile 64 and 32 bits targets. \ No newline at end of file diff --git a/windows/JackRouter/resource.rc b/windows/JackRouter/resource.rc index e1580227..23387184 100644 --- a/windows/JackRouter/resource.rc +++ b/windows/JackRouter/resource.rc @@ -1,4 +1,4 @@ -//Microsoft Developer Studio generated resource script. +// Microsoft Visual C++ generated resource script. // #include "resource.h" @@ -13,15 +13,12 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// French (France) resources +// Français (France) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) -#ifdef _WIN32 LANGUAGE LANG_FRENCH, SUBLANG_FRENCH #pragma code_page(1252) -#endif //_WIN32 -#ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version @@ -44,18 +41,14 @@ BEGIN BEGIN BLOCK "040c04b0" BEGIN - VALUE "Comments", "\0" - VALUE "CompanyName", "Grame\0" - VALUE "FileDescription", "JackRouter ASIO driver\0" - VALUE "FileVersion", "0, 2, 1, 0\0" - VALUE "InternalName", "JackRouter\0" - VALUE "LegalCopyright", "Copyright Grame © 2006-2010\0" - VALUE "LegalTrademarks", "\0" - VALUE "OriginalFilename", "JackRouter.dll\0" - VALUE "PrivateBuild", "\0" - VALUE "ProductName", "JackRouter\0" - VALUE "ProductVersion", "0, 2, 1, 0\0" - VALUE "SpecialBuild", "\0" + VALUE "CompanyName", "Grame" + VALUE "FileDescription", "JackRouter ASIO driver" + VALUE "FileVersion", "0, 2, 1, 0" + VALUE "InternalName", "JackRouter" + VALUE "LegalCopyright", "Copyright Grame © 2006-2011" + VALUE "OriginalFilename", "JackRouter.dll" + VALUE "ProductName", "JackRouter" + VALUE "ProductVersion", "0, 2, 1, 0" END END BLOCK "VarFileInfo" @@ -64,8 +57,6 @@ BEGIN END END -#endif // !_MAC - #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -73,18 +64,18 @@ END // TEXTINCLUDE // -1 TEXTINCLUDE DISCARDABLE +1 TEXTINCLUDE BEGIN "resource.h\0" END -2 TEXTINCLUDE DISCARDABLE +2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END -3 TEXTINCLUDE DISCARDABLE +3 TEXTINCLUDE BEGIN "\r\n" "\0" @@ -92,7 +83,7 @@ END #endif // APSTUDIO_INVOKED -#endif // French (France) resources +#endif // Français (France) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/windows/JackWinNamedPipeServerChannel.cpp b/windows/JackWinNamedPipeServerChannel.cpp index 3723af5e..fd5a8eda 100644 --- a/windows/JackWinNamedPipeServerChannel.cpp +++ b/windows/JackWinNamedPipeServerChannel.cpp @@ -85,7 +85,7 @@ bool JackClientPipeThread::Execute() jack_log("JackClientPipeThread::Execute"); return (HandleRequest()); } catch (JackQuitException& e) { - jack_log("JackMachServerChannel::Execute JackQuitException"); + jack_log("JackClientPipeThread::Execute JackQuitException"); return false; } } diff --git a/windows/JackWinThread.cpp b/windows/JackWinThread.cpp index e3f2cdd9..042279ca 100644 --- a/windows/JackWinThread.cpp +++ b/windows/JackWinThread.cpp @@ -200,7 +200,7 @@ int JackWinThread::AcquireSelfRealTime(int priority) int JackWinThread::AcquireRealTimeImp(jack_native_thread_t thread, int priority) { - jack_log("JackWinThread::AcquireRealTime"); + jack_log("JackWinThread::AcquireRealTimeImp priority = %d", THREAD_PRIORITY_TIME_CRITICAL); if (SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL)) { return 0; diff --git a/windows/Release/bin/libsamplerate-0.dll b/windows/Release/bin/libsamplerate_x86.dll similarity index 98% rename from windows/Release/bin/libsamplerate-0.dll rename to windows/Release/bin/libsamplerate_x86.dll index ceadc596..0eb2f104 100644 Binary files a/windows/Release/bin/libsamplerate-0.dll and b/windows/Release/bin/libsamplerate_x86.dll differ diff --git a/windows/Release/bin/portaudio_x86.dll b/windows/Release/bin/portaudio_x86.dll index ec083746..12f56208 100644 Binary files a/windows/Release/bin/portaudio_x86.dll and b/windows/Release/bin/portaudio_x86.dll differ diff --git a/windows/Release64/bin/libsamplerate_x86_64.dll b/windows/Release64/bin/libsamplerate_x86_64.dll new file mode 100644 index 00000000..099bed58 Binary files /dev/null and b/windows/Release64/bin/libsamplerate_x86_64.dll differ diff --git a/windows/Release64/bin/portaudio_x86_64.dll b/windows/Release64/bin/portaudio_x86_64.dll new file mode 100644 index 00000000..41086a3c Binary files /dev/null and b/windows/Release64/bin/portaudio_x86_64.dll differ diff --git a/windows/Setup/JackRouter.dll b/windows/Setup/JackRouter.dll index 860fcc39..e4709cd3 100644 Binary files a/windows/Setup/JackRouter.dll and b/windows/Setup/JackRouter.dll differ diff --git a/windows/Setup/JackRouter64.dll b/windows/Setup/JackRouter64.dll new file mode 100644 index 00000000..543820d4 Binary files /dev/null and b/windows/Setup/JackRouter64.dll differ diff --git a/windows/Setup/README b/windows/Setup/README index 78588ece..fa854b37 100644 --- a/windows/Setup/README +++ b/windows/Setup/README @@ -14,4 +14,11 @@ Just use : 'dlltool -l libjackserver.lib -D libjackserver.dll -d libjackserver.d Once all binaries are available, just execute the script in 'CreateInstall' to make 'setup.exe'. The setup will copy all binaries to a specified folder, register the JackRouter (in order to have it in the ASIO drivers list) and create some shortcuts in the start menu. -It's a good and proper way to get jack installed on windows. \ No newline at end of file +It's a good and proper way to get jack installed on windows. + +64 bits compilation +==================== + +- for some reasons CodeBlocks create libjack.dll.a and libjack.dll.def names. So the ".dll" part has to be removed before using "lib" tool to create ".lib" files. + +- to create 64 bits ".lib" files, the "/MACHINE:X64 option has to be used. diff --git a/windows/Setup/jack.ci b/windows/Setup/jack.ci index 7ad82cb3..e1dd6386 100644 --- a/windows/Setup/jack.ci +++ b/windows/Setup/jack.ci @@ -1,9 +1,9 @@ <*project version = 4 civer = "Free v4.14.5" winver = "2.6/5.1.2600" > . - Jack_v1.9.7_setup.exe + Jack_v1.9.8_32_setup.exe - Jack v1.9.7 + Jack v1.9.8 Default - 2 @@ -53,8 +53,8 @@ - <_>..\Release\bin\libjack.ainstlibovernewer0 -<_>.\src\vcredist_x86.exeinstovernewer0 +<_>.\src\vcredist_2010_x86.exeinstovernewer0 +<_>..\Release\bin\libjack.ainstlibovernewer0 <_>..\Release\bin\libjack.libinstlibovernewer0 <_>..\Release\bin\libjack.definstlibovernewer0 <_>..\Release\bin\libjackserver.ainstlibovernewer0 @@ -66,10 +66,11 @@ <_>..\Release\bin\jack_lsp.exeinstovernewer0 <_>..\Release\bin\jack_metro.exeinstovernewer0 <_>..\Release\bin\jack_unload.exeinstovernewer0 +<_>..\Release\bin\jack_midi_latency_test.exeinstovernewer0 <_>..\Release\bin\jackd.exeinstovernewer0 <_>..\Release\bin\libjack.dllsysovernewer0 <_>..\Release\bin\libjackserver.dllsysovernewer0 -<_>..\Release\bin\libsamplerate-0.dllinstovernewer0 +<_>..\Release\bin\libsamplerate_x86.dllinstovernewer0 <_>..\Release\bin\portaudio_x86.dllinstovernewer0 <_>..\Release\bin\jack\jack_net.dllinstjackovernewer0 <_>..\Release\bin\jack\jack_netone.dllinstjackovernewer0 @@ -106,8 +107,7 @@ - <_>appinstvcredist_x86.exe1instend - + <_>appinstvcredist_2010_x86.exe1instend diff --git a/windows/Setup/jack64.ci b/windows/Setup/jack64.ci new file mode 100644 index 00000000..24eaa6e9 --- /dev/null +++ b/windows/Setup/jack64.ci @@ -0,0 +1,155 @@ +<*project + version = 4 civer = "Free v4.14.5" winver = "2.8/6.1.7600" > + . + Jack_v1.9.8_64_setup.exe + + Jack v1.9.8 + + + Default - 2 + 1 + nolimit + + disk%i.pak + + 1000 + admin + + + Verdana,8 + English + Green + leftlogo + .\src\logo_installer.bmp + + + + 0 + 1 + .\src\README + .\src\gpl_installer.rtf + + 0 + 1 + 1 + 1 + defnorm + 0 + + over + + 1 + 1 + Uninstall - 2 + 1 + + 0 + + 1 + 1 + My Demo + + + + + +<_>.\src\vcredist_2010_x86.exeinstovernewer0 +<_>.\src\vcredist_2010_x64.exeinstovernewer0 +<_>..\Release64\bin\libjack64.ainstlibovernewer0 +<_>..\Release64\bin\libjack64.libinstlibovernewer0 +<_>..\Release64\bin\libjack64.definstlibovernewer0 +<_>..\Release64\bin\libjack64.dllwinovernewer0 +<_>..\Release64\bin\libjackserver64.ainstlibovernewer0 +<_>..\Release64\bin\libjackserver64.libinstlibovernewer0 +<_>..\Release64\bin\libjackserver64.definstlibovernewer0 +<_>..\Release64\bin\libjackserver64.dllwinovernewer0 +<_>..\Release\bin\libjack.ainstlibovernewer0 +<_>..\Release\bin\libjack.libinstlibovernewer0 +<_>..\Release\bin\libjack.definstlibovernewer0 +<_>..\Release\bin\libjack.dllsysovernewer0 +<_>..\Release\bin\libjackserver.ainstlibovernewer0 +<_>..\Release\bin\libjackserver.libinstlibovernewer0 +<_>..\Release\bin\libjackserver.definstlibovernewer0 +<_>..\Release\bin\libjackserver.dllsysovernewer0 +<_>..\Release64\bin\jack_connect.exeinstovernewer0 +<_>..\Release64\bin\jack_disconnect.exeinstovernewer0 +<_>..\Release64\bin\jack_load.exeinstovernewer0 +<_>..\Release64\bin\jack_lsp.exeinstovernewer0 +<_>..\Release64\bin\jack_metro.exeinstovernewer0 +<_>..\Release64\bin\jack_unload.exeinstovernewer0 +<_>..\Release64\bin\jack_midi_latency_test.exeinstovernewer0 +<_>..\Release64\bin\jackd.exeinstovernewer0 +<_>..\Release64\bin\libsamplerate_x86_64.dllinstovernewer0 +<_>..\Release64\bin\portaudio_x86_64.dllinstovernewer0 +<_>..\Release\bin\portaudio_x86.dllinstovernewer0 +<_>..\Release64\bin\jack\jack_net.dllinstjackovernewer0 +<_>..\Release64\bin\jack\jack_netone.dllinstjackovernewer0 +<_>..\Release64\bin\jack_netsource.exeinstovernewer0 +<_>..\Release64\bin\jack\jack_dummy.dllinstjackovernewer0 +<_>..\Release64\bin\jack\jack_loopback.dllinstjackovernewer0 +<_>..\Release64\bin\jack\jack_winmme.dllinstjackovernewer0 +<_>..\Release64\bin\jack\jack_portaudio.dllinstjackovernewer0 +<_>..\Release64\bin\jack\netmanager.dllinstjackovernewer0 +<_>..\Release64\bin\jack\audioadapter.dllinstjackovernewer0 +<_>..\Release64\bin\jack\netadapter.dllinstjackovernewer0 +<_>..\..\common\jack\control.hinstincludes\jackovernewer0 +<_>..\..\common\jack\intclient.hinstincludes\jackovernewer0 +<_>..\..\common\jack\jack.hinstincludes\jackovernewer0 +<_>..\..\common\jack\jslist.hinstincludes\jackovernewer0 +<_>..\..\common\jack\midiport.hinstincludes\jackovernewer0 +<_>..\..\common\jack\ringbuffer.hinstincludes\jackovernewer0 +<_>..\..\common\jack\statistics.hinstincludes\jackovernewer0 +<_>..\..\common\jack\thread.hinstincludes\jackovernewer0 +<_>..\..\common\jack\transport.hinstincludes\jackovernewer0 +<_>..\..\common\jack\types.hinstincludes\jackovernewer0 +<_>..\..\common\jack\systemdeps.hinstincludes\jackovernewer1 +<_>..\..\common\jack\weakjack.hinstincludes\jackovernewer1 +<_>..\..\common\jack\weakmacros.hinstincludes\jackovernewer1 +<_>.\JackRouter.dllinstovernewer0 +<_>.\JackRouter64.dllinstovernewer0 +<_>.\JackRouter.iniinstovernewer0 +<_>.\qjackctl\mingwm10.dllinstovernewer0 +<_>.\qjackctl\qjackctl.exeinstovernewer0 +<_>.\qjackctl\QtCore4.dllinstovernewer0 +<_>.\qjackctl\QtGui4.dllinstovernewer0 +<_>.\qjackctl\QtXml4.dllinstovernewer0 +<_>.\src\COPYINGinstovernewer0 +<_>.\src\READMEinstovernewer0 + + + + <_>appinstvcredist_2010_x86.exe1instend + <_>appinstvcredist_2010_x64.exe1instend + + + + + + <_>progJack NetDriverinstjackd.exe-R -S -d netinst +<_>progJack Portaudioinstjackd.exe-R -S -d portaudioinst +<_>progJack Controlinstqjackctl.exeinstjackdmp.exe +<_>progJack Commandsyscmd.exeinst + + + + + + + + + + <_>instJackRouter.dll + <_>instJackRouter64.dll + + + + + + + + + + + + Pathadd= + \ No newline at end of file diff --git a/windows/Setup/src/gpl_installer.rtf b/windows/Setup/src/gpl_installer.rtf index cc8bcb4e..fac711f5 100644 Binary files a/windows/Setup/src/gpl_installer.rtf and b/windows/Setup/src/gpl_installer.rtf differ diff --git a/windows/jack_audioadapter.cbp b/windows/jack_audioadapter.cbp index 77ad24cd..6ad084a7 100644 --- a/windows/jack_audioadapter.cbp +++ b/windows/jack_audioadapter.cbp @@ -1,112 +1,203 @@ - - - - - - + + + + + + diff --git a/windows/jack_connect.cbp b/windows/jack_connect.cbp index 928821d8..177bfca0 100644 --- a/windows/jack_connect.cbp +++ b/windows/jack_connect.cbp @@ -4,50 +4,112 @@