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.

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