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.

485 lines
13KB

  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. static const HostInfo* host;
  24. JackClient* JackClient::m_Singleton = NULL;
  25. bool JackClient::m_Attached = false;
  26. long unsigned int JackClient::m_BufferSize = 0;
  27. long unsigned int JackClient::m_SampleRate = 0;
  28. void (*JackClient::RunCallback)(void*, bool m)=NULL;
  29. void *JackClient::RunContext = NULL;
  30. jack_client_t *JackClient::m_Client = NULL;
  31. map<int,JackClient::JackPort*> JackClient::m_InputPortMap;
  32. map<int,JackClient::JackPort*> JackClient::m_OutputPortMap;
  33. int JackPlugin::m_RefCount = 0;
  34. int JackPlugin::m_NoExecuted = 0;
  35. ///////////////////////////////////////////////////////
  36. JackClient::JackClient()
  37. {
  38. }
  39. /////////////////////////////////////////////////////////////////////////////////////////////
  40. JackClient::~JackClient()
  41. {
  42. Detach();
  43. }
  44. /////////////////////////////////////////////////////////////////////////////////////////////
  45. bool JackClient::Attach()
  46. {
  47. if (m_Attached) return true;
  48. if (!(m_Client = jack_client_new("SSM")))
  49. {
  50. cerr<<"jack server not running?"<<endl;
  51. return false;
  52. }
  53. jack_set_process_callback(m_Client, JackClient::Process, 0);
  54. jack_set_buffer_size_callback(m_Client, JackClient::OnBufSizeChange, 0);
  55. jack_set_sample_rate_callback (m_Client, JackClient::OnSRateChange, 0);
  56. jack_on_shutdown (m_Client, JackClient::OnJackShutdown, this);
  57. m_InputPortMap.clear();
  58. m_OutputPortMap.clear();
  59. // create the ports
  60. for (int n=0; n<NUM_INPUTS; n++)
  61. {
  62. char Name[256];
  63. sprintf(Name,"In %d",n);
  64. JackPort *NewPort = new JackPort;
  65. NewPort->Name=Name;
  66. NewPort->Buf=NULL;
  67. NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
  68. m_InputPortMap[n]=NewPort;
  69. }
  70. for (int n=0; n<NUM_OUTPUTS; n++)
  71. {
  72. char Name[256];
  73. sprintf(Name,"Out %d",n);
  74. JackPort *NewPort = new JackPort;
  75. NewPort->Name=Name;
  76. NewPort->Buf=NULL;
  77. NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  78. m_OutputPortMap[n]=NewPort;
  79. }
  80. // tell the JACK server that we are ready to roll
  81. if (jack_activate (m_Client))
  82. {
  83. cerr<<"cannot activate client"<<endl;
  84. return false;
  85. }
  86. m_Attached=true;
  87. cerr<<"connected to jack..."<<endl;
  88. return true;
  89. }
  90. /////////////////////////////////////////////////////////////////////////////////////////////
  91. void JackClient::Detach()
  92. {
  93. if (m_Client)
  94. {
  95. cerr<<"Detaching from JACK"<<endl;
  96. jack_client_close(m_Client);
  97. m_Client=NULL;
  98. m_Attached=false;
  99. }
  100. // tells ssm to go back to non callback mode
  101. RunCallback(RunContext, false);
  102. }
  103. /////////////////////////////////////////////////////////////////////////////////////////////
  104. int JackClient::Process(jack_nframes_t nframes, void *o)
  105. {
  106. for (int n=0; n<NUM_INPUTS; n++)
  107. {
  108. if (jack_port_connected(m_InputPortMap[n]->Port))
  109. {
  110. sample_t *in = (sample_t *) jack_port_get_buffer(m_InputPortMap[n]->Port, nframes);
  111. memcpy (m_InputPortMap[n]->Buf, in, sizeof (sample_t) * m_BufferSize);
  112. }
  113. }
  114. for (int n=0; n<NUM_OUTPUTS; n++)
  115. {
  116. //if (m_OutputPortMap[n]->Connected)
  117. {
  118. if (m_OutputPortMap[n]->Buf)
  119. {
  120. sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes);
  121. memcpy (out, m_OutputPortMap[n]->Buf, sizeof (sample_t) * m_BufferSize);
  122. }
  123. else // no output availible, clear
  124. {
  125. sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes);
  126. memset (out, 0, sizeof (sample_t) * m_BufferSize);
  127. }
  128. }
  129. }
  130. if(RunCallback&&RunContext)
  131. {
  132. // do the work
  133. RunCallback(RunContext, true);
  134. }
  135. return 0;
  136. }
  137. /////////////////////////////////////////////////////////////////////////////////////////////
  138. int JackClient::OnBufSizeChange(long unsigned int n, void *o)
  139. {
  140. m_BufferSize=n;
  141. return 0;
  142. }
  143. /////////////////////////////////////////////////////////////////////////////////////////////
  144. int JackClient::OnSRateChange(long unsigned int n, void *o)
  145. {
  146. m_SampleRate=n;
  147. return 0;
  148. }
  149. /////////////////////////////////////////////////////////////////////////////////////////////
  150. void JackClient::OnJackShutdown(void *o)
  151. {
  152. cerr<<"Shutdown"<<endl;
  153. m_Attached=false;
  154. // tells ssm to go back to non callback mode
  155. RunCallback(RunContext, false);
  156. return;
  157. }
  158. /////////////////////////////////////////////////////////////////////////////////////////////
  159. void JackClient::GetPortNames(vector<string> &InputNames, vector<string> &OutputNames)
  160. {
  161. InputNames.clear();
  162. OutputNames.clear();
  163. if (!m_Attached) return;
  164. //Outputs first
  165. const char **PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsOutput);
  166. int n=0;
  167. while(PortNameList[n]!=NULL)
  168. {
  169. OutputNames.push_back(PortNameList[n]);
  170. n++;
  171. }
  172. delete PortNameList;
  173. //Inputs second
  174. PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsInput);
  175. n=0;
  176. while(PortNameList[n]!=NULL)
  177. {
  178. InputNames.push_back(PortNameList[n]);
  179. n++;
  180. }
  181. delete PortNameList;
  182. }
  183. /////////////////////////////////////////////////////////////////////////////////////////////
  184. // Input means input of SSM, so this connects jack sources to the plugin outputs
  185. void JackClient::ConnectInput(int n, const string &JackPort)
  186. {
  187. if (!IsAttached()) return;
  188. cerr<<"JackClient::ConnectInput: connecting source ["<<JackPort<<"] to dest ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  189. if (m_InputPortMap[n]->ConnectedTo!="")
  190. {
  191. if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
  192. cerr<<"JackClient::ConnectInput: cannot disconnect input port ["
  193. <<m_InputPortMap[n]->ConnectedTo<<"] from ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  194. }
  195. m_InputPortMap[n]->ConnectedTo = JackPort;
  196. if (jack_connect (m_Client, JackPort.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
  197. cerr<<"JackClient::ConnectInput: cannot connect input port ["
  198. <<JackPort<<"] to ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  199. m_InputPortMap[n]->Connected=true;
  200. }
  201. /////////////////////////////////////////////////////////////////////////////////////////////
  202. // Output means output of SSM, so this connects plugin inputs to a jack destination
  203. void JackClient::ConnectOutput(int n, const string &JackPort)
  204. {
  205. if (!IsAttached()) return;
  206. cerr<<"JackClient::ConnectOutput: connecting source ["<<m_OutputPortMap[n]->Name<<"] to dest ["<<JackPort<<"]"<<endl;
  207. if (m_OutputPortMap[n]->ConnectedTo!="")
  208. {
  209. if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str()))
  210. cerr<<"JackClient::ConnectOutput: cannot disconnect output port ["
  211. <<m_OutputPortMap[n]->ConnectedTo<<"] from ["<<m_OutputPortMap[n]->Name<<"]"<<endl;
  212. }
  213. m_OutputPortMap[n]->ConnectedTo = JackPort;
  214. if (jack_connect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), JackPort.c_str()))
  215. cerr<<"JackClient::ConnectOutput: cannot connect output port ["
  216. <<m_OutputPortMap[n]->Name<<"] to ["<<JackPort<<"]"<<endl;
  217. m_OutputPortMap[n]->Connected=true;
  218. }
  219. /////////////////////////////////////////////////////////////////////////////////////////////
  220. // Input means input of SSM, so this connects jack sources to the plugin outputs
  221. void JackClient::DisconnectInput(int n)
  222. {
  223. if (!IsAttached()) return;
  224. cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;
  225. if (m_InputPortMap[n]->ConnectedTo!="")
  226. {
  227. if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
  228. cerr<<"JackClient::ConnectInput: cannot disconnect input port ["
  229. <<m_InputPortMap[n]->ConnectedTo<<"] from ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  230. }
  231. m_InputPortMap[n]->Connected=false;
  232. }
  233. /////////////////////////////////////////////////////////////////////////////////////////////
  234. // Output means output of SSM, so this connects plugin inputs to a jack destination
  235. void JackClient::DisconnectOutput(int n)
  236. {
  237. if (!IsAttached()) return;
  238. cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;
  239. if (m_OutputPortMap[n]->ConnectedTo!="")
  240. {
  241. if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str()))
  242. cerr<<"JackClient::ConnectOutput: cannot disconnect output port ["
  243. <<m_OutputPortMap[n]->ConnectedTo<<"] from ["<<m_OutputPortMap[n]->Name<<"]"<<endl;
  244. }
  245. m_OutputPortMap[n]->Connected=false;
  246. }
  247. /////////////////////////////////////////////////////////////////////////////////////////////
  248. void JackClient::SetInputBuf(int ID, float* s)
  249. {
  250. if(m_InputPortMap.find(ID)!=m_InputPortMap.end()) m_InputPortMap[ID]->Buf=s;
  251. }
  252. /////////////////////////////////////////////////////////////////////////////////////////////
  253. void JackClient::SetOutputBuf(int ID, float* s)
  254. {
  255. if(m_OutputPortMap.find(ID)!=m_OutputPortMap.end()) m_OutputPortMap[ID]->Buf=s;
  256. }
  257. /////////////////////////////////////////////////////////////////////////////////////////////
  258. /////////////////////////////////////////////////////////////////////////////////////////////
  259. extern "C" {
  260. SpiralPlugin* CreateInstance()
  261. {
  262. return new JackPlugin;
  263. }
  264. char** GetIcon()
  265. {
  266. return SpiralIcon_xpm;
  267. }
  268. int GetID()
  269. {
  270. return 31;
  271. }
  272. string GetGroupName()
  273. {
  274. return "SpiralSound";
  275. }
  276. }
  277. ///////////////////////////////////////////////////////
  278. JackPlugin::JackPlugin() :
  279. m_UpdateNames(false),
  280. m_Connected(false)
  281. {
  282. m_RefCount++;
  283. // we are an output
  284. m_IsTerminal = true;
  285. m_PluginInfo.Name="Jack";
  286. m_PluginInfo.Width=200;
  287. m_PluginInfo.Height=325;
  288. m_PluginInfo.NumInputs=NUM_OUTPUTS;
  289. m_PluginInfo.NumOutputs=NUM_INPUTS;
  290. for (int n=0; n<NUM_OUTPUTS; n++)
  291. {
  292. char Temp[256];
  293. sprintf(Temp,"SSM Output %d",n);
  294. m_PluginInfo.PortTips.push_back(Temp);
  295. }
  296. for (int n=0; n<NUM_INPUTS; n++)
  297. {
  298. char Temp[256];
  299. sprintf(Temp,"SSM Input %d",n);
  300. m_PluginInfo.PortTips.push_back(Temp);
  301. }
  302. m_AudioCH->Register("Num",&m_GUIArgs.Num);
  303. m_AudioCH->RegisterData("Port",ChannelHandler::INPUT,&m_GUIArgs.Port,sizeof(m_GUIArgs.Port));
  304. m_AudioCH->Register("NumInputPortNames",&m_NumInputPortNames,ChannelHandler::OUTPUT);
  305. m_AudioCH->Register("NumOutputPortNames",&m_NumOutputPortNames,ChannelHandler::OUTPUT);
  306. m_AudioCH->RegisterData("InputPortNames",ChannelHandler::OUTPUT,&m_InputPortNames,sizeof(m_InputPortNames));
  307. m_AudioCH->RegisterData("OutputPortNames",ChannelHandler::OUTPUT,&m_OutputPortNames,sizeof(m_OutputPortNames));
  308. m_AudioCH->Register("UpdateNames",&m_UpdateNames,ChannelHandler::OUTPUT);
  309. m_AudioCH->Register("Connected",&m_Connected,ChannelHandler::OUTPUT);
  310. }
  311. JackPlugin::~JackPlugin()
  312. {
  313. m_RefCount--;
  314. if (m_RefCount==0)
  315. {
  316. JackClient::Get()->Detach();
  317. JackClient::PackUpAndGoHome();
  318. }
  319. }
  320. PluginInfo &JackPlugin::Initialise(const HostInfo *Host)
  321. {
  322. PluginInfo& Info= SpiralPlugin::Initialise(Host);
  323. host=Host;
  324. if (m_RefCount==1) JackClient::Get()->SetCallback(cb_Update,m_Parent);
  325. return Info;
  326. }
  327. SpiralGUIType *JackPlugin::CreateGUI()
  328. {
  329. return new JackPluginGUI(m_PluginInfo.Width,
  330. m_PluginInfo.Height,
  331. this,m_AudioCH,m_HostInfo);
  332. }
  333. void JackPlugin::Execute()
  334. {
  335. }
  336. void JackPlugin::ExecuteCommands()
  337. {
  338. // only do this once per set of plugins
  339. m_NoExecuted++;
  340. if (m_NoExecuted!=m_RefCount) return;
  341. m_NoExecuted=0;
  342. // we want to process this whether we are connected to stuff or not
  343. JackClient* pJack=JackClient::Get();
  344. // connect the buffers up if we are plugged into something
  345. for (int n=0; n<NUM_OUTPUTS; n++)
  346. {
  347. if (InputExists(n))
  348. {
  349. pJack->SetOutputBuf(n,(float*)GetInput(n)->GetBuffer());
  350. }
  351. else
  352. {
  353. pJack->SetOutputBuf(n,NULL);
  354. }
  355. }
  356. for (int n=0; n<NUM_INPUTS; n++)
  357. {
  358. pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer());
  359. }
  360. if (m_AudioCH->IsCommandWaiting())
  361. {
  362. switch (m_AudioCH->GetCommand())
  363. {
  364. //case ATTACH : Attach(); break;
  365. //case DETACH : Detach(); break;
  366. //case CONNECTINPUT : pJack->ConnectInput(m_GUIArgs.Num,m_GUIArgs.Port); break;
  367. //case CONNECTOUTPUT : pJack->ConnectOutput(m_GUIArgs.Num,m_GUIArgs.Port); break;
  368. case UPDATE_NAMES :
  369. {
  370. int c=0;
  371. vector<string> InputNames,OutputNames;
  372. GetPortNames(InputNames,OutputNames);
  373. for (vector<string>::iterator i=InputNames.begin();
  374. i!=InputNames.end(); ++i)
  375. {
  376. strcpy(m_InputPortNames[c],i->c_str());
  377. c++;
  378. }
  379. c=0;
  380. for (vector<string>::iterator i=OutputNames.begin();
  381. i!=OutputNames.end(); ++i)
  382. {
  383. strcpy(m_OutputPortNames[c],i->c_str());
  384. c++;
  385. }
  386. m_NumInputPortNames=InputNames.size();
  387. m_NumOutputPortNames=OutputNames.size();
  388. }
  389. break;
  390. default : break;
  391. }
  392. }
  393. m_Connected=JackClient::Get()->IsAttached();
  394. }