Browse Source

rebase from trunk 3482:3502

git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@3503 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.9.8
sletz 16 years ago
parent
commit
522fd2b7f8
33 changed files with 2242 additions and 298 deletions
  1. +4
    -0
      ChangeLog
  2. +6
    -3
      common/JackAudioAdapterInterface.cpp
  3. +1
    -1
      common/JackAudioDriver.cpp
  4. +2
    -2
      common/JackClient.cpp
  5. +2
    -2
      common/JackConnectionManager.cpp
  6. +4
    -4
      common/JackConstants.h
  7. +21
    -0
      common/JackControlAPI.cpp
  8. +7
    -0
      common/JackControlAPI.h
  9. +42
    -2
      common/JackDriver.cpp
  10. +22
    -0
      common/JackDriver.h
  11. +3
    -2
      common/JackDriverLoader.cpp
  12. +6
    -0
      common/JackDriverLoader.h
  13. +181
    -0
      common/JackMidiDriver.cpp
  14. +79
    -0
      common/JackMidiDriver.h
  15. +3
    -3
      common/JackMidiPort.cpp
  16. +2
    -1
      common/JackMidiPort.h
  17. +27
    -26
      common/JackServer.cpp
  18. +4
    -2
      common/JackServer.h
  19. +13
    -0
      common/JackThreadedDriver.h
  20. +68
    -40
      common/Jackdmp.cpp
  21. +8
    -0
      common/jack/control.h
  22. +2
    -1
      common/wscript
  23. +12
    -8
      example-clients/midisine.c
  24. +248
    -1
      macosx/Jackdmp.xcodeproj/project.pbxproj
  25. +426
    -0
      macosx/coremidi/JackCoreMidiDriver.cpp
  26. +80
    -0
      macosx/coremidi/JackCoreMidiDriver.h
  27. +17
    -0
      macosx/wscript
  28. +121
    -0
      windows/jack_winmme.cbp
  29. +2
    -1
      windows/jackd.workspace
  30. +41
    -0
      windows/jackwinmme.rc
  31. +200
    -199
      windows/libjackserver.cbp
  32. +501
    -0
      windows/winmme/JackWinMMEDriver.cpp
  33. +87
    -0
      windows/winmme/JackWinMMEDriver.h

+ 4
- 0
ChangeLog View File

@@ -25,6 +25,10 @@ Paul Davis
Jackdmp changes log
---------------------------

2009-04-08 Stephane Letz <letz@grame.fr>

* Native MIDI backend (JackCoreMidiDriver, JackWinMMEDriver) in progress.

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

* Simplify JackClient RT code, jack_thread_wait API marked deprecated."


+ 6
- 3
common/JackAudioAdapterInterface.cpp View File

@@ -78,7 +78,8 @@ namespace Jack
fprintf(file, "set multiplot\n");
fprintf(file, "set grid\n");
fprintf(file, "set title \"Audio adapter timing\"\n");
fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
fprintf(file, "set xlabel \"audio cycles\"\n");
fprintf(file, "set ylabel \"frames\"\n");
fprintf(file, "plot ");
@@ -109,7 +110,8 @@ namespace Jack
fprintf(file, "set multiplot\n");
fprintf(file, "set grid\n");
fprintf(file, "set title \"Audio adapter timing\"\n");
fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
fprintf(file, "set xlabel \"audio cycles\"\n");
fprintf(file, "set ylabel \"resampling ratio\"\n");
fprintf(file, "plot ");
@@ -140,7 +142,8 @@ namespace Jack
fprintf(file, "set multiplot\n");
fprintf(file, "set grid\n");
fprintf(file, "set title \"Audio adapter timing\"\n");
fprintf(file, "set title \"Audio adapter timing: host [rate = %.1f kHz buffer = %d frames] adapter [rate = %.1f kHz buffer = %d frames] \"\n"
,float(fHostSampleRate)/1000.f, fHostBufferSize, float(fAdaptedSampleRate)/1000.f, fAdaptedBufferSize);
fprintf(file, "set xlabel \"audio cycles\"\n");
fprintf(file, "set ylabel \"frames\"\n");
fprintf(file, "plot ");


+ 1
- 1
common/JackAudioDriver.cpp View File

@@ -1,6 +1,6 @@
/*
Copyright (C) 2001 Paul Davis
Copyright (C) 2004-2008 GramefClientControl.
Copyright (C) 2004-2008 Grame.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by


+ 2
- 2
common/JackClient.cpp View File

@@ -120,12 +120,12 @@ void JackClient::SetupDriverSync(bool freewheel)
jack_log("JackClient::SetupDriverSync driver sem in flush mode");
fSynchroTable[AUDIO_DRIVER_REFNUM].SetFlush(true);
fSynchroTable[FREEWHEEL_DRIVER_REFNUM].SetFlush(true);
fSynchroTable[LOOPBACK_DRIVER_REFNUM].SetFlush(true);
fSynchroTable[MIDI_DRIVER_REFNUM].SetFlush(true);
} else {
jack_log("JackClient::SetupDriverSync driver sem in normal mode");
fSynchroTable[AUDIO_DRIVER_REFNUM].SetFlush(false);
fSynchroTable[FREEWHEEL_DRIVER_REFNUM].SetFlush(false);
fSynchroTable[LOOPBACK_DRIVER_REFNUM].SetFlush(false);
fSynchroTable[MIDI_DRIVER_REFNUM].SetFlush(false);
}
}



+ 2
- 2
common/JackConnectionManager.cpp View File

@@ -58,8 +58,8 @@ bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const
|| ref2 == AUDIO_DRIVER_REFNUM
|| ref1 == FREEWHEEL_DRIVER_REFNUM
|| ref2 == FREEWHEEL_DRIVER_REFNUM
|| ref1 == LOOPBACK_DRIVER_REFNUM
|| ref2 == LOOPBACK_DRIVER_REFNUM) {
|| ref1 == MIDI_DRIVER_REFNUM
|| ref2 == MIDI_DRIVER_REFNUM) {
return false;
} else if (ref1 == ref2) { // Same refnum
return true;


+ 4
- 4
common/JackConstants.h View File

@@ -47,10 +47,10 @@
#define CLIENT_NUM 64
#endif

#define AUDIO_DRIVER_REFNUM 0 // Audio driver is initialized first, it will get the refnum 0
#define FREEWHEEL_DRIVER_REFNUM 1 // Freewheel driver is initialized second, it will get the refnum 1
#define LOOPBACK_DRIVER_REFNUM 2 // Loopback driver is initialized third, it will get the refnum 2
#define REAL_REFNUM LOOPBACK_DRIVER_REFNUM + 1 // Real clients start at LOOPBACK_DRIVER_REFNUM + 1
#define AUDIO_DRIVER_REFNUM 0 // Audio driver is initialized first, it will get the refnum 0
#define FREEWHEEL_DRIVER_REFNUM 1 // Freewheel driver is initialized second, it will get the refnum 1
#define MIDI_DRIVER_REFNUM 2 // Loopback driver is initialized third, it will get the refnum 2
#define REAL_REFNUM MIDI_DRIVER_REFNUM + 1 // Real clients start at MIDI_DRIVER_REFNUM + 1

#define JACK_DEFAULT_SERVER_NAME "default"



+ 21
- 0
common/JackControlAPI.cpp View File

@@ -42,6 +42,7 @@
#include "JackControlAPI.h"
#include "JackLockedEngine.h"
#include "JackConstants.h"
#include "JackDriverLoader.h"

using namespace Jack;

@@ -95,6 +96,7 @@ struct jackctl_driver
jack_driver_desc_t * desc_ptr;
JSList * parameters;
JSList * set_parameters;
JackDriverInfo* info;
};

struct jackctl_internal
@@ -1161,4 +1163,23 @@ EXPORT bool jackctl_server_unload_internal(
}
}

EXPORT bool jackctl_server_load_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
{
if (server_ptr->engine != NULL) {
driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters);
return (driver_ptr->info != 0);
} else {
return false;
}
}

EXPORT bool jackctl_server_unload_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
{
if (server_ptr->engine != NULL) {
server_ptr->engine->RemoveSlave(driver_ptr->info);
return true;
} else {
return false;
}
}


+ 7
- 0
common/JackControlAPI.h View File

@@ -219,6 +219,13 @@ EXPORT bool jackctl_server_load_internal(
EXPORT bool jackctl_server_unload_internal(
jackctl_server * server,
jackctl_internal * internal);
EXPORT bool jackctl_server_load_slave(jackctl_server_t * server,
jackctl_driver_t * driver);

EXPORT bool jackctl_server_unload_slave(jackctl_server_t * server,
jackctl_driver_t * driver);


#if 0
{ /* Adjust editor indent */


+ 42
- 2
common/JackDriver.cpp View File

@@ -68,7 +68,7 @@ int JackDriver::Open()
int refnum = -1;

if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) {
jack_error("Cannot allocate internal client for audio driver");
jack_error("Cannot allocate internal client for driver");
return -1;
}

@@ -79,6 +79,46 @@ int JackDriver::Open()
return 0;
}

int JackDriver::Open (bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency)
{
jack_log("JackDriver::Open capture_driver_name = %s", capture_driver_name);
jack_log("JackDriver::Open playback_driver_name = %s", playback_driver_name);
int refnum = -1;

if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) {
jack_error("Cannot allocate internal client for driver");
return -1;
}

fClientControl.fRefNum = refnum;
fClientControl.fActive = true;
fCaptureLatency = capture_latency;
fPlaybackLatency = playback_latency;

assert(strlen(capture_driver_name) < JACK_CLIENT_NAME_SIZE);
assert(strlen(playback_driver_name) < JACK_CLIENT_NAME_SIZE);

strcpy(fCaptureDriverName, capture_driver_name);
strcpy(fPlaybackDriverName, playback_driver_name);

fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // in microsec
if (!fEngineControl->fTimeOut)
fEngineControl->fTimeOutUsecs = jack_time_t(2.f * fEngineControl->fPeriodUsecs);

//fGraphManager->SetBufferSize(fEngineControl->fBufferSize);
fGraphManager->DirectConnect(fClientControl.fRefNum, fClientControl.fRefNum); // Connect driver to itself for "sync" mode
SetupDriverSync(fClientControl.fRefNum, false);
return 0;
}

int JackDriver::Open(jack_nframes_t buffer_size,
jack_nframes_t samplerate,
bool capturing,
@@ -96,7 +136,7 @@ int JackDriver::Open(jack_nframes_t buffer_size,
int refnum = -1;

if (fEngine->ClientInternalOpen(fClientControl.fName, &refnum, &fEngineControl, &fGraphManager, this, false) != 0) {
jack_error("Cannot allocate internal client for audio driver");
jack_error("Cannot allocate internal client for driver");
return -1;
}



+ 22
- 0
common/JackDriver.h View File

@@ -50,6 +50,17 @@ class SERVER_EXPORT JackDriverInterface
{}
virtual int Open() = 0;
virtual int Open (bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency) = 0;
virtual int Open(jack_nframes_t buffer_size,
jack_nframes_t samplerate,
bool capturing,
@@ -142,6 +153,17 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface
int ProcessSlaves();
virtual int Open();
virtual int Open (bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency);
virtual int Open(jack_nframes_t buffer_size,
jack_nframes_t samplerate,
bool capturing,


+ 3
- 2
common/JackDriverLoader.cpp View File

@@ -800,7 +800,8 @@ Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver
jack_error("no initialize function in shared object %s\n", driver_desc->file);
return NULL;
}

return fInitialize(engine, synchro, params);
fBackend = fInitialize(engine, synchro, params);
return fBackend;
}


+ 6
- 0
common/JackDriverLoader.h View File

@@ -42,6 +42,7 @@ class JackDriverInfo
driverInitialize fInitialize;
DRIVER_HANDLE fHandle;
Jack::JackDriverClientInterface* fBackend;
public:
@@ -54,6 +55,11 @@ class JackDriverInfo
}
Jack::JackDriverClientInterface* Open(jack_driver_desc_t* driver_desc, Jack::JackLockedEngine*, Jack::JackSynchro*, const JSList*);
Jack::JackDriverClientInterface* GetBackend()
{
return fBackend;
}
};



+ 181
- 0
common/JackMidiDriver.cpp View File

@@ -0,0 +1,181 @@
/*
Copyright (C) 2009 Grame.

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

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 "JackSystemDeps.h"
#include "JackMidiDriver.h"
#include "JackTime.h"
#include "JackError.h"
#include "JackEngineControl.h"
#include "JackPort.h"
#include "JackGraphManager.h"
#include "JackException.h"
#include <assert.h>

namespace Jack
{

JackMidiDriver::JackMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
: JackDriver(name, alias, engine, table),
fCaptureChannels(0),
fPlaybackChannels(0)
{
for (int i = 0; i < DRIVER_PORT_NUM; i++) {
fRingBuffer[i] = NULL;
}
}

JackMidiDriver::~JackMidiDriver()
{
for (int i = 0; i < fCaptureChannels; i++) {
if (fRingBuffer[i])
jack_ringbuffer_free(fRingBuffer[i]);
}
}

int JackMidiDriver::Open(bool capturing,
bool playing,
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)
{
fCaptureChannels = inchannels;
fPlaybackChannels = outchannels;
for (int i = 0; i < fCaptureChannels; i++) {
fRingBuffer[i] = jack_ringbuffer_create(sizeof(float) * BUFFER_SIZE_MAX);
}
return JackDriver::Open(capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency);
}

int JackMidiDriver::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];
unsigned long port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
int i;

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

for (i = 0; i < fCaptureChannels; i++) {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) {
jack_error("driver: cannot register port for %s", name);
return -1;
}
port = fGraphManager->GetPort(port_index);
port->SetAlias(alias);
fCapturePortList[i] = port_index;
jack_log("JackMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
}

port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;

for (i = 0; i < fPlaybackChannels; i++) {
snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1);
snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) {
jack_error("driver: cannot register port for %s", name);
return -1;
}
port = fGraphManager->GetPort(port_index);
port->SetAlias(alias);
fPlaybackPortList[i] = port_index;
jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
}

return 0;
}

int JackMidiDriver::Detach()
{
int i;
jack_log("JackMidiDriver::Detach");

for (i = 0; i < fCaptureChannels; i++) {
fGraphManager->ReleasePort(fClientControl.fRefNum, fCapturePortList[i]);
}

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

return 0;
}

int JackMidiDriver::Read()
{
return 0;
}

int JackMidiDriver::Write()
{
return 0;
}

int JackMidiDriver::ProcessNull()
{
return 0;
}

int JackMidiDriver::Process()
{
// 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...
}
fGraphManager->ResumeRefNum(&fClientControl, fSynchroTable);
if (fEngineControl->fSyncMode) {
if (fGraphManager->SuspendRefNum(&fClientControl, fSynchroTable, fEngineControl->fTimeOutUsecs) < 0) {
jack_error("JackFreewheelDriver::ProcessSync SuspendRefNum error");
return -1;
}
}
// Write output buffers for the current cycle
if (Write() < 0) {
jack_error("JackMidiDriver::Process: write error, skip cycle");
return 0; // Skip cycle, but continue processing...
}
return 0;
}

JackMidiBuffer* JackMidiDriver::GetInputBuffer(int port_index)
{
assert(fCapturePortList[port_index]);
return (JackMidiBuffer*)fGraphManager->GetBuffer(fCapturePortList[port_index], fEngineControl->fBufferSize);
}

JackMidiBuffer* JackMidiDriver::GetOutputBuffer(int port_index)
{
assert(fPlaybackPortList[port_index]);
return (JackMidiBuffer*)fGraphManager->GetBuffer(fPlaybackPortList[port_index], fEngineControl->fBufferSize);
}

} // end of namespace

+ 79
- 0
common/JackMidiDriver.h View File

@@ -0,0 +1,79 @@
/*
Copyright (C) 2009 Grame

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

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

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

*/

#ifndef __JackMidiDriver__
#define __JackMidiDriver__

#include "JackDriver.h"
#include "JackMidiPort.h"
#include "JackLockedEngine.h"
#include "ringbuffer.h"

namespace Jack
{

/*!
\brief The base class for MIDI drivers: drivers with MIDI ports.
*/

class SERVER_EXPORT JackMidiDriver : public JackDriver
{

protected:

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);
public:

JackMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);
virtual ~JackMidiDriver();

virtual int Open(bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency);
virtual int Process();
virtual int ProcessNull();

virtual int Attach();
virtual int Detach();
virtual int Read();
virtual int Write();
};

} // end of namespace

#endif

+ 3
- 3
common/JackMidiPort.cpp View File

@@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
namespace Jack
{

void JackMidiBuffer::Reset(jack_nframes_t nframes)
SERVER_EXPORT void JackMidiBuffer::Reset(jack_nframes_t nframes)
{
/* This line ate 1 hour of my life... dsbaikov */
this->nframes = nframes;
@@ -37,7 +37,7 @@ void JackMidiBuffer::Reset(jack_nframes_t nframes)
mix_index = 0;
}

jack_shmsize_t JackMidiBuffer::MaxEventSize() const
SERVER_EXPORT jack_shmsize_t JackMidiBuffer::MaxEventSize() const
{
assert (((jack_shmsize_t) - 1) < 0); // jack_shmsize_t should be signed
jack_shmsize_t left = buffer_size - (sizeof(JackMidiBuffer) + sizeof(JackMidiEvent) * (event_count + 1) + write_pos);
@@ -48,7 +48,7 @@ jack_shmsize_t JackMidiBuffer::MaxEventSize() const
return left;
}

jack_midi_data_t* JackMidiBuffer::ReserveEvent(jack_nframes_t time, jack_shmsize_t size)
SERVER_EXPORT jack_midi_data_t* JackMidiBuffer::ReserveEvent(jack_nframes_t time, jack_shmsize_t size)
{
jack_shmsize_t space = MaxEventSize();
if (space == 0 || size > space) {


+ 2
- 1
common/JackMidiPort.h View File

@@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include "types.h"
#include "JackConstants.h"
#include "JackPlatformPlug.h"
#include <stddef.h>

/** Type for raw event data contained in @ref jack_midi_event_t. */
@@ -42,7 +43,7 @@ struct jack_midi_event_t
namespace Jack
{

struct JackMidiEvent
struct SERVER_EXPORT JackMidiEvent
{
// Most MIDI events are < 4 bytes in size, so we can save a lot, storing them inplace.
enum { INLINE_SIZE_MAX = sizeof(jack_shmsize_t) };


+ 27
- 26
common/JackServer.cpp View File

@@ -22,7 +22,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackServerGlobals.h"
#include "JackTime.h"
#include "JackFreewheelDriver.h"
#include "JackLoopbackDriver.h"
#include "JackThreadedDriver.h"
#include "JackGlobals.h"
#include "JackLockedEngine.h"
@@ -50,10 +49,8 @@ JackServer::JackServer(bool sync, bool temporary, long timeout, bool rt, long pr
fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, server_name);
fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl);
fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver(fEngine, GetSynchroTable()));
fLoopbackDriver = new JackLoopbackDriver(fEngine, GetSynchroTable());
fAudioDriver = NULL;
fFreewheel = false;
fLoopback = loopback;
JackServerGlobals::fInstance = this; // Unique instance
JackServerGlobals::fUserCount = 1; // One user
jack_verbose = verbose;
@@ -64,7 +61,6 @@ JackServer::~JackServer()
delete fGraphManager;
delete fAudioDriver;
delete fFreewheelDriver;
delete fLoopbackDriver;
delete fEngine;
delete fEngineControl;
}
@@ -94,35 +90,17 @@ int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
goto fail_close4;
}
if (fLoopbackDriver->Open(fEngineControl->fBufferSize, fEngineControl->fSampleRate, 1, 1, fLoopback, fLoopback, false, "loopback", "loopback", 0, 0) != 0) {
jack_error("Cannot open driver");
goto fail_close5;
}

if (fAudioDriver->Attach() != 0) {
jack_error("Cannot attach audio driver");
goto fail_close6;
}
if (fLoopback > 0 && fLoopbackDriver->Attach() != 0) {
jack_error("Cannot attach loopback driver");
goto fail_close7;
goto fail_close5;
}
fFreewheelDriver->SetMaster(false);
fAudioDriver->SetMaster(true);
if (fLoopback > 0)
fAudioDriver->AddSlave(fLoopbackDriver);
fAudioDriver->AddSlave(fFreewheelDriver); // After ???
InitTime();
return 0;

fail_close7:
fAudioDriver->Detach();
fail_close6:
fLoopbackDriver->Close();

fail_close5:
fFreewheelDriver->Close();

@@ -145,11 +123,8 @@ int JackServer::Close()
jack_log("JackServer::Close");
fChannel.Close();
fAudioDriver->Detach();
if (fLoopback > 0)
fLoopbackDriver->Detach();
fAudioDriver->Close();
fFreewheelDriver->Close();
fLoopbackDriver->Close();
fEngine->Close();
// TODO: move that in reworked JackServerGlobals::Destroy()
JackMessageBuffer::Destroy();
@@ -305,6 +280,32 @@ void JackServer::ClientKill(int refnum)
}
}

//----------------------
// Backend management
//----------------------

JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
{
JackDriverInfo* info = new JackDriverInfo();
JackDriverClientInterface* backend = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
if (backend == NULL) {
delete info;
return NULL;
} else {
backend->Attach();
fAudioDriver->AddSlave(backend);
return info;
}
}

void JackServer::RemoveSlave(JackDriverInfo* info)
{
JackDriverClientInterface* backend = info->GetBackend();
fAudioDriver->RemoveSlave(info->GetBackend());
backend->Detach();
backend->Close();
}

//----------------------
// Transport management
//----------------------


+ 4
- 2
common/JackServer.h View File

@@ -50,7 +50,6 @@ class SERVER_EXPORT JackServer
JackDriverInfo fDriverInfo;
JackDriverClientInterface* fAudioDriver;
JackDriverClientInterface* fFreewheelDriver;
JackDriverClientInterface* fLoopbackDriver;
JackLockedEngine* fEngine;
JackEngineControl* fEngineControl;
JackGraphManager* fGraphManager;
@@ -58,7 +57,6 @@ class SERVER_EXPORT JackServer
JackConnectionManager fConnectionState;
JackSynchro fSynchroTable[CLIENT_NUM];
bool fFreewheel;
long fLoopback;
int InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int* status);

@@ -86,6 +84,10 @@ class SERVER_EXPORT JackServer
// Transport management
int ReleaseTimebase(int refnum);
int SetTimebaseCallback(int refnum, int conditional);
// Backend management
JackDriverInfo* AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params);
void RemoveSlave(JackDriverInfo* info);

// Object access
JackLockedEngine* GetEngine();


+ 13
- 0
common/JackThreadedDriver.h View File

@@ -45,6 +45,19 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi
virtual ~JackThreadedDriver();

virtual int Open();
virtual int Open (bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency)
{
return -1;
}
virtual int Open(jack_nframes_t buffer_size,
jack_nframes_t samplerate,
bool capturing,


+ 68
- 40
common/Jackdmp.cpp View File

@@ -33,7 +33,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackDriverLoader.h"

/*
This is a simple port of the old jackdmp.cpp file to use the new Jack 2.0 control API. Available options for the server
This is a simple port of the old jackdmp.cpp file to use the new Jack 2.0 control API. Available options for the server
are "hard-coded" in the source. A much better approach would be to use the control API to:
- dynamically retrieve available server parameters and then prepare to parse them
- get available drivers and their possible parameters, then prepare to parse them.
@@ -58,7 +58,7 @@ static void notify_server_start(const char* server_name)
static void notify_server_stop(const char* server_name)
{
// Send notification to be used in the JackRouter plugin
CFStringRef ref1 = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman);
CFStringRef ref1 = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman);
CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
CFSTR("com.grame.jackserver.stop"),
ref1,
@@ -95,14 +95,14 @@ static void usage(FILE* file)
"usage: jackdmp [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n"
" [ --name OR -n server-name ]\n"
" [ --timeout OR -t client-timeout-in-msecs ]\n"
" [ --loopback OR -L loopback-port-number ]\n"
" [ --midi OR -X midi-driver ]\n"
" [ --verbose OR -v ]\n"
" [ --replace-registry OR -r ]\n"
" [ --silent OR -s ]\n"
" [ --sync OR -S ]\n"
" [ --temporary OR -T ]\n"
" [ --version OR -V ]\n"
" -d driver [ ... driver args ... ]\n"
" -d audio-driver [ ... driver args ... ]\n"
" where driver can be `alsa', `coreaudio', 'portaudio' or `dummy'\n"
" jackdmp -d driver --help\n"
" to display options for each driver\n\n");
@@ -154,10 +154,12 @@ int main(int argc, char* argv[])
jackctl_server_t * server_ctl;
const JSList * server_parameters;
const char* server_name = "default";
jackctl_driver_t * driver_ctl;
const char *options = "-ad:P:uvrshVRL:STFl:t:mn:p:";
jackctl_driver_t * audio_driver_ctl;
jackctl_driver_t * midi_driver_ctl;
const char *options = "-ad:X:P:uvrshVRL:STFl:t:mn:p:";
struct option long_options[] = {
{ "driver", 1, 0, 'd' },
{ "audio-driver", 1, 0, 'd' },
{ "midi-driver", 1, 0, 'X' },
{ "verbose", 0, 0, 'v' },
{ "help", 0, 0, 'h' },
{ "port-max", 1, 0, 'p' },
@@ -177,10 +179,14 @@ int main(int argc, char* argv[])
};
int i,opt = 0;
int option_index = 0;
bool seen_driver = false;
char *driver_name = NULL;
char **driver_args = NULL;
int driver_nargs = 1;
bool seen_audio_driver = false;
bool seen_midi_driver = false;
char *audio_driver_name = NULL;
char **audio_driver_args = NULL;
int audio_driver_nargs = 1;
char *midi_driver_name = NULL;
char **midi_driver_args = NULL;
int midi_driver_nargs = 1;
int port_max = 512;
int do_mlock = 1;
int do_unlock = 0;
@@ -190,34 +196,39 @@ int main(int argc, char* argv[])
union jackctl_parameter_value value;

copyright(stdout);
server_ctl = jackctl_server_create();
if (server_ctl == NULL) {
fprintf(stderr, "Failed to create server object\n");
return -1;
}
server_parameters = jackctl_server_get_parameters(server_ctl);

opterr = 0;
while (!seen_driver &&
while (!seen_audio_driver &&
(opt = getopt_long(argc, argv, options,
long_options, &option_index)) != EOF) {
switch (opt) {

case 'd':
seen_driver = true;
driver_name = optarg;
seen_audio_driver = true;
audio_driver_name = optarg;
break;

case 'X':
seen_midi_driver = true;
midi_driver_name = optarg;
break;

case 'p':
port_max = (unsigned int)atol(optarg);
break;
case 'm':
do_mlock = 0;
break;
case 'u':
do_unlock = 1;
break;
@@ -306,6 +317,7 @@ int main(int argc, char* argv[])
default:
fprintf(stderr, "unknown option character %c\n", optopt);
/*fallthru*/

case 'h':
usage(stdout);
goto fail_free;
@@ -313,61 +325,77 @@ int main(int argc, char* argv[])
}

if (show_version) {
printf("jackdmp version" VERSION
"\n");
printf( "jackdmp version " VERSION
" tmpdir " jack_server_dir
" protocol %d"
"\n", JACK_PROTOCOL_VERSION);
return -1;
}
if (!seen_driver) {
if (!seen_audio_driver) {
usage(stderr);
goto fail_free;
}

driver_ctl = jackctl_server_get_driver(server_ctl, driver_name);
if (driver_ctl == NULL) {
fprintf(stderr, "Unkown driver \"%s\"\n", driver_name);
// Audio driver
audio_driver_ctl = jackctl_server_get_driver(server_ctl, audio_driver_name);
if (audio_driver_ctl == NULL) {
fprintf(stderr, "Unkown driver \"%s\"\n", audio_driver_name);
goto fail_free;
}

if (optind < argc) {
driver_nargs = 1 + argc - optind;
audio_driver_nargs = 1 + argc - optind;
} else {
driver_nargs = 1;
audio_driver_nargs = 1;
}

if (driver_nargs == 0) {
if (audio_driver_nargs == 0) {
fprintf(stderr, "No driver specified ... hmm. JACK won't do"
" anything when run like this.\n");
goto fail_free;
}

driver_args = (char **) malloc(sizeof(char *) * driver_nargs);
driver_args[0] = driver_name;
audio_driver_args = (char **) malloc(sizeof(char *) * audio_driver_nargs);
audio_driver_args[0] = audio_driver_name;

for (i = 1; i < driver_nargs; i++) {
driver_args[i] = argv[optind++];
for (i = 1; i < audio_driver_nargs; i++) {
audio_driver_args[i] = argv[optind++];
}

if (jackctl_parse_driver_params(driver_ctl, driver_nargs, driver_args)) {
if (jackctl_parse_driver_params(audio_driver_ctl, audio_driver_nargs, audio_driver_args)) {
goto fail_free;
}
if (!jackctl_server_start(server_ctl, driver_ctl)) {

// Start server
if (!jackctl_server_start(server_ctl, audio_driver_ctl)) {
fprintf(stderr, "Failed to start server\n");
goto fail_free;
}

// MIDI driver
if (seen_midi_driver) {

midi_driver_ctl = jackctl_server_get_driver(server_ctl, midi_driver_name);
if (midi_driver_ctl == NULL) {
fprintf(stderr, "Unkown driver \"%s\"\n", midi_driver_name);
goto fail_free;
}

jackctl_server_load_slave(server_ctl, midi_driver_ctl);
}

notify_server_start(server_name);

// Waits for signal
signals = jackctl_setup_signals(0);
jackctl_wait_signals(signals);
if (!jackctl_server_stop(server_ctl))
fprintf(stderr, "Cannot stop server...\n");
fail_free:
jackctl_server_destroy(server_ctl);
notify_server_stop(server_name);
return 1;


+ 8
- 0
common/jack/control.h View File

@@ -510,6 +510,14 @@ jack_log(

/* @} */

bool
jackctl_server_load_slave(jackctl_server_t * server,
jackctl_driver_t * driver);

bool
jackctl_server_unload_slave(jackctl_server_t * server,
jackctl_driver_t * driver);

#if 0
{ /* Adjust editor indent */
#endif


+ 2
- 1
common/wscript View File

@@ -113,6 +113,7 @@ def build(bld):
serverlib.source = [] + common_libsources
serverlib.source += [
'JackAudioDriver.cpp',
'JackMidiDriver.cpp',
'JackDriver.cpp',
'JackEngine.cpp',
'JackExternalClient.cpp',
@@ -170,7 +171,7 @@ def build(bld):
serverlib.env.append_value("CPPFLAGS", "-fvisibility=hidden")
serverlib.env.append_value("CPPFLAGS", "-mmacosx-version-min=10.4 -arch i386 -arch ppc")
#serverlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework vecLib -single_module -arch i386 -arch ppc")
serverlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework vecLib -single_module")
serverlib.env.append_value("LINKFLAGS", "-framework CoreAudio -framework CoreFoundation -framework vecLib -single_module")
serverlib.env.append_value("LINKFLAGS", "-compatibility_version 1 -current_version 1")

if bld.env['IS_SUN']:


+ 12
- 8
example-clients/midisine.c View File

@@ -71,17 +71,21 @@ static int process(jack_nframes_t nframes, void *arg)
/* printf("1st byte of 1st event addr is %p\n", in_events[0].buffer);*/
}
jack_midi_event_get(&in_event, port_buf, 0);
for(i=0; i<nframes; i++)
for(i = 0; i < nframes; i++)
{
if((in_event.time == i) && (event_index < event_count))
if ((in_event.time == i) && (event_index < event_count))
{
if( ((*(in_event.buffer) & 0xf0)) == 0x90 )
{
/* note on */
note = *(in_event.buffer + 1);
note_on = 1.0;
if (((*(in_event.buffer) & 0xf0)) == 0x90)
{
/* note on */
note = *(in_event.buffer + 1);
if (*(in_event.buffer + 2) == 0) {
note_on = 0.0;
} else {
note_on = (float)(*(in_event.buffer + 2)) / 127.f;
}
}
else if( ((*(in_event.buffer)) & 0xf0) == 0x80 )
else if (((*(in_event.buffer)) & 0xf0) == 0x80)
{
/* note off */
note = *(in_event.buffer + 1);


+ 248
- 1
macosx/Jackdmp.xcodeproj/project.pbxproj View File

@@ -58,6 +58,7 @@
4B699DB6097D421700A18468 /* PBXTargetDependency */,
4B699DB8097D421700A18468 /* PBXTargetDependency */,
4B699DBA097D421700A18468 /* PBXTargetDependency */,
4BF339280F8B87800080FB5B /* PBXTargetDependency */,
4B699DBC097D421700A18468 /* PBXTargetDependency */,
BA222AF20DC883F3001A17F4 /* PBXTargetDependency */,
4BD624D30CBCF55700DE782F /* PBXTargetDependency */,
@@ -576,6 +577,16 @@
4BF284190F31B4BC00B05BE3 /* JackArgParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF284170F31B4BC00B05BE3 /* JackArgParser.h */; };
4BF2841A0F31B4BC00B05BE3 /* JackArgParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF284160F31B4BC00B05BE3 /* JackArgParser.cpp */; };
4BF2841B0F31B4BC00B05BE3 /* JackArgParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF284170F31B4BC00B05BE3 /* JackArgParser.h */; };
4BF339160F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */; };
4BF339170F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF339150F8B86DC0080FB5B /* JackCoreMidiDriver.cpp */; };
4BF339180F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */; };
4BF339190F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF339150F8B86DC0080FB5B /* JackCoreMidiDriver.cpp */; };
4BF3391A0F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */; };
4BF3391B0F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF339150F8B86DC0080FB5B /* JackCoreMidiDriver.cpp */; };
4BF339210F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF3391F0F8B873E0080FB5B /* JackMidiDriver.cpp */; };
4BF339220F8B873E0080FB5B /* JackMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339200F8B873E0080FB5B /* JackMidiDriver.h */; };
4BF339230F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF3391F0F8B873E0080FB5B /* JackMidiDriver.cpp */; };
4BF339240F8B873E0080FB5B /* JackMidiDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF339200F8B873E0080FB5B /* JackMidiDriver.h */; };
4BF4BAB10E3480AB00403CDF /* JackAudioAdapterFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF4BAB00E3480AB00403CDF /* JackAudioAdapterFactory.cpp */; };
4BF520530CB8D0E80037470E /* timestamps.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BF520520CB8D0E80037470E /* timestamps.c */; };
4BF520540CB8D0E80037470E /* timestamps.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BF520520CB8D0E80037470E /* timestamps.c */; };
@@ -963,6 +974,13 @@
remoteGlobalIDString = 4BE99D260AD7A04800C59091;
remoteInfo = "jack_cpu Universal";
};
4BF339270F8B87800080FB5B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 4BF339020F8B864B0080FB5B;
remoteInfo = jack_coremidi;
};
4BFA83310DF6AB540087B4E1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
@@ -1345,6 +1363,11 @@
4BECB2F40F4451C10091B70A /* JackProcessSync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackProcessSync.h; path = ../posix/JackProcessSync.h; sourceTree = SOURCE_ROOT; };
4BF284160F31B4BC00B05BE3 /* JackArgParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackArgParser.cpp; path = ../common/JackArgParser.cpp; sourceTree = SOURCE_ROOT; };
4BF284170F31B4BC00B05BE3 /* JackArgParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackArgParser.h; path = ../common/JackArgParser.h; sourceTree = SOURCE_ROOT; };
4BF3390C0F8B864B0080FB5B /* jack_coremidi.so */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = jack_coremidi.so; sourceTree = BUILT_PRODUCTS_DIR; };
4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackCoreMidiDriver.h; path = coremidi/JackCoreMidiDriver.h; sourceTree = SOURCE_ROOT; };
4BF339150F8B86DC0080FB5B /* JackCoreMidiDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackCoreMidiDriver.cpp; path = coremidi/JackCoreMidiDriver.cpp; sourceTree = SOURCE_ROOT; };
4BF3391F0F8B873E0080FB5B /* JackMidiDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackMidiDriver.cpp; path = ../common/JackMidiDriver.cpp; sourceTree = SOURCE_ROOT; };
4BF339200F8B873E0080FB5B /* JackMidiDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackMidiDriver.h; path = ../common/JackMidiDriver.h; sourceTree = SOURCE_ROOT; };
4BF3937C0626BF3600CC67FA /* JackMacLibClientRPC.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JackMacLibClientRPC.cpp; sourceTree = SOURCE_ROOT; };
4BF4BAB00E3480AB00403CDF /* JackAudioAdapterFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackAudioAdapterFactory.cpp; path = ../common/JackAudioAdapterFactory.cpp; sourceTree = SOURCE_ROOT; };
4BF520520CB8D0E80037470E /* timestamps.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = timestamps.c; path = ../common/timestamps.c; sourceTree = SOURCE_ROOT; };
@@ -1899,6 +1922,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4BF339070F8B864B0080FB5B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
4BFA5E910DEC4D9C00FA4CDB /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -2094,6 +2124,7 @@
4BFA82CF0DF6A9E40087B4E1 /* jack_impulse_grabber */,
4B19B3000E23620F00DD4A82 /* audioadapter.so */,
4B5E08D50E5B66EE00BEE4E0 /* netadapter.so */,
4BF3390C0F8B864B0080FB5B /* jack_coremidi.so */,
);
name = Products;
sourceTree = "<group>";
@@ -2389,7 +2420,6 @@
4BA550F605E241B800569492 /* Driver */ = {
isa = PBXGroup;
children = (
4B19B3010E23629800DD4A82 /* Adapter */,
4B869B3D08C8D21C001CF041 /* driver_interface.h */,
4B869B4208C8D22F001CF041 /* JackDriverLoader.h */,
4B869D7F08C9CB00001CF041 /* JackDriverLoader.cpp */,
@@ -2399,6 +2429,8 @@
4BF70ACA0908EE95008B75AD /* JackLoopbackDriver.cpp */,
4BC3988A08B3CF6C00B6F371 /* JackDummyDriver.h */,
4BC3988908B3CF6C00B6F371 /* JackDummyDriver.cpp */,
4BF3390D0F8B86AF0080FB5B /* MIDI */,
4B19B3010E23629800DD4A82 /* Adapter */,
BA222AEA0DC88379001A17F4 /* Net */,
4BD56D8707968982006D44F9 /* Threaded */,
4BD56D8607968979006D44F9 /* Audio */,
@@ -2539,6 +2571,17 @@
name = Threaded;
sourceTree = "<group>";
};
4BF3390D0F8B86AF0080FB5B /* MIDI */ = {
isa = PBXGroup;
children = (
4BF3391F0F8B873E0080FB5B /* JackMidiDriver.cpp */,
4BF339200F8B873E0080FB5B /* JackMidiDriver.h */,
4BF339140F8B86DC0080FB5B /* JackCoreMidiDriver.h */,
4BF339150F8B86DC0080FB5B /* JackCoreMidiDriver.cpp */,
);
name = MIDI;
sourceTree = "<group>";
};
4BFB299808AF451200D450D4 /* Mach */ = {
isa = PBXGroup;
children = (
@@ -2684,6 +2727,7 @@
4B4F9C910DC20C0400706CB0 /* JackMessageBuffer.h in Headers */,
4B93F19E0E87998400E4ECCD /* JackPosixThread.h in Headers */,
4BECB2FA0F4451C10091B70A /* JackProcessSync.h in Headers */,
4BF339160F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2748,6 +2792,8 @@
4B93F19A0E87992200E4ECCD /* JackPosixThread.h in Headers */,
4BBAE4120F42FA6100B8BD3F /* JackEngineProfiling.h in Headers */,
4BECB2FC0F4451C10091B70A /* JackProcessSync.h in Headers */,
4BF339180F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */,
4BF339220F8B873E0080FB5B /* JackMidiDriver.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3116,6 +3162,7 @@
4BF2841B0F31B4BC00B05BE3 /* JackArgParser.h in Headers */,
4BBAE4100F42FA6100B8BD3F /* JackEngineProfiling.h in Headers */,
4BECB2F60F4451C10091B70A /* JackProcessSync.h in Headers */,
4BF339240F8B873E0080FB5B /* JackMidiDriver.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3270,6 +3317,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4BF339030F8B864B0080FB5B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
4BF3391A0F8B86DC0080FB5B /* JackCoreMidiDriver.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4BFA5E8C0DEC4D9C00FA4CDB /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -4529,6 +4584,23 @@
productReference = 4BE99D300AD7A04800C59091 /* jack_cpu */;
productType = "com.apple.product-type.tool";
};
4BF339020F8B864B0080FB5B /* jack_coremidi Universal */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4BF339080F8B864B0080FB5B /* Build configuration list for PBXNativeTarget "jack_coremidi Universal" */;
buildPhases = (
4BF339030F8B864B0080FB5B /* Headers */,
4BF339050F8B864B0080FB5B /* Sources */,
4BF339070F8B864B0080FB5B /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "jack_coremidi Universal";
productName = jack_coreaudio;
productReference = 4BF3390C0F8B864B0080FB5B /* jack_coremidi.so */;
productType = "com.apple.product-type.library.dynamic";
};
4BFA5E8B0DEC4D9C00FA4CDB /* testMutex Universal */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4BFA5E940DEC4D9C00FA4CDB /* Build configuration list for PBXNativeTarget "testMutex Universal" */;
@@ -4763,6 +4835,7 @@
4B699D7F097D421700A18468 /* synchroServerClient Universal */,
4B699D97097D421700A18468 /* jack_coreaudio Universal */,
4B978DB10A31CF4A009E2DD1 /* jack_portaudio Universal */,
4BF339020F8B864B0080FB5B /* jack_coremidi Universal */,
4B699DA6097D421700A18468 /* jack_dummy Universal */,
BA222AC50DC88132001A17F4 /* jack_net Universal */,
4BD623ED0CBCF0F000DE782F /* inprocess */,
@@ -5343,6 +5416,7 @@
4B93F19D0E87998400E4ECCD /* JackPosixThread.cpp in Sources */,
4B93F1C00E87A35400E4ECCD /* JackMachTime.c in Sources */,
4BECB2F90F4451C10091B70A /* JackProcessSync.cpp in Sources */,
4BF339170F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -5399,6 +5473,8 @@
4B93F22B0E87A72500E4ECCD /* JackMachTime.c in Sources */,
4BBAE4130F42FA6100B8BD3F /* JackEngineProfiling.cpp in Sources */,
4BECB2FB0F4451C10091B70A /* JackProcessSync.cpp in Sources */,
4BF339190F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */,
4BF339210F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -5778,6 +5854,7 @@
4BF2841A0F31B4BC00B05BE3 /* JackArgParser.cpp in Sources */,
4BBAE4110F42FA6100B8BD3F /* JackEngineProfiling.cpp in Sources */,
4BECB2F50F4451C10091B70A /* JackProcessSync.cpp in Sources */,
4BF339230F8B873E0080FB5B /* JackMidiDriver.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -5949,6 +6026,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4BF339050F8B864B0080FB5B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4BF3391B0F8B86DC0080FB5B /* JackCoreMidiDriver.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4BFA5E8D0DEC4D9C00FA4CDB /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -6293,6 +6378,11 @@
target = 4BE99D260AD7A04800C59091 /* jack_cpu Universal */;
targetProxy = 4BE99D620AD7A19100C59091 /* PBXContainerItemProxy */;
};
4BF339280F8B87800080FB5B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 4BF339020F8B864B0080FB5B /* jack_coremidi Universal */;
targetProxy = 4BF339270F8B87800080FB5B /* PBXContainerItemProxy */;
};
4BFA83320DF6AB540087B4E1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 4BFA82820DF6A9E40087B4E1 /* jack_evmon 64 bits */;
@@ -13852,6 +13942,153 @@
};
name = Default;
};
4BF339090F8B864B0080FB5B /* Development */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
COPY_PHASE_STRIP = NO;
DEBUGGING_SYMBOLS = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
FRAMEWORK_SEARCH_PATHS = "";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_MODEL_TUNING = G4;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "";
HEADER_SEARCH_PATHS = (
.,
../common/jack,
../posix,
../common,
);
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
"-framework",
Jackservermp,
"-framework",
CoreMIDI,
"-framework",
CoreServices,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = jack_coremidi;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
ZERO_LINK = YES;
};
name = Development;
};
4BF3390A0F8B864B0080FB5B /* Deployment */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
COPY_PHASE_STRIP = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
FRAMEWORK_SEARCH_PATHS = "";
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G4;
GCC_PREPROCESSOR_DEFINITIONS = "";
HEADER_SEARCH_PATHS = (
.,
../common/jack,
../posix,
../common,
);
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
MACOSX_DEPLOYMENT_TARGET = 10.4;
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
"-framework",
Jackservermp,
"-framework",
CoreMIDI,
"-framework",
CoreServices,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = jack_coremidi;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
ZERO_LINK = NO;
};
name = Deployment;
};
4BF3390B0F8B864B0080FB5B /* Default */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
i386,
ppc,
);
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
EXECUTABLE_EXTENSION = so;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G4;
GCC_PREPROCESSOR_DEFINITIONS = "";
HEADER_SEARCH_PATHS = ../common;
INSTALL_PATH = /usr/local/lib;
LIBRARY_STYLE = DYNAMIC;
MACH_O_TYPE = mh_dylib;
OTHER_CFLAGS = "";
OTHER_CPLUSPLUSFLAGS = "-DMACH_RPC_MACH_SEMA";
OTHER_LDFLAGS = (
"-framework",
Jackdmp,
"-framework",
AudioToolBox,
"-framework",
CoreAudio,
"-framework",
CoreServices,
"-framework",
AudioUnit,
);
OTHER_REZFLAGS = "";
PREBINDING = NO;
PRODUCT_NAME = jack_coreaudio;
SDKROOT = "";
SECTORDER_FLAGS = "";
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
"-Wno-unknown-pragmas",
);
};
name = Default;
};
4BFA5E950DEC4D9C00FA4CDB /* Development */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -15635,6 +15872,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
4BF339080F8B864B0080FB5B /* Build configuration list for PBXNativeTarget "jack_coremidi Universal" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4BF339090F8B864B0080FB5B /* Development */,
4BF3390A0F8B864B0080FB5B /* Deployment */,
4BF3390B0F8B864B0080FB5B /* Default */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Default;
};
4BFA5E940DEC4D9C00FA4CDB /* Build configuration list for PBXNativeTarget "testMutex Universal" */ = {
isa = XCConfigurationList;
buildConfigurations = (


+ 426
- 0
macosx/coremidi/JackCoreMidiDriver.cpp View File

@@ -0,0 +1,426 @@
/*
Copyright (C) 2009 Grame

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

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

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

*/

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

#include <mach/mach_time.h>
#include <assert.h>
#include <iostream>
#include <sstream>
#include <string>

namespace Jack
{

static MIDITimeStamp MIDIGetCurrentHostTime()
{
return mach_absolute_time();
}

void JackCoreMidiDriver::ReadProcAux(const MIDIPacketList *pktlist, jack_ringbuffer_t* ringbuffer)
{
// Write the number of packets
size_t size = jack_ringbuffer_write(ringbuffer, (char*)&pktlist->numPackets, sizeof(UInt32));
if (size != sizeof(UInt32)) {
jack_error("ReadProc : ring buffer is full, skip events...");
return;
}
for (unsigned int i = 0; i < pktlist->numPackets; ++i) {
MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
// TODO : use timestamp
// Write length of each packet first
size = jack_ringbuffer_write(ringbuffer, (char*)&packet->length, sizeof(UInt16));
if (size != sizeof(UInt16)) {
jack_error("ReadProc : ring buffer is full, skip events...");
return;
}
// Write event actual data
size = jack_ringbuffer_write(ringbuffer, (char*)packet->data, packet->length);
if (size != packet->length) {
jack_error("ReadProc : ring buffer is full, skip events...");
return;
}
packet = MIDIPacketNext(packet);
}
}

void JackCoreMidiDriver::ReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
{
jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)connRefCon;
ReadProcAux(pktlist, ringbuffer);
}

void JackCoreMidiDriver::ReadVirtualProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
{
jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)refCon;
ReadProcAux(pktlist, ringbuffer);
}

void JackCoreMidiDriver::NotifyProc(const MIDINotification *message, void *refCon)
{
jack_info("NotifyProc %d", message->messageID);
}

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

err = MIDIOutputPortCreate(fMidiClient, CFSTR("Output port"), &fOutputPort);
if (!fOutputPort) {
jack_error("Cannot open CoreMidi out port\n");
goto error;
}
fMidiDestination = new MIDIEndpointRef[inchannels + fRealCaptureChannels];
assert(fMidiDestination);
// 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;
}
}
// Real input
for (int i = 0; i < fRealCaptureChannels; i++) {
fMidiDestination[i + inchannels] = MIDIGetSource(i);
MIDIPortConnectSource(fInputPort, fMidiDestination[i + inchannels], fRingBuffer[i + inchannels]);
}
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;
}
}
// Real output
for (int i = 0; i < fRealPlaybackChannels; i++) {
fMidiSource[i + outchannels] = MIDIGetDestination(i);
}
return 0;
error:
Close();
return -1;
}
int JackCoreMidiDriver::Close()
{
if (fInputPort)
MIDIPortDispose(fInputPort);
if (fOutputPort)
MIDIPortDispose(fOutputPort);
// Only dispose "virtual" endpoints
for (int i = 0; i < fCaptureChannels - fRealCaptureChannels; i++) {
if (fMidiDestination)
MIDIEndpointDispose(fMidiDestination[i]);
}
delete[] fMidiDestination;
// Only dispose "virtual" endpoints
for (int i = 0; i < fPlaybackChannels - fRealPlaybackChannels; i++) {
if (fMidiSource[i])
MIDIEndpointDispose(fMidiSource[i]);
}
delete[] fMidiSource;
if (fMidiClient)
MIDIClientDispose(fMidiClient);
return 0;
}

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];
unsigned long port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
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);
}
snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, (JackPortFlags)port_flags, 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);
}

port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;

for (i = 0; i < fPlaybackChannels; i++) {
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);
}
snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) {
jack_error("driver: cannot register port for %s", name);
return -1;
}
port = fGraphManager->GetPort(port_index);
port->SetAlias(alias);
fPlaybackPortList[i] = port_index;
jack_log("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) {
// Get JACK port
JackMidiBuffer* midi_buffer = GetInputBuffer(chan);
if (jack_ringbuffer_read_space(fRingBuffer[chan]) == 0) {
// Reset buffer
midi_buffer->Reset(midi_buffer->nframes);
} else {
while (jack_ringbuffer_read_space(fRingBuffer[chan]) > 0) {
// Read event number
int ev_count = 0;
jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int));
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);
}
}
}
} else {
// Consume ring buffer
jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan]));
}
}
return 0;
}

int JackCoreMidiDriver::Write()
{
MIDIPacketList* pktlist = (MIDIPacketList*)fMIDIBuffer;
for (int chan = 0; chan < fPlaybackChannels; chan++) {
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) {
MIDIPacket* packet = MIDIPacketListInit(pktlist);
JackMidiBuffer* midi_buffer = GetOutputBuffer(chan);
// TODO : use timestamp
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));
}
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");
}
}
}
}
return 0;
}

} // end of namespace

#ifdef __cplusplus
extern "C"
{
#endif

SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
{
jack_driver_desc_t * desc;
unsigned int i;

desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
strcpy(desc->name, "coremidi"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
strcpy(desc->desc, "Apple CoreMIDI API based MIDI backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1

desc->nparams = 2;
desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
i = 0;
strcpy(desc->params[i].name, "inchannels");
desc->params[i].character = 'i';
desc->params[i].type = JackDriverParamInt;
desc->params[i].value.ui = 0;
strcpy(desc->params[i].short_desc, "CoreMIDI virtual bus");
strcpy(desc->params[i].long_desc, desc->params[i].short_desc);

i++;
strcpy(desc->params[i].name, "outchannels");
desc->params[i].character = 'o';
desc->params[i].type = JackDriverParamInt;
desc->params[i].value.ui = 0;
strcpy(desc->params[i].short_desc, "CoreMIDI virtual bus");
strcpy(desc->params[i].long_desc, desc->params[i].short_desc);

return desc;
}

SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
{
const JSList * node;
const jack_driver_param_t * param;
int virtual_in = 0;
int virtual_out = 0;

for (node = params; node; node = jack_slist_next (node)) {
param = (const jack_driver_param_t *) node->data;

switch (param->character) {

case 'i':
virtual_in = param->value.ui;
break;

case 'o':
virtual_out = param->value.ui;
break;
}
}
Jack::JackDriverClientInterface* driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table);
if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) {
return driver;
} else {
delete driver;
return NULL;
}
}

#ifdef __cplusplus
}
#endif


+ 80
- 0
macosx/coremidi/JackCoreMidiDriver.h View File

@@ -0,0 +1,80 @@
/*
Copyright (C) 2009 Grame

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

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

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

*/

#ifndef __JackCoreMidiDriver__
#define __JackCoreMidiDriver__

#include <CoreMIDI/CoreMIDI.h>
#include "JackMidiDriver.h"
#include "JackTime.h"

namespace Jack
{

/*!
\brief The CoreMidi driver.
*/

class JackCoreMidiDriver : public JackMidiDriver
{

private:

MIDIClientRef fMidiClient;
MIDIPortRef fInputPort;
MIDIPortRef fOutputPort;
MIDIEndpointRef* fMidiDestination;
MIDIEndpointRef* fMidiSource;
char fMIDIBuffer[BUFFER_SIZE_MAX * sizeof(float)];
int fRealCaptureChannels;
int fRealPlaybackChannels;
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);
public:

JackCoreMidiDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);
virtual ~JackCoreMidiDriver();

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

int Read();
int Write();

};

} // end of namespace

#endif

+ 17
- 0
macosx/wscript View File

@@ -30,6 +30,21 @@ def create_jack_audio_driver_obj(bld, target, sources, uselib = None):
driver.uselib = uselib
return driver

def create_jack_midi_driver_obj(bld, target, sources, uselib = None):
driver = bld.new_task_gen('cxx', 'shlib')
driver.features.append('cc')
driver.env['shlib_PATTERN'] = 'jack_%s.so'
driver.defines = 'HAVE_CONFIG_H'
driver.includes = ['.', '../macosx', '../posix', '../common', '../common/jack']
driver.target = target
driver.source = sources
driver.install_path = '${ADDON_DIR}/'
driver.uselib_local = 'serverlib'
driver.env.append_value("LINKFLAGS", "-framework CoreMIDI -framework CoreServices -framework AudioUnit")
if uselib:
driver.uselib = uselib
return driver

def build(bld):
jackd = bld.new_task_gen('cxx', 'program')
jackd.includes = ['.', '../macosx', '../posix', '../common', '../common/jack']
@@ -43,6 +58,8 @@ def build(bld):
create_jack_driver_obj(bld, 'dummy', '../common/JackDummyDriver.cpp')

create_jack_audio_driver_obj(bld, 'coreaudio', 'coreaudio/JackCoreAudioDriver.cpp')

create_jack_midi_driver_obj(bld, 'coremidi', 'coremidi/JackCoreMidiDriver.cpp')
portaudio_src = [
'../windows/JackPortAudioDriver.cpp',


+ 121
- 0
windows/jack_winmme.cbp View File

@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="jack_winmme" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Win32 Release">
<Option output="Release\bin\jack\jack_winmme" prefix_auto="1" extension_auto="1" />
<Option object_output="Release" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add option="-Wall" />
<Add option="-DWIN32" />
<Add option="-DNDEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DSERVER_SIDE" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
<Add directory="winmme" />
</Compiler>
<Linker>
<Add directory="..\windows" />
<Add directory="Release\bin" />
</Linker>
</Target>
<Target title="Win32 Debug">
<Option output="Debug\bin\jack\jack_winmme" prefix_auto="1" extension_auto="1" />
<Option object_output="Debug" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-W" />
<Add option="-g" />
<Add option="-DWIN32" />
<Add option="-D_DEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DSERVER_SIDE" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
<Add directory="winmme" />
</Compiler>
<Linker>
<Add directory="Debug\bin" />
<Add directory="..\windows" />
</Linker>
</Target>
<Target title="Win32 Profiling">
<Option output="Release\bin\jack\jack_winmme" prefix_auto="1" extension_auto="1" />
<Option object_output="Release" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add option="-Wall" />
<Add option="-DWIN32" />
<Add option="-DNDEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DJACK_MONITOR" />
<Add option="-DSERVER_SIDE" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
<Add directory="winmme" />
</Compiler>
<Linker>
<Add directory="Release\bin" />
<Add directory="..\windows" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
</Compiler>
<Linker>
<Add library="kernel32" />
<Add library="user32" />
<Add library="gdi32" />
<Add library="winspool" />
<Add library="comdlg32" />
<Add library="advapi32" />
<Add library="shell32" />
<Add library="ole32" />
<Add library="oleaut32" />
<Add library="uuid" />
<Add library="odbc32" />
<Add library="odbccp32" />
<Add library="libjackserver" />
<Add library="winmm" />
</Linker>
<Unit filename="jackwinmme.rc">
<Option compilerVar="WINDRES" />
</Unit>
<Unit filename="winmme\JackWinMMEDriver.cpp" />
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
<AutoVersioning>
<Scheme minor_max="10" build_max="0" rev_max="0" rev_rand_max="10" build_times_to_increment_minor="100" />
<Settings autoincrement="1" date_declarations="1" do_auto_increment="0" ask_to_increment="0" language="C++" svn="0" svn_directory="" header_path="version.h" />
<Changes_Log show_changes_editor="0" app_title="released version %M.%m.%b of %p" changeslog_path="ChangesLog.txt" />
</AutoVersioning>
</Extensions>
</Project>
</CodeBlocks_project_file>

+ 2
- 1
windows/jackd.workspace View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_workspace_file>
<Workspace title="jack">
<Project filename="libjackserver.cbp" active="1" />
<Project filename="libjackserver.cbp" />
<Project filename="jackd.cbp">
<Depends filename="libjackserver.cbp" />
</Project>
@@ -46,5 +46,6 @@
<Project filename="multiple_metro.cbp">
<Depends filename="libjack.cbp" />
</Project>
<Project filename="jack_winmme.cbp" active="1" />
</Workspace>
</CodeBlocks_workspace_file>

+ 41
- 0
windows/jackwinmme.rc View File

@@ -0,0 +1,41 @@
// Generated by ResEdit 1.4.3
// Copyright (C) 2006-2008
// http://www.resedit.net
#include "resource.h"
#include "afxres.h"
//
// Version Information resources
//
LANGUAGE LANG_FRENCH, SUBLANG_DEFAULT
1 VERSIONINFO
FILEVERSION 1,9,3,0
PRODUCTVERSION 1,9,3,0
FILEOS VOS_UNKNOWN
FILETYPE VFT_DLL
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040c04b0"
BEGIN
VALUE "Comments", "\0"
VALUE "CompanyName", "Grame\0"
VALUE "FileDescription", "Jackmp WinMMEo Driver for Windows\0"
VALUE "FileVersion", "1, 9, 3, 0\0"
VALUE "InternalName", "jack_portaudio\0"
VALUE "LegalCopyright", "Copyright Grame © 2006-2009\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "jack_winmme.dll\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "jack_winmme\0"
VALUE "ProductVersion", "1, 9, 3, 0\0"
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 1036, 1200
END
END

+ 200
- 199
windows/libjackserver.cbp View File

@@ -1,199 +1,200 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="libjackserver" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Win32 Release">
<Option output="Release\bin\libjackserver" prefix_auto="1" extension_auto="1" />
<Option object_output="Release" />
<Option type="3" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-O2" />
<Add option="-Wall" />
<Add option="-DWIN32" />
<Add option="-DNDEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DLIBJACKDMP_EXPORTS" />
<Add option="-DREGEX_MALLOC" />
<Add option="-DSTDC_HEADERS" />
<Add option="-DSERVER_SIDE" />
<Add option="-D__SMP__" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
</Compiler>
<Linker>
<Add directory="Release\bin" />
</Linker>
</Target>
<Target title="Win32 Debug">
<Option output="Debug\bin\libjackserver" prefix_auto="1" extension_auto="1" />
<Option object_output="Debug" />
<Option type="3" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-Wall" />
<Add option="-g" />
<Add option="-DWIN32" />
<Add option="-D_DEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DLIBJACKDMP_EXPORTS" />
<Add option="-DREGEX_MALLOC" />
<Add option="-DSTDC_HEADERS" />
<Add option="-DSERVER_SIDE" />
<Add option="-D__SMP__" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
</Compiler>
<Linker>
<Add directory="Debug\bin" />
</Linker>
</Target>
<Target title="Win32 Profiling">
<Option output="Release\bin\libjackserver" prefix_auto="1" extension_auto="1" />
<Option object_output="Release" />
<Option type="3" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-O2" />
<Add option="-Wall" />
<Add option="-DWIN32" />
<Add option="-DNDEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DLIBJACKDMP_EXPORTS" />
<Add option="-DREGEX_MALLOC" />
<Add option="-DSTDC_HEADERS" />
<Add option="-DSERVER_SIDE" />
<Add option="-D__SMP__" />
<Add option="-DJACK_MONITOR" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
</Compiler>
<Linker>
<Add directory="Release\bin" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add directory="." />
<Add directory="..\common" />
<Add directory="..\common\jack" />
</Compiler>
<Linker>
<Add library="kernel32" />
<Add library="user32" />
<Add library="gdi32" />
<Add library="winspool" />
<Add library="comdlg32" />
<Add library="advapi32" />
<Add library="shell32" />
<Add library="ole32" />
<Add library="oleaut32" />
<Add library="uuid" />
<Add library="odbc32" />
<Add library="odbccp32" />
<Add library="ws2_32" />
</Linker>
<Unit filename="..\common\JackAPI.cpp" />
<Unit filename="..\common\JackActivationCount.cpp" />
<Unit filename="..\common\JackArgParser.cpp" />
<Unit filename="..\common\JackAudioDriver.cpp" />
<Unit filename="..\common\JackAudioPort.cpp" />
<Unit filename="..\common\JackClient.cpp" />
<Unit filename="..\common\JackConnectionManager.cpp" />
<Unit filename="..\common\JackControlAPI.cpp" />
<Unit filename="..\common\JackDriver.cpp" />
<Unit filename="..\common\JackDriverLoader.cpp" />
<Unit filename="..\common\JackEngine.cpp" />
<Unit filename="..\common\JackEngineControl.cpp" />
<Unit filename="..\common\JackEngineProfiling.cpp">
<Option target="Win32 Profiling" />
</Unit>
<Unit filename="..\common\JackError.cpp" />
<Unit filename="..\common\JackExternalClient.cpp" />
<Unit filename="..\common\JackFrameTimer.cpp" />
<Unit filename="..\common\JackFreewheelDriver.cpp" />
<Unit filename="..\common\JackGlobals.cpp" />
<Unit filename="..\common\JackGraphManager.cpp" />
<Unit filename="..\common\JackInternalClient.cpp" />
<Unit filename="..\common\JackLoopbackDriver.cpp" />
<Unit filename="..\common\JackMessageBuffer.cpp" />
<Unit filename="..\common\JackMidiAPI.cpp" />
<Unit filename="..\common\JackMidiPort.cpp" />
<Unit filename="..\common\JackNetInterface.cpp" />
<Unit filename="..\common\JackNetTool.cpp" />
<Unit filename="..\common\JackPort.cpp" />
<Unit filename="..\common\JackPortType.cpp" />
<Unit filename="..\common\JackRestartThreadedDriver.cpp" />
<Unit filename="..\common\JackServer.cpp" />
<Unit filename="..\common\JackServerAPI.cpp" />
<Unit filename="..\common\JackServerGlobals.cpp" />
<Unit filename="..\common\JackShmMem.cpp" />
<Unit filename="..\common\JackThreadedDriver.cpp" />
<Unit filename="..\common\JackTools.cpp" />
<Unit filename="..\common\JackTransportEngine.cpp" />
<Unit filename="..\common\JackWaitThreadedDriver.cpp" />
<Unit filename="..\common\ringbuffer.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\common\shm.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="JackNetWinSocket.cpp" />
<Unit filename="JackWinNamedPipe.cpp" />
<Unit filename="JackWinNamedPipeClientChannel.cpp" />
<Unit filename="JackWinNamedPipeNotifyChannel.cpp" />
<Unit filename="JackWinNamedPipeServerChannel.cpp" />
<Unit filename="JackWinNamedPipeServerNotifyChannel.cpp" />
<Unit filename="JackWinProcessSync.cpp" />
<Unit filename="JackWinSemaphore.cpp" />
<Unit filename="JackWinThread.cpp" />
<Unit filename="JackWinTime.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="getopt.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="getopt1.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="libjackserver.rc">
<Option compilerVar="WINDRES" />
</Unit>
<Unit filename="regex.c">
<Option compilerVar="CC" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
<AutoVersioning>
<Scheme minor_max="10" build_max="0" rev_max="0" rev_rand_max="10" build_times_to_increment_minor="100" />
<Settings autoincrement="0" date_declarations="0" do_auto_increment="0" ask_to_increment="0" language="C++" svn="0" svn_directory="" header_path="version.h" />
<Changes_Log show_changes_editor="0" app_title="released version %M.%m.%b of %p" changeslog_path="ChangesLog.txt" />
</AutoVersioning>
</Extensions>
</Project>
</CodeBlocks_project_file>
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="libjackserver" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Win32 Release">
<Option output="Release\bin\libjackserver" prefix_auto="1" extension_auto="1" />
<Option object_output="Release" />
<Option type="3" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-O2" />
<Add option="-Wall" />
<Add option="-DWIN32" />
<Add option="-DNDEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DLIBJACKDMP_EXPORTS" />
<Add option="-DREGEX_MALLOC" />
<Add option="-DSTDC_HEADERS" />
<Add option="-DSERVER_SIDE" />
<Add option="-D__SMP__" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
</Compiler>
<Linker>
<Add directory="Release\bin" />
</Linker>
</Target>
<Target title="Win32 Debug">
<Option output="Debug\bin\libjackserver" prefix_auto="1" extension_auto="1" />
<Option object_output="Debug" />
<Option type="3" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-Wall" />
<Add option="-g" />
<Add option="-DWIN32" />
<Add option="-D_DEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DLIBJACKDMP_EXPORTS" />
<Add option="-DREGEX_MALLOC" />
<Add option="-DSTDC_HEADERS" />
<Add option="-DSERVER_SIDE" />
<Add option="-D__SMP__" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
</Compiler>
<Linker>
<Add directory="Debug\bin" />
</Linker>
</Target>
<Target title="Win32 Profiling">
<Option output="Release\bin\libjackserver" prefix_auto="1" extension_auto="1" />
<Option object_output="Release" />
<Option type="3" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-O2" />
<Add option="-Wall" />
<Add option="-DWIN32" />
<Add option="-DNDEBUG" />
<Add option="-D_WINDOWS" />
<Add option="-D_MBCS" />
<Add option="-D_USRDLL" />
<Add option="-DLIBJACKDMP_EXPORTS" />
<Add option="-DREGEX_MALLOC" />
<Add option="-DSTDC_HEADERS" />
<Add option="-DSERVER_SIDE" />
<Add option="-D__SMP__" />
<Add option="-DJACK_MONITOR" />
<Add directory="." />
<Add directory="..\windows" />
<Add directory="..\common\jack" />
<Add directory="..\common" />
</Compiler>
<Linker>
<Add directory="Release\bin" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add directory="." />
<Add directory="..\common" />
<Add directory="..\common\jack" />
</Compiler>
<Linker>
<Add library="kernel32" />
<Add library="user32" />
<Add library="gdi32" />
<Add library="winspool" />
<Add library="comdlg32" />
<Add library="advapi32" />
<Add library="shell32" />
<Add library="ole32" />
<Add library="oleaut32" />
<Add library="uuid" />
<Add library="odbc32" />
<Add library="odbccp32" />
<Add library="ws2_32" />
</Linker>
<Unit filename="..\common\JackAPI.cpp" />
<Unit filename="..\common\JackActivationCount.cpp" />
<Unit filename="..\common\JackArgParser.cpp" />
<Unit filename="..\common\JackAudioDriver.cpp" />
<Unit filename="..\common\JackAudioPort.cpp" />
<Unit filename="..\common\JackClient.cpp" />
<Unit filename="..\common\JackConnectionManager.cpp" />
<Unit filename="..\common\JackControlAPI.cpp" />
<Unit filename="..\common\JackDriver.cpp" />
<Unit filename="..\common\JackDriverLoader.cpp" />
<Unit filename="..\common\JackEngine.cpp" />
<Unit filename="..\common\JackEngineControl.cpp" />
<Unit filename="..\common\JackEngineProfiling.cpp">
<Option target="Win32 Profiling" />
</Unit>
<Unit filename="..\common\JackError.cpp" />
<Unit filename="..\common\JackExternalClient.cpp" />
<Unit filename="..\common\JackFrameTimer.cpp" />
<Unit filename="..\common\JackFreewheelDriver.cpp" />
<Unit filename="..\common\JackGlobals.cpp" />
<Unit filename="..\common\JackGraphManager.cpp" />
<Unit filename="..\common\JackInternalClient.cpp" />
<Unit filename="..\common\JackLoopbackDriver.cpp" />
<Unit filename="..\common\JackMessageBuffer.cpp" />
<Unit filename="..\common\JackMidiAPI.cpp" />
<Unit filename="..\common\JackMidiDriver.cpp" />
<Unit filename="..\common\JackMidiPort.cpp" />
<Unit filename="..\common\JackNetInterface.cpp" />
<Unit filename="..\common\JackNetTool.cpp" />
<Unit filename="..\common\JackPort.cpp" />
<Unit filename="..\common\JackPortType.cpp" />
<Unit filename="..\common\JackRestartThreadedDriver.cpp" />
<Unit filename="..\common\JackServer.cpp" />
<Unit filename="..\common\JackServerAPI.cpp" />
<Unit filename="..\common\JackServerGlobals.cpp" />
<Unit filename="..\common\JackShmMem.cpp" />
<Unit filename="..\common\JackThreadedDriver.cpp" />
<Unit filename="..\common\JackTools.cpp" />
<Unit filename="..\common\JackTransportEngine.cpp" />
<Unit filename="..\common\JackWaitThreadedDriver.cpp" />
<Unit filename="..\common\ringbuffer.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\common\shm.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="JackNetWinSocket.cpp" />
<Unit filename="JackWinNamedPipe.cpp" />
<Unit filename="JackWinNamedPipeClientChannel.cpp" />
<Unit filename="JackWinNamedPipeNotifyChannel.cpp" />
<Unit filename="JackWinNamedPipeServerChannel.cpp" />
<Unit filename="JackWinNamedPipeServerNotifyChannel.cpp" />
<Unit filename="JackWinProcessSync.cpp" />
<Unit filename="JackWinSemaphore.cpp" />
<Unit filename="JackWinThread.cpp" />
<Unit filename="JackWinTime.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="getopt.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="getopt1.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="libjackserver.rc">
<Option compilerVar="WINDRES" />
</Unit>
<Unit filename="regex.c">
<Option compilerVar="CC" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
<AutoVersioning>
<Scheme minor_max="10" build_max="0" rev_max="0" rev_rand_max="10" build_times_to_increment_minor="100" />
<Settings autoincrement="0" date_declarations="0" do_auto_increment="0" ask_to_increment="0" language="C++" svn="0" svn_directory="" header_path="version.h" />
<Changes_Log show_changes_editor="0" app_title="released version %M.%m.%b of %p" changeslog_path="ChangesLog.txt" />
</AutoVersioning>
</Extensions>
</Project>
</CodeBlocks_project_file>

+ 501
- 0
windows/winmme/JackWinMMEDriver.cpp View File

@@ -0,0 +1,501 @@
/*
Copyright (C) 2009 Grame
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "JackWinMMEDriver.h"
#include "JackGraphManager.h"
#include "JackEngineControl.h"
#include "JackDriverLoader.h"
#include <assert.h>
#include <iostream>
#include <sstream>
#include <string>
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
namespace Jack
{
static bool InitHeaders(MidiSlot* slot)
{
slot->fHeader = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, sizeof(MIDIHDR) + kBuffSize);
if (!slot->fHeader)
return false;
slot->fHeader->lpData = (LPSTR)((LPBYTE)slot->fHeader + sizeof(MIDIHDR));
slot->fHeader->dwBufferLength = kBuffSize;
slot->fHeader->dwFlags = 0;
slot->fHeader->dwUser = 0;
slot->fHeader->lpNext = 0;
slot->fHeader->dwBytesRecorded = 0;
return true;
}
void CALLBACK JackWinMMEDriver::MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD userData, DWORD dwParam1, DWORD dwParam2)
{
jack_ringbuffer_t* ringbuffer = (jack_ringbuffer_t*)userData;
//jack_info("JackWinMMEDriver::MidiInProc 0\n");
switch (wMsg) {
case MIM_OPEN:
break;
case MIM_ERROR:
case MIM_DATA: {
//jack_info("JackWinMMEDriver::MidiInProc");
// One event
unsigned int num_packet = 1;
jack_ringbuffer_write(ringbuffer, (char*)&num_packet, sizeof(unsigned int));
// Write event actual data
jack_ringbuffer_write(ringbuffer, (char*)&dwParam1, 3);
break;
}
case MIM_LONGERROR:
case MIM_LONGDATA:
/*
Nothing for now
*/
break;
}
}
JackWinMMEDriver::JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
: JackMidiDriver(name, alias, engine, table),
fRealCaptureChannels(0),
fRealPlaybackChannels(0),
fMidiSource(NULL),
fMidiDestination(NULL)
{}
JackWinMMEDriver::~JackWinMMEDriver()
{}
int JackWinMMEDriver::Open(bool capturing,
bool playing,
int inchannels,
int outchannels,
bool monitor,
const char* capture_driver_name,
const char* playback_driver_name,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency)
{
jack_log("JackWinMMEDriver::Open");
fRealCaptureChannels = midiInGetNumDevs();
fRealPlaybackChannels = midiOutGetNumDevs ();
// Generic JackMidiDriver Open
if (JackMidiDriver::Open(capturing, playing, inchannels + fRealCaptureChannels, outchannels + fRealPlaybackChannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0)
return -1;
fMidiDestination = new MidiSlot[fRealCaptureChannels];
assert(fMidiDestination);
// Real input
for (int i = 0; i < fRealCaptureChannels; i++) {
HMIDIIN handle;
fMidiDestination[i].fIndex = i;
MMRESULT ret = midiInOpen(&handle, fMidiDestination[i].fIndex, (DWORD)MidiInProc, (DWORD)fRingBuffer[i], CALLBACK_FUNCTION);
if (ret == MMSYSERR_NOERROR) {
fMidiDestination[i].fHandle = handle;
if (!InitHeaders(&fMidiDestination[i])) {
jack_error("memory allocation failed");
midiInClose(handle);
goto error;
//continue;
}
ret = midiInPrepareHeader(handle, fMidiDestination[i].fHeader, sizeof(MIDIHDR));
if (ret == MMSYSERR_NOERROR) {
fMidiDestination[i].fHeader->dwUser = 1;
ret = midiInAddBuffer(handle, fMidiDestination[i].fHeader, sizeof(MIDIHDR));
if (ret == MMSYSERR_NOERROR) {
ret = midiInStart(handle);
if (ret != MMSYSERR_NOERROR) {
jack_error("midiInStart error");
CloseInput(&fMidiDestination[i]);
goto error;
}
} else {
jack_error ("midiInAddBuffer error");
CloseInput(&fMidiDestination[i]);
goto error;
}
} else {
jack_error("midiInPrepareHeader error");
midiInClose(handle);
goto error;
}
} else {
jack_error ("midiInOpen error");
goto error;
}
}
fMidiSource = new MidiSlot[fRealPlaybackChannels];
assert(fMidiSource);
// Real output
for (int i = 0; i < fRealPlaybackChannels; i++) {
MMRESULT res;
HMIDIOUT handle;
fMidiSource[i].fIndex = i;
UINT ret = midiOutOpen(&handle, fMidiSource[i].fIndex, 0L, 0L, CALLBACK_NULL);
if (ret == MMSYSERR_NOERROR) {
fMidiSource[i].fHandle = handle;
if (!InitHeaders(&fMidiSource[i])) {
jack_error("memory allocation failed");
midiOutClose(handle);
//continue;
goto error;
}
res = midiOutPrepareHeader(handle, fMidiSource[i].fHeader, sizeof(MIDIHDR));
if (res != MMSYSERR_NOERROR) {
jack_error("midiOutPrepareHeader error %d %d %d", i, handle, res);
//continue;
goto error;
} else {
fMidiSource[i].fHeader->dwUser = 1;
}
} else {
jack_error("midiOutOpen error");
goto error;
}
}
return 0;
error:
Close();
return -1;
}
void JackWinMMEDriver::CloseInput(MidiSlot* slot)
{
MMRESULT res;
int retry = 0;
if (slot->fHandle == 0)
return;
HMIDIIN handle = (HMIDIIN)slot->fHandle;
slot->fHeader->dwUser = 0;
res = midiInStop(handle);
if (res != MMSYSERR_NOERROR) {
jack_error("midiInStop error");
}
res = midiInReset(handle);
if (res != MMSYSERR_NOERROR) {
jack_error("midiInReset error");
}
res = midiInUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
if (res != MMSYSERR_NOERROR) {
jack_error("midiInUnprepareHeader error");
}
do {
res = midiInClose(handle);
if (res != MMSYSERR_NOERROR) {
jack_error("midiInClose error");
}
if (res == MIDIERR_STILLPLAYING)
midiInReset(handle);
Sleep (10);
retry++;
} while ((res == MIDIERR_STILLPLAYING) && (retry < 10));
if (slot->fHeader) {
GlobalFreePtr(slot->fHeader);
}
}
void JackWinMMEDriver::CloseOutput(MidiSlot* slot)
{
MMRESULT res;
int retry = 0;
if (slot->fHandle == 0)
return;
HMIDIOUT handle = (HMIDIOUT)slot->fHandle;
res = midiOutReset(handle);
if (res != MMSYSERR_NOERROR)
jack_error("midiOutReset error");
midiOutUnprepareHeader(handle, slot->fHeader, sizeof(MIDIHDR));
do {
res = midiOutClose(handle);
if (res != MMSYSERR_NOERROR)
jack_error("midiOutClose error");
Sleep(10);
retry++;
} while ((res == MIDIERR_STILLPLAYING) && (retry < 10));
if (slot->fHeader) {
GlobalFreePtr(slot->fHeader);
}
}
int JackWinMMEDriver::Close()
{
jack_log("JackWinMMEDriver::Close");
// Close input
if (fMidiDestination) {
for (int i = 0; i < fRealCaptureChannels; i++) {
CloseInput(&fMidiDestination[i]);
}
delete[] fMidiDestination;
}
// Close output
if (fMidiSource) {
for (int i = 0; i < fRealPlaybackChannels; i++) {
CloseOutput(&fMidiSource[i]);
}
delete[] fMidiSource;
}
return 0;
}
int JackWinMMEDriver::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];
unsigned long port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
MMRESULT res;
int i;
jack_log("JackMidiDriver::Attach fBufferSize = %ld fSampleRate = %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
for (i = 0; i < fCaptureChannels; i++) {
MIDIINCAPS caps;
res = midiInGetDevCaps(i, &caps, sizeof(caps));
if (res == MMSYSERR_NOERROR) {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
} else {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
}
snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1);
if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) {
jack_error("driver: cannot register port for %s", name);
return -1;
}
port = fGraphManager->GetPort(port_index);
port->SetAlias(alias);
fCapturePortList[i] = port_index;
jack_log("JackMidiDriver::Attach fCapturePortList[i] port_index = %ld", port_index);
}
port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;
for (i = 0; i < fPlaybackChannels; i++) {
MIDIOUTCAPS caps;
res = midiOutGetDevCaps(i, &caps, sizeof(caps));
if (res == MMSYSERR_NOERROR) {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, caps.szPname, i + 1);
} else {
snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fPlaybackDriverName, i + 1);
}
snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1);
if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_MIDI_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) {
jack_error("driver: cannot register port for %s", name);
return -1;
}
port = fGraphManager->GetPort(port_index);
port->SetAlias(alias);
fPlaybackPortList[i] = port_index;
jack_log("JackMidiDriver::Attach fPlaybackPortList[i] port_index = %ld", port_index);
}
return 0;
}
int JackWinMMEDriver::Read()
{
size_t size;
for (int chan = 0; chan < fCaptureChannels; chan++) {
if (fGraphManager->GetConnectionsNum(fCapturePortList[chan]) > 0) {
JackMidiBuffer* midi_buffer = GetInputBuffer(chan);
if (jack_ringbuffer_read_space (fRingBuffer[chan]) == 0) {
// Reset buffer
midi_buffer->Reset(midi_buffer->nframes);
} else {
while ((size = jack_ringbuffer_read_space (fRingBuffer[chan])) > 0) {
//jack_info("jack_ringbuffer_read_space %d", size);
int ev_count = 0;
jack_ringbuffer_read(fRingBuffer[chan], (char*)&ev_count, sizeof(int));
if (ev_count > 0) {
for (int j = 0; j < ev_count; j++) {
unsigned int event_len = 3;
// Read event actual data
jack_midi_data_t* dest = midi_buffer->ReserveEvent(0, event_len);
jack_ringbuffer_read(fRingBuffer[chan], (char*)dest, event_len);
}
}
}
}
} else {
//jack_info("Consume ring buffer");
jack_ringbuffer_read_advance(fRingBuffer[chan], jack_ringbuffer_read_space(fRingBuffer[chan]));
}
}
return 0;
}
int JackWinMMEDriver::Write()
{
for (int chan = 0; chan < fPlaybackChannels; chan++) {
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chan]) > 0) {
JackMidiBuffer* midi_buffer = GetOutputBuffer(chan);
// TODO : use timestamp
for (unsigned int j = 0; j < midi_buffer->event_count; j++) {
JackMidiEvent* ev = &midi_buffer->events[j];
if (ev->size <= 3) {
MMRESULT res = midiOutShortMsg((HMIDIOUT)fMidiSource[chan].fHandle, *((DWORD*)ev->GetData(midi_buffer)));
if (res != MMSYSERR_NOERROR)
jack_error ("midiOutShortMsg error res %d", res);
} else {
}
}
}
}
return 0;
}
} // end of namespace
#ifdef __cplusplus
extern "C"
{
#endif
SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
{
jack_driver_desc_t * desc;
unsigned int i;
desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
strcpy(desc->name, "winmme"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
strcpy(desc->desc, "WinMME API based MIDI backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
desc->nparams = 0;
desc->params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
return desc;
}
SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
{
/*
unsigned int capture_ports = 2;
unsigned int playback_ports = 2;
unsigned long wait_time = 0;
const JSList * node;
const jack_driver_param_t * param;
bool monitor = false;
for (node = params; node; node = jack_slist_next (node)) {
param = (const jack_driver_param_t *) node->data;
switch (param->character) {
case 'C':
capture_ports = param->value.ui;
break;
case 'P':
playback_ports = param->value.ui;
break;
case 'r':
sample_rate = param->value.ui;
break;
case 'p':
period_size = param->value.ui;
break;
case 'w':
wait_time = param->value.ui;
break;
case 'm':
monitor = param->value.i;
break;
}
}
*/
Jack::JackDriverClientInterface* driver = new Jack::JackWinMMEDriver("system_midi", "winmme", engine, table);
if (driver->Open(1, 1, 0, 0, false, "in", "out", 0, 0) == 0) {
return driver;
} else {
delete driver;
return NULL;
}
}
#ifdef __cplusplus
}
#endif
/*
jack_connect system:midi_capture_1 system_midi:playback_1
jack_connect system:midi_capture_1 system_midi:playback_2
jack_connect system:midi_capture_1 system_midi:playback_1
jack_connect system:midi_capture_1 system_midi:playback_1
jack_connect system:midi_capture_1 system_midi:playback_1
jack_connect system_midi:capture_1 system:midi_playback_1
jack_connect system_midi:capture_2 system:midi_playback_1
jack_connect system_midi:capture_1 system_midi:playback_1
*/

+ 87
- 0
windows/winmme/JackWinMMEDriver.h View File

@@ -0,0 +1,87 @@
/*
Copyright (C) 2009 Grame

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

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

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

*/

#ifndef __JackWinMMEDriver__
#define __JackWinMMEDriver__

#include "JackMidiDriver.h"
#include "JackTime.h"

namespace Jack
{

/*!
\brief The WinMME driver.
*/

#define kBuffSize 512

struct MidiSlot {

LPVOID fHandle; // MMSystem handler
short fIndex; // MMSystem dev index
LPMIDIHDR fHeader; // for long msg output

MidiSlot():fHandle(0),fIndex(0)
{}

};

class JackWinMMEDriver : public JackMidiDriver
{

private:

int fRealCaptureChannels;
int fRealPlaybackChannels;

MidiSlot* fMidiSource;
MidiSlot* fMidiDestination;

void CloseInput(MidiSlot* slot);
void CloseOutput(MidiSlot* slot);

static void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);

public:

JackWinMMEDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);
virtual ~JackWinMMEDriver();

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

int Read();
int Write();

};

} // end of namespace

#endif

Loading…
Cancel
Save