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.

662 lines
17KB

  1. /* SpiralSound
  2. * Copyleft (C) 2001 David Griffiths <dave@pawfal.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <stdio.h>
  19. #include <limits.h>
  20. #include <math.h>
  21. #include "JackPlugin.h"
  22. #include "JackPluginGUI.h"
  23. #include "SpiralIcon.xpm"
  24. using namespace std;
  25. int JackClient::JackProcessInstanceID = -1;
  26. int JackPlugin::JackInstanceCount = 0;
  27. /////////////////////////////////////////////////////////////////////////////////////////////
  28. inline void JackClient::JackProcess_i(jack_nframes_t nframes)
  29. {
  30. SetBufferSize(nframes);
  31. for (int n=0; n<GetJackInputCount(); n++)
  32. {
  33. if (jack_port_connected(m_InputPortMap[n]->Port))
  34. {
  35. sample_t *in = (sample_t *) jack_port_get_buffer(m_InputPortMap[n]->Port, nframes);
  36. memcpy (m_InputPortMap[n]->Buf, in, sizeof (sample_t) * GetBufferSize());
  37. }
  38. }
  39. for (int n=0; n<GetJackOutputCount(); n++)
  40. {
  41. if (jack_port_connected(m_OutputPortMap[n]->Port))
  42. {
  43. if (m_OutputPortMap[n]->Buf)
  44. {
  45. sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes);
  46. memcpy (out, m_OutputPortMap[n]->Buf, sizeof (sample_t) * GetBufferSize());
  47. }
  48. else // no output availible, clear
  49. {
  50. sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes);
  51. memset (out, 0, sizeof (sample_t) * GetBufferSize());
  52. }
  53. }
  54. }
  55. if (RunCallback&&RunContext)
  56. {
  57. if (JackProcessInstanceID==-1)
  58. JackProcessInstanceID = m_JackInstanceID;
  59. if (JackProcessInstanceID==m_JackInstanceID)
  60. RunCallback(RunContext,true);
  61. }
  62. }
  63. /////////////////////////////////////////////////////////////////////////////////////////////
  64. inline void JackClient::SampleRateChange_i(jack_nframes_t nframes)
  65. {
  66. SetSampleRate(nframes);
  67. }
  68. /////////////////////////////////////////////////////////////////////////////////////////////
  69. inline void JackClient::JackShutdown_i()
  70. {
  71. cerr<<"Shutdown"<<endl;
  72. SetAttached(false);
  73. if (JackProcessInstanceID==m_JackInstanceID)
  74. JackProcessInstanceID = -1;
  75. // tells ssm to go back to non callback mode
  76. RunCallback(RunContext, false);
  77. }
  78. ///////////////////////////////////////////////////////
  79. JackClient::JackClient()
  80. {
  81. m_JackInstanceID = 0;
  82. m_Attached = false;
  83. m_SampleRate = 0;
  84. m_BufferSize = 0;
  85. m_JackInputCount = 4;
  86. m_JackOutputCount = 4;
  87. m_Client=NULL;
  88. }
  89. /////////////////////////////////////////////////////////////////////////////////////////////
  90. JackClient::~JackClient()
  91. {
  92. if (IsAttached()) Detach();
  93. }
  94. /////////////////////////////////////////////////////////////////////////////////////////////
  95. void JackClient::AddInputPort(int NewPortNumber)
  96. {
  97. char Name[256];
  98. JackPort *NewPort;
  99. if (!(m_Client)) return;
  100. NewPort = new JackPort;
  101. sprintf(Name,"In%d", NewPortNumber);
  102. NewPort->PortNo = NewPortNumber;
  103. NewPort->Name=Name;
  104. NewPort->Buf=NULL;
  105. NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
  106. m_InputPortMap[NewPortNumber]=NewPort;
  107. }
  108. void JackClient::AddOutputPort(int NewPortNumber)
  109. {
  110. char Name[256];
  111. JackPort *NewPort;
  112. if (!(m_Client)) return;
  113. NewPort = new JackPort;
  114. sprintf(Name,"Out%d", NewPortNumber);
  115. NewPort->PortNo = NewPortNumber;
  116. NewPort->Name=Name;
  117. NewPort->Buf=NULL;
  118. NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  119. m_OutputPortMap[NewPortNumber]=NewPort;
  120. }
  121. void JackClient::RemoveInputPort(int PortNumber)
  122. {
  123. char Name[256];
  124. JackPort *OldPort;
  125. if (!(m_Client)) return;
  126. OldPort = m_InputPortMap[PortNumber];
  127. m_InputPortMap[PortNumber] = NULL;
  128. jack_port_unregister (m_Client, OldPort->Port);
  129. delete OldPort;
  130. }
  131. void JackClient::RemoveOutputPort(int PortNumber)
  132. {
  133. char Name[256];
  134. JackPort *OldPort;
  135. if (!(m_Client)) return;
  136. OldPort = m_OutputPortMap[PortNumber];
  137. m_OutputPortMap[PortNumber] = NULL;
  138. jack_port_unregister (m_Client, OldPort->Port);
  139. delete OldPort;
  140. }
  141. bool JackClient::Attach()
  142. {
  143. char JackClientName[256];
  144. if (m_Attached) return true;
  145. sprintf(JackClientName,"SSM%d",GetJackInstanceID());
  146. if (!(m_Client = jack_client_new(JackClientName)))
  147. {
  148. cerr<<"jack server not running?"<<endl;
  149. return false;
  150. }
  151. jack_set_process_callback(m_Client, JackProcess, this);
  152. jack_set_sample_rate_callback (m_Client, SampleRateChange, this);
  153. jack_on_shutdown (m_Client, JackShutdown, this);
  154. // create the ports
  155. m_InputPortMap.clear();
  156. for (int n=0; n<GetJackInputCount(); n++)
  157. AddInputPort(n);
  158. m_OutputPortMap.clear();
  159. for (int n=0; n<GetJackOutputCount(); n++)
  160. AddOutputPort(n);
  161. // tell the JACK server that we are ready to roll
  162. if (jack_activate (m_Client))
  163. {
  164. cerr<<"cannot activate client"<<endl;
  165. return false;
  166. }
  167. m_Attached=true;
  168. cerr<<"connected to jack..."<<endl;
  169. return true;
  170. }
  171. /////////////////////////////////////////////////////////////////////////////////////////////
  172. void JackClient::Detach()
  173. {
  174. if (m_Client)
  175. {
  176. cerr<<"Detaching from JACK"<<endl;
  177. jack_client_close(m_Client);
  178. m_Client=NULL;
  179. m_Attached=false;
  180. }
  181. if (JackProcessInstanceID==m_JackInstanceID)
  182. JackProcessInstanceID = -1;
  183. // tells ssm to go back to non callback mode
  184. RunCallback(RunContext, false);
  185. }
  186. /////////////////////////////////////////////////////////////////////////////////////////////
  187. void JackClient::GetPortNames(vector<string> &InputNames, vector<string> &OutputNames)
  188. {
  189. InputNames.clear();
  190. OutputNames.clear();
  191. if (!m_Attached) return;
  192. //Outputs first
  193. const char **PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsOutput);
  194. int n=0;
  195. while(PortNameList[n]!=NULL)
  196. {
  197. OutputNames.push_back(PortNameList[n]);
  198. n++;
  199. }
  200. delete PortNameList;
  201. //Inputs second
  202. PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsInput);
  203. n=0;
  204. while(PortNameList[n]!=NULL)
  205. {
  206. InputNames.push_back(PortNameList[n]);
  207. n++;
  208. }
  209. delete PortNameList;
  210. }
  211. /////////////////////////////////////////////////////////////////////////////////////////////
  212. // Input means input of SSM, so this connects jack sources to the plugin outputs
  213. void JackClient::ConnectInput(int n, const string &JackPort)
  214. {
  215. if (!IsAttached()) return;
  216. cerr<<"JackClient::ConnectInput: connecting source ["<<JackPort<<"] to dest ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  217. if (m_InputPortMap[n]->ConnectedTo!="")
  218. {
  219. if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
  220. cerr<<"JackClient::ConnectInput: cannot disconnect input port ["
  221. <<m_InputPortMap[n]->ConnectedTo<<"] from ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  222. }
  223. m_InputPortMap[n]->ConnectedTo = JackPort;
  224. if (jack_connect (m_Client, JackPort.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
  225. cerr<<"JackClient::ConnectInput: cannot connect input port ["
  226. <<JackPort<<"] to ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  227. m_InputPortMap[n]->Connected=true;
  228. }
  229. /////////////////////////////////////////////////////////////////////////////////////////////
  230. // Output means output of SSM, so this connects plugin inputs to a jack destination
  231. void JackClient::ConnectOutput(int n, const string &JackPort)
  232. {
  233. if (!IsAttached()) return;
  234. cerr<<"JackClient::ConnectOutput: connecting source ["<<m_OutputPortMap[n]->Name<<"] to dest ["<<JackPort<<"]"<<endl;
  235. if (m_OutputPortMap[n]->ConnectedTo!="")
  236. {
  237. if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str()))
  238. cerr<<"JackClient::ConnectOutput: cannot disconnect output port ["
  239. <<m_OutputPortMap[n]->ConnectedTo<<"] from ["<<m_OutputPortMap[n]->Name<<"]"<<endl;
  240. }
  241. m_OutputPortMap[n]->ConnectedTo = JackPort;
  242. if (jack_connect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), JackPort.c_str()))
  243. cerr<<"JackClient::ConnectOutput: cannot connect output port ["
  244. <<m_OutputPortMap[n]->Name<<"] to ["<<JackPort<<"]"<<endl;
  245. m_OutputPortMap[n]->Connected=true;
  246. }
  247. /////////////////////////////////////////////////////////////////////////////////////////////
  248. // Input means input of SSM, so this connects jack sources to the plugin outputs
  249. void JackClient::DisconnectInput(int n)
  250. {
  251. if (!IsAttached()) return;
  252. cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;
  253. if (m_InputPortMap[n]->ConnectedTo!="")
  254. {
  255. if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
  256. cerr<<"JackClient::ConnectInput: cannot disconnect input port ["
  257. <<m_InputPortMap[n]->ConnectedTo<<"] from ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  258. }
  259. m_InputPortMap[n]->Connected=false;
  260. }
  261. /////////////////////////////////////////////////////////////////////////////////////////////
  262. // Output means output of SSM, so this connects plugin inputs to a jack destination
  263. void JackClient::DisconnectOutput(int n)
  264. {
  265. if (!IsAttached()) return;
  266. cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;
  267. if (m_OutputPortMap[n]->ConnectedTo!="")
  268. {
  269. if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str()))
  270. cerr<<"JackClient::ConnectOutput: cannot disconnect output port ["
  271. <<m_OutputPortMap[n]->ConnectedTo<<"] from ["<<m_OutputPortMap[n]->Name<<"]"<<endl;
  272. }
  273. m_OutputPortMap[n]->Connected=false;
  274. }
  275. /////////////////////////////////////////////////////////////////////////////////////////////
  276. void JackClient::SetInputBuf(int ID, float* s)
  277. {
  278. if(m_InputPortMap.find(ID)!=m_InputPortMap.end()) m_InputPortMap[ID]->Buf=s;
  279. }
  280. /////////////////////////////////////////////////////////////////////////////////////////////
  281. void JackClient::SetOutputBuf(int ID, float* s)
  282. {
  283. if(m_OutputPortMap.find(ID)!=m_OutputPortMap.end()) m_OutputPortMap[ID]->Buf=s;
  284. }
  285. /////////////////////////////////////////////////////////////////////////////////////////////
  286. extern "C" {
  287. SpiralPlugin* SpiralPlugin_CreateInstance()
  288. {
  289. return new JackPlugin;
  290. }
  291. char** SpiralPlugin_GetIcon()
  292. {
  293. return SpiralIcon_xpm;
  294. }
  295. int SpiralPlugin_GetID()
  296. {
  297. return 31;
  298. }
  299. string SpiralPlugin_GetGroupName()
  300. {
  301. return "InputOutput";
  302. }
  303. }
  304. ///////////////////////////////////////////////////////
  305. JackPlugin::JackPlugin() :
  306. m_UpdateNames(false),
  307. m_Connected(false)
  308. {
  309. m_JackClient=new JackClient;
  310. //clunky way to ensure unique JackID - JackInstanceCount is never dec
  311. //so new JackInstances per session always get a higher number even on
  312. //reload and new Patch
  313. m_JackInstanceID = JackInstanceCount;
  314. JackInstanceCount++;
  315. m_JackClient->SetJackInstanceID(m_JackInstanceID);
  316. // we are an output
  317. m_IsTerminal = true;
  318. m_Version = 2;
  319. m_PluginInfo.Name="Jack";
  320. m_PluginInfo.Width=225;
  321. m_PluginInfo.Height=230;
  322. m_PluginInfo.NumInputs=0;
  323. m_PluginInfo.NumOutputs=0;
  324. m_PluginInfo.PortTips.clear();
  325. m_PluginInfo.NumInputs = m_JackClient->GetJackOutputCount();
  326. m_GUIArgs.NumInputs = m_PluginInfo.NumInputs;
  327. for (int n=0; n<m_JackClient->GetJackInputCount(); n++)
  328. {
  329. char Temp[256];
  330. sprintf(Temp,"SSM Input %d",n);
  331. m_PluginInfo.PortTips.push_back(Temp);
  332. }
  333. m_PluginInfo.NumOutputs = m_JackClient->GetJackOutputCount();
  334. m_GUIArgs.NumOutputs = m_PluginInfo.NumOutputs;
  335. for (int n=0; n<m_JackClient->GetJackOutputCount(); n++)
  336. {
  337. char Temp[256];
  338. sprintf(Temp,"SSM Output %d",n);
  339. m_PluginInfo.PortTips.push_back(Temp);
  340. }
  341. m_AudioCH->Register("NumInputs",&m_GUIArgs.NumInputs);
  342. m_AudioCH->Register("NumOutputs",&m_GUIArgs.NumOutputs);
  343. m_AudioCH->RegisterData("Port",ChannelHandler::INPUT,&m_GUIArgs.Port,sizeof(m_GUIArgs.Port));
  344. m_AudioCH->Register("NumInputPortNames",&m_NumInputPortNames,ChannelHandler::OUTPUT);
  345. m_AudioCH->Register("NumOutputPortNames",&m_NumOutputPortNames,ChannelHandler::OUTPUT);
  346. m_AudioCH->RegisterData("InputPortNames",ChannelHandler::OUTPUT,&m_InputPortNames,sizeof(m_InputPortNames));
  347. m_AudioCH->RegisterData("OutputPortNames",ChannelHandler::OUTPUT,&m_OutputPortNames,sizeof(m_OutputPortNames));
  348. m_AudioCH->Register("UpdateNames",&m_UpdateNames,ChannelHandler::OUTPUT);
  349. m_AudioCH->Register("Connected",&m_Connected,ChannelHandler::OUTPUT);
  350. }
  351. JackPlugin::~JackPlugin()
  352. {
  353. m_JackClient->Detach();
  354. delete m_JackClient;
  355. m_JackClient=NULL;
  356. }
  357. PluginInfo &JackPlugin::Initialise(const HostInfo *Host)
  358. {
  359. PluginInfo& Info= SpiralPlugin::Initialise(Host);
  360. host=Host;
  361. m_JackClient->SetCallback(cb_Update,m_Parent);
  362. return Info;
  363. }
  364. SpiralGUIType *JackPlugin::CreateGUI()
  365. {
  366. return new JackPluginGUI(m_PluginInfo.Width,
  367. m_PluginInfo.Height,
  368. this,m_AudioCH,m_HostInfo);
  369. }
  370. void JackPlugin::SetNumberPorts (int nInputs, int nOutputs) {
  371. UpdatePluginInfoWithHost();
  372. RemoveAllInputs ();
  373. RemoveAllOutputs ();
  374. m_PluginInfo.NumInputs = 0;
  375. m_PluginInfo.NumOutputs = 0;
  376. m_PluginInfo.PortTips.clear ();
  377. CreatePorts (nInputs, nOutputs, true);
  378. UpdatePluginInfoWithHost ();
  379. }
  380. void JackPlugin::CreatePorts (int nInputs, int nOutputs, bool AddPorts) {
  381. m_PluginInfo.PortTips.clear();
  382. m_PluginInfo.NumInputs = nInputs;
  383. m_JackClient->SetJackInputCount(nInputs);
  384. for (int n=0; n<nInputs; n++)
  385. {
  386. char Temp[256];
  387. sprintf(Temp,"SSM Input %d",n);
  388. m_PluginInfo.PortTips.push_back(Temp);
  389. }
  390. m_PluginInfo.NumOutputs = nOutputs;
  391. m_JackClient->SetJackOutputCount(nOutputs);
  392. for (int n=0; n<nOutputs; n++)
  393. {
  394. char Temp[256];
  395. sprintf(Temp,"SSM Output %d",n);
  396. m_PluginInfo.PortTips.push_back(Temp);
  397. }
  398. if (AddPorts) {
  399. for (int n=0; n<nInputs; n++) AddInput();
  400. for (int n=0; n<nOutputs; n++) AddOutput();
  401. }
  402. }
  403. void JackPlugin::Execute()
  404. {
  405. }
  406. void JackPlugin::ExecuteCommands()
  407. {
  408. bool commandwaiting = m_AudioCH->IsCommandWaiting();
  409. int command = (commandwaiting)?(int)m_AudioCH->GetCommand():0;
  410. if (commandwaiting)
  411. {
  412. switch (command) {
  413. case SET_PORT_COUNT :
  414. SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs);
  415. }
  416. }
  417. // we want to process this whether we are connected to stuff or not
  418. JackClient* pJack=m_JackClient;
  419. // connect the buffers up if we are plugged into something
  420. for (int n=0; n<pJack->GetJackOutputCount(); n++)
  421. {
  422. if (InputExists(n))
  423. {
  424. pJack->SetOutputBuf(n,(float*)GetInput(n)->GetBuffer());
  425. }
  426. else
  427. {
  428. pJack->SetOutputBuf(n,NULL);
  429. }
  430. }
  431. for (int n=0; n<pJack->GetJackInputCount(); n++)
  432. {
  433. if (OutputExists(n))
  434. {
  435. pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer());
  436. }
  437. else
  438. {
  439. pJack->SetInputBuf(n,NULL);
  440. }
  441. }
  442. if (commandwaiting)
  443. {
  444. switch (command)
  445. {
  446. case UPDATE_NAMES :
  447. {
  448. int c=0;
  449. std::vector<string> InputNames,OutputNames;
  450. GetPortNames(InputNames,OutputNames);
  451. for (vector<string>::iterator i=InputNames.begin();
  452. i!=InputNames.end(); ++i)
  453. {
  454. strcpy(m_InputPortNames[c],i->c_str());
  455. c++;
  456. }
  457. c=0;
  458. for (std::vector<string>::iterator i=OutputNames.begin();
  459. i!=OutputNames.end(); ++i)
  460. {
  461. strcpy(m_OutputPortNames[c],i->c_str());
  462. c++;
  463. }
  464. m_NumInputPortNames=InputNames.size();
  465. m_NumOutputPortNames=OutputNames.size();
  466. }
  467. break;
  468. case CHECK_PORT_CHANGES :
  469. if ((m_JackClient->IsAttached()) && (!m_JackClient->CheckingPortChanges)) {
  470. m_JackClient->CheckingPortChanges = true;
  471. for (int n=0; n<m_PluginInfo.NumInputs; n++) {
  472. if (jack_port_connected(m_JackClient->m_OutputPortMap[n]->Port)!=m_JackClient->m_OutputPortMap[n]->Connected)
  473. m_JackClient->m_OutputPortsChanged.push_back(m_JackClient->m_OutputPortMap[n]);
  474. if (jack_port_connected(m_JackClient->m_InputPortMap[n]->Port)!=m_JackClient->m_InputPortMap[n]->Connected)
  475. m_JackClient->m_InputPortsChanged.push_back(m_JackClient->m_InputPortMap[n]);
  476. }
  477. m_JackClient->CheckingPortChanges = false;
  478. }
  479. break;
  480. default : break;
  481. }
  482. }
  483. m_Connected=m_JackClient->IsAttached();
  484. }
  485. void JackPlugin::StreamOut (ostream &s)
  486. {
  487. s << m_Version << " " << m_GUIArgs.NumInputs << " " << m_GUIArgs.NumOutputs << " ";
  488. }
  489. void JackPlugin::StreamIn (istream &s)
  490. {
  491. char Test;
  492. int Version, NumInputs, NumOutputs;
  493. s.seekg (2, ios_base::cur );//skip to next line
  494. Test = s.peek();//peek first char
  495. s.seekg (-2, ios_base::cur );//jump back to prior line
  496. if ( (Test >= '0') && (Test <= '9') )
  497. {
  498. s >> Version;
  499. }
  500. else
  501. {
  502. //No Version, so use Version 1
  503. Version = 1;
  504. }
  505. switch (Version)
  506. {
  507. case 2:
  508. {
  509. s >> NumInputs >> NumOutputs;
  510. m_GUIArgs.NumOutputs = min(max(NumOutputs, MIN_PORTS), MAX_PORTS);
  511. m_GUIArgs.NumInputs = min(max(NumInputs, MIN_PORTS), MAX_PORTS);
  512. SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs);
  513. }
  514. break;
  515. case 1:
  516. {
  517. //use original fixed defaults
  518. m_GUIArgs.NumInputs = 16;
  519. m_GUIArgs.NumOutputs = 16;
  520. SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs);
  521. }
  522. break;
  523. }
  524. }