Browse Source

Merge branch 'newer-midi'

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@4243 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.9.8
sletz 14 years ago
parent
commit
5ef5f58f78
100 changed files with 7551 additions and 1616 deletions
  1. +74
    -27
      common/JackAudioDriver.cpp
  2. +7
    -2
      common/JackAudioDriver.h
  3. +43
    -4
      common/JackDriver.cpp
  4. +18
    -3
      common/JackDriver.h
  5. +1
    -0
      common/JackDummyDriver.cpp
  6. +60
    -14
      common/JackFreewheelDriver.cpp
  7. +10
    -0
      common/JackFreewheelDriver.h
  8. +48
    -7
      common/JackLoopbackDriver.cpp
  9. +11
    -2
      common/JackLoopbackDriver.h
  10. +103
    -0
      common/JackMidiAsyncQueue.cpp
  11. +98
    -0
      common/JackMidiAsyncQueue.h
  12. +85
    -0
      common/JackMidiAsyncWaitQueue.cpp
  13. +99
    -0
      common/JackMidiAsyncWaitQueue.h
  14. +67
    -0
      common/JackMidiBufferReadQueue.cpp
  15. +60
    -0
      common/JackMidiBufferReadQueue.h
  16. +65
    -0
      common/JackMidiBufferWriteQueue.cpp
  17. +62
    -0
      common/JackMidiBufferWriteQueue.h
  18. +88
    -12
      common/JackMidiDriver.cpp
  19. +19
    -7
      common/JackMidiDriver.h
  20. +4
    -3
      common/JackMidiPort.cpp
  21. +300
    -0
      common/JackMidiRawInputWriteQueue.cpp
  22. +170
    -0
      common/JackMidiRawInputWriteQueue.h
  23. +228
    -0
      common/JackMidiRawOutputWriteQueue.cpp
  24. +147
    -0
      common/JackMidiRawOutputWriteQueue.h
  25. +27
    -0
      common/JackMidiReadQueue.cpp
  26. +55
    -0
      common/JackMidiReadQueue.h
  27. +27
    -0
      common/JackMidiReceiveQueue.cpp
  28. +42
    -0
      common/JackMidiReceiveQueue.h
  29. +34
    -0
      common/JackMidiSendQueue.cpp
  30. +52
    -0
      common/JackMidiSendQueue.h
  31. +120
    -0
      common/JackMidiUtil.cpp
  32. +102
    -0
      common/JackMidiUtil.h
  33. +27
    -0
      common/JackMidiWriteQueue.cpp
  34. +82
    -0
      common/JackMidiWriteQueue.h
  35. +36
    -16
      common/JackNetDriver.cpp
  36. +1
    -1
      common/JackNetManager.cpp
  37. +0
    -287
      common/JackPhysicalMidiInput.cpp
  38. +0
    -146
      common/JackPhysicalMidiInput.h
  39. +0
    -320
      common/JackPhysicalMidiOutput.cpp
  40. +0
    -118
      common/JackPhysicalMidiOutput.h
  41. +0
    -2
      common/JackServer.cpp
  42. +17
    -2
      common/JackThreadedDriver.cpp
  43. +8
    -1
      common/JackThreadedDriver.h
  44. +12
    -3
      common/Jackdmp.cpp
  45. +1
    -1
      common/shm.h
  46. +15
    -2
      common/wscript
  47. +642
    -0
      example-clients/midi_latency_test.c
  48. +1
    -0
      example-clients/wscript
  49. +29
    -12
      linux/alsa/JackAlsaDriver.cpp
  50. +2
    -0
      linux/alsa/JackAlsaDriver.h
  51. +602
    -0
      linux/alsarawmidi/JackALSARawMidiDriver.cpp
  52. +79
    -0
      linux/alsarawmidi/JackALSARawMidiDriver.h
  53. +124
    -0
      linux/alsarawmidi/JackALSARawMidiInputPort.cpp
  54. +43
    -0
      linux/alsarawmidi/JackALSARawMidiInputPort.h
  55. +153
    -0
      linux/alsarawmidi/JackALSARawMidiOutputPort.cpp
  56. +44
    -0
      linux/alsarawmidi/JackALSARawMidiOutputPort.h
  57. +159
    -0
      linux/alsarawmidi/JackALSARawMidiPort.cpp
  58. +53
    -0
      linux/alsarawmidi/JackALSARawMidiPort.h
  59. +35
    -0
      linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp
  60. +32
    -0
      linux/alsarawmidi/JackALSARawMidiReceiveQueue.h
  61. +40
    -0
      linux/alsarawmidi/JackALSARawMidiSendQueue.cpp
  62. +32
    -0
      linux/alsarawmidi/JackALSARawMidiSendQueue.h
  63. +12
    -26
      linux/firewire/JackFFADODriver.cpp
  64. +0
    -59
      linux/firewire/JackFFADOMidiInput.cpp
  65. +94
    -0
      linux/firewire/JackFFADOMidiInputPort.cpp
  66. +51
    -0
      linux/firewire/JackFFADOMidiInputPort.h
  67. +0
    -60
      linux/firewire/JackFFADOMidiOutput.cpp
  68. +98
    -0
      linux/firewire/JackFFADOMidiOutputPort.cpp
  69. +53
    -0
      linux/firewire/JackFFADOMidiOutputPort.h
  70. +55
    -0
      linux/firewire/JackFFADOMidiReceiveQueue.cpp
  71. +16
    -18
      linux/firewire/JackFFADOMidiReceiveQueue.h
  72. +64
    -0
      linux/firewire/JackFFADOMidiSendQueue.cpp
  73. +17
    -20
      linux/firewire/JackFFADOMidiSendQueue.h
  74. +14
    -4
      linux/wscript
  75. +1
    -1
      macosx/JackMachThread.h
  76. +465
    -57
      macosx/Jackdmp.xcodeproj/project.pbxproj
  77. +33
    -34
      macosx/coreaudio/JackCoreAudioAdapter.cpp
  78. +62
    -38
      macosx/coreaudio/JackCoreAudioDriver.cpp
  79. +9
    -7
      macosx/coreaudio/JackCoreAudioDriver.h
  80. +532
    -256
      macosx/coremidi/JackCoreMidiDriver.cpp
  81. +54
    -40
      macosx/coremidi/JackCoreMidiDriver.h
  82. +184
    -0
      macosx/coremidi/JackCoreMidiInputPort.cpp
  83. +73
    -0
      macosx/coremidi/JackCoreMidiInputPort.h
  84. +250
    -0
      macosx/coremidi/JackCoreMidiOutputPort.cpp
  85. +90
    -0
      macosx/coremidi/JackCoreMidiOutputPort.h
  86. +53
    -0
      macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp
  87. +45
    -0
      macosx/coremidi/JackCoreMidiPhysicalInputPort.h
  88. +78
    -0
      macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp
  89. +55
    -0
      macosx/coremidi/JackCoreMidiPhysicalOutputPort.h
  90. +93
    -0
      macosx/coremidi/JackCoreMidiPort.cpp
  91. +67
    -0
      macosx/coremidi/JackCoreMidiPort.h
  92. +43
    -0
      macosx/coremidi/JackCoreMidiUtil.cpp
  93. +39
    -0
      macosx/coremidi/JackCoreMidiUtil.h
  94. +75
    -0
      macosx/coremidi/JackCoreMidiVirtualInputPort.cpp
  95. +50
    -0
      macosx/coremidi/JackCoreMidiVirtualInputPort.h
  96. +72
    -0
      macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp
  97. +49
    -0
      macosx/coremidi/JackCoreMidiVirtualOutputPort.h
  98. +2
    -2
      tests/test.cpp
  99. +6
    -0
      windows/jack_winmme.cbp
  100. +2
    -2
      windows/jackd.workspace

+ 74
- 27
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,
@@ -95,13 +101,33 @@ int JackAudioDriver::Open(bool capturing,
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 +141,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 +154,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 +165,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 +212,9 @@ int JackAudioDriver::ProcessNull()
JackDriver::CycleTakeBeginTime();

if (fEngineControl->fSyncMode) {
ProcessGraphSync();
ProcessGraphSyncMaster();
} else {
ProcessGraphAsync();
ProcessGraphAsyncMaster();
}

// Keep end cycle time
@@ -230,9 +249,9 @@ int JackAudioDriver::ProcessAsync()

// Process graph
if (fIsMaster) {
ProcessGraphAsync();
ProcessGraphAsyncMaster();
} else {
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
ProcessGraphAsyncSlave();
}

// Keep end cycle time
@@ -255,12 +274,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 +298,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 +354,11 @@ int JackAudioDriver::ProcessGraphSync()
return res;
}

int JackAudioDriver::ProcessGraphSyncSlave()
{
return fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
}

int JackAudioDriver::Start()
{
int res = JackDriver::Start();


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



+ 43
- 4
common/JackDriver.cpp View File

@@ -300,19 +300,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;
@@ -395,12 +418,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);


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


+ 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


+ 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

+ 88
- 12
common/JackMidiDriver.cpp View File

@@ -104,6 +104,7 @@ int JackMidiDriver::Attach()
jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
}

UpdateLatencies();
return 0;
}

@@ -133,33 +134,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;
}

// Write output buffers for the current cycle
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 from the current cycle
if (Write() < 0) {
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::Process: write error, skip cycle");
return 0; // Skip cycle, but continue processing...
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;
}



+ 19
- 7
common/JackMidiDriver.h View File

@@ -39,15 +39,23 @@ 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 +70,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


+ 4
- 3
common/JackMidiPort.cpp View File

@@ -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<JackMidiBuffer*>(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<JackMidiBuffer*>(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;


+ 300
- 0
common/JackMidiRawInputWriteQueue.cpp View File

@@ -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 <cassert>
#include <memory>
#include <new>

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

+ 170
- 0
common/JackMidiRawInputWriteQueue.h View File

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

+ 228
- 0
common/JackMidiRawOutputWriteQueue.cpp View File

@@ -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 <memory>
#include <new>

#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<JackMidiAsyncQueue> non_rt_ptr(non_rt_queue);
rt_queue = new JackMidiAsyncQueue(max_rt_messages, max_rt_messages);
std::auto_ptr<JackMidiAsyncQueue> 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;
}
}
}

+ 147
- 0
common/JackMidiRawOutputWriteQueue.h View File

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

+ 27
- 0
common/JackMidiReadQueue.cpp View File

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

+ 55
- 0
common/JackMidiReadQueue.h View File

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

+ 27
- 0
common/JackMidiReceiveQueue.cpp View File

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

+ 42
- 0
common/JackMidiReceiveQueue.h View File

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

+ 34
- 0
common/JackMidiSendQueue.cpp View File

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

+ 52
- 0
common/JackMidiSendQueue.h View File

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

+ 120
- 0
common/JackMidiUtil.cpp View File

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

+ 102
- 0
common/JackMidiUtil.h View File

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

+ 27
- 0
common/JackMidiWriteQueue.cpp View File

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

+ 82
- 0
common/JackMidiWriteQueue.h View File

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

+ 36
- 16
common/JackNetDriver.cpp View File

@@ -151,8 +151,16 @@ namespace Jack
//allocate midi ports lists
fMidiCapturePortList = new jack_port_id_t [fParams.fSendMidiChannels];
fMidiPlaybackPortList = new jack_port_id_t [fParams.fReturnMidiChannels];
assert ( fMidiCapturePortList );
assert ( fMidiPlaybackPortList );

assert(fMidiCapturePortList);
assert(fMidiPlaybackPortList);

for (uint midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
fMidiCapturePortList[midi_port_index] = NULL;
}
for (uint midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
fMidiPlaybackPortList[midi_port_index] = NULL;
}

//register jack ports
if ( AllocPorts() != 0 )
@@ -362,20 +370,32 @@ namespace Jack
{
jack_log ( "JackNetDriver::FreePorts" );

int audio_port_index;
uint midi_port_index;
for ( audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++ )
if (fCapturePortList[audio_port_index] > 0)
fGraphManager->ReleasePort ( fClientControl.fRefNum, fCapturePortList[audio_port_index] );
for ( audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++ )
if (fPlaybackPortList[audio_port_index] > 0)
fGraphManager->ReleasePort ( fClientControl.fRefNum, fPlaybackPortList[audio_port_index] );
for ( midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++ )
if (fMidiCapturePortList[midi_port_index] > 0)
fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiCapturePortList[midi_port_index] );
for ( midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++ )
if (fMidiPlaybackPortList[midi_port_index] > 0)
fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index] );
for (int audio_port_index = 0; audio_port_index < fCaptureChannels; audio_port_index++) {
if (fCapturePortList[audio_port_index] > 0) {
fGraphManager->ReleasePort ( fClientControl.fRefNum, fCapturePortList[audio_port_index]);
}
}

for (int audio_port_index = 0; audio_port_index < fPlaybackChannels; audio_port_index++) {
if (fPlaybackPortList[audio_port_index] > 0) {
fGraphManager->ReleasePort ( fClientControl.fRefNum, fPlaybackPortList[audio_port_index]);
}
}

for (uint midi_port_index = 0; midi_port_index < fParams.fSendMidiChannels; midi_port_index++) {
if (fMidiCapturePortList && fMidiCapturePortList[midi_port_index] > 0) {
fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiCapturePortList[midi_port_index]);
}
}

for (uint midi_port_index = 0; midi_port_index < fParams.fReturnMidiChannels; midi_port_index++) {
if (fMidiPlaybackPortList && fMidiPlaybackPortList[midi_port_index] > 0) {
fGraphManager->ReleasePort ( fClientControl.fRefNum, fMidiPlaybackPortList[midi_port_index]);
}
}
// Clear MIDI channels
fParams.fSendMidiChannels = 0;
fParams.fReturnMidiChannels = 0;
return 0;
}



+ 1
- 1
common/JackNetManager.cpp View File

@@ -392,7 +392,7 @@ namespace Jack
{
JackNetMaster* obj = static_cast<JackNetMaster*>(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;


+ 0
- 287
common/JackPhysicalMidiInput.cpp View File

@@ -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 <cassert>
#include <cstring>
#include <new>

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

}

+ 0
- 146
common/JackPhysicalMidiInput.h View File

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

+ 0
- 320
common/JackPhysicalMidiOutput.cpp View File

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

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

}

+ 0
- 118
common/JackPhysicalMidiOutput.h View File

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

+ 0
- 2
common/JackServer.cpp View File

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


+ 17
- 2
common/JackThreadedDriver.cpp View File

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


+ 8
- 1
common/JackThreadedDriver.h View File

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


+ 12
- 3
common/Jackdmp.cpp View File

@@ -476,7 +476,10 @@ 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
@@ -491,7 +494,10 @@ 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;
}
}

}
@@ -509,7 +515,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);


+ 1
- 1
common/shm.h View File

@@ -14,7 +14,7 @@ extern "C"
{
#endif

#define MAX_SERVERS 8 /* maximum concurrent servers */
#define MAX_SERVERS 64 /* maximum concurrent servers */
#define MAX_SHM_ID 256 /* generally about 16 per server */
#define JACK_SERVER_NAME_SIZE 256 /* maximum length of server name */
#define JACK_SHM_MAGIC 0x4a41434b /* shm magic number: "JACK" */


+ 15
- 2
common/wscript View File

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


+ 642
- 0
example-clients/midi_latency_test.c View File

@@ -0,0 +1,642 @@
/*
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 mutexes, semaphores, and command-line argument handling.
*/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <getopt.h>
#include <pthread.h>
#include <semaphore.h>

#include <jack/jack.h>
#include <jack/midiport.h>

#define ABS(x) (((x) >= 0) ? (x) : (-(x)))

const char *ERROR_UNEXPECTED = "in port received unexpected MIDI message";
const char *ERROR_UNEXPECTED_EXTRA = "received more than one MIDI message";
const char *ERROR_RESERVE = "could not reserve MIDI event on port buffer";
const char *ERROR_TIMEOUT = "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_TRYLOCK = "pthread_mutex_trylock";
const char *SOURCE_UNLOCK = "pthread_mutex_unlock";

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;
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;
int process_state;
char *program_name;
jack_port_t *remote_in_port;
jack_port_t *remote_out_port;
size_t samples;

#ifdef __APPLE__
sem_t* semaphore;
#else
sem_t semaphore;
#endif

pthread_mutex_t start_mutex;
int timeout;
jack_nframes_t total_latency;
jack_time_t total_latency_time;
size_t unexpected_messages;
size_t xrun_count;

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 void
die(char *source, char *error_message)
{
output_error(source, error_message);
output_usage();
exit(EXIT_FAILURE);
}

static void
handle_info(const char *message)
{
/* Suppress info */
}

static int
handle_process(jack_nframes_t frames, void *arg)
{
jack_midi_data_t *buffer;
int code;
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;
void *port_buffer;
jack_time_t time;
switch (process_state) {

case 0:
/* State: initializing */
code = pthread_mutex_trylock(&start_mutex);
if (code) {
if (code != EBUSY) {
set_process_error(SOURCE_TRYLOCK, strerror(code));
}
break;
}
code = pthread_mutex_unlock(&start_mutex);
if (code) {
set_process_error(SOURCE_UNLOCK, strerror(code));
break;
}
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 */
jack_midi_clear_buffer(jack_port_get_buffer(out_port, frames));
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++;
}
jack_time_t microseconds =
jack_frames_to_time(client, last_frame_time) - last_activity_time;
if ((microseconds / 1000000) >= timeout) {
set_process_error(SOURCE_PROCESS, ERROR_TIMEOUT);
}
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;

#ifdef __APPLE__
sem_post(semaphore);
#else
sem_post(&semaphore);
#endif

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);
jack_midi_clear_buffer(port_buffer);
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("handle_shutdown", "The JACK server has been 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;

#ifdef __APPLE__
sem_post(semaphore);
#else
sem_post(&semaphore);
#endif

}

int
main(int argc, char **argv)
{
int code;
size_t jitter_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;
}
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;

#ifdef __APPLE__
// sem_init is not implemented on OSX
char name[128];
sprintf(name, "midi_sem_%p", client);
if ((semaphore = sem_open(name, O_CREAT, 0777, 0)) == (sem_t*)SEM_FAILED) {
error_message = strerror(errno);
error_source = "sem_open";
goto unregister_out_port;
}
#else
if (sem_init(&semaphore, 0, 0)) {
error_message = strerror(errno);
error_source = "sem_init";
goto unregister_out_port;
}
#endif

code = pthread_mutex_init(&start_mutex, NULL);
if (code) {
error_message = strerror(errno);
error_source = "pthread_mutex_init";
goto destroy_semaphore;
}
code = pthread_mutex_trylock(&start_mutex);
if (code) {
error_message = strerror(code);
error_source = "pthread_mutex_trylock";
goto destroy_mutex;
}
if (jack_activate(client)) {
error_message = "could not activate client";
error_source = "jack_activate";
goto destroy_mutex;
}
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;
}
code = pthread_mutex_unlock(&start_mutex);
if (code) {
error_message = strerror(code);
error_source = "pthread_mutex_unlock";
goto deactivate_client;
}

#ifdef __APPLE__
while (sem_wait(semaphore) != 0) {
#else
while (sem_wait(&semaphore) != 0) {
#endif

if (errno != EINTR) {
error_message = strerror(errno);
error_source = "sem_wait";
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 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;
}
for (i = 0; i < samples; i++) {
double jitter_time = ABS(average_latency_time -
((double) latency_time_values[i]));
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"
"Best latency: %.2f ms (%u frames)\n"
"Worst 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("\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_mutex:
pthread_mutex_destroy(&start_mutex);
destroy_semaphore:

#ifdef __APPLE__
sem_destroy(semaphore);
sem_unlink(name);
#else
sem_destroy(&semaphore);
#endif

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

+ 1
- 0
example-clients/wscript View File

@@ -27,6 +27,7 @@ example_programs = {
'jack_server_control' : 'server_control.cpp',
'jack_latent_client' : 'latent_client.c',
'jack_midi_dump' : 'midi_dump.c',
'jack_midi_latency_test' : 'midi_latency_test.c'
}

example_libs = {


+ 29
- 12
linux/alsa/JackAlsaDriver.cpp View File

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


+ 2
- 0
linux/alsa/JackAlsaDriver.h View File

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


+ 602
- 0
linux/alsarawmidi/JackALSARawMidiDriver.cpp View File

@@ -0,0 +1,602 @@
#include <memory>
#include <new>
#include <stdexcept>

#include <alsa/asoundlib.h>

#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()
{
Stop();
delete thread;
Close();
}

int
JackALSARawMidiDriver::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;
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;
}
port = fGraphManager->GetPort(index);
port->SetAlias(input_port->GetAlias());
port->SetLatencyRange(JackCaptureLatency, &latency_range);
fCapturePortList[i] = index;
}
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;
}
port = fGraphManager->GetPort(index);
port->SetAlias(output_port->GetAlias());
port->SetLatencyRange(JackPlaybackLatency, &latency_range);
fPlaybackPortList[i] = index;
}
return 0;
}

int
JackALSARawMidiDriver::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 0;
}

bool
JackALSARawMidiDriver::Execute()
{
jack_nframes_t timeout_frame = 0;
for (;;) {
jack_nframes_t process_frame;
jack_time_t wait_time;
jack_time_t *wait_time_ptr;
unsigned short revents;
if (! timeout_frame) {
wait_time_ptr = 0;
} else {
jack_time_t next_time = GetTimeFromFrames(timeout_frame);
jack_time_t now = GetMicroSeconds();
wait_time = next_time <= now ? 0 : next_time - now;
wait_time_ptr = &wait_time;
}
if (Poll(wait_time_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<snd_rawmidi_info_t *> *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<snd_rawmidi_info_t *> in_info_list;
std::vector<snd_rawmidi_info_t *> 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<JackALSARawMidiInputPort *> input_ptr;
if (potential_inputs) {
input_ports = new JackALSARawMidiInputPort *[potential_inputs];
input_ptr.reset(input_ports);
}
std::auto_ptr<JackALSARawMidiOutputPort *> 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;
}

#ifdef HAVE_PPOLL

int
JackALSARawMidiDriver::Poll(const jack_time_t *wait_time)
{
struct timespec timeout;
struct timespec *timeout_ptr;
if (! wait_time) {
timeout_ptr = 0;
} else {
timeout.tv_sec = (*wait_time) / 1000000;
timeout.tv_nsec = ((*wait_time) % 1000000) * 1000;
timeout_ptr = &timeout;
}
return ppoll(poll_fds, poll_fd_count, timeout_ptr, 0);
}

#else

int
JackALSARawMidiDriver::Poll(const jack_time_t *wait_time)
{
int result = poll(poll_fds, poll_fd_count,
! wait_time ? -1 : (int) ((*wait_time) / 1000));
if ((! result) && wait_time) {
jack_time_t time_left = (*wait_time) % 1000;
if (time_left) {
// Cheap hack.
usleep(time_left);
result = poll(poll_fds, poll_fd_count, 0);
}
}
return result;
}

#endif

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

+ 79
- 0
linux/alsarawmidi/JackALSARawMidiDriver.h View File

@@ -0,0 +1,79 @@
#ifndef __JackALSARawMidiDriver__
#define __JackALSARawMidiDriver__

#include <vector>

#include <alsa/asoundlib.h>
#include <poll.h>

#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<snd_rawmidi_info_t *> *info_list);

void
HandleALSAError(const char *driver_func, const char *alsa_func,
int code);

int
Poll(const jack_time_t *wait_time);

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

+ 124
- 0
linux/alsarawmidi/JackALSARawMidiInputPort.cpp View File

@@ -0,0 +1,124 @@
#include <memory>

#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<JackALSARawMidiReceiveQueue> receive_ptr(receive_queue);
thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
write_queue = new JackMidiBufferWriteQueue();
std::auto_ptr<JackMidiBufferWriteQueue> 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;
}

+ 43
- 0
linux/alsarawmidi/JackALSARawMidiInputPort.h View File

@@ -0,0 +1,43 @@
#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

+ 153
- 0
linux/alsarawmidi/JackALSARawMidiOutputPort.cpp View File

@@ -0,0 +1,153 @@
#include <memory>

#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<JackMidiBufferReadQueue> read_ptr(read_queue);
send_queue = new JackALSARawMidiSendQueue(rawmidi);
std::auto_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
std::auto_ptr<JackMidiAsyncQueue> 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;
}

+ 44
- 0
linux/alsarawmidi/JackALSARawMidiOutputPort.h View File

@@ -0,0 +1,44 @@
#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

+ 159
- 0
linux/alsarawmidi/JackALSARawMidiPort.cpp View File

@@ -0,0 +1,159 @@
#include <stdexcept>
#include <string>

#include "JackALSARawMidiPort.h"
#include "JackError.h"

using Jack::JackALSARawMidiPort;

JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
size_t index)
{
char device_id[32];
snprintf(device_id, sizeof(device_id), "hw:%d,%d,%d",
snd_rawmidi_info_get_card(info),
snd_rawmidi_info_get_device(info),
snd_rawmidi_info_get_subdevice(info));
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(&params);
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;
}
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;
}
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);
device_name = snd_rawmidi_info_get_subdevice_name(info);
if (! strlen(device_name)) {
device_name = snd_rawmidi_info_get_name(info);
}
snprintf(name, sizeof(name), "system:%s %s", device_name, 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;
}
}

+ 53
- 0
linux/alsarawmidi/JackALSARawMidiPort.h View File

@@ -0,0 +1,53 @@
#ifndef __JackALSARawMidiPort__
#define __JackALSARawMidiPort__

#include <alsa/asoundlib.h>
#include <poll.h>

#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

+ 35
- 0
linux/alsarawmidi/JackALSARawMidiReceiveQueue.cpp View File

@@ -0,0 +1,35 @@
#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;
}

+ 32
- 0
linux/alsarawmidi/JackALSARawMidiReceiveQueue.h View File

@@ -0,0 +1,32 @@
#ifndef __JackALSARawMidiReceiveQueue__
#define __JackALSARawMidiReceiveQueue__

#include <alsa/asoundlib.h>

#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

+ 40
- 0
linux/alsarawmidi/JackALSARawMidiSendQueue.cpp View File

@@ -0,0 +1,40 @@
#include <cassert>

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

+ 32
- 0
linux/alsarawmidi/JackALSARawMidiSendQueue.h View File

@@ -0,0 +1,32 @@
#ifndef __JackALSARawMidiSendQueue__
#define __JackALSARawMidiSendQueue__

#include <alsa/asoundlib.h>

#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

+ 12
- 26
linux/firewire/JackFFADODriver.cpp View File

@@ -36,8 +36,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <string.h>

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



+ 0
- 59
linux/firewire/JackFFADOMidiInput.cpp View File

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

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

}

+ 94
- 0
linux/firewire/JackFFADOMidiInputPort.cpp View File

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

#include "JackFFADOMidiInputPort.h"
#include "JackMidiUtil.h"

using Jack::JackFFADOMidiInputPort;

JackFFADOMidiInputPort::JackFFADOMidiInputPort(size_t max_bytes)
{
event = 0;
receive_queue = new JackFFADOMidiReceiveQueue();
std::auto_ptr<JackFFADOMidiReceiveQueue> receive_queue_ptr(receive_queue);
write_queue = new JackMidiBufferWriteQueue();
std::auto_ptr<JackMidiBufferWriteQueue> 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);
}

+ 51
- 0
linux/firewire/JackFFADOMidiInputPort.h View File

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

+ 0
- 60
linux/firewire/JackFFADOMidiOutput.cpp View File

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

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

}

+ 98
- 0
linux/firewire/JackFFADOMidiOutputPort.cpp 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.

*/

#include <memory>

#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<JackMidiBufferReadQueue> read_queue_ptr(read_queue);
send_queue = new JackFFADOMidiSendQueue();
std::auto_ptr<JackFFADOMidiSendQueue> 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);
}

+ 53
- 0
linux/firewire/JackFFADOMidiOutputPort.h View File

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

+ 55
- 0
linux/firewire/JackFFADOMidiReceiveQueue.cpp View File

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

linux/firewire/JackFFADOMidiInput.h → linux/firewire/JackFFADOMidiReceiveQueue.h View File

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

};


+ 64
- 0
linux/firewire/JackFFADOMidiSendQueue.cpp View File

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

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

linux/firewire/JackFFADOMidiOutput.h → linux/firewire/JackFFADOMidiSendQueue.h View File

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

};


+ 14
- 4
linux/wscript View File

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


+ 1
- 1
macosx/JackMachThread.h View File

@@ -62,7 +62,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define __JackMachThread__

#include "JackPosixThread.h"
#import <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>

#include <mach/thread_policy.h>
#include <mach/thread_act.h>


+ 465
- 57
macosx/Jackdmp.xcodeproj/project.pbxproj View File

@@ -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 = "<absolute>"; };
4B37C20406DF1FBE0016E567 /* CALatencyLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CALatencyLog.h; path = /Developer/Examples/CoreAudio/PublicUtility/CALatencyLog.h; sourceTree = "<absolute>"; };
4B37C20906DF1FE20016E567 /* latency.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = latency.c; path = /Developer/Examples/CoreAudio/PublicUtility/latency.c; sourceTree = "<absolute>"; };
@@ -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 = "<absolute>"; };
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 = "<group>";
@@ -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 = "<group>";
};
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 = (
@@ -9114,7 +9512,7 @@
CoreAudio,
);
OTHER_REZFLAGS = "";
PRODUCT_NAME = Jackdmp;
PRODUCT_NAME = Jackservermp;
REZ_EXECUTABLE = NO;
SDKROOT = "";
SECTORDER_FLAGS = "";
@@ -11111,7 +11509,7 @@
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
"-framework",
Jackdmp,
Jackservermp,
"-framework",
CoreAudio,
"-framework",
@@ -11261,7 +11659,7 @@
OTHER_LDFLAGS = (
libportaudio.a,
"-framework",
Jackdmp,
Jackservermp,
"-framework",
AudioToolbox,
"-framework",
@@ -11410,7 +11808,7 @@
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
"-framework",
Jackdmp,
Jackservermp,
"-framework",
CoreAudio,
"-framework",
@@ -11548,7 +11946,7 @@
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-framework",
Jackdmp,
Jackservermp,
"-framework",
CoreAudio,
"-framework",
@@ -16060,7 +16458,7 @@
CoreAudio,
);
OTHER_REZFLAGS = "";
PRODUCT_NAME = Jackdmp;
PRODUCT_NAME = Jackservermp;
REZ_EXECUTABLE = NO;
SDKROOT = "";
SECTORDER_FLAGS = "";
@@ -17071,7 +17469,7 @@
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
/usr/local/lib/libsamplerate.a,
/opt/local/lib/libsamplerate.a,
"-framework",
Jackservermp,
"-framework",
@@ -17220,7 +17618,7 @@
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
/usr/local/lib/libsamplerate.a,
/opt/local/lib/libsamplerate.a,
"-framework",
Jackservermp,
"-framework",
@@ -18767,6 +19165,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 = (


+ 33
- 34
macosx/coreaudio/JackCoreAudioAdapter.cpp View File

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


+ 62
- 38
macosx/coreaudio/JackCoreAudioDriver.cpp View File

@@ -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");
@@ -386,12 +386,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 +1552,6 @@ error:
int JackCoreAudioDriver::Close()
{
jack_log("JackCoreAudioDriver::Close");
Stop();

// Generic audio driver close
int res = JackAudioDriver::Close();
@@ -1561,6 +1563,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 +1620,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 +1644,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 +1670,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 +1682,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 +1736,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++) {


+ 9
- 7
macosx/coreaudio/JackCoreAudioDriver.h View File

@@ -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<AudioDeviceID> captureDeviceID, vector<AudioDeviceID> 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);


+ 532
- 256
macosx/coremidi/JackCoreMidiDriver.cpp View File

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

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

*/

#include <stdexcept>

#include <mach/mach_time.h>

#include "JackCoreMidiDriver.h"
#include "JackGraphManager.h"
#include "JackServer.h"
#include "JackCoreMidiUtil.h"
#include "JackEngineControl.h"
#include "JackDriverLoader.h"

#include <mach/mach_time.h>
#include <assert.h>
#include <iostream>
#include <sstream>
#include <string>
using Jack::JackCoreMidiDriver;

namespace Jack
///////////////////////////////////////////////////////////////////////////////
// Static callbacks
///////////////////////////////////////////////////////////////////////////////

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()
{
Stop();
Close();
}

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);
int result = 0;
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()
@@ -423,4 +700,3 @@ extern "C"
#ifdef __cplusplus
}
#endif


+ 54
- 40
macosx/coremidi/JackCoreMidiDriver.h View File

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

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,61 +21,74 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#ifndef __JackCoreMidiDriver__
#define __JackCoreMidiDriver__

#include <CoreMIDI/CoreMIDI.h>
#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

+ 184
- 0
macosx/coremidi/JackCoreMidiInputPort.cpp View File

@@ -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 <cassert>
#include <memory>

#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<JackMidiAsyncQueue> thread_queue_ptr(thread_queue);
write_queue = new JackMidiBufferWriteQueue();
std::auto_ptr<JackMidiBufferWriteQueue> write_queue_ptr(write_queue);
sysex_buffer = new jack_midi_data_t[max_bytes];
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;
}

+ 73
- 0
macosx/coremidi/JackCoreMidiInputPort.h View File

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

+ 250
- 0
macosx/coremidi/JackCoreMidiOutputPort.cpp View File

@@ -0,0 +1,250 @@
/*
Copyright (C) 2011 Devin Anderson

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <cassert>
#include <cerrno>
#include <cstring>
#include <new>
#include <stdexcept>

#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<JackMidiBufferReadQueue> read_queue_ptr(read_queue);
thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
std::auto_ptr<JackMidiAsyncQueue> thread_queue_ptr(thread_queue);
thread = new JackThread(this);
std::auto_ptr<JackThread> thread_ptr(thread);
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()
{
Stop();
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;
}

+ 90
- 0
macosx/coremidi/JackCoreMidiOutputPort.h View File

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

#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

+ 53
- 0
macosx/coremidi/JackCoreMidiPhysicalInputPort.cpp View File

@@ -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 <sstream>
#include <stdexcept>

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

+ 45
- 0
macosx/coremidi/JackCoreMidiPhysicalInputPort.h View File

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

+ 78
- 0
macosx/coremidi/JackCoreMidiPhysicalOutputPort.cpp View File

@@ -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 <sstream>
#include <stdexcept>

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

+ 55
- 0
macosx/coremidi/JackCoreMidiPhysicalOutputPort.h View File

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

+ 93
- 0
macosx/coremidi/JackCoreMidiPort.cpp View File

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

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

+ 67
- 0
macosx/coremidi/JackCoreMidiPort.h View File

@@ -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 <CoreMIDI/CoreMIDI.h>

#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

+ 43
- 0
macosx/coremidi/JackCoreMidiUtil.cpp View File

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

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

+ 39
- 0
macosx/coremidi/JackCoreMidiUtil.h View File

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

#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Debugging.h>

namespace Jack {

std::string
GetMacOSErrorString(OSStatus status);

void
WriteMacOSError(const char *jack_function, const char *mac_function,
OSStatus status);

}

#endif

+ 75
- 0
macosx/coremidi/JackCoreMidiVirtualInputPort.cpp View File

@@ -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 <sstream>
#include <stdexcept>

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

+ 50
- 0
macosx/coremidi/JackCoreMidiVirtualInputPort.h View File

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

+ 72
- 0
macosx/coremidi/JackCoreMidiVirtualOutputPort.cpp View File

@@ -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 <sstream>
#include <stdexcept>

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

+ 49
- 0
macosx/coremidi/JackCoreMidiVirtualOutputPort.h View File

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

+ 2
- 2
tests/test.cpp View File

@@ -972,14 +972,14 @@ int main (int argc, char *argv[])

float factor = 0.5f;
old_buffer_size = jack_get_buffer_size(client1);
Log("Testing BufferSize change & Callback...\n--> Current buffer size : %i.\n", old_buffer_size);
Log("Testing BufferSize change & Callback...\n--> Current buffer size : %d.\n", old_buffer_size);
linebuf = linecount;
if (jack_set_buffer_size(client1, (jack_nframes_t)(old_buffer_size * factor)) < 0) {
printf("!!! ERROR !!! jack_set_buffer_size fails !\n");
}
jack_sleep(1 * 1000);
cur_buffer_size = jack_get_buffer_size(client1);
if ((old_buffer_size * factor) != cur_buffer_size) {
if (abs((old_buffer_size * factor) - cur_buffer_size) > 5) { // Tolerance needed for dummy driver...
printf("!!! ERROR !!! Buffer size has not been changed !\n");
printf("!!! Maybe jack was compiled without the '--enable-resize' flag...\n");
} else {


+ 6
- 0
windows/jack_winmme.cbp View File

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


+ 2
- 2
windows/jackd.workspace View File

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

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save