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