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.

480 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. }
  273. ///////////////////////////////////////////////////////
  274. JackPlugin::JackPlugin() :
  275. m_UpdateNames(false),
  276. m_Connected(false)
  277. {
  278. m_RefCount++;
  279. // we are an output
  280. m_IsTerminal = true;
  281. m_PluginInfo.Name="Jack";
  282. m_PluginInfo.Width=200;
  283. m_PluginInfo.Height=325;
  284. m_PluginInfo.NumInputs=NUM_OUTPUTS;
  285. m_PluginInfo.NumOutputs=NUM_INPUTS;
  286. for (int n=0; n<NUM_OUTPUTS; n++)
  287. {
  288. char Temp[256];
  289. sprintf(Temp,"SSM Output %d",n);
  290. m_PluginInfo.PortTips.push_back(Temp);
  291. }
  292. for (int n=0; n<NUM_INPUTS; n++)
  293. {
  294. char Temp[256];
  295. sprintf(Temp,"SSM Input %d",n);
  296. m_PluginInfo.PortTips.push_back(Temp);
  297. }
  298. m_AudioCH->Register("Num",&m_GUIArgs.Num);
  299. m_AudioCH->RegisterData("Port",ChannelHandler::INPUT,&m_GUIArgs.Port,sizeof(m_GUIArgs.Port));
  300. m_AudioCH->Register("NumInputPortNames",&m_NumInputPortNames,ChannelHandler::OUTPUT);
  301. m_AudioCH->Register("NumOutputPortNames",&m_NumOutputPortNames,ChannelHandler::OUTPUT);
  302. m_AudioCH->RegisterData("InputPortNames",ChannelHandler::OUTPUT,&m_InputPortNames,sizeof(m_InputPortNames));
  303. m_AudioCH->RegisterData("OutputPortNames",ChannelHandler::OUTPUT,&m_OutputPortNames,sizeof(m_OutputPortNames));
  304. m_AudioCH->Register("UpdateNames",&m_UpdateNames,ChannelHandler::OUTPUT);
  305. m_AudioCH->Register("Connected",&m_Connected,ChannelHandler::OUTPUT);
  306. }
  307. JackPlugin::~JackPlugin()
  308. {
  309. m_RefCount--;
  310. if (m_RefCount==0)
  311. {
  312. JackClient::Get()->Detach();
  313. JackClient::PackUpAndGoHome();
  314. }
  315. }
  316. PluginInfo &JackPlugin::Initialise(const HostInfo *Host)
  317. {
  318. PluginInfo& Info= SpiralPlugin::Initialise(Host);
  319. host=Host;
  320. if (m_RefCount==1) JackClient::Get()->SetCallback(cb_Update,m_Parent);
  321. return Info;
  322. }
  323. SpiralGUIType *JackPlugin::CreateGUI()
  324. {
  325. return new JackPluginGUI(m_PluginInfo.Width,
  326. m_PluginInfo.Height,
  327. this,m_AudioCH,m_HostInfo);
  328. }
  329. void JackPlugin::Execute()
  330. {
  331. }
  332. void JackPlugin::ExecuteCommands()
  333. {
  334. // only do this once per set of plugins
  335. m_NoExecuted++;
  336. if (m_NoExecuted!=m_RefCount) return;
  337. m_NoExecuted=0;
  338. // we want to process this whether we are connected to stuff or not
  339. JackClient* pJack=JackClient::Get();
  340. // connect the buffers up if we are plugged into something
  341. for (int n=0; n<NUM_OUTPUTS; n++)
  342. {
  343. if (InputExists(n))
  344. {
  345. pJack->SetOutputBuf(n,(float*)GetInput(n)->GetBuffer());
  346. }
  347. else
  348. {
  349. pJack->SetOutputBuf(n,NULL);
  350. }
  351. }
  352. for (int n=0; n<NUM_INPUTS; n++)
  353. {
  354. pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer());
  355. }
  356. if (m_AudioCH->IsCommandWaiting())
  357. {
  358. switch (m_AudioCH->GetCommand())
  359. {
  360. //case ATTACH : Attach(); break;
  361. //case DETACH : Detach(); break;
  362. //case CONNECTINPUT : pJack->ConnectInput(m_GUIArgs.Num,m_GUIArgs.Port); break;
  363. //case CONNECTOUTPUT : pJack->ConnectOutput(m_GUIArgs.Num,m_GUIArgs.Port); break;
  364. case UPDATE_NAMES :
  365. {
  366. int c=0;
  367. vector<string> InputNames,OutputNames;
  368. GetPortNames(InputNames,OutputNames);
  369. for (vector<string>::iterator i=InputNames.begin();
  370. i!=InputNames.end(); ++i)
  371. {
  372. strcpy(m_InputPortNames[c],i->c_str());
  373. c++;
  374. }
  375. c=0;
  376. for (vector<string>::iterator i=OutputNames.begin();
  377. i!=OutputNames.end(); ++i)
  378. {
  379. strcpy(m_OutputPortNames[c],i->c_str());
  380. c++;
  381. }
  382. m_NumInputPortNames=InputNames.size();
  383. m_NumOutputPortNames=OutputNames.size();
  384. }
  385. break;
  386. default : break;
  387. }
  388. }
  389. m_Connected=JackClient::Get()->IsAttached();
  390. }