git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3863 0c269be4-1314-0410-8aa9-9f06e86f4224tags/v1.9.5
@@ -48,7 +48,8 @@ extern "C" | |||||
require linker arguments in the client as well. | require linker arguments in the client as well. | ||||
*/ | */ | ||||
#define JACK_WEAK_EXPORT __attribute__((weak)) | #define JACK_WEAK_EXPORT __attribute__((weak)) | ||||
#else | |||||
#else | |||||
#define JACK_WEAK_EXPORT | |||||
/* Add other things here for non-gcc platforms */ | /* Add other things here for non-gcc platforms */ | ||||
#endif | #endif | ||||
#endif | #endif | ||||
@@ -0,0 +1,840 @@ | |||||
/* | |||||
Copyright (C) 2006 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. | |||||
*/ | |||||
#ifdef WIN32 | |||||
#pragma warning (disable : 4786) | |||||
#endif | |||||
#include <stdio.h> | |||||
#include <string.h> | |||||
#include <assert.h> | |||||
#include <process.h> | |||||
#include "JackRouter.h" | |||||
#include "profport.h" | |||||
/* | |||||
08/07/2007 SL : USe jack_client_open instead of jack_client_new (automatic client renaming). | |||||
09/08/2007 SL : Add JackRouter.ini parameter file. | |||||
09/20/2007 SL : Better error report in DllRegisterServer (for Vista). | |||||
09/27/2007 SL : Add AUDO_CONNECT property in JackRouter.ini file. | |||||
10/10/2007 SL : Use ASIOSTInt32LSB instead of ASIOSTInt16LSB. | |||||
*/ | |||||
//------------------------------------------------------------------------------------------ | |||||
// extern | |||||
void getNanoSeconds(ASIOTimeStamp *time); | |||||
// local | |||||
double AsioSamples2double (ASIOSamples* samples); | |||||
static const double twoRaisedTo32 = 4294967296.; | |||||
static const double twoRaisedTo32Reciprocal = 1. / twoRaisedTo32; | |||||
//------------------------------------------------------------------------------------------ | |||||
// on windows, we do the COM stuff. | |||||
#if WINDOWS | |||||
#include "windows.h" | |||||
#include "mmsystem.h" | |||||
#include "psapi.h" | |||||
using namespace std; | |||||
// class id. | |||||
// {838FE50A-C1AB-4b77-B9B6-0A40788B53F3} | |||||
CLSID IID_ASIO_DRIVER = { 0x838fe50a, 0xc1ab, 0x4b77, { 0xb9, 0xb6, 0xa, 0x40, 0x78, 0x8b, 0x53, 0xf3 } }; | |||||
CFactoryTemplate g_Templates[1] = { | |||||
{L"ASIOJACK", &IID_ASIO_DRIVER, JackRouter::CreateInstance} | |||||
}; | |||||
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); | |||||
CUnknown* JackRouter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) | |||||
{ | |||||
return (CUnknown*)new JackRouter(pUnk,phr); | |||||
}; | |||||
STDMETHODIMP JackRouter::NonDelegatingQueryInterface(REFIID riid, void ** ppv) | |||||
{ | |||||
if (riid == IID_ASIO_DRIVER) { | |||||
return GetInterface(this, ppv); | |||||
} | |||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv); | |||||
} | |||||
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |||||
// Register ASIO Driver | |||||
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |||||
extern LONG RegisterAsioDriver(CLSID,char *,char *,char *,char *); | |||||
extern LONG UnregisterAsioDriver(CLSID,char *,char *); | |||||
// | |||||
// Server registration, called on REGSVR32.EXE "the dllname.dll" | |||||
// | |||||
HRESULT _stdcall DllRegisterServer() | |||||
{ | |||||
LONG rc; | |||||
char errstr[128]; | |||||
rc = RegisterAsioDriver (IID_ASIO_DRIVER,"JackRouter.dll","JackRouter","JackRouter","Apartment"); | |||||
if (rc) { | |||||
memset(errstr,0,128); | |||||
sprintf(errstr,"Register Server failed ! (%d)",rc); | |||||
MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"JackRouter",MB_OK); | |||||
return -1; | |||||
} | |||||
return S_OK; | |||||
} | |||||
// | |||||
// Server unregistration | |||||
// | |||||
HRESULT _stdcall DllUnregisterServer() | |||||
{ | |||||
LONG rc; | |||||
char errstr[128]; | |||||
rc = UnregisterAsioDriver (IID_ASIO_DRIVER,"JackRouter.dll","JackRouter"); | |||||
if (rc) { | |||||
memset(errstr,0,128); | |||||
sprintf(errstr,"Unregister Server failed ! (%d)",rc); | |||||
MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"JackRouter",MB_OK); | |||||
return -1; | |||||
} | |||||
return S_OK; | |||||
} | |||||
// Globals | |||||
list<pair<string, string> > JackRouter::fConnections; | |||||
bool JackRouter::fFirstActivate = true; | |||||
//------------------------------------------------------------------------------------------ | |||||
//------------------------------------------------------------------------------------------ | |||||
JackRouter::JackRouter (LPUNKNOWN pUnk, HRESULT *phr) | |||||
: CUnknown("ASIOJACK", pUnk, phr) | |||||
//------------------------------------------------------------------------------------------ | |||||
#else | |||||
// when not on windows, we derive from AsioDriver | |||||
JackRouter::JackRouter() : AsioDriver() | |||||
#endif | |||||
{ | |||||
long i; | |||||
fSamplePosition = 0; | |||||
fActive = false; | |||||
fStarted = false; | |||||
fTimeInfoMode = false; | |||||
fTcRead = false; | |||||
fClient = NULL; | |||||
fAutoConnectIn = true; | |||||
fAutoConnectOut = true; | |||||
for (i = 0; i < kNumInputs; i++) { | |||||
fInputBuffers[i] = 0; | |||||
fInputPorts[i] = 0; | |||||
fInMap[i] = 0; | |||||
} | |||||
for (i = 0; i < kNumOutputs; i++) { | |||||
fOutputBuffers[i] = 0; | |||||
fOutputPorts[i] = 0; | |||||
fOutMap[i] = 0; | |||||
} | |||||
fCallbacks = 0; | |||||
fActiveInputs = fActiveOutputs = 0; | |||||
fToggle = 0; | |||||
fBufferSize = 512; | |||||
fSampleRate = 44100; | |||||
printf("Constructor\n"); | |||||
// Use "jackrouter.ini" parameters if available | |||||
HMODULE handle = LoadLibrary("JackRouter.dll"); | |||||
if (handle) { | |||||
// Get JackRouter.dll path | |||||
char dllName[512]; | |||||
string confPath; | |||||
DWORD res = GetModuleFileName(handle, dllName, 512); | |||||
// Compute .ini file path | |||||
string fullPath = dllName; | |||||
int lastPos = fullPath.find_last_of(PATH_SEP); | |||||
string dllFolder = fullPath.substr(0, lastPos); | |||||
confPath = dllFolder + PATH_SEP + "JackRouter.ini"; | |||||
// Get parameters | |||||
kNumInputs = get_private_profile_int("IO", "input", 2, confPath.c_str()); | |||||
kNumOutputs = get_private_profile_int("IO", "output", 2, confPath.c_str()); | |||||
fAutoConnectIn = get_private_profile_int("AUTO_CONNECT", "input", 1, confPath.c_str()); | |||||
fAutoConnectOut = get_private_profile_int("AUTO_CONNECT", "output", 1, confPath.c_str()); | |||||
FreeLibrary(handle); | |||||
} else { | |||||
printf("LoadLibrary error\n"); | |||||
} | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
JackRouter::~JackRouter() | |||||
{ | |||||
stop (); | |||||
disposeBuffers (); | |||||
printf("Destructor\n"); | |||||
jack_client_close(fClient); | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
#include <windows.h> | |||||
#include <stdio.h> | |||||
#include <tchar.h> | |||||
#include "psapi.h" | |||||
static bool GetEXEName(DWORD dwProcessID, char* name) | |||||
{ | |||||
DWORD aProcesses [1024], cbNeeded, cProcesses; | |||||
unsigned int i; | |||||
// Enumerate all processes | |||||
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) | |||||
return false; | |||||
// Calculate how many process identifiers were returned. | |||||
cProcesses = cbNeeded / sizeof(DWORD); | |||||
TCHAR szEXEName[MAX_PATH]; | |||||
// Loop through all process to find the one that matches | |||||
// the one we are looking for | |||||
for (i = 0; i < cProcesses; i++) { | |||||
if (aProcesses [i] == dwProcessID) { | |||||
// Get a handle to the process | |||||
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | | |||||
PROCESS_VM_READ, FALSE, dwProcessID); | |||||
// Get the process name | |||||
if (NULL != hProcess) { | |||||
HMODULE hMod; | |||||
DWORD cbNeeded; | |||||
if(EnumProcessModules(hProcess, &hMod, | |||||
sizeof(hMod), &cbNeeded)) { | |||||
//Get the name of the exe file | |||||
GetModuleBaseName(hProcess, hMod, szEXEName, | |||||
sizeof(szEXEName)/sizeof(TCHAR)); | |||||
int len = strlen((char*)szEXEName) - 4; // remove ".exe" | |||||
strncpy(name, (char*)szEXEName, len); | |||||
name[len] = '\0'; | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
static inline float ClipFloat(float sample) | |||||
{ | |||||
return (sample < -1.0f) ? -1.0f : (sample > 1.0f) ? 1.0f : sample; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
void JackRouter::shutdown(void* arg) | |||||
{ | |||||
JackRouter* driver = (JackRouter*)arg; | |||||
/* | |||||
//exit(1); | |||||
char errstr[128]; | |||||
memset(errstr,0,128); | |||||
sprintf(errstr,"JACK server has quitted"); | |||||
MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"JackRouter",MB_OK); | |||||
*/ | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
int JackRouter::process(jack_nframes_t nframes, void* arg) | |||||
{ | |||||
JackRouter* driver = (JackRouter*)arg; | |||||
int i,j; | |||||
int pos = (driver->fToggle) ? 0 : driver->fBufferSize ; | |||||
for (i = 0; i < driver->fActiveInputs; i++) { | |||||
#ifdef LONG_SAMPLE | |||||
float* buffer = (float*)jack_port_get_buffer(driver->fInputPorts[i], nframes); | |||||
long* in = driver->fInputBuffers[i] + pos; | |||||
for (j = 0; j < nframes; j++) { | |||||
in[j] = buffer[j] * float(0x7fffffff); | |||||
} | |||||
#else | |||||
memcpy(driver->fInputBuffers[i] + pos, | |||||
jack_port_get_buffer(driver->fInputPorts[i], nframes), | |||||
nframes * sizeof(float)); | |||||
#endif | |||||
} | |||||
driver->bufferSwitch(); | |||||
for (i = 0; i < driver->fActiveOutputs; i++) { | |||||
#ifdef LONG_SAMPLE | |||||
float* buffer = (float*)jack_port_get_buffer(driver->fOutputPorts[i], nframes); | |||||
long* out = driver->fOutputBuffers[i] + pos; | |||||
float gain = 1.f/float(0x7fffffff); | |||||
for (j = 0; j < nframes; j++) { | |||||
buffer[j] = out[j] * gain; | |||||
} | |||||
#else | |||||
memcpy(jack_port_get_buffer(driver->fOutputPorts[i], nframes), | |||||
driver->fOutputBuffers[i] + pos, | |||||
nframes * sizeof(float)); | |||||
#endif | |||||
} | |||||
return 0; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
void JackRouter::getDriverName(char *name) | |||||
{ | |||||
strcpy (name, "JackRouter"); | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
long JackRouter::getDriverVersion() | |||||
{ | |||||
return 0x00000001L; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
void JackRouter::getErrorMessage(char *string) | |||||
{ | |||||
strcpy (string, fErrorMessage); | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOBool JackRouter::init(void* sysRef) | |||||
{ | |||||
char name[MAX_PATH]; | |||||
sysRef = sysRef; | |||||
if (fActive) | |||||
return true; | |||||
HANDLE win = (HANDLE)sysRef; | |||||
int my_pid = _getpid(); | |||||
if (!GetEXEName(my_pid, name)) { // If getting the .exe name fails, takes a generic one. | |||||
_snprintf(name, sizeof(name) - 1, "JackRouter_%d", my_pid); | |||||
} | |||||
if (fClient) { | |||||
printf("Error: jack client still present...\n"); | |||||
return true; | |||||
} | |||||
fClient = jack_client_open(name, JackNullOption, NULL); | |||||
if (fClient == NULL) { | |||||
strcpy (fErrorMessage, "Open error: is jack server running?"); | |||||
printf("Open error: is jack server running?\n"); | |||||
return false; | |||||
} | |||||
fBufferSize = jack_get_buffer_size(fClient); | |||||
fSampleRate = jack_get_sample_rate(fClient); | |||||
jack_set_process_callback(fClient, process, this); | |||||
jack_on_shutdown(fClient, shutdown, this); | |||||
fInputLatency = fBufferSize; // typically | |||||
fOutputLatency = fBufferSize * 2; | |||||
fMilliSeconds = (long)((double)(fBufferSize * 1000) / fSampleRate); | |||||
// Typically fBufferSize * 2; try to get 1 by offering direct buffer | |||||
// access, and using asioPostOutput for lower latency | |||||
printf("Init ASIO Jack\n"); | |||||
fActive = true; | |||||
return true; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::start() | |||||
{ | |||||
if (fCallbacks) { | |||||
fSamplePosition = 0; | |||||
fTheSystemTime.lo = fTheSystemTime.hi = 0; | |||||
fToggle = 0; | |||||
fStarted = true; | |||||
printf("Start ASIO Jack\n"); | |||||
if (jack_activate(fClient) == 0) { | |||||
if (fFirstActivate) { | |||||
AutoConnect(); | |||||
fFirstActivate = false; | |||||
} else { | |||||
RestoreConnections(); | |||||
} | |||||
return ASE_OK; | |||||
} else { | |||||
return ASE_NotPresent; | |||||
} | |||||
} | |||||
return ASE_NotPresent; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::stop() | |||||
{ | |||||
fStarted = false; | |||||
printf("Stop ASIO Jack\n"); | |||||
SaveConnections(); | |||||
jack_deactivate(fClient); | |||||
return ASE_OK; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::getChannels(long *numInputChannels, long *numOutputChannels) | |||||
{ | |||||
*numInputChannels = kNumInputs; | |||||
*numOutputChannels = kNumOutputs; | |||||
return ASE_OK; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::getLatencies(long *_inputLatency, long *_outputLatency) | |||||
{ | |||||
*_inputLatency = fInputLatency; | |||||
*_outputLatency = fOutputLatency; | |||||
return ASE_OK; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) | |||||
{ | |||||
*minSize = *maxSize = *preferredSize = fBufferSize; // allow this size only | |||||
*granularity = 0; | |||||
return ASE_OK; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::canSampleRate(ASIOSampleRate sampleRate) | |||||
{ | |||||
return (sampleRate == fSampleRate) ? ASE_OK : ASE_NoClock; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::getSampleRate(ASIOSampleRate *sampleRate) | |||||
{ | |||||
*sampleRate = fSampleRate; | |||||
return ASE_OK; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::setSampleRate(ASIOSampleRate sampleRate) | |||||
{ | |||||
return (sampleRate == fSampleRate) ? ASE_OK : ASE_NoClock; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::getClockSources(ASIOClockSource *clocks, long *numSources) | |||||
{ | |||||
// Internal | |||||
if (clocks && numSources) { | |||||
clocks->index = 0; | |||||
clocks->associatedChannel = -1; | |||||
clocks->associatedGroup = -1; | |||||
clocks->isCurrentSource = ASIOTrue; | |||||
strcpy(clocks->name, "Internal"); | |||||
*numSources = 1; | |||||
return ASE_OK; | |||||
} else { | |||||
return ASE_InvalidParameter; | |||||
} | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::setClockSource(long index) | |||||
{ | |||||
if (!index) { | |||||
fAsioTime.timeInfo.flags |= kClockSourceChanged; | |||||
return ASE_OK; | |||||
} else { | |||||
return ASE_NotPresent; | |||||
} | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) | |||||
{ | |||||
tStamp->lo = fTheSystemTime.lo; | |||||
tStamp->hi = fTheSystemTime.hi; | |||||
if (fSamplePosition >= twoRaisedTo32) { | |||||
sPos->hi = (unsigned long)(fSamplePosition * twoRaisedTo32Reciprocal); | |||||
sPos->lo = (unsigned long)(fSamplePosition - (sPos->hi * twoRaisedTo32)); | |||||
} else { | |||||
sPos->hi = 0; | |||||
sPos->lo = (unsigned long)fSamplePosition; | |||||
} | |||||
return ASE_OK; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::getChannelInfo(ASIOChannelInfo *info) | |||||
{ | |||||
if (info->channel < 0 || (info->isInput ? info->channel >= kNumInputs : info->channel >= kNumOutputs)) | |||||
return ASE_InvalidParameter; | |||||
#ifdef LONG_SAMPLE | |||||
info->type = ASIOSTInt32LSB; | |||||
#else | |||||
info->type = ASIOSTFloat32LSB; | |||||
#endif | |||||
info->channelGroup = 0; | |||||
info->isActive = ASIOFalse; | |||||
long i; | |||||
char buf[32]; | |||||
if (info->isInput) { | |||||
for (i = 0; i < fActiveInputs; i++) { | |||||
if (fInMap[i] == info->channel) { | |||||
info->isActive = ASIOTrue; | |||||
//_snprintf(buf, sizeof(buf) - 1, "Jack::In%d ", info->channel); | |||||
//strcpy(info->name, buf); | |||||
//strcpy(info->name, jack_port_name(fInputPorts[i])); | |||||
break; | |||||
} | |||||
} | |||||
_snprintf(buf, sizeof(buf) - 1, "In%d ", info->channel); | |||||
strcpy(info->name, buf); | |||||
} else { | |||||
for (i = 0; i < fActiveOutputs; i++) { | |||||
if (fOutMap[i] == info->channel) { //NOT USED !! | |||||
info->isActive = ASIOTrue; | |||||
//_snprintf(buf, sizeof(buf) - 1, "Jack::Out%d ", info->channel); | |||||
//strcpy(info->name, buf); | |||||
//strcpy(info->name, jack_port_name(fOutputPorts[i])); | |||||
break; | |||||
} | |||||
} | |||||
_snprintf(buf, sizeof(buf) - 1, "Out%d ", info->channel); | |||||
strcpy(info->name, buf); | |||||
} | |||||
return ASE_OK; | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
ASIOError JackRouter::createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, | |||||
long bufferSize, ASIOCallbacks *callbacks) | |||||
{ | |||||
ASIOBufferInfo *info = bufferInfos; | |||||
long i; | |||||
bool notEnoughMem = false; | |||||
char buf[256]; | |||||
fActiveInputs = 0; | |||||
fActiveOutputs = 0; | |||||
for (i = 0; i < numChannels; i++, info++) { | |||||
if (info->isInput) { | |||||
if (info->channelNum < 0 || info->channelNum >= kNumInputs) | |||||
goto error; | |||||
fInMap[fActiveInputs] = info->channelNum; | |||||
#ifdef LONG_SAMPLE | |||||
fInputBuffers[fActiveInputs] = new long[fBufferSize * 2]; // double buffer | |||||
#else | |||||
fInputBuffers[fActiveInputs] = new float[fBufferSize * 2]; // double buffer | |||||
#endif | |||||
if (fInputBuffers[fActiveInputs]) { | |||||
info->buffers[0] = fInputBuffers[fActiveInputs]; | |||||
info->buffers[1] = fInputBuffers[fActiveInputs] + fBufferSize; | |||||
} else { | |||||
info->buffers[0] = info->buffers[1] = 0; | |||||
notEnoughMem = true; | |||||
} | |||||
_snprintf(buf, sizeof(buf) - 1, "in%d", fActiveInputs + 1); | |||||
fInputPorts[fActiveInputs] | |||||
= jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput,0); | |||||
if (fInputPorts[fActiveInputs] == NULL) | |||||
goto error; | |||||
fActiveInputs++; | |||||
if (fActiveInputs > kNumInputs) { | |||||
error: | |||||
disposeBuffers(); | |||||
return ASE_InvalidParameter; | |||||
} | |||||
} else { // output | |||||
if (info->channelNum < 0 || info->channelNum >= kNumOutputs) | |||||
goto error; | |||||
fOutMap[fActiveOutputs] = info->channelNum; | |||||
#ifdef LONG_SAMPLE | |||||
fOutputBuffers[fActiveOutputs] = new long[fBufferSize * 2]; // double buffer | |||||
#else | |||||
fOutputBuffers[fActiveOutputs] = new float[fBufferSize * 2]; // double buffer | |||||
#endif | |||||
if (fOutputBuffers[fActiveOutputs]) { | |||||
info->buffers[0] = fOutputBuffers[fActiveOutputs]; | |||||
info->buffers[1] = fOutputBuffers[fActiveOutputs] + fBufferSize; | |||||
} else { | |||||
info->buffers[0] = info->buffers[1] = 0; | |||||
notEnoughMem = true; | |||||
} | |||||
_snprintf(buf, sizeof(buf) - 1, "out%d", fActiveOutputs + 1); | |||||
fOutputPorts[fActiveOutputs] | |||||
= jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput,0); | |||||
if (fOutputPorts[fActiveOutputs] == NULL) | |||||
goto error; | |||||
fActiveOutputs++; | |||||
if (fActiveOutputs > kNumOutputs) { | |||||
fActiveOutputs--; | |||||
disposeBuffers(); | |||||
return ASE_InvalidParameter; | |||||
} | |||||
} | |||||
} | |||||
if (notEnoughMem) { | |||||
disposeBuffers(); | |||||
return ASE_NoMemory; | |||||
} | |||||
this->fCallbacks = callbacks; | |||||
if (callbacks->asioMessage (kAsioSupportsTimeInfo, 0, 0, 0)) { | |||||
fTimeInfoMode = true; | |||||
fAsioTime.timeInfo.speed = 1.; | |||||
fAsioTime.timeInfo.systemTime.hi = fAsioTime.timeInfo.systemTime.lo = 0; | |||||
fAsioTime.timeInfo.samplePosition.hi = fAsioTime.timeInfo.samplePosition.lo = 0; | |||||
fAsioTime.timeInfo.sampleRate = fSampleRate; | |||||
fAsioTime.timeInfo.flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; | |||||
fAsioTime.timeCode.speed = 1.; | |||||
fAsioTime.timeCode.timeCodeSamples.lo = fAsioTime.timeCode.timeCodeSamples.hi = 0; | |||||
fAsioTime.timeCode.flags = kTcValid | kTcRunning ; | |||||
} else { | |||||
fTimeInfoMode = false; | |||||
} | |||||
return ASE_OK; | |||||
} | |||||
//--------------------------------------------------------------------------------------------- | |||||
ASIOError JackRouter::disposeBuffers() | |||||
{ | |||||
long i; | |||||
fCallbacks = 0; | |||||
stop(); | |||||
for (i = 0; i < fActiveInputs; i++) { | |||||
delete[] fInputBuffers[i]; | |||||
jack_port_unregister(fClient, fInputPorts[i]); | |||||
} | |||||
fActiveInputs = 0; | |||||
for (i = 0; i < fActiveOutputs; i++) { | |||||
delete[] fOutputBuffers[i]; | |||||
jack_port_unregister(fClient, fOutputPorts[i]); | |||||
} | |||||
fActiveOutputs = 0; | |||||
return ASE_OK; | |||||
} | |||||
//--------------------------------------------------------------------------------------------- | |||||
ASIOError JackRouter::controlPanel() | |||||
{ | |||||
return ASE_NotPresent; | |||||
} | |||||
//--------------------------------------------------------------------------------------------- | |||||
ASIOError JackRouter::future(long selector, void* opt) // !!! check properties | |||||
{ | |||||
ASIOTransportParameters* tp = (ASIOTransportParameters*)opt; | |||||
switch (selector) | |||||
{ | |||||
case kAsioEnableTimeCodeRead: fTcRead = true; return ASE_SUCCESS; | |||||
case kAsioDisableTimeCodeRead: fTcRead = false; return ASE_SUCCESS; | |||||
case kAsioSetInputMonitor: return ASE_SUCCESS; // for testing!!! | |||||
case kAsioCanInputMonitor: return ASE_SUCCESS; // for testing!!! | |||||
case kAsioCanTimeInfo: return ASE_SUCCESS; | |||||
case kAsioCanTimeCode: return ASE_SUCCESS; | |||||
} | |||||
return ASE_NotPresent; | |||||
} | |||||
//-------------------------------------------------------------------------------------------------------- | |||||
// private methods | |||||
//-------------------------------------------------------------------------------------------------------- | |||||
//--------------------------------------------------------------------------------------------- | |||||
void JackRouter::bufferSwitch() | |||||
{ | |||||
if (fStarted && fCallbacks) { | |||||
getNanoSeconds(&fTheSystemTime); // latch system time | |||||
fSamplePosition += fBufferSize; | |||||
if (fTimeInfoMode) { | |||||
bufferSwitchX (); | |||||
} else { | |||||
fCallbacks->bufferSwitch (fToggle, ASIOFalse); | |||||
} | |||||
fToggle = fToggle ? 0 : 1; | |||||
} | |||||
} | |||||
//--------------------------------------------------------------------------------------------- | |||||
// asio2 buffer switch | |||||
void JackRouter::bufferSwitchX () | |||||
{ | |||||
getSamplePosition (&fAsioTime.timeInfo.samplePosition, &fAsioTime.timeInfo.systemTime); | |||||
long offset = fToggle ? fBufferSize : 0; | |||||
if (fTcRead) { | |||||
// Create a fake time code, which is 10 minutes ahead of the card's sample position | |||||
// Please note that for simplicity here time code will wrap after 32 bit are reached | |||||
fAsioTime.timeCode.timeCodeSamples.lo = fAsioTime.timeInfo.samplePosition.lo + 600.0 * fSampleRate; | |||||
fAsioTime.timeCode.timeCodeSamples.hi = 0; | |||||
} | |||||
fCallbacks->bufferSwitchTimeInfo (&fAsioTime, fToggle, ASIOFalse); | |||||
fAsioTime.timeInfo.flags &= ~(kSampleRateChanged | kClockSourceChanged); | |||||
} | |||||
//--------------------------------------------------------------------------------------------- | |||||
ASIOError JackRouter::outputReady() | |||||
{ | |||||
return ASE_NotPresent; | |||||
} | |||||
//--------------------------------------------------------------------------------------------- | |||||
double AsioSamples2double(ASIOSamples* samples) | |||||
{ | |||||
double a = (double)(samples->lo); | |||||
if (samples->hi) | |||||
a += (double)(samples->hi) * twoRaisedTo32; | |||||
return a; | |||||
} | |||||
//--------------------------------------------------------------------------------------------- | |||||
void getNanoSeconds(ASIOTimeStamp* ts) | |||||
{ | |||||
double nanoSeconds = (double)((unsigned long)timeGetTime ()) * 1000000.; | |||||
ts->hi = (unsigned long)(nanoSeconds / twoRaisedTo32); | |||||
ts->lo = (unsigned long)(nanoSeconds - (ts->hi * twoRaisedTo32)); | |||||
} | |||||
//------------------------------------------------------------------------ | |||||
void JackRouter::SaveConnections() | |||||
{ | |||||
const char** connections; | |||||
int i; | |||||
for (i = 0; i < fActiveInputs; ++i) { | |||||
if (fInputPorts[i] && (connections = jack_port_get_connections(fInputPorts[i])) != 0) { | |||||
for (int j = 0; connections[j]; j++) { | |||||
fConnections.push_back(make_pair(connections[j], jack_port_name(fInputPorts[i]))); | |||||
} | |||||
jack_free(connections); | |||||
} | |||||
} | |||||
for (i = 0; i < fActiveOutputs; ++i) { | |||||
if (fOutputPorts[i] && (connections = jack_port_get_connections(fOutputPorts[i])) != 0) { | |||||
for (int j = 0; connections[j]; j++) { | |||||
fConnections.push_back(make_pair(jack_port_name(fOutputPorts[i]), connections[j])); | |||||
} | |||||
jack_free(connections); | |||||
} | |||||
} | |||||
} | |||||
//------------------------------------------------------------------------ | |||||
void JackRouter::RestoreConnections() | |||||
{ | |||||
list<pair<string, string> >::const_iterator it; | |||||
for (it = fConnections.begin(); it != fConnections.end(); it++) { | |||||
pair<string, string> connection = *it; | |||||
jack_connect(fClient, connection.first.c_str(), connection.second.c_str()); | |||||
} | |||||
fConnections.clear(); | |||||
} | |||||
//------------------------------------------------------------------------------------------ | |||||
void JackRouter::AutoConnect() | |||||
{ | |||||
const char** ports; | |||||
if ((ports = jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput)) == NULL) { | |||||
printf("Cannot find any physical capture ports\n"); | |||||
} else { | |||||
if (fAutoConnectIn) { | |||||
for (int i = 0; i < fActiveInputs; i++) { | |||||
if (!ports[i]) { | |||||
printf("source port is null i = %ld\n", i); | |||||
break; | |||||
} else if (jack_connect(fClient, ports[i], jack_port_name(fInputPorts[i])) != 0) { | |||||
printf("Cannot connect input ports\n"); | |||||
} | |||||
} | |||||
} | |||||
jack_free(ports); | |||||
} | |||||
if ((ports = jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput)) == NULL) { | |||||
printf("Cannot find any physical playback ports"); | |||||
} else { | |||||
if (fAutoConnectOut) { | |||||
for (int i = 0; i < fActiveOutputs; i++) { | |||||
if (!ports[i]){ | |||||
printf("destination port is null i = %ld\n", i); | |||||
break; | |||||
} else if (jack_connect(fClient, jack_port_name(fOutputPorts[i]), ports[i]) != 0) { | |||||
printf("Cannot connect output ports\n"); | |||||
} | |||||
} | |||||
} | |||||
jack_free(ports); | |||||
} | |||||
} | |||||
@@ -0,0 +1,9 @@ | |||||
LIBRARY JackRouter | |||||
DESCRIPTION 'ASIO Jack Driver' | |||||
PROTMODE | |||||
EXPORTS | |||||
DllMain | |||||
DllGetClassObject | |||||
DllCanUnloadNow | |||||
DllRegisterServer | |||||
DllUnregisterServer |
@@ -0,0 +1,163 @@ | |||||
# Microsoft Developer Studio Project File - Name="JackRouter" - Package Owner=<4> | |||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00 | |||||
# ** DO NOT EDIT ** | |||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 | |||||
CFG=JackRouter - Win32 Debug | |||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE, | |||||
!MESSAGE use the Export Makefile command and run | |||||
!MESSAGE | |||||
!MESSAGE NMAKE /f "JackRouter.mak". | |||||
!MESSAGE | |||||
!MESSAGE You can specify a configuration when running NMAKE | |||||
!MESSAGE by defining the macro CFG on the command line. For example: | |||||
!MESSAGE | |||||
!MESSAGE NMAKE /f "JackRouter.mak" CFG="JackRouter - Win32 Debug" | |||||
!MESSAGE | |||||
!MESSAGE Possible choices for configuration are: | |||||
!MESSAGE | |||||
!MESSAGE "JackRouter - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") | |||||
!MESSAGE "JackRouter - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") | |||||
!MESSAGE | |||||
# Begin Project | |||||
# PROP AllowPerConfigDependencies 0 | |||||
# PROP Scc_ProjName "" | |||||
# PROP Scc_LocalPath "" | |||||
CPP=cl.exe | |||||
MTL=midl.exe | |||||
RSC=rc.exe | |||||
!IF "$(CFG)" == "JackRouter - Win32 Release" | |||||
# PROP BASE Use_MFC 0 | |||||
# PROP BASE Use_Debug_Libraries 0 | |||||
# PROP BASE Output_Dir "Release" | |||||
# PROP BASE Intermediate_Dir "Release" | |||||
# PROP BASE Target_Dir "" | |||||
# PROP Use_MFC 0 | |||||
# PROP Use_Debug_Libraries 0 | |||||
# PROP Output_Dir "Release" | |||||
# PROP Intermediate_Dir "Release" | |||||
# PROP Ignore_Export_Lib 0 | |||||
# PROP Target_Dir "" | |||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c | |||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\ASIOSDK2\common" /I "..\..\common" /I "..\..\common\jack" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c | |||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | |||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 | |||||
# ADD BASE RSC /l 0x409 /d "NDEBUG" | |||||
# ADD RSC /l 0x409 /d "NDEBUG" | |||||
BSC32=bscmake.exe | |||||
# ADD BASE BSC32 /nologo | |||||
# ADD BSC32 /nologo | |||||
LINK32=link.exe | |||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 | |||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386 | |||||
!ELSEIF "$(CFG)" == "JackRouter - Win32 Debug" | |||||
# PROP BASE Use_MFC 0 | |||||
# PROP BASE Use_Debug_Libraries 1 | |||||
# PROP BASE Output_Dir "Debug" | |||||
# PROP BASE Intermediate_Dir "Debug" | |||||
# PROP BASE Target_Dir "" | |||||
# PROP Use_MFC 0 | |||||
# PROP Use_Debug_Libraries 1 | |||||
# PROP Output_Dir "Debug" | |||||
# PROP Intermediate_Dir "Debug" | |||||
# PROP Ignore_Export_Lib 0 | |||||
# PROP Target_Dir "" | |||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c | |||||
# ADD CPP /nologo /G5 /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\..\ASIOSDK2\common" /I "..\..\common" /I "..\..\common\jack" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c | |||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | |||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 | |||||
# ADD BASE RSC /l 0x409 /d "_DEBUG" | |||||
# ADD RSC /l 0x409 /d "_DEBUG" | |||||
BSC32=bscmake.exe | |||||
# ADD BASE BSC32 /nologo | |||||
# ADD BSC32 /nologo | |||||
LINK32=link.exe | |||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept | |||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/JackRouter_debug.dll" /pdbtype:sept | |||||
!ENDIF | |||||
# Begin Target | |||||
# Name "JackRouter - Win32 Release" | |||||
# Name "JackRouter - Win32 Debug" | |||||
# Begin Group "Source Files" | |||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" | |||||
# Begin Source File | |||||
SOURCE=..\..\..\..\..\ASIOSDK2\common\combase.cpp | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=..\..\..\..\..\ASIOSDK2\common\dllentry.cpp | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=.\JackRouter.cpp | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=.\JackRouter.def | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=.\profport.cpp | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=..\..\..\..\..\ASIOSDK2\common\register.cpp | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=.\resource.rc | |||||
# End Source File | |||||
# End Group | |||||
# Begin Group "Header Files" | |||||
# PROP Default_Filter "h;hpp;hxx;hm;inl" | |||||
# Begin Source File | |||||
SOURCE=..\..\..\common\asio.h | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=..\..\Common\Asiodrvr.h | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=..\asiosmpl.h | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=..\..\..\common\asiosys.h | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=..\..\..\common\combase.h | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=..\..\..\common\iasiodrv.h | |||||
# End Source File | |||||
# End Group | |||||
# Begin Group "Resource Files" | |||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" | |||||
# End Group | |||||
# Begin Source File | |||||
SOURCE=.\Psapi.Lib | |||||
# End Source File | |||||
# Begin Source File | |||||
SOURCE=..\Release\bin\libjack.lib | |||||
# End Source File | |||||
# End Target | |||||
# End Project |
@@ -0,0 +1,29 @@ | |||||
Microsoft Developer Studio Workspace File, Format Version 6.00 | |||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! | |||||
############################################################################### | |||||
Project: "JackRouter"=".\JackRouter.dsp" - Package Owner=<4> | |||||
Package=<5> | |||||
{{{ | |||||
}}} | |||||
Package=<4> | |||||
{{{ | |||||
}}} | |||||
############################################################################### | |||||
Global: | |||||
Package=<5> | |||||
{{{ | |||||
}}} | |||||
Package=<3> | |||||
{{{ | |||||
}}} | |||||
############################################################################### | |||||
@@ -0,0 +1,174 @@ | |||||
/* | |||||
Copyright (C) 2006 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 _asiosmpl_ | |||||
#define _asiosmpl_ | |||||
#include "asiosys.h" | |||||
// Globals | |||||
static int kBlockFrames = 256; | |||||
static int kNumInputs = 4; | |||||
static int kNumOutputs = 4; | |||||
#if WINDOWS | |||||
#include "jack.h" | |||||
#include "rpc.h" | |||||
#include "rpcndr.h" | |||||
#ifndef COM_NO_WINDOWS_H | |||||
#include <windows.h> | |||||
#include "ole2.h" | |||||
#endif | |||||
#include "combase.h" | |||||
#include "iasiodrv.h" | |||||
#define MAX_PORTS 32 | |||||
#define LONG_SAMPLE 1 | |||||
#define PATH_SEP "\\" | |||||
#include <list> | |||||
#include <string> | |||||
class JackRouter : public IASIO, public CUnknown | |||||
{ | |||||
public: | |||||
JackRouter(LPUNKNOWN pUnk, HRESULT *phr); | |||||
~JackRouter(); | |||||
DECLARE_IUNKNOWN | |||||
//STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \ | |||||
// return GetOwner()->QueryInterface(riid,ppv); \ | |||||
//}; \ | |||||
//STDMETHODIMP_(ULONG) AddRef() { \ | |||||
// return GetOwner()->AddRef(); \ | |||||
//}; \ | |||||
//STDMETHODIMP_(ULONG) Release() { \ | |||||
// return GetOwner()->Release(); \ | |||||
//}; | |||||
// Factory method | |||||
static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); | |||||
// IUnknown | |||||
virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject); | |||||
#else | |||||
#include "asiodrvr.h" | |||||
//--------------------------------------------------------------------------------------------- | |||||
class JackRouter : public AsioDriver | |||||
{ | |||||
public: | |||||
JackRouter(); | |||||
~JackRouter(); | |||||
#endif | |||||
static int process(jack_nframes_t nframes, void* arg); | |||||
static void shutdown(void* arg); | |||||
ASIOBool init(void* sysRef); | |||||
void getDriverName(char *name); // max 32 bytes incl. terminating zero | |||||
long getDriverVersion(); | |||||
void getErrorMessage(char *string); // max 128 bytes incl. | |||||
ASIOError start(); | |||||
ASIOError stop(); | |||||
ASIOError getChannels(long *numInputChannels, long *numOutputChannels); | |||||
ASIOError getLatencies(long *inputLatency, long *outputLatency); | |||||
ASIOError getBufferSize(long *minSize, long *maxSize, | |||||
long *preferredSize, long *granularity); | |||||
ASIOError canSampleRate(ASIOSampleRate sampleRate); | |||||
ASIOError getSampleRate(ASIOSampleRate *sampleRate); | |||||
ASIOError setSampleRate(ASIOSampleRate sampleRate); | |||||
ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); | |||||
ASIOError setClockSource(long index); | |||||
ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); | |||||
ASIOError getChannelInfo(ASIOChannelInfo *info); | |||||
ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, | |||||
long bufferSize, ASIOCallbacks *callbacks); | |||||
ASIOError disposeBuffers(); | |||||
ASIOError controlPanel(); | |||||
ASIOError future(long selector, void *opt); | |||||
ASIOError outputReady(); | |||||
void bufferSwitch(); | |||||
long getMilliSeconds() {return fMilliSeconds;} | |||||
static bool fFirstActivate; | |||||
static std::list<std::pair<std::string, std::string> > fConnections; // Connections list | |||||
private: | |||||
void bufferSwitchX(); | |||||
double fSamplePosition; | |||||
ASIOCallbacks* fCallbacks; | |||||
ASIOTime fAsioTime; | |||||
ASIOTimeStamp fTheSystemTime; | |||||
#ifdef LONG_SAMPLE | |||||
long* fInputBuffers[MAX_PORTS * 2]; | |||||
long* fOutputBuffers[MAX_PORTS * 2]; | |||||
#else | |||||
float* fInputBuffers[MAX_PORTS * 2]; | |||||
float* fOutputBuffers[MAX_PORTS * 2]; | |||||
#endif | |||||
long fInMap[MAX_PORTS]; | |||||
long fOutMap[MAX_PORTS]; | |||||
long fInputLatency; | |||||
long fOutputLatency; | |||||
long fActiveInputs; | |||||
long fActiveOutputs; | |||||
long fToggle; | |||||
long fMilliSeconds; | |||||
bool fActive, fStarted; | |||||
bool fTimeInfoMode, fTcRead; | |||||
char fErrorMessage[128]; | |||||
bool fAutoConnectIn; | |||||
bool fAutoConnectOut; | |||||
// Jack part | |||||
jack_client_t* fClient; | |||||
jack_port_t* fInputPorts[MAX_PORTS]; | |||||
jack_port_t* fOutputPorts[MAX_PORTS]; | |||||
long fBufferSize; | |||||
ASIOSampleRate fSampleRate; | |||||
void AutoConnect(); | |||||
void SaveConnections(); | |||||
void RestoreConnections(); | |||||
}; | |||||
#endif | |||||
@@ -0,0 +1,3 @@ | |||||
This folder contains the sources for ASIO/JACK bridge ASIO driver called "JackRouter". The included project is a Microsoft VC++ 6 one. | |||||
It requires some files (combase.cpp, dllentry.cpp, register.cpp) that are part on the ASIO driver SDK. The produced "JackRouter.dll" file | |||||
has to be registered in the system using the "regsvr32" tool. |
@@ -0,0 +1,315 @@ | |||||
/* | |||||
History : | |||||
01-28-02 : Change the location of temporary files created in write_private_profile_string | |||||
now done in TmpDirectory. | |||||
01-29-02 : Correct bug when the '=' character is not present. | |||||
06-18-02 : Return default value if file does not exist, new write_private_profile_int function. | |||||
*/ | |||||
/***** Routines to read profile strings -- by Joseph J. Graf ******/ | |||||
/***** corrections and improvements -- by D. Fober - Grame ******/ | |||||
/* | |||||
corrections: buffer sizes control | |||||
improvements: behavior more similar to windows | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <string.h> | |||||
#include <stdlib.h> | |||||
#include <errno.h> | |||||
#include <string> | |||||
#include <ctype.h> | |||||
#include "profport.h" /* function prototypes in here */ | |||||
#ifndef WIN32 | |||||
static int read_line (FILE *fp, char *bp, int size); | |||||
static int read_section(FILE *fp, char *section); | |||||
static int read_entry (FILE *fp, char *entry, char *buff, int size); | |||||
static char * read_value (char *buff); | |||||
static int read_int_value (char *buff, int def); | |||||
static char * read_file (char *file); | |||||
static char * str_search (char * buff, char * str, int stopCond); | |||||
/***************************************************************** | |||||
* Function: read_line() | |||||
* Arguments: <FILE *> fp - a pointer to the file to be read from | |||||
* <char *> bp - a pointer to the copy buffer | |||||
* <int> size - size of the copy buffer | |||||
* Returns: the line length if successful -1 otherwise | |||||
******************************************************************/ | |||||
static int read_line(FILE *fp, char *bp, int size) | |||||
{ | |||||
char c = '\0'; | |||||
int i = 0, limit = size-2; | |||||
/* Read one line from the source file */ | |||||
while (((c = getc(fp)) != '\n') && (i < limit)) { | |||||
if (c == EOF) { | |||||
if (!i) return -1; | |||||
else break; | |||||
} | |||||
bp[i++] = c; | |||||
} | |||||
bp[i] = '\0'; | |||||
return i; | |||||
} | |||||
static int read_section (FILE *fp, char *section) | |||||
{ | |||||
char buff[MAX_LINE_LENGTH]; | |||||
char t_section[MAX_LINE_LENGTH]; | |||||
int n, slen; | |||||
sprintf(t_section,"[%s]", section); /* Format the section name */ | |||||
slen = strlen (t_section); | |||||
/* Move through file 1 line at a time until a section is matched or EOF */ | |||||
do { | |||||
n = read_line(fp, buff, MAX_LINE_LENGTH); | |||||
if (n == -1) | |||||
return 0; | |||||
} while (strncmp (buff,t_section, slen)); | |||||
return 1; | |||||
} | |||||
static int read_entry (FILE *fp, char *entry, char *buff, int size) | |||||
{ | |||||
int n, elen = strlen (entry); | |||||
do { | |||||
n = read_line(fp, buff, size); | |||||
if (n == -1) | |||||
return 0; | |||||
else if (*buff == '[') | |||||
return 0; | |||||
} while (strncmp (buff, entry, elen)); | |||||
return 1; | |||||
} | |||||
#define isBlank(c) ((c == ' ') || (c == '\t')) | |||||
static char * read_value (char *buff) | |||||
{ | |||||
char * eq = strrchr (buff,'='); /* Parse out the equal sign */ | |||||
if (eq) { | |||||
eq++; | |||||
while (*eq && isBlank(*eq)) | |||||
eq++; | |||||
// return *eq ? eq : 0; | |||||
return eq; | |||||
} | |||||
return eq; | |||||
} | |||||
#define isSignedDigit(c) (isdigit(c) || (c == '+') || (c == '-')) | |||||
static int read_int_value (char *buff, int def) | |||||
{ | |||||
char * val = read_value (buff); | |||||
char value[20]; int i; | |||||
if (!*val) return def; | |||||
for (i = 0; isSignedDigit(*val) && (i <= 10); i++ ) | |||||
value[i] = *val++; | |||||
value[i] = '\0'; | |||||
return value[0] ? atoi(value) : def; | |||||
} | |||||
static char * read_file (char *file) | |||||
{ | |||||
FILE *fd = fopen (file,"r"); | |||||
int size; char * buff = 0; | |||||
if (!fd) return 0; | |||||
if (fseek (fd, 0, SEEK_END) == -1) goto err; | |||||
size = ftell (fd); | |||||
if (size < 0) goto err; | |||||
if (fseek (fd, 0, SEEK_SET) == -1) goto err; | |||||
buff = (char *) malloc (size+1); | |||||
if (buff) { | |||||
*buff = 0; | |||||
fread (buff, 1, size, fd); | |||||
buff[size] = 0; | |||||
} | |||||
err: | |||||
fclose (fd); | |||||
return buff; | |||||
} | |||||
static char * str_search (char * buff, char * str, int stopCond) | |||||
{ | |||||
char *ptr = buff; | |||||
int len = strlen (str); | |||||
while (*ptr && strncmp (ptr, str, len)) { | |||||
while (*ptr && (*ptr++ != '\n')) | |||||
; | |||||
if (*ptr == stopCond) | |||||
return 0; | |||||
} | |||||
return *ptr ? ptr : 0; | |||||
} | |||||
/************************************************************************** | |||||
* Function: get_private_profile_int() | |||||
* Arguments: <char *> section - the name of the section to search for | |||||
* <char *> entry - the name of the entry to find the value of | |||||
* <int> def - the default value in the event of a failed read | |||||
* <char *> file_name - the name of the .ini file to read from | |||||
* Returns: the value located at entry | |||||
***************************************************************************/ | |||||
int get_private_profile_int(char *section, | |||||
char *entry, int def, char *file_name) | |||||
{ | |||||
FILE *fp = fopen(file_name,"r"); | |||||
char buff[MAX_LINE_LENGTH]; | |||||
if( !fp ) return def; /* Return default value if file does not exist */ | |||||
if (!read_section (fp, section)) goto err; | |||||
if (!read_entry (fp, entry, buff, MAX_LINE_LENGTH)) goto err; | |||||
def = read_int_value (buff, def); | |||||
err: | |||||
fclose (fp); | |||||
return def; | |||||
} | |||||
/************************************************************************** | |||||
* Function: get_private_profile_string() | |||||
* Arguments: <char *> section - the name of the section to search for | |||||
* <char *> entry - the name of the entry to find the value of | |||||
* <char *> def - default string in the event of a failed read | |||||
* <char *> buffer - a pointer to the buffer to copy into | |||||
* <int> buffer_len - the max number of characters to copy | |||||
* <char *> file_name - the name of the .ini file to read from | |||||
* Returns: the number of characters copied into the supplied buffer | |||||
***************************************************************************/ | |||||
int get_private_profile_string(char *section, char *entry, char *def, | |||||
char *buffer, int buffer_len, char *file_name) | |||||
{ | |||||
FILE *fp = fopen (file_name,"r"); | |||||
char buff[MAX_LINE_LENGTH]; | |||||
char *val; | |||||
if( !fp ) goto err; /* Return default value if file does not exist */ | |||||
if (!read_section (fp, section)) goto err; | |||||
if (!read_entry (fp, entry, buff, MAX_LINE_LENGTH)) goto err; | |||||
val = read_value (buff); | |||||
if(val) def = val; | |||||
err: | |||||
if (fp) fclose (fp); | |||||
if (def) { | |||||
strncpy (buffer, def, buffer_len - 1); | |||||
buffer[buffer_len] = '\0'; | |||||
} | |||||
else buffer[buffer_len] = '\0'; | |||||
return strlen (buffer); | |||||
} | |||||
/*************************************************************************** | |||||
* Function: write_private_profile_string() | |||||
* Arguments: <char *> section - the name of the section to search for | |||||
* <char *> entry - the name of the entry to find the value of | |||||
* <char *> buffer - pointer to the buffer that holds the string | |||||
* <char *> file_name - the name of the .ini file to read from | |||||
* Returns: TRUE if successful, otherwise FALSE | |||||
***************************************************************************/ | |||||
int write_private_profile_string(char *section, | |||||
char *entry, char *buffer, char *file_name) | |||||
{ | |||||
char * content = read_file(file_name); | |||||
FILE * fd = fopen(file_name,"w"); | |||||
char t_section[MAX_LINE_LENGTH], *ptr; | |||||
int ret = 0; | |||||
if (!fd) goto end; | |||||
if (!content) { | |||||
fprintf (fd, "[%s]\n%s = %s\n", section, entry, buffer); | |||||
ret = 1; | |||||
goto end; | |||||
} | |||||
sprintf(t_section,"[%s]",section); /* Format the section name */ | |||||
ptr = str_search (content, t_section, 0); /* look for the section start */ | |||||
if (!ptr) { | |||||
/* no such section: add the new section at end of file */ | |||||
fprintf (fd, "%s\n[%s]\n%s = %s\n", content, section, entry, buffer); | |||||
} | |||||
else { | |||||
char * eptr; | |||||
eptr = str_search (ptr, entry, '['); | |||||
if (!eptr) { | |||||
/* no such entry: looks for next section */ | |||||
eptr = str_search (++ptr, "[", 0); | |||||
if (!eptr) { | |||||
/* section is the last one */ | |||||
fprintf (fd, "%s\n%s = %s\n", content, entry, buffer); | |||||
} | |||||
else { | |||||
while (*ptr && (*ptr != '\n')) ptr++; | |||||
*ptr = 0; | |||||
fprintf (fd, "%s\n%s = %s", content, entry, buffer); | |||||
*ptr = '\n'; | |||||
fprintf (fd, "%s", ptr); | |||||
} | |||||
} | |||||
else { | |||||
*eptr++ = 0; | |||||
fprintf (fd, "%s%s = %s", content, entry, buffer); | |||||
while (*eptr && (*eptr != '\n')) eptr++; | |||||
if (eptr) fprintf (fd, "%s", eptr); | |||||
} | |||||
} | |||||
ret = 1; | |||||
end: | |||||
if (content) free(content); | |||||
if (fd) fclose(fd); | |||||
return 0; | |||||
} | |||||
/*************************************************************************** | |||||
* Function: write_private_profile_int() | |||||
* Arguments: <char *> section - the name of the section to search for | |||||
* <char *> entry - the name of the entry to find the value of | |||||
* <int> buffer - the value to be written | |||||
* <char *> file_name - the name of the .ini file to read from | |||||
* Returns: TRUE if successful, otherwise FALSE | |||||
***************************************************************************/ | |||||
int write_private_profile_int(char *section, | |||||
char *entry, int val, char *file_name) | |||||
{ | |||||
char buffer [64]; | |||||
sprintf(buffer, "%d", val); | |||||
return write_private_profile_string (section,entry, buffer, file_name); | |||||
} | |||||
#endif // #ifndef WIN32 | |||||
/************************************************************************** | |||||
* Function: get_private_profile_float() | |||||
* Arguments: <char *> section - the name of the section to search for | |||||
* <char *> entry - the name of the entry to find the value of | |||||
* <float> def - the default value in the event of a failed read | |||||
* <char *> file_name - the name of the .ini file to read from | |||||
* Returns: the value located at entry | |||||
* Warning: The float value to be read must not contain more than 100 digits. | |||||
* Author: CD, 15/11/2006. | |||||
***************************************************************************/ | |||||
#define maxFloatLen 100 | |||||
float get_private_profile_float (char * section, char * entry, float def, char * file_name) | |||||
{ | |||||
float result = def; | |||||
char buffer[ maxFloatLen ], *endptr; | |||||
if ( get_private_profile_string(section, entry, "", buffer, maxFloatLen, file_name) > 0 ) | |||||
{ | |||||
result = (float)strtod(buffer, &endptr); | |||||
if ((result==0) && (endptr==buffer)) | |||||
result = def; | |||||
} | |||||
return result; | |||||
} |
@@ -0,0 +1,37 @@ | |||||
/****************************************************************************** | |||||
PORTABLE ROUTINES FOR WRITING PRIVATE PROFILE STRINGS -- by Joseph J. Graf | |||||
Header file containing prototypes and compile-time configuration. | |||||
[09/05/02] D. Fober - Windows definitions added | |||||
******************************************************************************/ | |||||
#ifndef __profport__ | |||||
#define __profport__ | |||||
#define MAX_LINE_LENGTH 1024 | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
#ifdef WIN32 | |||||
#include "Windows.h" | |||||
#define get_private_profile_int GetPrivateProfileInt | |||||
#define get_private_profile_string GetPrivateProfileString | |||||
#define write_private_profile_string WritePrivateProfileString | |||||
#define write_private_profile_int WritePrivateProfileInt | |||||
#else | |||||
int get_private_profile_int (char * section, char * entry, int def, char * file_name); | |||||
int get_private_profile_string (char * section, char * entry, char * def, char * buffer, int buffer_len, char * file_name); | |||||
int write_private_profile_string (char * section, char * entry, char * buffer, char * file_name); | |||||
int write_private_profile_int (char * section, char * entry, int val, char * file_name); | |||||
#endif | |||||
float get_private_profile_float (char * section, char * entry, float def, char * file_name); | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif //__profport__ |
@@ -0,0 +1,95 @@ | |||||
/* | |||||
psapi.h - Include file for PSAPI.DLL APIs | |||||
Written by Mumit Khan <khan@nanotech.wisc.edu> | |||||
This file is part of a free library for the Win32 API. | |||||
NOTE: This strictly does not belong in the Win32 API since it's | |||||
really part of Platform SDK. However,GDB needs it and we might | |||||
as well provide it here. | |||||
This library 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. | |||||
*/ | |||||
#ifndef _PSAPI_H | |||||
#define _PSAPI_H | |||||
#if __GNUC__ >=3 | |||||
#pragma GCC system_header | |||||
#endif | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
#ifndef RC_INVOKED | |||||
typedef struct _MODULEINFO { | |||||
LPVOID lpBaseOfDll; | |||||
DWORD SizeOfImage; | |||||
LPVOID EntryPoint; | |||||
} MODULEINFO,*LPMODULEINFO; | |||||
typedef struct _PSAPI_WS_WATCH_INFORMATION { | |||||
LPVOID FaultingPc; | |||||
LPVOID FaultingVa; | |||||
} PSAPI_WS_WATCH_INFORMATION,*PPSAPI_WS_WATCH_INFORMATION; | |||||
typedef struct _PROCESS_MEMORY_COUNTERS { | |||||
DWORD cb; | |||||
DWORD PageFaultCount; | |||||
DWORD PeakWorkingSetSize; | |||||
DWORD WorkingSetSize; | |||||
DWORD QuotaPeakPagedPoolUsage; | |||||
DWORD QuotaPagedPoolUsage; | |||||
DWORD QuotaPeakNonPagedPoolUsage; | |||||
DWORD QuotaNonPagedPoolUsage; | |||||
DWORD PagefileUsage; | |||||
DWORD PeakPagefileUsage; | |||||
} PROCESS_MEMORY_COUNTERS,*PPROCESS_MEMORY_COUNTERS; | |||||
/* Grouped by application,not in alphabetical order. */ | |||||
BOOL WINAPI EnumProcesses(DWORD *,DWORD,DWORD *); | |||||
BOOL WINAPI EnumProcessModules(HANDLE,HMODULE *,DWORD,LPDWORD); | |||||
DWORD WINAPI GetModuleBaseNameA(HANDLE,HMODULE,LPSTR,DWORD); | |||||
DWORD WINAPI GetModuleBaseNameW(HANDLE,HMODULE,LPWSTR,DWORD); | |||||
DWORD WINAPI GetModuleFileNameExA(HANDLE,HMODULE,LPSTR,DWORD); | |||||
DWORD WINAPI GetModuleFileNameExW(HANDLE,HMODULE,LPWSTR,DWORD); | |||||
BOOL WINAPI GetModuleInformation(HANDLE,HMODULE,LPMODULEINFO,DWORD); | |||||
BOOL WINAPI EmptyWorkingSet(HANDLE); | |||||
BOOL WINAPI QueryWorkingSet(HANDLE,PVOID,DWORD); | |||||
BOOL WINAPI InitializeProcessForWsWatch(HANDLE); | |||||
BOOL WINAPI GetWsChanges(HANDLE,PPSAPI_WS_WATCH_INFORMATION,DWORD); | |||||
DWORD WINAPI GetMappedFileNameW(HANDLE,LPVOID,LPWSTR,DWORD); | |||||
DWORD WINAPI GetMappedFileNameA(HANDLE,LPVOID,LPSTR,DWORD); | |||||
BOOL WINAPI EnumDeviceDrivers(LPVOID *,DWORD,LPDWORD); | |||||
DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID,LPSTR,DWORD); | |||||
DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID,LPWSTR,DWORD); | |||||
DWORD WINAPI GetDeviceDriverFileNameA(LPVOID,LPSTR,DWORD); | |||||
DWORD WINAPI GetDeviceDriverFileNameW(LPVOID,LPWSTR,DWORD); | |||||
BOOL WINAPI GetProcessMemoryInfo(HANDLE,PPROCESS_MEMORY_COUNTERS,DWORD); | |||||
#endif /* not RC_INVOKED */ | |||||
#ifdef UNICODE | |||||
#define GetModuleBaseName GetModuleBaseNameW | |||||
#define GetModuleFileNameEx GetModuleFileNameExW | |||||
#define GetMappedFilenameEx GetMappedFilenameExW | |||||
#define GetDeviceDriverBaseName GetDeviceDriverBaseNameW | |||||
#define GetDeviceDriverFileName GetDeviceDriverFileNameW | |||||
#else | |||||
#define GetModuleBaseName GetModuleBaseNameA | |||||
#define GetModuleFileNameEx GetModuleFileNameExA | |||||
#define GetMappedFilenameEx GetMappedFilenameExA | |||||
#define GetDeviceDriverBaseName GetDeviceDriverBaseNameA | |||||
#define GetDeviceDriverFileName GetDeviceDriverFileNameA | |||||
#endif | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* _PSAPI_H */ | |||||
@@ -0,0 +1,15 @@ | |||||
//{{NO_DEPENDENCIES}} | |||||
// Microsoft Developer Studio generated include file. | |||||
// Used by resource.rc | |||||
// | |||||
// Next default values for new objects | |||||
// | |||||
#ifdef APSTUDIO_INVOKED | |||||
#ifndef APSTUDIO_READONLY_SYMBOLS | |||||
#define _APS_NEXT_RESOURCE_VALUE 102 | |||||
#define _APS_NEXT_COMMAND_VALUE 40001 | |||||
#define _APS_NEXT_CONTROL_VALUE 1000 | |||||
#define _APS_NEXT_SYMED_VALUE 101 | |||||
#endif | |||||
#endif |
@@ -0,0 +1,109 @@ | |||||
//Microsoft Developer Studio generated resource script. | |||||
// | |||||
#include "resource.h" | |||||
#define APSTUDIO_READONLY_SYMBOLS | |||||
///////////////////////////////////////////////////////////////////////////// | |||||
// | |||||
// Generated from the TEXTINCLUDE 2 resource. | |||||
// | |||||
#include "afxres.h" | |||||
///////////////////////////////////////////////////////////////////////////// | |||||
#undef APSTUDIO_READONLY_SYMBOLS | |||||
///////////////////////////////////////////////////////////////////////////// | |||||
// French (France) resources | |||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) | |||||
#ifdef _WIN32 | |||||
LANGUAGE LANG_FRENCH, SUBLANG_FRENCH | |||||
#pragma code_page(1252) | |||||
#endif //_WIN32 | |||||
#ifndef _MAC | |||||
///////////////////////////////////////////////////////////////////////////// | |||||
// | |||||
// Version | |||||
// | |||||
VS_VERSION_INFO VERSIONINFO | |||||
FILEVERSION 0,2,0,0 | |||||
PRODUCTVERSION 0,2,0,0 | |||||
FILEFLAGSMASK 0x3fL | |||||
#ifdef _DEBUG | |||||
FILEFLAGS 0x1L | |||||
#else | |||||
FILEFLAGS 0x0L | |||||
#endif | |||||
FILEOS 0x40004L | |||||
FILETYPE 0x2L | |||||
FILESUBTYPE 0x0L | |||||
BEGIN | |||||
BLOCK "StringFileInfo" | |||||
BEGIN | |||||
BLOCK "040c04b0" | |||||
BEGIN | |||||
VALUE "Comments", "\0" | |||||
VALUE "CompanyName", "Grame\0" | |||||
VALUE "FileDescription", "JackRouter ASIO driver\0" | |||||
VALUE "FileVersion", "0, 2, 0, 0\0" | |||||
VALUE "InternalName", "JackRouter\0" | |||||
VALUE "LegalCopyright", "Copyright Grame © 2006-2009\0" | |||||
VALUE "LegalTrademarks", "\0" | |||||
VALUE "OriginalFilename", "JackRouter.dll\0" | |||||
VALUE "PrivateBuild", "\0" | |||||
VALUE "ProductName", "JackRouter\0" | |||||
VALUE "ProductVersion", "0, 2, 0, 0\0" | |||||
VALUE "SpecialBuild", "\0" | |||||
END | |||||
END | |||||
BLOCK "VarFileInfo" | |||||
BEGIN | |||||
VALUE "Translation", 0x40c, 1200 | |||||
END | |||||
END | |||||
#endif // !_MAC | |||||
#ifdef APSTUDIO_INVOKED | |||||
///////////////////////////////////////////////////////////////////////////// | |||||
// | |||||
// TEXTINCLUDE | |||||
// | |||||
1 TEXTINCLUDE DISCARDABLE | |||||
BEGIN | |||||
"resource.h\0" | |||||
END | |||||
2 TEXTINCLUDE DISCARDABLE | |||||
BEGIN | |||||
"#include ""afxres.h""\r\n" | |||||
"\0" | |||||
END | |||||
3 TEXTINCLUDE DISCARDABLE | |||||
BEGIN | |||||
"\r\n" | |||||
"\0" | |||||
END | |||||
#endif // APSTUDIO_INVOKED | |||||
#endif // French (France) resources | |||||
///////////////////////////////////////////////////////////////////////////// | |||||
#ifndef APSTUDIO_INVOKED | |||||
///////////////////////////////////////////////////////////////////////////// | |||||
// | |||||
// Generated from the TEXTINCLUDE 3 resource. | |||||
// | |||||
///////////////////////////////////////////////////////////////////////////// | |||||
#endif // not APSTUDIO_INVOKED | |||||