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.

404 lines
10KB

  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("SSMJackPlugin")))
  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_buffer_size_callback(m_Client, JackClient::OnBufSizeChange, 0);
  56. jack_set_sample_rate_callback (m_Client, JackClient::OnSRateChange, 0);
  57. jack_on_shutdown (m_Client, JackClient::OnJackShutdown, this);
  58. printf ("engine sample rate: %lu\n", jack_get_sample_rate(m_Client));
  59. m_InputPortMap.clear();
  60. m_OutputPortMap.clear();
  61. // create the ports
  62. for (int n=0; n<NUM_INPUTS; n++)
  63. {
  64. char Name[256];
  65. sprintf(Name,"Out %d",n);
  66. JackPort *NewPort = new JackPort;
  67. NewPort->Name=Name;
  68. NewPort->Buf=NULL;
  69. NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
  70. m_InputPortMap[n]=NewPort;
  71. }
  72. for (int n=0; n<NUM_OUTPUTS; n++)
  73. {
  74. char Name[256];
  75. sprintf(Name,"In %d",n);
  76. JackPort *NewPort = new JackPort;
  77. NewPort->Name=Name;
  78. NewPort->Buf=NULL;
  79. NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  80. m_OutputPortMap[n]=NewPort;
  81. }
  82. // tell the JACK server that we are ready to roll
  83. if (jack_activate (m_Client))
  84. {
  85. cerr<<"cannot activate client"<<endl;
  86. return false;
  87. }
  88. m_Attached=true;
  89. cerr<<"connected to jack..."<<endl;
  90. return true;
  91. }
  92. /////////////////////////////////////////////////////////////////////////////////////////////
  93. void JackClient::Detach()
  94. {
  95. if (m_Client)
  96. {
  97. cerr<<"Detaching from JACK"<<endl;
  98. jack_client_close(m_Client);
  99. m_Client=NULL;
  100. m_Attached=false;
  101. }
  102. // tells ssm to go back to non callback mode
  103. RunCallback(RunContext, false);
  104. }
  105. /////////////////////////////////////////////////////////////////////////////////////////////
  106. int JackClient::Process(long unsigned int n, void *o)
  107. {
  108. //cerr<<"process called "<<n<<endl;
  109. for (int n=0; n<NUM_INPUTS; n++)
  110. {
  111. if (m_InputPortMap[n]->Connected)
  112. {
  113. if (m_InputPortMap[n]->Buf)
  114. {
  115. sample_t *in = (sample_t *) jack_port_get_buffer(m_InputPortMap[n]->Port, m_BufferSize);
  116. memcpy (m_InputPortMap[n]->Buf, in, sizeof (sample_t) * m_BufferSize);
  117. //cerr<<"got "<<m_InputPortMap[n]->Buf[0]<<" from "<<m_InputPortMap[n]->Name<<endl;
  118. }
  119. }
  120. }
  121. for (int n=0; n<NUM_OUTPUTS; n++)
  122. {
  123. //if (m_OutputPortMap[n]->Connected)
  124. {
  125. if (m_OutputPortMap[n]->Buf)
  126. {
  127. sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, m_BufferSize);
  128. memcpy (out, m_OutputPortMap[n]->Buf, sizeof (sample_t) * m_BufferSize);
  129. }
  130. else // no output availible, clear
  131. {
  132. sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, m_BufferSize);
  133. memset (out, 0, sizeof (sample_t) * m_BufferSize);
  134. }
  135. }
  136. }
  137. if(RunCallback&&RunContext)
  138. {
  139. // do the work
  140. RunCallback(RunContext, true);
  141. }
  142. return 1;
  143. }
  144. /////////////////////////////////////////////////////////////////////////////////////////////
  145. int JackClient::OnBufSizeChange(long unsigned int n, void *o)
  146. {
  147. m_BufferSize=n;
  148. return 1;
  149. }
  150. /////////////////////////////////////////////////////////////////////////////////////////////
  151. int JackClient::OnSRateChange(long unsigned int n, void *o)
  152. {
  153. m_SampleRate=n;
  154. return 1;
  155. }
  156. /////////////////////////////////////////////////////////////////////////////////////////////
  157. void JackClient::OnJackShutdown(void *o)
  158. {
  159. cerr<<"Shutdown"<<endl;
  160. m_Attached=false;
  161. // tells ssm to go back to non callback mode
  162. RunCallback(RunContext, false);
  163. return;
  164. }
  165. /////////////////////////////////////////////////////////////////////////////////////////////
  166. void JackClient::GetPortNames(vector<string> &InputNames, vector<string> &OutputNames)
  167. {
  168. InputNames.clear();
  169. OutputNames.clear();
  170. if (!m_Attached) return;
  171. //Outputs first
  172. const char **PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsOutput);
  173. int n=0;
  174. while(PortNameList[n]!=NULL)
  175. {
  176. OutputNames.push_back(PortNameList[n]);
  177. n++;
  178. }
  179. delete PortNameList;
  180. //Inputs second
  181. PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsInput);
  182. n=0;
  183. while(PortNameList[n]!=NULL)
  184. {
  185. InputNames.push_back(PortNameList[n]);
  186. n++;
  187. }
  188. delete PortNameList;
  189. }
  190. /////////////////////////////////////////////////////////////////////////////////////////////
  191. void JackClient::ConnectInput(int n, const string &JackPort)
  192. {
  193. cerr<<"JackClient::ConnectInput: connecting source ["<<JackPort<<"] to dest ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  194. if (m_InputPortMap[n]->ConnectedTo!="")
  195. {
  196. if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
  197. cerr<<"JackClient::ConnectInput: cannot disconnect input port ["
  198. <<m_InputPortMap[n]->ConnectedTo<<"] from ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  199. }
  200. m_InputPortMap[n]->ConnectedTo = JackPort;
  201. if (jack_connect (m_Client, JackPort.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
  202. cerr<<"JackClient::ConnectInput: cannot connect input port ["
  203. <<JackPort<<"] to ["<<m_InputPortMap[n]->Name<<"]"<<endl;
  204. m_InputPortMap[n]->Connected=true;
  205. }
  206. /////////////////////////////////////////////////////////////////////////////////////////////
  207. void JackClient::ConnectOutput(int n, const string &JackPort)
  208. {
  209. cerr<<"JackClient::ConnectOutput: connecting source ["<<m_OutputPortMap[n]->Name<<"] to dest ["<<JackPort<<"]"<<endl;
  210. if (m_OutputPortMap[n]->ConnectedTo!="")
  211. {
  212. if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str()))
  213. cerr<<"JackClient::ConnectOutput: cannot disconnect output port ["
  214. <<m_OutputPortMap[n]->ConnectedTo<<"] from ["<<m_OutputPortMap[n]->Name<<"]"<<endl;
  215. }
  216. m_OutputPortMap[n]->ConnectedTo = JackPort;
  217. if (jack_connect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), JackPort.c_str()))
  218. cerr<<"JackClient::ConnectOutput: cannot connect output port ["
  219. <<m_OutputPortMap[n]->Name<<"] to ["<<JackPort<<"]"<<endl;
  220. m_OutputPortMap[n]->Connected=true;
  221. }
  222. /////////////////////////////////////////////////////////////////////////////////////////////
  223. void JackClient::SetInputBuf(int ID, float* s)
  224. {
  225. if(m_InputPortMap.find(ID)!=m_InputPortMap.end()) m_InputPortMap[ID]->Buf=s;
  226. }
  227. /////////////////////////////////////////////////////////////////////////////////////////////
  228. void JackClient::SetOutputBuf(int ID, float* s)
  229. {
  230. if(m_OutputPortMap.find(ID)!=m_OutputPortMap.end()) m_OutputPortMap[ID]->Buf=s;
  231. }
  232. /////////////////////////////////////////////////////////////////////////////////////////////
  233. /////////////////////////////////////////////////////////////////////////////////////////////
  234. extern "C" {
  235. SpiralPlugin* CreateInstance()
  236. {
  237. return new JackPlugin;
  238. }
  239. char** GetIcon()
  240. {
  241. return SpiralIcon_xpm;
  242. }
  243. int GetID()
  244. {
  245. return 31;
  246. }
  247. }
  248. ///////////////////////////////////////////////////////
  249. JackPlugin::JackPlugin()
  250. {
  251. m_RefCount++;
  252. m_PluginInfo.Name="Jack";
  253. m_PluginInfo.Width=200;
  254. m_PluginInfo.Height=415;
  255. m_PluginInfo.NumInputs=NUM_OUTPUTS;
  256. m_PluginInfo.NumOutputs=NUM_INPUTS;
  257. for (int n=0; n<NUM_OUTPUTS; n++)
  258. {
  259. char Temp[256];
  260. sprintf(Temp,"SSM Output %d",n);
  261. m_PluginInfo.PortTips.push_back(Temp);
  262. }
  263. for (int n=0; n<NUM_INPUTS; n++)
  264. {
  265. char Temp[256];
  266. sprintf(Temp,"SSM Input %d",n);
  267. m_PluginInfo.PortTips.push_back(Temp);
  268. }
  269. }
  270. JackPlugin::~JackPlugin()
  271. {
  272. m_RefCount--;
  273. if (m_RefCount==0)
  274. {
  275. JackClient::Get()->Detach();
  276. JackClient::PackUpAndGoHome();
  277. }
  278. }
  279. PluginInfo &JackPlugin::Initialise(const HostInfo *Host)
  280. {
  281. PluginInfo& Info= SpiralPlugin::Initialise(Host);
  282. host=Host;
  283. JackClient::Get()->SetCallback(cb_Update,m_Parent);
  284. return Info;
  285. }
  286. SpiralGUIType *JackPlugin::CreateGUI()
  287. {
  288. m_GUI = new JackPluginGUI(m_PluginInfo.Width,
  289. m_PluginInfo.Height,
  290. this,m_HostInfo);
  291. m_GUI->hide();
  292. return m_GUI;
  293. }
  294. void JackPlugin::Execute()
  295. {
  296. for (int n=0; n<NUM_OUTPUTS; n++)
  297. {
  298. GetOutputBuf(n)->Zero();
  299. }
  300. JackClient* pJack=JackClient::Get();
  301. ((JackPluginGUI*)m_GUI)->SetAttached(pJack->IsAttached());
  302. // connect the buffers up if we are plugged into something
  303. for (int n=0; n<NUM_OUTPUTS; n++)
  304. {
  305. if (InputExists(n))
  306. {
  307. JackClient::Get()->SetOutputBuf(n,(float*)GetInput(n)->GetBuffer());
  308. }
  309. else JackClient::Get()->SetOutputBuf(n,NULL);
  310. }
  311. // don't really want to do this all the time, as it only needs to
  312. // be done once per attach.
  313. for (int n=0; n<NUM_INPUTS; n++)
  314. {
  315. pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer());
  316. }
  317. }