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.

458 lines
12KB

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