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.

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