jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

841 lines
25KB

  1. /*
  2. Copyright (C) 2006 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #ifdef WIN32
  16. #pragma warning (disable : 4786)
  17. #endif
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <assert.h>
  21. #include <process.h>
  22. #include "JackRouter.h"
  23. #include "profport.h"
  24. /*
  25. 08/07/2007 SL : USe jack_client_open instead of jack_client_new (automatic client renaming).
  26. 09/08/2007 SL : Add JackRouter.ini parameter file.
  27. 09/20/2007 SL : Better error report in DllRegisterServer (for Vista).
  28. 09/27/2007 SL : Add AUDO_CONNECT property in JackRouter.ini file.
  29. 10/10/2007 SL : Use ASIOSTInt32LSB instead of ASIOSTInt16LSB.
  30. */
  31. //------------------------------------------------------------------------------------------
  32. // extern
  33. void getNanoSeconds(ASIOTimeStamp *time);
  34. // local
  35. double AsioSamples2double (ASIOSamples* samples);
  36. static const double twoRaisedTo32 = 4294967296.;
  37. static const double twoRaisedTo32Reciprocal = 1. / twoRaisedTo32;
  38. //------------------------------------------------------------------------------------------
  39. // on windows, we do the COM stuff.
  40. #if WINDOWS
  41. #include "windows.h"
  42. #include "mmsystem.h"
  43. #include "psapi.h"
  44. using namespace std;
  45. // class id.
  46. // {838FE50A-C1AB-4b77-B9B6-0A40788B53F3}
  47. CLSID IID_ASIO_DRIVER = { 0x838fe50a, 0xc1ab, 0x4b77, { 0xb9, 0xb6, 0xa, 0x40, 0x78, 0x8b, 0x53, 0xf3 } };
  48. CFactoryTemplate g_Templates[1] = {
  49. {L"ASIOJACK", &IID_ASIO_DRIVER, JackRouter::CreateInstance}
  50. };
  51. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  52. CUnknown* JackRouter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
  53. {
  54. return (CUnknown*)new JackRouter(pUnk,phr);
  55. };
  56. STDMETHODIMP JackRouter::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
  57. {
  58. if (riid == IID_ASIO_DRIVER) {
  59. return GetInterface(this, ppv);
  60. }
  61. return CUnknown::NonDelegatingQueryInterface(riid, ppv);
  62. }
  63. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  64. // Register ASIO Driver
  65. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  66. extern LONG RegisterAsioDriver(CLSID,char *,char *,char *,char *);
  67. extern LONG UnregisterAsioDriver(CLSID,char *,char *);
  68. //
  69. // Server registration, called on REGSVR32.EXE "the dllname.dll"
  70. //
  71. HRESULT _stdcall DllRegisterServer()
  72. {
  73. LONG rc;
  74. char errstr[128];
  75. rc = RegisterAsioDriver (IID_ASIO_DRIVER,"JackRouter.dll","JackRouter","JackRouter","Apartment");
  76. if (rc) {
  77. memset(errstr,0,128);
  78. sprintf(errstr,"Register Server failed ! (%d)",rc);
  79. MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"JackRouter",MB_OK);
  80. return -1;
  81. }
  82. return S_OK;
  83. }
  84. //
  85. // Server unregistration
  86. //
  87. HRESULT _stdcall DllUnregisterServer()
  88. {
  89. LONG rc;
  90. char errstr[128];
  91. rc = UnregisterAsioDriver (IID_ASIO_DRIVER,"JackRouter.dll","JackRouter");
  92. if (rc) {
  93. memset(errstr,0,128);
  94. sprintf(errstr,"Unregister Server failed ! (%d)",rc);
  95. MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"JackRouter",MB_OK);
  96. return -1;
  97. }
  98. return S_OK;
  99. }
  100. // Globals
  101. list<pair<string, string> > JackRouter::fConnections;
  102. bool JackRouter::fFirstActivate = true;
  103. //------------------------------------------------------------------------------------------
  104. //------------------------------------------------------------------------------------------
  105. JackRouter::JackRouter (LPUNKNOWN pUnk, HRESULT *phr)
  106. : CUnknown("ASIOJACK", pUnk, phr)
  107. //------------------------------------------------------------------------------------------
  108. #else
  109. // when not on windows, we derive from AsioDriver
  110. JackRouter::JackRouter() : AsioDriver()
  111. #endif
  112. {
  113. long i;
  114. fSamplePosition = 0;
  115. fActive = false;
  116. fStarted = false;
  117. fTimeInfoMode = false;
  118. fTcRead = false;
  119. fClient = NULL;
  120. fAutoConnectIn = true;
  121. fAutoConnectOut = true;
  122. for (i = 0; i < kNumInputs; i++) {
  123. fInputBuffers[i] = 0;
  124. fInputPorts[i] = 0;
  125. fInMap[i] = 0;
  126. }
  127. for (i = 0; i < kNumOutputs; i++) {
  128. fOutputBuffers[i] = 0;
  129. fOutputPorts[i] = 0;
  130. fOutMap[i] = 0;
  131. }
  132. fCallbacks = 0;
  133. fActiveInputs = fActiveOutputs = 0;
  134. fToggle = 0;
  135. fBufferSize = 512;
  136. fSampleRate = 44100;
  137. printf("Constructor\n");
  138. // Use "jackrouter.ini" parameters if available
  139. HMODULE handle = LoadLibrary("JackRouter.dll");
  140. if (handle) {
  141. // Get JackRouter.dll path
  142. char dllName[512];
  143. string confPath;
  144. DWORD res = GetModuleFileName(handle, dllName, 512);
  145. // Compute .ini file path
  146. string fullPath = dllName;
  147. int lastPos = fullPath.find_last_of(PATH_SEP);
  148. string dllFolder = fullPath.substr(0, lastPos);
  149. confPath = dllFolder + PATH_SEP + "JackRouter.ini";
  150. // Get parameters
  151. kNumInputs = get_private_profile_int("IO", "input", 2, confPath.c_str());
  152. kNumOutputs = get_private_profile_int("IO", "output", 2, confPath.c_str());
  153. fAutoConnectIn = get_private_profile_int("AUTO_CONNECT", "input", 1, confPath.c_str());
  154. fAutoConnectOut = get_private_profile_int("AUTO_CONNECT", "output", 1, confPath.c_str());
  155. FreeLibrary(handle);
  156. } else {
  157. printf("LoadLibrary error\n");
  158. }
  159. }
  160. //------------------------------------------------------------------------------------------
  161. JackRouter::~JackRouter()
  162. {
  163. stop ();
  164. disposeBuffers ();
  165. printf("Destructor\n");
  166. jack_client_close(fClient);
  167. }
  168. //------------------------------------------------------------------------------------------
  169. #include <windows.h>
  170. #include <stdio.h>
  171. #include <tchar.h>
  172. #include "psapi.h"
  173. static bool GetEXEName(DWORD dwProcessID, char* name)
  174. {
  175. DWORD aProcesses [1024], cbNeeded, cProcesses;
  176. unsigned int i;
  177. // Enumerate all processes
  178. if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
  179. return false;
  180. // Calculate how many process identifiers were returned.
  181. cProcesses = cbNeeded / sizeof(DWORD);
  182. TCHAR szEXEName[MAX_PATH];
  183. // Loop through all process to find the one that matches
  184. // the one we are looking for
  185. for (i = 0; i < cProcesses; i++) {
  186. if (aProcesses [i] == dwProcessID) {
  187. // Get a handle to the process
  188. HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
  189. PROCESS_VM_READ, FALSE, dwProcessID);
  190. // Get the process name
  191. if (NULL != hProcess) {
  192. HMODULE hMod;
  193. DWORD cbNeeded;
  194. if(EnumProcessModules(hProcess, &hMod,
  195. sizeof(hMod), &cbNeeded)) {
  196. //Get the name of the exe file
  197. GetModuleBaseName(hProcess, hMod, szEXEName,
  198. sizeof(szEXEName)/sizeof(TCHAR));
  199. int len = strlen((char*)szEXEName) - 4; // remove ".exe"
  200. strncpy(name, (char*)szEXEName, len);
  201. name[len] = '\0';
  202. return true;
  203. }
  204. }
  205. }
  206. }
  207. return false;
  208. }
  209. //------------------------------------------------------------------------------------------
  210. static inline float ClipFloat(float sample)
  211. {
  212. return (sample < -1.0f) ? -1.0f : (sample > 1.0f) ? 1.0f : sample;
  213. }
  214. //------------------------------------------------------------------------------------------
  215. void JackRouter::shutdown(void* arg)
  216. {
  217. JackRouter* driver = (JackRouter*)arg;
  218. /*
  219. //exit(1);
  220. char errstr[128];
  221. memset(errstr,0,128);
  222. sprintf(errstr,"JACK server has quitted");
  223. MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"JackRouter",MB_OK);
  224. */
  225. }
  226. //------------------------------------------------------------------------------------------
  227. int JackRouter::process(jack_nframes_t nframes, void* arg)
  228. {
  229. JackRouter* driver = (JackRouter*)arg;
  230. int i,j;
  231. int pos = (driver->fToggle) ? 0 : driver->fBufferSize ;
  232. for (i = 0; i < driver->fActiveInputs; i++) {
  233. #ifdef LONG_SAMPLE
  234. float* buffer = (float*)jack_port_get_buffer(driver->fInputPorts[i], nframes);
  235. long* in = driver->fInputBuffers[i] + pos;
  236. for (j = 0; j < nframes; j++) {
  237. in[j] = buffer[j] * float(0x7fffffff);
  238. }
  239. #else
  240. memcpy(driver->fInputBuffers[i] + pos,
  241. jack_port_get_buffer(driver->fInputPorts[i], nframes),
  242. nframes * sizeof(float));
  243. #endif
  244. }
  245. driver->bufferSwitch();
  246. for (i = 0; i < driver->fActiveOutputs; i++) {
  247. #ifdef LONG_SAMPLE
  248. float* buffer = (float*)jack_port_get_buffer(driver->fOutputPorts[i], nframes);
  249. long* out = driver->fOutputBuffers[i] + pos;
  250. float gain = 1.f/float(0x7fffffff);
  251. for (j = 0; j < nframes; j++) {
  252. buffer[j] = out[j] * gain;
  253. }
  254. #else
  255. memcpy(jack_port_get_buffer(driver->fOutputPorts[i], nframes),
  256. driver->fOutputBuffers[i] + pos,
  257. nframes * sizeof(float));
  258. #endif
  259. }
  260. return 0;
  261. }
  262. //------------------------------------------------------------------------------------------
  263. void JackRouter::getDriverName(char *name)
  264. {
  265. strcpy (name, "JackRouter");
  266. }
  267. //------------------------------------------------------------------------------------------
  268. long JackRouter::getDriverVersion()
  269. {
  270. return 0x00000001L;
  271. }
  272. //------------------------------------------------------------------------------------------
  273. void JackRouter::getErrorMessage(char *string)
  274. {
  275. strcpy (string, fErrorMessage);
  276. }
  277. //------------------------------------------------------------------------------------------
  278. ASIOBool JackRouter::init(void* sysRef)
  279. {
  280. char name[MAX_PATH];
  281. sysRef = sysRef;
  282. if (fActive)
  283. return true;
  284. HANDLE win = (HANDLE)sysRef;
  285. int my_pid = _getpid();
  286. if (!GetEXEName(my_pid, name)) { // If getting the .exe name fails, takes a generic one.
  287. _snprintf(name, sizeof(name) - 1, "JackRouter_%d", my_pid);
  288. }
  289. if (fClient) {
  290. printf("Error: jack client still present...\n");
  291. return true;
  292. }
  293. fClient = jack_client_open(name, JackNullOption, NULL);
  294. if (fClient == NULL) {
  295. strcpy (fErrorMessage, "Open error: is jack server running?");
  296. printf("Open error: is jack server running?\n");
  297. return false;
  298. }
  299. fBufferSize = jack_get_buffer_size(fClient);
  300. fSampleRate = jack_get_sample_rate(fClient);
  301. jack_set_process_callback(fClient, process, this);
  302. jack_on_shutdown(fClient, shutdown, this);
  303. fInputLatency = fBufferSize; // typically
  304. fOutputLatency = fBufferSize * 2;
  305. fMilliSeconds = (long)((double)(fBufferSize * 1000) / fSampleRate);
  306. // Typically fBufferSize * 2; try to get 1 by offering direct buffer
  307. // access, and using asioPostOutput for lower latency
  308. printf("Init ASIO Jack\n");
  309. fActive = true;
  310. return true;
  311. }
  312. //------------------------------------------------------------------------------------------
  313. ASIOError JackRouter::start()
  314. {
  315. if (fCallbacks) {
  316. fSamplePosition = 0;
  317. fTheSystemTime.lo = fTheSystemTime.hi = 0;
  318. fToggle = 0;
  319. fStarted = true;
  320. printf("Start ASIO Jack\n");
  321. if (jack_activate(fClient) == 0) {
  322. if (fFirstActivate) {
  323. AutoConnect();
  324. fFirstActivate = false;
  325. } else {
  326. RestoreConnections();
  327. }
  328. return ASE_OK;
  329. } else {
  330. return ASE_NotPresent;
  331. }
  332. }
  333. return ASE_NotPresent;
  334. }
  335. //------------------------------------------------------------------------------------------
  336. ASIOError JackRouter::stop()
  337. {
  338. fStarted = false;
  339. printf("Stop ASIO Jack\n");
  340. SaveConnections();
  341. jack_deactivate(fClient);
  342. return ASE_OK;
  343. }
  344. //------------------------------------------------------------------------------------------
  345. ASIOError JackRouter::getChannels(long *numInputChannels, long *numOutputChannels)
  346. {
  347. *numInputChannels = kNumInputs;
  348. *numOutputChannels = kNumOutputs;
  349. return ASE_OK;
  350. }
  351. //------------------------------------------------------------------------------------------
  352. ASIOError JackRouter::getLatencies(long *_inputLatency, long *_outputLatency)
  353. {
  354. *_inputLatency = fInputLatency;
  355. *_outputLatency = fOutputLatency;
  356. return ASE_OK;
  357. }
  358. //------------------------------------------------------------------------------------------
  359. ASIOError JackRouter::getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity)
  360. {
  361. *minSize = *maxSize = *preferredSize = fBufferSize; // allow this size only
  362. *granularity = 0;
  363. return ASE_OK;
  364. }
  365. //------------------------------------------------------------------------------------------
  366. ASIOError JackRouter::canSampleRate(ASIOSampleRate sampleRate)
  367. {
  368. return (sampleRate == fSampleRate) ? ASE_OK : ASE_NoClock;
  369. }
  370. //------------------------------------------------------------------------------------------
  371. ASIOError JackRouter::getSampleRate(ASIOSampleRate *sampleRate)
  372. {
  373. *sampleRate = fSampleRate;
  374. return ASE_OK;
  375. }
  376. //------------------------------------------------------------------------------------------
  377. ASIOError JackRouter::setSampleRate(ASIOSampleRate sampleRate)
  378. {
  379. return (sampleRate == fSampleRate) ? ASE_OK : ASE_NoClock;
  380. }
  381. //------------------------------------------------------------------------------------------
  382. ASIOError JackRouter::getClockSources(ASIOClockSource *clocks, long *numSources)
  383. {
  384. // Internal
  385. if (clocks && numSources) {
  386. clocks->index = 0;
  387. clocks->associatedChannel = -1;
  388. clocks->associatedGroup = -1;
  389. clocks->isCurrentSource = ASIOTrue;
  390. strcpy(clocks->name, "Internal");
  391. *numSources = 1;
  392. return ASE_OK;
  393. } else {
  394. return ASE_InvalidParameter;
  395. }
  396. }
  397. //------------------------------------------------------------------------------------------
  398. ASIOError JackRouter::setClockSource(long index)
  399. {
  400. if (!index) {
  401. fAsioTime.timeInfo.flags |= kClockSourceChanged;
  402. return ASE_OK;
  403. } else {
  404. return ASE_NotPresent;
  405. }
  406. }
  407. //------------------------------------------------------------------------------------------
  408. ASIOError JackRouter::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)
  409. {
  410. tStamp->lo = fTheSystemTime.lo;
  411. tStamp->hi = fTheSystemTime.hi;
  412. if (fSamplePosition >= twoRaisedTo32) {
  413. sPos->hi = (unsigned long)(fSamplePosition * twoRaisedTo32Reciprocal);
  414. sPos->lo = (unsigned long)(fSamplePosition - (sPos->hi * twoRaisedTo32));
  415. } else {
  416. sPos->hi = 0;
  417. sPos->lo = (unsigned long)fSamplePosition;
  418. }
  419. return ASE_OK;
  420. }
  421. //------------------------------------------------------------------------------------------
  422. ASIOError JackRouter::getChannelInfo(ASIOChannelInfo *info)
  423. {
  424. if (info->channel < 0 || (info->isInput ? info->channel >= kNumInputs : info->channel >= kNumOutputs))
  425. return ASE_InvalidParameter;
  426. #ifdef LONG_SAMPLE
  427. info->type = ASIOSTInt32LSB;
  428. #else
  429. info->type = ASIOSTFloat32LSB;
  430. #endif
  431. info->channelGroup = 0;
  432. info->isActive = ASIOFalse;
  433. long i;
  434. char buf[32];
  435. if (info->isInput) {
  436. for (i = 0; i < fActiveInputs; i++) {
  437. if (fInMap[i] == info->channel) {
  438. info->isActive = ASIOTrue;
  439. //_snprintf(buf, sizeof(buf) - 1, "Jack::In%d ", info->channel);
  440. //strcpy(info->name, buf);
  441. //strcpy(info->name, jack_port_name(fInputPorts[i]));
  442. break;
  443. }
  444. }
  445. _snprintf(buf, sizeof(buf) - 1, "In%d ", info->channel);
  446. strcpy(info->name, buf);
  447. } else {
  448. for (i = 0; i < fActiveOutputs; i++) {
  449. if (fOutMap[i] == info->channel) { //NOT USED !!
  450. info->isActive = ASIOTrue;
  451. //_snprintf(buf, sizeof(buf) - 1, "Jack::Out%d ", info->channel);
  452. //strcpy(info->name, buf);
  453. //strcpy(info->name, jack_port_name(fOutputPorts[i]));
  454. break;
  455. }
  456. }
  457. _snprintf(buf, sizeof(buf) - 1, "Out%d ", info->channel);
  458. strcpy(info->name, buf);
  459. }
  460. return ASE_OK;
  461. }
  462. //------------------------------------------------------------------------------------------
  463. ASIOError JackRouter::createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
  464. long bufferSize, ASIOCallbacks *callbacks)
  465. {
  466. ASIOBufferInfo *info = bufferInfos;
  467. long i;
  468. bool notEnoughMem = false;
  469. char buf[256];
  470. fActiveInputs = 0;
  471. fActiveOutputs = 0;
  472. for (i = 0; i < numChannels; i++, info++) {
  473. if (info->isInput) {
  474. if (info->channelNum < 0 || info->channelNum >= kNumInputs)
  475. goto error;
  476. fInMap[fActiveInputs] = info->channelNum;
  477. #ifdef LONG_SAMPLE
  478. fInputBuffers[fActiveInputs] = new long[fBufferSize * 2]; // double buffer
  479. #else
  480. fInputBuffers[fActiveInputs] = new float[fBufferSize * 2]; // double buffer
  481. #endif
  482. if (fInputBuffers[fActiveInputs]) {
  483. info->buffers[0] = fInputBuffers[fActiveInputs];
  484. info->buffers[1] = fInputBuffers[fActiveInputs] + fBufferSize;
  485. } else {
  486. info->buffers[0] = info->buffers[1] = 0;
  487. notEnoughMem = true;
  488. }
  489. _snprintf(buf, sizeof(buf) - 1, "in%d", fActiveInputs + 1);
  490. fInputPorts[fActiveInputs]
  491. = jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput,0);
  492. if (fInputPorts[fActiveInputs] == NULL)
  493. goto error;
  494. fActiveInputs++;
  495. if (fActiveInputs > kNumInputs) {
  496. error:
  497. disposeBuffers();
  498. return ASE_InvalidParameter;
  499. }
  500. } else { // output
  501. if (info->channelNum < 0 || info->channelNum >= kNumOutputs)
  502. goto error;
  503. fOutMap[fActiveOutputs] = info->channelNum;
  504. #ifdef LONG_SAMPLE
  505. fOutputBuffers[fActiveOutputs] = new long[fBufferSize * 2]; // double buffer
  506. #else
  507. fOutputBuffers[fActiveOutputs] = new float[fBufferSize * 2]; // double buffer
  508. #endif
  509. if (fOutputBuffers[fActiveOutputs]) {
  510. info->buffers[0] = fOutputBuffers[fActiveOutputs];
  511. info->buffers[1] = fOutputBuffers[fActiveOutputs] + fBufferSize;
  512. } else {
  513. info->buffers[0] = info->buffers[1] = 0;
  514. notEnoughMem = true;
  515. }
  516. _snprintf(buf, sizeof(buf) - 1, "out%d", fActiveOutputs + 1);
  517. fOutputPorts[fActiveOutputs]
  518. = jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput,0);
  519. if (fOutputPorts[fActiveOutputs] == NULL)
  520. goto error;
  521. fActiveOutputs++;
  522. if (fActiveOutputs > kNumOutputs) {
  523. fActiveOutputs--;
  524. disposeBuffers();
  525. return ASE_InvalidParameter;
  526. }
  527. }
  528. }
  529. if (notEnoughMem) {
  530. disposeBuffers();
  531. return ASE_NoMemory;
  532. }
  533. this->fCallbacks = callbacks;
  534. if (callbacks->asioMessage (kAsioSupportsTimeInfo, 0, 0, 0)) {
  535. fTimeInfoMode = true;
  536. fAsioTime.timeInfo.speed = 1.;
  537. fAsioTime.timeInfo.systemTime.hi = fAsioTime.timeInfo.systemTime.lo = 0;
  538. fAsioTime.timeInfo.samplePosition.hi = fAsioTime.timeInfo.samplePosition.lo = 0;
  539. fAsioTime.timeInfo.sampleRate = fSampleRate;
  540. fAsioTime.timeInfo.flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid;
  541. fAsioTime.timeCode.speed = 1.;
  542. fAsioTime.timeCode.timeCodeSamples.lo = fAsioTime.timeCode.timeCodeSamples.hi = 0;
  543. fAsioTime.timeCode.flags = kTcValid | kTcRunning ;
  544. } else {
  545. fTimeInfoMode = false;
  546. }
  547. return ASE_OK;
  548. }
  549. //---------------------------------------------------------------------------------------------
  550. ASIOError JackRouter::disposeBuffers()
  551. {
  552. long i;
  553. fCallbacks = 0;
  554. stop();
  555. for (i = 0; i < fActiveInputs; i++) {
  556. delete[] fInputBuffers[i];
  557. jack_port_unregister(fClient, fInputPorts[i]);
  558. }
  559. fActiveInputs = 0;
  560. for (i = 0; i < fActiveOutputs; i++) {
  561. delete[] fOutputBuffers[i];
  562. jack_port_unregister(fClient, fOutputPorts[i]);
  563. }
  564. fActiveOutputs = 0;
  565. return ASE_OK;
  566. }
  567. //---------------------------------------------------------------------------------------------
  568. ASIOError JackRouter::controlPanel()
  569. {
  570. return ASE_NotPresent;
  571. }
  572. //---------------------------------------------------------------------------------------------
  573. ASIOError JackRouter::future(long selector, void* opt) // !!! check properties
  574. {
  575. ASIOTransportParameters* tp = (ASIOTransportParameters*)opt;
  576. switch (selector)
  577. {
  578. case kAsioEnableTimeCodeRead: fTcRead = true; return ASE_SUCCESS;
  579. case kAsioDisableTimeCodeRead: fTcRead = false; return ASE_SUCCESS;
  580. case kAsioSetInputMonitor: return ASE_SUCCESS; // for testing!!!
  581. case kAsioCanInputMonitor: return ASE_SUCCESS; // for testing!!!
  582. case kAsioCanTimeInfo: return ASE_SUCCESS;
  583. case kAsioCanTimeCode: return ASE_SUCCESS;
  584. }
  585. return ASE_NotPresent;
  586. }
  587. //--------------------------------------------------------------------------------------------------------
  588. // private methods
  589. //--------------------------------------------------------------------------------------------------------
  590. //---------------------------------------------------------------------------------------------
  591. void JackRouter::bufferSwitch()
  592. {
  593. if (fStarted && fCallbacks) {
  594. getNanoSeconds(&fTheSystemTime); // latch system time
  595. fSamplePosition += fBufferSize;
  596. if (fTimeInfoMode) {
  597. bufferSwitchX ();
  598. } else {
  599. fCallbacks->bufferSwitch (fToggle, ASIOFalse);
  600. }
  601. fToggle = fToggle ? 0 : 1;
  602. }
  603. }
  604. //---------------------------------------------------------------------------------------------
  605. // asio2 buffer switch
  606. void JackRouter::bufferSwitchX ()
  607. {
  608. getSamplePosition (&fAsioTime.timeInfo.samplePosition, &fAsioTime.timeInfo.systemTime);
  609. long offset = fToggle ? fBufferSize : 0;
  610. if (fTcRead) {
  611. // Create a fake time code, which is 10 minutes ahead of the card's sample position
  612. // Please note that for simplicity here time code will wrap after 32 bit are reached
  613. fAsioTime.timeCode.timeCodeSamples.lo = fAsioTime.timeInfo.samplePosition.lo + 600.0 * fSampleRate;
  614. fAsioTime.timeCode.timeCodeSamples.hi = 0;
  615. }
  616. fCallbacks->bufferSwitchTimeInfo (&fAsioTime, fToggle, ASIOFalse);
  617. fAsioTime.timeInfo.flags &= ~(kSampleRateChanged | kClockSourceChanged);
  618. }
  619. //---------------------------------------------------------------------------------------------
  620. ASIOError JackRouter::outputReady()
  621. {
  622. return ASE_NotPresent;
  623. }
  624. //---------------------------------------------------------------------------------------------
  625. double AsioSamples2double(ASIOSamples* samples)
  626. {
  627. double a = (double)(samples->lo);
  628. if (samples->hi)
  629. a += (double)(samples->hi) * twoRaisedTo32;
  630. return a;
  631. }
  632. //---------------------------------------------------------------------------------------------
  633. void getNanoSeconds(ASIOTimeStamp* ts)
  634. {
  635. double nanoSeconds = (double)((unsigned long)timeGetTime ()) * 1000000.;
  636. ts->hi = (unsigned long)(nanoSeconds / twoRaisedTo32);
  637. ts->lo = (unsigned long)(nanoSeconds - (ts->hi * twoRaisedTo32));
  638. }
  639. //------------------------------------------------------------------------
  640. void JackRouter::SaveConnections()
  641. {
  642. const char** connections;
  643. int i;
  644. for (i = 0; i < fActiveInputs; ++i) {
  645. if (fInputPorts[i] && (connections = jack_port_get_connections(fInputPorts[i])) != 0) {
  646. for (int j = 0; connections[j]; j++) {
  647. fConnections.push_back(make_pair(connections[j], jack_port_name(fInputPorts[i])));
  648. }
  649. jack_free(connections);
  650. }
  651. }
  652. for (i = 0; i < fActiveOutputs; ++i) {
  653. if (fOutputPorts[i] && (connections = jack_port_get_connections(fOutputPorts[i])) != 0) {
  654. for (int j = 0; connections[j]; j++) {
  655. fConnections.push_back(make_pair(jack_port_name(fOutputPorts[i]), connections[j]));
  656. }
  657. jack_free(connections);
  658. }
  659. }
  660. }
  661. //------------------------------------------------------------------------
  662. void JackRouter::RestoreConnections()
  663. {
  664. list<pair<string, string> >::const_iterator it;
  665. for (it = fConnections.begin(); it != fConnections.end(); it++) {
  666. pair<string, string> connection = *it;
  667. jack_connect(fClient, connection.first.c_str(), connection.second.c_str());
  668. }
  669. fConnections.clear();
  670. }
  671. //------------------------------------------------------------------------------------------
  672. void JackRouter::AutoConnect()
  673. {
  674. const char** ports;
  675. if ((ports = jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsOutput)) == NULL) {
  676. printf("Cannot find any physical capture ports\n");
  677. } else {
  678. if (fAutoConnectIn) {
  679. for (int i = 0; i < fActiveInputs; i++) {
  680. if (!ports[i]) {
  681. printf("source port is null i = %ld\n", i);
  682. break;
  683. } else if (jack_connect(fClient, ports[i], jack_port_name(fInputPorts[i])) != 0) {
  684. printf("Cannot connect input ports\n");
  685. }
  686. }
  687. }
  688. jack_free(ports);
  689. }
  690. if ((ports = jack_get_ports(fClient, NULL, NULL, JackPortIsPhysical | JackPortIsInput)) == NULL) {
  691. printf("Cannot find any physical playback ports");
  692. } else {
  693. if (fAutoConnectOut) {
  694. for (int i = 0; i < fActiveOutputs; i++) {
  695. if (!ports[i]){
  696. printf("destination port is null i = %ld\n", i);
  697. break;
  698. } else if (jack_connect(fClient, jack_port_name(fOutputPorts[i]), ports[i]) != 0) {
  699. printf("Cannot connect output ports\n");
  700. }
  701. }
  702. }
  703. jack_free(ports);
  704. }
  705. }