/* SpiralSound * Copyleft (C) 2001 David Griffiths * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "JackPlugin.h" #include "JackPluginGUI.h" #include "SpiralIcon.xpm" using namespace std; static const HostInfo* host; JackClient* JackClient::m_Singleton = NULL; bool JackClient::m_Attached = false; long unsigned int JackClient::m_BufferSize = 0; long unsigned int JackClient::m_SampleRate = 0; void (*JackClient::RunCallback)(void*, bool m)=NULL; void *JackClient::RunContext = NULL; jack_client_t *JackClient::m_Client = NULL; map JackClient::m_InputPortMap; map JackClient::m_OutputPortMap; int JackPlugin::m_RefCount = 0; int JackPlugin::m_NoExecuted = 0; /////////////////////////////////////////////////////// JackClient::JackClient() { } ///////////////////////////////////////////////////////////////////////////////////////////// JackClient::~JackClient() { Detach(); } ///////////////////////////////////////////////////////////////////////////////////////////// bool JackClient::Attach() { if (m_Attached) return true; if (!(m_Client = jack_client_new("SSM"))) { cerr<<"jack server not running?"<Name=Name; NewPort->Buf=NULL; NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); m_InputPortMap[n]=NewPort; } for (int n=0; nName=Name; NewPort->Buf=NULL; NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); m_OutputPortMap[n]=NewPort; } // tell the JACK server that we are ready to roll if (jack_activate (m_Client)) { cerr<<"cannot activate client"<Port)) { sample_t *in = (sample_t *) jack_port_get_buffer(m_InputPortMap[n]->Port, nframes); memcpy (m_InputPortMap[n]->Buf, in, sizeof (sample_t) * m_BufferSize); } } for (int n=0; nConnected) { if (m_OutputPortMap[n]->Buf) { sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes); memcpy (out, m_OutputPortMap[n]->Buf, sizeof (sample_t) * m_BufferSize); } else // no output availible, clear { sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes); memset (out, 0, sizeof (sample_t) * m_BufferSize); } } } if(RunCallback&&RunContext) { // do the work RunCallback(RunContext, true); } return 0; } ///////////////////////////////////////////////////////////////////////////////////////////// int JackClient::OnSRateChange(long unsigned int n, void *o) { m_SampleRate=n; return 0; } ///////////////////////////////////////////////////////////////////////////////////////////// void JackClient::OnJackShutdown(void *o) { cerr<<"Shutdown"< &InputNames, vector &OutputNames) { InputNames.clear(); OutputNames.clear(); if (!m_Attached) return; //Outputs first const char **PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsOutput); int n=0; while(PortNameList[n]!=NULL) { OutputNames.push_back(PortNameList[n]); n++; } delete PortNameList; //Inputs second PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsInput); n=0; while(PortNameList[n]!=NULL) { InputNames.push_back(PortNameList[n]); n++; } delete PortNameList; } ///////////////////////////////////////////////////////////////////////////////////////////// // Input means input of SSM, so this connects jack sources to the plugin outputs void JackClient::ConnectInput(int n, const string &JackPort) { if (!IsAttached()) return; cerr<<"JackClient::ConnectInput: connecting source ["<Name<<"]"<ConnectedTo!="") { if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port))) cerr<<"JackClient::ConnectInput: cannot disconnect input port [" <ConnectedTo<<"] from ["<Name<<"]"<ConnectedTo = JackPort; if (jack_connect (m_Client, JackPort.c_str(), jack_port_name(m_InputPortMap[n]->Port))) cerr<<"JackClient::ConnectInput: cannot connect input port [" <Name<<"]"<Connected=true; } ///////////////////////////////////////////////////////////////////////////////////////////// // Output means output of SSM, so this connects plugin inputs to a jack destination void JackClient::ConnectOutput(int n, const string &JackPort) { if (!IsAttached()) return; cerr<<"JackClient::ConnectOutput: connecting source ["<Name<<"] to dest ["<ConnectedTo!="") { if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str())) cerr<<"JackClient::ConnectOutput: cannot disconnect output port [" <ConnectedTo<<"] from ["<Name<<"]"<ConnectedTo = JackPort; if (jack_connect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), JackPort.c_str())) cerr<<"JackClient::ConnectOutput: cannot connect output port [" <Name<<"] to ["<Connected=true; } ///////////////////////////////////////////////////////////////////////////////////////////// // Input means input of SSM, so this connects jack sources to the plugin outputs void JackClient::DisconnectInput(int n) { if (!IsAttached()) return; cerr<<"JackClient::DisconnectInput: Disconnecting input "<ConnectedTo!="") { if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port))) cerr<<"JackClient::ConnectInput: cannot disconnect input port [" <ConnectedTo<<"] from ["<Name<<"]"<Connected=false; } ///////////////////////////////////////////////////////////////////////////////////////////// // Output means output of SSM, so this connects plugin inputs to a jack destination void JackClient::DisconnectOutput(int n) { if (!IsAttached()) return; cerr<<"JackClient::DisconnectInput: Disconnecting input "<ConnectedTo!="") { if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str())) cerr<<"JackClient::ConnectOutput: cannot disconnect output port [" <ConnectedTo<<"] from ["<Name<<"]"<Connected=false; } ///////////////////////////////////////////////////////////////////////////////////////////// void JackClient::SetInputBuf(int ID, float* s) { if(m_InputPortMap.find(ID)!=m_InputPortMap.end()) m_InputPortMap[ID]->Buf=s; } ///////////////////////////////////////////////////////////////////////////////////////////// void JackClient::SetOutputBuf(int ID, float* s) { if(m_OutputPortMap.find(ID)!=m_OutputPortMap.end()) m_OutputPortMap[ID]->Buf=s; } ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// extern "C" { SpiralPlugin* SpiralPlugin_CreateInstance() { return new JackPlugin; } char** SpiralPlugin_GetIcon() { return SpiralIcon_xpm; } int SpiralPlugin_GetID() { return 31; } string SpiralPlugin_GetGroupName() { return "InputOutput"; } } /////////////////////////////////////////////////////// JackPlugin::JackPlugin() : m_UpdateNames(false), m_Connected(false) { m_RefCount++; // we are an output m_IsTerminal = true; m_PluginInfo.Name="Jack"; m_PluginInfo.Width=200; m_PluginInfo.Height=325; m_PluginInfo.NumInputs=NUM_OUTPUTS; m_PluginInfo.NumOutputs=NUM_INPUTS; for (int n=0; nRegister("Num",&m_GUIArgs.Num); m_AudioCH->RegisterData("Port",ChannelHandler::INPUT,&m_GUIArgs.Port,sizeof(m_GUIArgs.Port)); m_AudioCH->Register("NumInputPortNames",&m_NumInputPortNames,ChannelHandler::OUTPUT); m_AudioCH->Register("NumOutputPortNames",&m_NumOutputPortNames,ChannelHandler::OUTPUT); m_AudioCH->RegisterData("InputPortNames",ChannelHandler::OUTPUT,&m_InputPortNames,sizeof(m_InputPortNames)); m_AudioCH->RegisterData("OutputPortNames",ChannelHandler::OUTPUT,&m_OutputPortNames,sizeof(m_OutputPortNames)); m_AudioCH->Register("UpdateNames",&m_UpdateNames,ChannelHandler::OUTPUT); m_AudioCH->Register("Connected",&m_Connected,ChannelHandler::OUTPUT); } JackPlugin::~JackPlugin() { m_RefCount--; if (m_RefCount==0) { JackClient::Get()->Detach(); JackClient::PackUpAndGoHome(); } } PluginInfo &JackPlugin::Initialise(const HostInfo *Host) { PluginInfo& Info= SpiralPlugin::Initialise(Host); host=Host; if (m_RefCount==1) JackClient::Get()->SetCallback(cb_Update,m_Parent); return Info; } SpiralGUIType *JackPlugin::CreateGUI() { return new JackPluginGUI(m_PluginInfo.Width, m_PluginInfo.Height, this,m_AudioCH,m_HostInfo); } void JackPlugin::Execute() { } void JackPlugin::ExecuteCommands() { // only do this once per set of plugins m_NoExecuted++; if (m_NoExecuted!=m_RefCount) return; m_NoExecuted=0; // we want to process this whether we are connected to stuff or not JackClient* pJack=JackClient::Get(); // connect the buffers up if we are plugged into something for (int n=0; nSetOutputBuf(n,(float*)GetInput(n)->GetBuffer()); } else { pJack->SetOutputBuf(n,NULL); } } for (int n=0; nSetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer()); } if (m_AudioCH->IsCommandWaiting()) { switch (m_AudioCH->GetCommand()) { //case ATTACH : Attach(); break; //case DETACH : Detach(); break; //case CONNECTINPUT : pJack->ConnectInput(m_GUIArgs.Num,m_GUIArgs.Port); break; //case CONNECTOUTPUT : pJack->ConnectOutput(m_GUIArgs.Num,m_GUIArgs.Port); break; case UPDATE_NAMES : { int c=0; vector InputNames,OutputNames; GetPortNames(InputNames,OutputNames); for (vector::iterator i=InputNames.begin(); i!=InputNames.end(); ++i) { strcpy(m_InputPortNames[c],i->c_str()); c++; } c=0; for (vector::iterator i=OutputNames.begin(); i!=OutputNames.end(); ++i) { strcpy(m_OutputPortNames[c],i->c_str()); c++; } m_NumInputPortNames=InputNames.size(); m_NumOutputPortNames=OutputNames.size(); } break; default : break; } } m_Connected=JackClient::Get()->IsAttached(); }