Browse Source

rebase from trunk 4238:4306

git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@4307 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.9.8
sletz 12 years ago
parent
commit
ecb84b5f9f
100 changed files with 6026 additions and 2352 deletions
  1. +25
    -0
      ChangeLog
  2. +2
    -2
      README
  3. +89
    -33
      common/JackAudioDriver.cpp
  4. +7
    -2
      common/JackAudioDriver.h
  5. +2
    -1
      common/JackChannel.h
  6. +0
    -1
      common/JackClient.h
  7. +1
    -1
      common/JackClientControl.h
  8. +2
    -2
      common/JackConstants.h
  9. +23
    -8
      common/JackControlAPI.cpp
  10. +14
    -13
      common/JackControlAPI.h
  11. +50
    -10
      common/JackDriver.cpp
  12. +18
    -3
      common/JackDriver.h
  13. +18
    -4
      common/JackDriverLoader.cpp
  14. +1
    -1
      common/JackDriverLoader.h
  15. +1
    -0
      common/JackDummyDriver.cpp
  16. +1
    -0
      common/JackExternalClient.cpp
  17. +60
    -14
      common/JackFreewheelDriver.cpp
  18. +10
    -0
      common/JackFreewheelDriver.h
  19. +8
    -0
      common/JackLibGlobals.h
  20. +2
    -2
      common/JackLibSampleRateResampler.cpp
  21. +48
    -7
      common/JackLoopbackDriver.cpp
  22. +11
    -2
      common/JackLoopbackDriver.h
  23. +103
    -0
      common/JackMidiAsyncQueue.cpp
  24. +98
    -0
      common/JackMidiAsyncQueue.h
  25. +85
    -0
      common/JackMidiAsyncWaitQueue.cpp
  26. +99
    -0
      common/JackMidiAsyncWaitQueue.h
  27. +67
    -0
      common/JackMidiBufferReadQueue.cpp
  28. +60
    -0
      common/JackMidiBufferReadQueue.h
  29. +65
    -0
      common/JackMidiBufferWriteQueue.cpp
  30. +62
    -0
      common/JackMidiBufferWriteQueue.h
  31. +90
    -28
      common/JackMidiDriver.cpp
  32. +18
    -8
      common/JackMidiDriver.h
  33. +4
    -3
      common/JackMidiPort.cpp
  34. +300
    -0
      common/JackMidiRawInputWriteQueue.cpp
  35. +170
    -0
      common/JackMidiRawInputWriteQueue.h
  36. +228
    -0
      common/JackMidiRawOutputWriteQueue.cpp
  37. +147
    -0
      common/JackMidiRawOutputWriteQueue.h
  38. +27
    -0
      common/JackMidiReadQueue.cpp
  39. +55
    -0
      common/JackMidiReadQueue.h
  40. +27
    -0
      common/JackMidiReceiveQueue.cpp
  41. +42
    -0
      common/JackMidiReceiveQueue.h
  42. +34
    -0
      common/JackMidiSendQueue.cpp
  43. +52
    -0
      common/JackMidiSendQueue.h
  44. +120
    -0
      common/JackMidiUtil.cpp
  45. +102
    -0
      common/JackMidiUtil.h
  46. +27
    -0
      common/JackMidiWriteQueue.cpp
  47. +82
    -0
      common/JackMidiWriteQueue.h
  48. +23
    -23
      common/JackNetAdapter.cpp
  49. +31
    -27
      common/JackNetAdapter.h
  50. +61
    -33
      common/JackNetDriver.cpp
  51. +6
    -3
      common/JackNetDriver.h
  52. +45
    -45
      common/JackNetInterface.cpp
  53. +22
    -16
      common/JackNetInterface.h
  54. +34
    -11
      common/JackNetManager.cpp
  55. +9
    -0
      common/JackNetManager.h
  56. +778
    -821
      common/JackNetOneDriver.cpp
  57. +63
    -66
      common/JackNetOneDriver.h
  58. +2
    -0
      common/JackNetTool.cpp
  59. +4
    -4
      common/JackNetTool.h
  60. +0
    -287
      common/JackPhysicalMidiInput.cpp
  61. +0
    -146
      common/JackPhysicalMidiInput.h
  62. +0
    -320
      common/JackPhysicalMidiOutput.cpp
  63. +0
    -118
      common/JackPhysicalMidiOutput.h
  64. +1
    -1
      common/JackPort.h
  65. +1
    -3
      common/JackServer.cpp
  66. +69
    -0
      common/JackSession.h
  67. +17
    -4
      common/JackThreadedDriver.cpp
  68. +8
    -1
      common/JackThreadedDriver.h
  69. +26
    -22
      common/JackWaitThreadedDriver.h
  70. +6
    -6
      common/JackWeakAPI.cpp
  71. +32
    -9
      common/Jackdmp.cpp
  72. +3
    -3
      common/jack/jack.h
  73. +22
    -11
      common/jack/weakmacros.h
  74. +2
    -3
      common/netjack.c
  75. +2
    -3
      common/netjack_packet.c
  76. +15
    -2
      common/wscript
  77. +92
    -18
      dbus/controller.c
  78. +75
    -118
      dbus/controller_iface_configure.c
  79. +32
    -14
      dbus/controller_iface_control.c
  80. +11
    -2
      dbus/controller_internal.h
  81. +1
    -0
      dbus/jackdbus.h
  82. +1
    -1
      doxyfile
  83. +22
    -0
      example-clients/jack_control
  84. +9
    -8
      example-clients/latent_client.c
  85. +777
    -0
      example-clients/midi_latency_test.c
  86. +1
    -1
      example-clients/showtime.c
  87. +1
    -1
      example-clients/thru_client.c
  88. +23
    -23
      example-clients/tw.c
  89. +1
    -1
      example-clients/wait.c
  90. +1
    -0
      example-clients/wscript
  91. +9
    -9
      example-clients/zombie.c
  92. +4
    -4
      linux/alsa/JackAlsaAdapter.cpp
  93. +34
    -17
      linux/alsa/JackAlsaDriver.cpp
  94. +2
    -0
      linux/alsa/JackAlsaDriver.h
  95. +2
    -2
      linux/alsa/alsa_driver.c
  96. +614
    -0
      linux/alsarawmidi/JackALSARawMidiDriver.cpp
  97. +98
    -0
      linux/alsarawmidi/JackALSARawMidiDriver.h
  98. +143
    -0
      linux/alsarawmidi/JackALSARawMidiInputPort.cpp
  99. +62
    -0
      linux/alsarawmidi/JackALSARawMidiInputPort.h
  100. +172
    -0
      linux/alsarawmidi/JackALSARawMidiOutputPort.cpp

+ 25
- 0
ChangeLog View File

@@ -34,6 +34,31 @@ Valerio Pilo
Jackdmp changes log
---------------------------

2011-04-04 Stephane Letz <letz@grame.fr>

* Correct driver lifetime management.

2011-04-03 Stephane Letz <letz@grame.fr>

* Fix in JackCoreAudioDriver::Read when there is no inputs.

2011-04-02 Stephane Letz <letz@grame.fr>

* Netdriver can now ask for in/out values from the master (in progress).
* Correct drivers parameter settings.

2011-04-01 Stephane Letz <letz@grame.fr>

* 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 <letz@grame.fr>

* Version 1.9.8 started.

2011-03-29 Stephane Letz <letz@grame.fr>

* Synchronize JackWeakAPI.cpp with new APIs.


+ 2
- 2
README View File

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


+ 89
- 33
common/JackAudioDriver.cpp View File

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


+ 7
- 2
common/JackAudioDriver.h View File

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



+ 2
- 1
common/JackChannel.h View File

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


+ 0
- 1
common/JackClient.h View File

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



+ 1
- 1
common/JackClientControl.h View File

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


+ 2
- 2
common/JackConstants.h View File

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


+ 23
- 8
common/JackControlAPI.cpp View File

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


+ 14
- 13
common/JackControlAPI.h View File

@@ -27,7 +27,8 @@

#ifdef WIN32
#ifdef __MINGW32__
#include <sys/types.h>
#include <sys/types.h>
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);



+ 50
- 10
common/JackDriver.cpp View File

@@ -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<JackDriverInterface*>::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<JackDriverInterface*>::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<JackDriverInterface*>::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<JackDriverInterface*>::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()


+ 18
- 3
common/JackDriver.h View File

@@ -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<JackDriverInterface*> 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<JackDriverInterface*> 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);


+ 18
- 4
common/JackDriverLoader.cpp View File

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



+ 1
- 1
common/JackDriverLoader.h View File

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


+ 1
- 0
common/JackDummyDriver.cpp View File

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


+ 1
- 0
common/JackExternalClient.cpp View File

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


+ 60
- 14
common/JackFreewheelDriver.cpp View File

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

+ 10
- 0
common/JackFreewheelDriver.h View File

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


+ 8
- 0
common/JackLibGlobals.h View File

@@ -32,6 +32,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <assert.h>
#include <signal.h>

#ifdef WIN32
#ifdef __MINGW32__
#include <sys/types.h>
typedef _sigset_t sigset_t;
#else
typedef HANDLE sigset_t;
#endif
#endif

namespace Jack
{


+ 2
- 2
common/JackLibSampleRateResampler.cpp View File

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


+ 48
- 7
common/JackLoopbackDriver.cpp View File

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



+ 11
- 2
common/JackLoopbackDriver.h View File

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


+ 103
- 0
common/JackMidiAsyncQueue.cpp View File

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

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

+ 98
- 0
common/JackMidiAsyncQueue.h View File

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

+ 85
- 0
common/JackMidiAsyncWaitQueue.cpp View File

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

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

+ 99
- 0
common/JackMidiAsyncWaitQueue.h View File

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

+ 67
- 0
common/JackMidiBufferReadQueue.cpp View File

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

+ 60
- 0
common/JackMidiBufferReadQueue.h View File

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

+ 65
- 0
common/JackMidiBufferWriteQueue.cpp View File

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

+ 62
- 0
common/JackMidiBufferWriteQueue.h View File

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

+ 90
- 28
common/JackMidiDriver.cpp View File

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



+ 18
- 8
common/JackMidiDriver.h View File

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