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. | |||
*/ | |||
#define JACK_WEAK_EXPORT __attribute__((weak)) | |||
#else | |||
#else | |||
#define JACK_WEAK_EXPORT | |||
/* Add other things here for non-gcc platforms */ | |||
#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 | |||