/* 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 #include "JackPlugin.h" #include "JackPluginGUI.h" #include "SpiralIcon.xpm" using namespace std; int JackClient::JackProcessInstanceID = -1; int JackPlugin::JackInstanceCount = 0; const HostInfo *host = NULL; ///////////////////////////////////////////////////////////////////////////////////////////// inline void JackClient::JackProcess_i(jack_nframes_t nframes) { SetBufferSize(nframes); for (int n=0; nPort)) { sample_t *in = (sample_t *) jack_port_get_buffer(m_InputPortMap[n]->Port, nframes); assert( m_InputPortMap[n]->Buf ); memcpy( m_InputPortMap[n]->Buf, in, sizeof (sample_t) * GetBufferSize()); } } for (int n=0; nPort)) { if ((m_OutputPortMap[n]->Buf) && (!host->PAUSED)) { sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes); assert( m_OutputPortMap[n]->Buf ); memcpy (out, m_OutputPortMap[n]->Buf, sizeof (sample_t) * GetBufferSize()); } 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) * GetBufferSize()); } } } if (RunCallback&&RunContext) { if (JackProcessInstanceID==-1) JackProcessInstanceID = m_JackInstanceID; if (JackProcessInstanceID==m_JackInstanceID) RunCallback(RunContext,true); } } ///////////////////////////////////////////////////////////////////////////////////////////// inline void JackClient::SampleRateChange_i(jack_nframes_t nframes) { SetSampleRate(nframes); } ///////////////////////////////////////////////////////////////////////////////////////////// inline void JackClient::JackShutdown_i() { cerr<<"Shutdown"<PortNo = NewPortNumber; NewPort->Name=Name; NewPort->Buf=NULL; NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); m_InputPortMap[NewPortNumber]=NewPort; } void JackClient::AddOutputPort(int NewPortNumber) { char Name[256]; JackPort *NewPort; if (!(m_Client)) return; NewPort = new JackPort; sprintf(Name,"Out%d", NewPortNumber); NewPort->PortNo = NewPortNumber; NewPort->Name=Name; NewPort->Buf=NULL; NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); m_OutputPortMap[NewPortNumber]=NewPort; } void JackClient::RemoveInputPort(int PortNumber) { char Name[256]; JackPort *OldPort; if (!(m_Client)) return; OldPort = m_InputPortMap[PortNumber]; m_InputPortMap[PortNumber] = NULL; jack_port_unregister (m_Client, OldPort->Port); delete OldPort; } void JackClient::RemoveOutputPort(int PortNumber) { char Name[256]; JackPort *OldPort; if (!(m_Client)) return; OldPort = m_OutputPortMap[PortNumber]; m_OutputPortMap[PortNumber] = NULL; jack_port_unregister (m_Client, OldPort->Port); delete OldPort; } bool JackClient::Attach() { char JackClientName[256]; if (m_Attached) return true; sprintf(JackClientName,"SSM%d",GetJackInstanceID()); if (!(m_Client = jack_client_new(JackClientName))) { cerr<<"jack server not running?"< &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_JackClient=new JackClient; //clunky way to ensure unique JackID - JackInstanceCount is never dec //so new JackInstances per session always get a higher number even on //reload and new Patch m_JackInstanceID = JackInstanceCount; JackInstanceCount++; m_JackClient->SetJackInstanceID(m_JackInstanceID); // we are an output m_IsTerminal = true; m_Version = 2; m_PluginInfo.Name="Jack"; m_PluginInfo.Width=225; m_PluginInfo.Height=230; m_PluginInfo.NumInputs=0; m_PluginInfo.NumOutputs=0; m_PluginInfo.PortTips.clear(); m_PluginInfo.NumInputs = m_JackClient->GetJackOutputCount(); m_GUIArgs.NumInputs = m_PluginInfo.NumInputs; for (int n=0; nGetJackInputCount(); n++) { char Temp[256]; sprintf(Temp,"SSM Input %d",n); m_PluginInfo.PortTips.push_back(Temp); } m_PluginInfo.NumOutputs = m_JackClient->GetJackOutputCount(); m_GUIArgs.NumOutputs = m_PluginInfo.NumOutputs; for (int n=0; nGetJackOutputCount(); n++) { char Temp[256]; sprintf(Temp,"SSM Output %d",n); m_PluginInfo.PortTips.push_back(Temp); } m_AudioCH->Register("NumInputs",&m_GUIArgs.NumInputs); m_AudioCH->Register("NumOutputs",&m_GUIArgs.NumOutputs); 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() { if (m_JackClient) { m_JackClient->Detach(); delete m_JackClient; m_JackClient=NULL; } } PluginInfo &JackPlugin::Initialise(const HostInfo *Host) { PluginInfo& Info= SpiralPlugin::Initialise(Host); host = Host; m_JackClient->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() { if (m_IsDead) return; if (m_AudioCH->IsCommandWaiting()) { switch (m_AudioCH->GetCommand()) { case SET_PORT_COUNT : SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs); break; case UPDATE_NAMES : { int c=0; std::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 (std::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; case CHECK_PORT_CHANGES : if ((m_JackClient->IsAttached()) && (!m_JackClient->CheckingPortChanges)) { m_JackClient->CheckingPortChanges = true; for (int n=0; nm_OutputPortMap[n]->Port)!=m_JackClient->m_OutputPortMap[n]->Connected) m_JackClient->m_OutputPortsChanged.push_back(m_JackClient->m_OutputPortMap[n]); if (jack_port_connected(m_JackClient->m_InputPortMap[n]->Port)!=m_JackClient->m_InputPortMap[n]->Connected) m_JackClient->m_InputPortsChanged.push_back(m_JackClient->m_InputPortMap[n]); } m_JackClient->CheckingPortChanges = false; } break; default : break; } } m_Connected=m_JackClient->IsAttached(); } bool JackPlugin::Kill() { m_IsDead=true; UpdatePluginInfoWithHost(); RemoveAllInputs (); RemoveAllOutputs (); UpdatePluginInfoWithHost(); if (m_JackClient) { m_JackClient->Detach(); delete m_JackClient; m_JackClient=NULL; } return true; } void JackPlugin::Reset() { // connect the buffers up if we are plugged into something for (int n=0; nGetJackOutputCount(); n++) { m_JackClient->SetOutputBuf(n,NULL); } for (int n=0; nGetJackInputCount(); n++) { m_JackClient->SetInputBuf(n,NULL); } ResetPorts(); } void JackPlugin::ProcessAudio() { if (m_IsDead) return; // Make sure all plugins match Jack's SampleRate and Buffersize if ((m_JackClient->JackSampleRate() != -1) && (m_JackClient->JackBufferSize() != -1)) { ChangeBufferAndSampleRate(m_JackClient->JackBufferSize(), m_JackClient->JackSampleRate(), m_Parent); } // connect the buffers up if we are plugged into something for (int n=0; nGetJackOutputCount(); n++) { if (InputExists(n) && !m_HostInfo->PAUSED) { m_JackClient->SetOutputBuf(n,(float*)GetInput(n)->GetBuffer()); } else { m_JackClient->SetOutputBuf(n,NULL); } } for (int n=0; nGetJackInputCount(); n++) { if (OutputExists(n) && !m_HostInfo->PAUSED) { m_JackClient->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer()); } else { m_JackClient->SetInputBuf(n,NULL); } } } void JackPlugin::SetNumberPorts (int nInputs, int nOutputs) { UpdatePluginInfoWithHost(); RemoveAllInputs (); RemoveAllOutputs (); m_PluginInfo.NumInputs = 0; m_PluginInfo.NumOutputs = 0; m_PluginInfo.PortTips.clear (); CreatePorts (nInputs, nOutputs, true); UpdatePluginInfoWithHost (); } void JackPlugin::CreatePorts (int nInputs, int nOutputs, bool AddPorts) { m_PluginInfo.PortTips.clear(); m_PluginInfo.NumInputs = nInputs; m_JackClient->SetJackInputCount(nInputs); for (int n=0; nSetJackOutputCount(nOutputs); for (int n=0; n= '0') && (Test <= '9') ) { s >> Version; } else { //No Version, so use Version 1 Version = 1; } switch (Version) { case 2: { s >> NumInputs >> NumOutputs; m_GUIArgs.NumOutputs = min(max(NumOutputs, MIN_PORTS), MAX_PORTS); m_GUIArgs.NumInputs = min(max(NumInputs, MIN_PORTS), MAX_PORTS); SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs); } break; case 1: { //use original fixed defaults m_GUIArgs.NumInputs = 16; m_GUIArgs.NumOutputs = 16; SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs); } break; } }