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