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.

609 lines
16KB

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