git-svn-id: http://subversion.jackaudio.org/jack/jack2/branches/libjacknet@3503 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.8
@@ -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." | |||
@@ -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,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 | |||
@@ -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); | |||
} | |||
} | |||
@@ -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; | |||
@@ -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" | |||
@@ -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; | |||
} | |||
} | |||
@@ -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 */ | |||
@@ -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; | |||
} | |||
@@ -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, | |||
@@ -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; | |||
} | |||
@@ -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; | |||
} | |||
}; | |||
@@ -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 |
@@ -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 |
@@ -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) { | |||
@@ -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) }; | |||
@@ -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 | |||
//---------------------- | |||
@@ -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(); | |||
@@ -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, | |||
@@ -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; | |||
@@ -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 | |||
@@ -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']: | |||
@@ -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); | |||
@@ -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 = ( | |||
@@ -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 | |||
@@ -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 |
@@ -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', | |||
@@ -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> |
@@ -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> |
@@ -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 |
@@ -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> |
@@ -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 | |||
*/ |
@@ -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 |