diff --git a/SpiralSound/Plugins/JackPlugin/JackPlugin.C b/SpiralSound/Plugins/JackPlugin/JackPlugin.C index 381b5f7..11bc160 100644 --- a/SpiralSound/Plugins/JackPlugin/JackPlugin.C +++ b/SpiralSound/Plugins/JackPlugin/JackPlugin.C @@ -25,76 +25,182 @@ 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; +static int JackInstances = 0; +static int JackProcessInstance = -1; +///////////////////////////////////////////////////////////////////////////////////////////// +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); + memcpy (m_InputPortMap[n]->Buf, in, sizeof (sample_t) * GetBufferSize()); + } + } + + for (int n=0; nPort)) + { + 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) * 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 (JackProcessInstance==-1) + JackProcessInstance = m_JackInstanceID; + + if (JackProcessInstance==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; - if (!(m_Client = jack_client_new("SSM"))) + sprintf(JackClientName,"SSM%d",GetJackInstanceID()); + if (!(m_Client = jack_client_new(JackClientName))) { 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; - } + m_InputPortMap.clear(); + 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; - } + m_OutputPortMap.clear(); + for (int n=0; nPort)) - { - 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; -} + if (JackProcessInstance==m_JackInstanceID) + JackProcessInstance = -1; -///////////////////////////////////////////////////////////////////////////////////////////// - -void JackClient::OnJackShutdown(void *o) -{ - cerr<<"Shutdown"<Name<<"]"<Name<<"]"<ConnectedTo!="") { @@ -249,7 +298,7 @@ void JackClient::ConnectInput(int n, const string &JackPort) void JackClient::ConnectOutput(int n, const string &JackPort) { if (!IsAttached()) return; - cerr<<"JackClient::ConnectOutput: connecting source ["<Name<<"] to dest ["<Name<<"] to dest ["<ConnectedTo!="") { @@ -270,7 +319,7 @@ void JackClient::ConnectOutput(int n, const string &JackPort) void JackClient::DisconnectInput(int n) { if (!IsAttached()) return; - cerr<<"JackClient::DisconnectInput: Disconnecting input "<ConnectedTo!="") { @@ -287,7 +336,7 @@ void JackClient::DisconnectInput(int n) void JackClient::DisconnectOutput(int n) { if (!IsAttached()) return; - cerr<<"JackClient::DisconnectInput: Disconnecting input "<ConnectedTo!="") { @@ -312,7 +361,6 @@ void JackClient::SetOutputBuf(int ID, float* s) if(m_OutputPortMap.find(ID)!=m_OutputPortMap.end()) m_OutputPortMap[ID]->Buf=s; } -///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// extern "C" { @@ -343,32 +391,44 @@ JackPlugin::JackPlugin() : m_UpdateNames(false), m_Connected(false) { - m_RefCount++; - + m_JackClient=new JackClient; + + m_JackInstanceID = JackInstances ; + JackInstances++; + + m_JackClient->SetJackInstanceID(m_JackInstanceID); + // 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; + m_PluginInfo.Width=225; + m_PluginInfo.Height=230; + m_PluginInfo.NumInputs=0; + m_PluginInfo.NumOutputs=0; - for (int n=0; nGetJackOutputCount(); + + for (int n=0; nGetJackInputCount(); n++) + { char Temp[256]; - sprintf(Temp,"SSM Output %d",n); + sprintf(Temp,"SSM Input %d",n); m_PluginInfo.PortTips.push_back(Temp); - } + } - for (int n=0; nGetJackOutputCount(); + + for (int n=0; nGetJackOutputCount(); n++) { char Temp[256]; - sprintf(Temp,"SSM Input %d",n); + sprintf(Temp,"SSM Output %d",n); m_PluginInfo.PortTips.push_back(Temp); - } - - m_AudioCH->Register("Num",&m_GUIArgs.Num); + } + + 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); @@ -380,12 +440,9 @@ m_Connected(false) JackPlugin::~JackPlugin() { - m_RefCount--; - if (m_RefCount==0) - { - JackClient::Get()->Detach(); - JackClient::PackUpAndGoHome(); - } + m_JackClient->Detach(); + delete m_JackClient; + m_JackClient=NULL; } PluginInfo &JackPlugin::Initialise(const HostInfo *Host) @@ -393,7 +450,7 @@ PluginInfo &JackPlugin::Initialise(const HostInfo *Host) PluginInfo& Info= SpiralPlugin::Initialise(Host); host=Host; - if (m_RefCount==1) JackClient::Get()->SetCallback(cb_Update,m_Parent); + m_JackClient->SetCallback(cb_Update,m_Parent); return Info; } @@ -405,23 +462,70 @@ SpiralGUIType *JackPlugin::CreateGUI() this,m_AudioCH,m_HostInfo); } +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; nIsCommandWaiting(); + int command = (commandwaiting)?(int)m_AudioCH->GetCommand():0; + + if (commandwaiting) + { + switch (command) { + case SET_PORT_COUNT : + SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs); + } + } + + // we want to process this whether we are connected to stuff or not - JackClient* pJack=JackClient::Get(); + JackClient* pJack=m_JackClient; // connect the buffers up if we are plugged into something - for (int n=0; nGetJackOutputCount(); n++) { if (InputExists(n)) { @@ -433,24 +537,27 @@ void JackPlugin::ExecuteCommands() } } - for (int n=0; nGetJackInputCount(); n++) { - pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer()); - } - - if (m_AudioCH->IsCommandWaiting()) + if (OutputExists(n)) + { + pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer()); + } + else + { + pJack->SetInputBuf(n,NULL); + } + } + + if (commandwaiting) { - switch (m_AudioCH->GetCommand()) + switch (command) { - //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; + std::vector InputNames,OutputNames; GetPortNames(InputNames,OutputNames); for (vector::iterator i=InputNames.begin(); i!=InputNames.end(); ++i) @@ -461,7 +568,7 @@ void JackPlugin::ExecuteCommands() c=0; - for (vector::iterator i=OutputNames.begin(); + for (std::vector::iterator i=OutputNames.begin(); i!=OutputNames.end(); ++i) { strcpy(m_OutputPortNames[c],i->c_str()); @@ -472,8 +579,25 @@ void JackPlugin::ExecuteCommands() 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=JackClient::Get()->IsAttached(); + m_Connected=m_JackClient->IsAttached(); } diff --git a/SpiralSound/Plugins/JackPlugin/JackPlugin.h b/SpiralSound/Plugins/JackPlugin/JackPlugin.h index 50e1661..a43e3b1 100644 --- a/SpiralSound/Plugins/JackPlugin/JackPlugin.h +++ b/SpiralSound/Plugins/JackPlugin/JackPlugin.h @@ -19,28 +19,34 @@ #include "../SpiralPlugin.h" #include "../../RiffWav.h" #include -#include #include +using namespace std; + typedef jack_default_audio_sample_t sample_t; #ifndef JackPLUGIN #define JackPLUGIN -const int NUM_INPUTS = 8; -const int NUM_OUTPUTS = 8; -const int MAX_INPUTPORTS = 256; -const int MAX_OUTPUTPORTS = 256; +const int MAX_PORTS = 64; +const int MIN_PORTS = 2; class JackClient { public: - static JackClient *Get() { if(!m_Singleton) m_Singleton=new JackClient; return m_Singleton; } - static void PackUpAndGoHome() { if(m_Singleton) { delete m_Singleton; m_Singleton=NULL; } } + JackClient(); + virtual ~JackClient(); + + void AddInputPort(int NewPortNumber); + void AddOutputPort(int NewPortNumber); + + void RemoveInputPort(int PortNumber); + void RemoveOutputPort(int PortNumber); bool Attach(); void Detach(); bool IsAttached() { return m_Attached; } + void SetAttached(bool Attached) { m_Attached = Attached; } void SetCallback(void(*Run)(void*, bool m),void *Context) { RunCallback=Run; RunContext=Context; } void GetPortNames(std::vector &InputNames,std::vector &OutputNames); void ConnectInput(int n, const std::string &JackPort); @@ -51,17 +57,16 @@ public: std::string GetOutputName(int ID) { return m_OutputPortMap[ID]->Name; } void SetInputBuf(int ID, float* s); void SetOutputBuf(int ID, float* s); - -protected: - JackClient(); - ~JackClient(); - - static int Process(jack_nframes_t nframes, void *o); - static int OnBufSizeChange(long unsigned int n, void *o); - static int OnSRateChange(long unsigned int n, void *o); - static void OnJackShutdown(void *o); - -private: + int GetJackInstanceID() { return m_JackInstanceID; } + void SetJackInstanceID(int JackInstanceID) { m_JackInstanceID=JackInstanceID; } + int GetBufferSize() { return m_BufferSize; } + void SetBufferSize(jack_nframes_t BufferSize) { m_BufferSize=BufferSize; } + int GetSampleRate() { return m_BufferSize; } + void SetSampleRate(jack_nframes_t SampleRate) { m_SampleRate=SampleRate; } + int GetJackInputCount() { return m_JackInputCount; } + void SetJackInputCount(int JackInputCount) { m_JackInputCount=JackInputCount; } + int GetJackOutputCount() { return m_JackOutputCount; } + void SetJackOutputCount(int JackOutputCount) { m_JackOutputCount=JackOutputCount; } class JackPort { @@ -69,23 +74,42 @@ private: JackPort::JackPort() : Connected(false),Buf(NULL),Port(NULL) {} - std::string Name; + int PortNo; + std::string Name; bool Connected; float* Buf; jack_port_t* Port; std::string ConnectedTo; }; - static JackClient* m_Singleton; - static jack_client_t* m_Client; - static std::map m_InputPortMap; - static std::map m_OutputPortMap; - static long unsigned int m_BufferSize; - static long unsigned int m_SampleRate; - static bool m_Attached; + jack_client_t* m_Client; + std::map m_InputPortMap; + std::map m_OutputPortMap; + + //// Kludge for GUI //// + bool CheckingPortChanges; + std::vector m_OutputPortsChanged; + std::vector m_InputPortsChanged; - static void(*RunCallback)(void*, bool m); - static void *RunContext; + //// inline Callbacks //// + inline void JackProcess_i(jack_nframes_t nframes); + inline void SampleRateChange_i(jack_nframes_t nframes); + inline void JackShutdown_i(); + + //// static Callbacks //// + static int JackProcess(jack_nframes_t nframes, void *jack_client) { ((JackClient *)jack_client)->JackProcess_i(nframes); return 0;} + static int SampleRateChange(jack_nframes_t nframes, void *jack_client) { ((JackClient *)jack_client)->SampleRateChange_i(nframes); return 0;} + static void JackShutdown(void *jack_client) { ((JackClient *)jack_client)->JackShutdown_i();} +private: + jack_nframes_t m_BufferSize; + jack_nframes_t m_SampleRate; + bool m_Attached; + int m_JackInputCount; + int m_JackOutputCount; + int m_JackInstanceID; + + void(*RunCallback)(void*, bool m); + void *RunContext; }; /////////////////////////////////////////////////// @@ -103,32 +127,42 @@ public: virtual void StreamOut(std::ostream &s) {} virtual void StreamIn(std::istream &s) {} - enum GUICommands{NONE,ATTACH,DETACH,CONNECTINPUT,CONNECTOUTPUT,UPDATE_NAMES}; + JackClient *GetJackClient() { return m_JackClient; } + + void SetNumberPorts (int nInputs, int nOutputs); + + enum GUICommands{NONE,UPDATE_NAMES,SET_PORT_COUNT,CHECK_PORT_CHANGES}; struct GUIArgs { + int NumInputs; + int NumOutputs; int Num; char Port[256]; }; - + + void Attach() { m_JackClient->Attach(); } + void Detach() { m_JackClient->Detach(); } private: + const HostInfo* host; + GUIArgs m_GUIArgs; // slightly clumsy, but we have to share this data with the gui int m_NumInputPortNames; - char m_InputPortNames[MAX_INPUTPORTS][256]; + char m_InputPortNames[MAX_PORTS][256]; int m_NumOutputPortNames; - char m_OutputPortNames[MAX_OUTPUTPORTS][256]; - - void Attach() { JackClient::Get()->Attach(); } - void Detach() { JackClient::Get()->Detach(); } - void GetPortNames(std::vector &InputNames,std::vector &OutputNames) { JackClient::Get()->GetPortNames(InputNames,OutputNames); } - void ConnectInput(int n, const std::string &JackPort) { JackClient::Get()->ConnectInput(n,JackPort); } - void ConnectOutput(int n, const std::string &JackPort) { JackClient::Get()->ConnectOutput(n,JackPort); } - - static int m_RefCount; - static int m_NoExecuted; - bool m_UpdateNames; - bool m_Connected; + char m_OutputPortNames[MAX_PORTS][256]; + + void GetPortNames(std::vector &InputNames,std::vector &OutputNames) { m_JackClient->GetPortNames(InputNames,OutputNames); } + void ConnectInput(int n, const std::string &JackPort) { m_JackClient->ConnectInput(n,JackPort); } + void ConnectOutput(int n, const std::string &JackPort) { m_JackClient->ConnectOutput(n,JackPort); } + + void CreatePorts (int nInputs, int nOutputs, bool ); + + bool m_UpdateNames; + bool m_Connected; + JackClient *m_JackClient; + int m_JackInstanceID; }; #endif diff --git a/SpiralSound/Plugins/JackPlugin/JackPluginGUI.C b/SpiralSound/Plugins/JackPlugin/JackPluginGUI.C index 7a1e304..9d4eae7 100644 --- a/SpiralSound/Plugins/JackPlugin/JackPluginGUI.C +++ b/SpiralSound/Plugins/JackPlugin/JackPluginGUI.C @@ -24,11 +24,9 @@ using namespace std; -static int Numbers[255]; - //////////////////////////////////////////////////////////////////////// -int OptionsList(const vector &List) +int OptionsList(const std::vector &List) { Fl_Double_Window *Win = new Fl_Double_Window(300,300); Fl_Button *Ok = new Fl_Button(10,275,40,20,"Ok"); @@ -37,7 +35,7 @@ int OptionsList(const vector &List) Cancel->labelsize(10); Fl_Hold_Browser* Browser = new Fl_Hold_Browser(5,5,290,265,""); - for (vector::const_iterator i = List.begin(); + for (std::vector::const_iterator i = List.begin(); i!=List.end(); i++) { Browser->add(i->c_str()); @@ -77,102 +75,357 @@ int OptionsList(const vector &List) JackPluginGUI::JackPluginGUI(int w, int h,JackPlugin *o,ChannelHandler *ch,const HostInfo *Info) : SpiralPluginGUI(w,h,o,ch) { - for (int n=0; n<255; n++) Numbers[n]=n; + m_GUIColour = (Fl_Color)Info->GUI_COLOUR; + m_JackPlugin =o; + m_JackClient = o->GetJackClient(); - m_Indicator = new Fl_LED_Button(85,15,30,30,""); + m_Indicator = new Fl_LED_Button(w/2 - 15,15,30,30,""); m_Indicator->value(0); m_Indicator->color(FL_RED); + add(m_Indicator); + + m_Remove = new Fl_Button(5,15,25,25,"-"); + m_Remove->box (FL_PLASTIC_UP_BOX); + m_Remove->color (m_GUIColour); + m_Remove->type(0); + m_Remove->labelsize(2); + m_Remove->selection_color (m_GUIColour); + m_Remove->callback((Fl_Callback*)cb_Remove, this); + add(m_Remove); - m_Attach = new Fl_Button(5,40,190,20,"Attach"); + m_Add = new Fl_Button(30,15,25,25,"+"); + m_Add->box (FL_PLASTIC_UP_BOX); + m_Add->color (m_GUIColour); + m_Add->type(0); + m_Add->labelsize(2); + m_Add->selection_color (m_GUIColour); + m_Add->callback((Fl_Callback*)cb_Add, this); + add(m_Add); + + m_Attach = new Fl_Button(5,45,w - 10,20,"Attach"); + m_Attach->box (FL_PLASTIC_UP_BOX); + m_Attach->color (m_GUIColour); m_Attach->type(0); m_Attach->labelsize(10); - m_Attach->callback((Fl_Callback*)cb_Attach); + m_Attach->selection_color (m_GUIColour); + m_Attach->callback((Fl_Callback*)cb_Attach, this); + add(m_Attach); - m_Detach = new Fl_Button(5,60,190,20,"Detach"); + m_Detach = new Fl_Button(5,65,w - 10,20,"Detach"); + m_Detach->box (FL_PLASTIC_UP_BOX); + m_Detach->color (m_GUIColour); m_Detach->type(0); m_Detach->labelsize(10); - m_Detach->callback((Fl_Callback*)cb_Detach); + m_Detach->selection_color (m_GUIColour); + m_Detach->callback((Fl_Callback*)cb_Detach, this); + add(m_Detach); - int yoff=80; + m_Scroll = new Fl_Scroll(5, 90, w - 10, h - 102); + m_Scroll->box(FL_PLASTIC_DOWN_BOX); + m_Scroll->type(Fl_Scroll::VERTICAL_ALWAYS); + m_Scroll->position(0, 0); + add(m_Scroll); + + m_OutputPack = new Fl_Pack(15, 90, 85, h - 102); + m_Scroll->add(m_OutputPack); - for (int n=0; nlabelsize(8); - //m_OutputLabel[n]->labeltype(FL_ENGRAVED_LABEL); - m_OutputButton[n] = new Fl_Button(5,n*30+yoff+10,95,20,"None"); - m_OutputButton[n]->type(1); - m_OutputButton[n]->labelsize(8); - m_OutputButton[n]->callback((Fl_Callback*)cb_OutputConnect,&Numbers[n]); - } + m_InputPack = new Fl_Pack(110, 90, 85, h - 102); + m_Scroll->add(m_InputPack); - for (int n=0; nGetJackInputCount(); n++) { - sprintf(m_InputName[n],"Input %d",n); - m_InputLabel[n] = new Fl_Box(100,n*30+yoff,95,10,m_InputName[n]); - m_InputLabel[n]->labelsize(8); - //m_InputLabel[n]->labeltype(FL_ENGRAVED_LABEL); - m_InputButton[n] = new Fl_Button(100,n*30+yoff+10,95,20,"None"); - m_InputButton[n]->type(1); - m_InputButton[n]->labelsize(8); - m_InputButton[n]->callback((Fl_Callback*)cb_InputConnect,&Numbers[n]); + AddOutput(); + AddInput(); } - + end(); } void JackPluginGUI::UpdateValues(SpiralPlugin *o) { - } void JackPluginGUI::Update() { + if (m_GUICH->GetBool("Connected")) { + m_JackClient->CheckingPortChanges = true; + + for (unsigned int n=0; nm_OutputPortsChanged.size(); n++) { + m_JackClient->m_OutputPortsChanged[n]->Connected = jack_port_connected(m_JackClient->m_OutputPortsChanged[n]->Port); + + if (jack_port_connected(m_JackClient->m_OutputPortsChanged[n]->Port)) { + if (m_JackClient->m_OutputPortsChanged[n]->ConnectedTo!="") { + m_OutputButton[n]->label(m_JackClient->m_OutputPortsChanged[n]->ConnectedTo.c_str()); + } + else + { + const char** connections = jack_port_get_all_connections(m_JackClient->m_Client,m_JackClient->m_OutputPortsChanged[n]->Port); + if (connections) { + m_OutputButton[m_JackClient->m_OutputPortsChanged[n]->PortNo]->label(connections[0]); + free(connections); + } + } + m_OutputButton[m_JackClient->m_OutputPortsChanged[n]->PortNo]->value(1); + } + else + { + m_OutputButton[m_JackClient->m_OutputPortsChanged[n]->PortNo]->value(0); + m_OutputButton[m_JackClient->m_OutputPortsChanged[n]->PortNo]->label("None"); + } + } + + m_JackClient->m_OutputPortsChanged.clear(); + + for (unsigned int n=0; nm_InputPortsChanged.size(); n++) { + m_JackClient->m_InputPortsChanged[n]->Connected = jack_port_connected(m_JackClient->m_InputPortsChanged[n]->Port); + + if (m_JackClient->m_InputPortsChanged[n]->Connected) { + if (m_JackClient->m_InputPortsChanged[n]->ConnectedTo!="") { + m_InputButton[n]->label(m_JackClient->m_InputPortsChanged[n]->ConnectedTo.c_str()); + } + else + { + const char** connections = jack_port_get_all_connections(m_JackClient->m_Client,m_JackClient->m_InputPortsChanged[n]->Port); + if (connections) { + m_InputButton[m_JackClient->m_InputPortsChanged[n]->PortNo]->label(connections[0]); + free(connections); + } + } + m_InputButton[m_JackClient->m_InputPortsChanged[n]->PortNo]->value(1); + } + else + { + m_InputButton[m_JackClient->m_InputPortsChanged[n]->PortNo]->value(0); + m_InputButton[m_JackClient->m_InputPortsChanged[n]->PortNo]->label("None"); + } + + } + + m_JackClient->m_InputPortsChanged.clear(); + + m_JackClient->CheckingPortChanges = false; + } + + m_GUICH->SetCommand (JackPlugin::CHECK_PORT_CHANGES); + m_Indicator->value(m_GUICH->GetBool("Connected")); redraw(); } //// Callbacks //// -inline void JackPluginGUI::cb_Attach_i(Fl_Button* o, void* v) +void JackPluginGUI::RemoveOutput() { + int n =(int) m_InputName.size() - 1; + + if (m_OutputName[n]) + { + delete(m_OutputName[n]); + m_OutputName[n] = NULL; + m_OutputName.pop_back(); + } + + if (m_OutputLabel[n]) + { + m_OutputPack->remove(m_OutputLabel[n]); + delete(m_OutputLabel[n]); + m_OutputLabel[n] = NULL; + m_OutputLabel.pop_back(); + m_OutputPack->redraw(); + m_Scroll->redraw(); + } + + if (m_OutputButton[n]) + { + m_OutputPack->remove(m_OutputButton[n]); + delete(m_OutputButton[n]); + m_OutputButton[n] = NULL; + m_OutputButton.pop_back(); + m_OutputPack->redraw(); + m_Scroll->redraw(); + } +} + +void JackPluginGUI::RemoveInput() { + int n = (int) m_InputName.size() - 1; + + if (m_InputName[n]) + { + delete(m_InputName[n]); + m_InputName[n] = NULL; + m_InputName.pop_back(); + } + + if (m_InputLabel[n]) + { + m_InputPack->remove(m_InputLabel[n]); + delete(m_InputLabel[n]); + m_InputLabel[n] = NULL; + m_InputLabel.pop_back(); + m_InputPack->redraw(); + m_Scroll->redraw(); + } + + if (m_InputButton[n]) + { + m_InputPack->remove(m_InputButton[n]); + delete(m_InputButton[n]); + m_InputButton[n] = NULL; + m_InputButton.pop_back(); + m_InputPack->redraw(); + m_Scroll->redraw(); + + } +} + +void JackPluginGUI::AddOutput() { + int n = (int) m_OutputName.size(); + char *NewName = new char [256]; + + sprintf(NewName,"Output %d",n); + m_OutputName.push_back(NewName); + + m_OutputLabel.push_back(new Fl_Box(0,n*30,90,10,m_OutputName[n])); + m_OutputLabel[n]->labelsize(8); + m_OutputPack->add(m_OutputLabel[n]); + + m_OutputButton.push_back(new Fl_Button(0,n*30+10,90,20,"None")); + m_OutputButton[n]->type(1); + m_OutputButton[n]->labelsize(8); + m_OutputButton[n]->callback((Fl_Callback*)cb_OutputConnect,this); + m_OutputPack->add(m_OutputButton[n]); + + redraw(); + Fl::check(); +} + +void JackPluginGUI::AddInput() { + int n = (int) m_InputName.size(); + char *NewName = new char [256]; + + sprintf(NewName,"Input %d",n); + m_InputName.push_back(NewName); + + m_InputLabel.push_back(new Fl_Box(95,n*30,90,10, m_InputName[n])); + m_InputLabel[n]->labelsize(8); + m_InputPack->add(m_InputLabel[n]); + + m_InputButton.push_back(new Fl_Button(95,n*30+10,90,20,"None")); + m_InputButton[n]->type(1); + m_InputButton[n]->labelsize(8); + m_InputButton[n]->callback((Fl_Callback*)cb_InputConnect,this); + m_InputPack->add(m_InputButton[n]); + + redraw(); + Fl::check(); +} + +inline void JackPluginGUI::cb_Remove_i(Fl_Button* o) { - //m_GUICH->SetCommand(JackPlugin::ATTACH); - JackClient::Get()->Attach(); + int n = (int) m_InputName.size(); + + if (n > MIN_PORTS) + { + RemoveOutput() ; + RemoveInput() ; + + m_GUICH->Set ("NumInputs", n-1); + m_GUICH->Set ("NumOutputs", n-1); + m_GUICH->SetCommand (JackPlugin::SET_PORT_COUNT); + m_GUICH->Wait (); + + /* removing connections live must be called directly from here in the GUI thread */ + if (m_GUICH->GetBool("Connected")) { + m_JackClient->RemoveInputPort(n-1); + m_JackClient->RemoveOutputPort(n-1); + } + + if (n > 19) { + resize (x(), y(), w(), h()-7); + + m_Indicator->resize (x()+w()/2 - 15,y()+15,30,30); + m_Remove->resize (x()+5,y()+15,25,25); + m_Add->resize (x()+30,y()+15,25,25); + m_Attach->resize (x()+5,y()+45,w() - 10,20); + m_Detach->resize (x()+5,y()+65,w() - 10,20); + m_Scroll->resize (x()+5, y()+90, w() - 10, h() - 102); + m_OutputPack->resize (x()+15, y()+90, 85, h() - 102); + m_InputPack->resize (x()+110, y()+90, 85, h() - 102); + } + } } -void JackPluginGUI::cb_Attach(Fl_Button* o, void* v) -{ ((JackPluginGUI*)(o->parent()))->cb_Attach_i(o,v);} -inline void JackPluginGUI::cb_Detach_i(Fl_Button* o, void* v) +inline void JackPluginGUI::cb_Add_i(Fl_Button* o) { - //m_GUICH->SetCommand(JackPlugin::DETACH); - - for (int n=0; nGetBool("Connected")) { + m_JackClient->AddInputPort(n); + m_JackClient->AddOutputPort(n); + } + + m_GUICH->Set ("NumInputs", n+1); + m_GUICH->Set ("NumOutputs", n+1); + m_GUICH->SetCommand (JackPlugin::SET_PORT_COUNT); + m_GUICH->Wait (); + + AddOutput() ; + AddInput() ; + + if (n > 20) { + resize (x(), y(), w(), h()+12); + + m_Indicator->resize (x()+w()/2 - 15,y()+15,30,30); + m_Remove->resize (x()+5,y()+15,25,25); + m_Add->resize (x()+30,y()+15,25,25); + m_Attach->resize (x()+5,y()+45,w() - 10,20); + m_Detach->resize (x()+5,y()+65,w() - 10,20); + m_Scroll->resize (x()+5, y()+90, w() - 10, h() - 102); + m_OutputPack->resize (x()+15, y()+90, 85, h() - 102); + m_InputPack->resize (x()+110, y()+90, 85, h() - 102); + } + } +} + +inline void JackPluginGUI::cb_Attach_i(Fl_Button* o) +{ + m_JackPlugin->Attach(); +} + +inline void JackPluginGUI::cb_Detach_i(Fl_Button* o) +{ + for (int n=0; n<(int)m_OutputName.size(); n++) { m_OutputButton[n]->value(false); m_OutputButton[n]->label("None"); } - for (int n=0; nvalue(false); m_InputButton[n]->label("None"); } - JackClient::Get()->Detach(); + m_JackPlugin->Detach(); } -void JackPluginGUI::cb_Detach(Fl_Button* o, void* v) -{ ((JackPluginGUI*)(o->parent()))->cb_Detach_i(o,v);} -inline void JackPluginGUI::cb_OutputConnect_i(Fl_Button* o, void* v) +inline void JackPluginGUI::cb_OutputConnect_i(Fl_Button* o) { - if (o->value()) + int index=0; + std::vector::iterator it = std::find( m_OutputButton.begin(), m_OutputButton.end(), o ); + + if ( it != m_OutputButton.end() ) + index = std::distance( m_OutputButton.begin(), it ); + + if ((o->value()) && m_GUICH->GetBool("Connected")) { m_GUICH->SetCommand(JackPlugin::UPDATE_NAMES); m_GUICH->Wait(); // bit of a hack for multithreaded safety int ninputs=m_GUICH->GetInt("NumOutputPortNames"); - char inputs[MAX_INPUTPORTS][256]; + char inputs[MAX_PORTS][256]; m_GUICH->GetData("InputPortNames",inputs); vector Inputs; @@ -181,37 +434,43 @@ inline void JackPluginGUI::cb_OutputConnect_i(Fl_Button* o, void* v) // connect this plugin's output to a jack input if (choice>0) - { - //m_GUICH->Set("Num",(*(int*)v)); - //m_GUICH->SetData("Port",inputs[choice-1]); - //m_GUICH->SetCommand(JackPlugin::CONNECTOUTPUT); - - JackClient::Get()->ConnectOutput((*(int*)v),inputs[choice-1]); + { + m_JackClient->ConnectOutput(index,inputs[choice-1]); o->label(inputs[choice-1]); o->redraw(); } + else { + o->label("None"); + o->value(0); + o->redraw(); + } } else { - JackClient::Get()->DisconnectOutput((*(int*)v)); + m_JackClient->DisconnectOutput(index); o->label("None"); + o->value(0); o->redraw(); } } -void JackPluginGUI::cb_OutputConnect(Fl_Button* o, void* v) -{ ((JackPluginGUI*)(o->parent()))->cb_OutputConnect_i(o,v);} -inline void JackPluginGUI::cb_InputConnect_i(Fl_Button* o, void* v) +inline void JackPluginGUI::cb_InputConnect_i(Fl_Button* o) { - if (o->value()) + int index=0; + std::vector::iterator it = std::find( m_InputButton.begin(), m_InputButton.end(), o ); + + if ( it != m_InputButton.end() ) + index = std::distance( m_InputButton.begin(), it ); + + if ((o->value()) && (m_JackClient) && (m_JackClient->IsAttached())) { m_GUICH->SetCommand(JackPlugin::UPDATE_NAMES); m_GUICH->Wait(); // bit of a hack for multithreaded safety int noutputs=m_GUICH->GetInt("NumOutputPortNames"); - char outputs[MAX_OUTPUTPORTS][256]; + char outputs[MAX_PORTS][256]; m_GUICH->GetData("OutputPortNames",outputs); vector Outputs; @@ -220,40 +479,36 @@ inline void JackPluginGUI::cb_InputConnect_i(Fl_Button* o, void* v) // connect this plugin's input to a jack output if (choice>0) - { - //m_GUICH->Set("Num",(*(int*)v)); - //m_GUICH->SetData("Port",outputs[choice-1]); - //m_GUICH->SetCommand(JackPlugin::CONNECTINPUT); - - JackClient::Get()->ConnectInput((*(int*)v),outputs[choice-1]); + { + m_JackClient->ConnectInput(index,outputs[choice-1]); o->label(outputs[choice-1]); o->redraw(); } + else { + o->label("None"); + o->value(0); + o->redraw(); + } } else { - JackClient::Get()->DisconnectInput((*(int*)v)); + m_JackClient->DisconnectInput(index); o->label("None"); + o->value(0); o->redraw(); } } -void JackPluginGUI::cb_InputConnect(Fl_Button* o, void* v) -{ ((JackPluginGUI*)(o->parent()))->cb_InputConnect_i(o,v);} const string JackPluginGUI::GetHelpText(const string &loc){ return string("") + "JACK is the Jack Audio Connection Kit, and allows multiple Linux audio\n" + "apps to be connected together and run simultaneously in a low latency.\n" + "environment.\n\n" - + "This plugin allows you to connect up to 8 inputs and outputs to other\n" - + "JACK apps (providing a server is running)\n" - + "You can use the JackPlugin to connect the ports, or a external program\n" - + "such as the excellent qjackconnect app. Be aware however that if you\n" - + "connect from an external app, the port GUI does not update itself yet.\n" - + "Another problem yet to be fixed is that ssm will get confused if more\n" - + "than one JackPlugin is being used. It's best to use one central\n" - + "JackPlugin at this time.\n\n" + + "This plugin allows you to connect up to 64 inputs and outputs to other\n" + + "JACK apps (providing a server is running and your system can handle it)\n" + + "You can use the JackPlugin to connect the ports, or an external program\n" + + "such as the excellent qjackconnect app.\n\n" + "When using JACK, make sure the buffer size and samplerate are set to\n" + "match the JACK server, otherwise glitchy playback, and/or crashes may\n" + "result"; diff --git a/SpiralSound/Plugins/JackPlugin/JackPluginGUI.h b/SpiralSound/Plugins/JackPlugin/JackPluginGUI.h index ff62dc3..f754e43 100644 --- a/SpiralSound/Plugins/JackPlugin/JackPluginGUI.h +++ b/SpiralSound/Plugins/JackPlugin/JackPluginGUI.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "../Widgets/Fl_Knob.H" #include "../Widgets/Fl_LED_Button.H" #include "JackPlugin.h" @@ -30,6 +32,8 @@ #ifndef JACK_GUI_H #define JACK_GUI_H +using namespace std; + class JackPluginGUI : public SpiralPluginGUI { public: @@ -42,28 +46,52 @@ protected: const std::string GetHelpText(const std::string &loc); private: + JackClient *m_JackClient; + JackPlugin *m_JackPlugin; + + Fl_Color m_GUIColour; Fl_LED_Button *m_Indicator; + + Fl_Button *m_Remove; + Fl_Button *m_Add; + Fl_Button *m_Attach; Fl_Button *m_Detach; - char m_InputName[NUM_INPUTS][256]; - Fl_Box *m_InputLabel[NUM_INPUTS]; - Fl_Button *m_InputButton[NUM_INPUTS]; + Fl_Scroll *m_Scroll; + Fl_Pack *m_InputPack; + Fl_Pack *m_OutputPack; + + std::vector m_InputName; + std::vector m_InputLabel; + std::vector m_InputButton; - char m_OutputName[NUM_INPUTS][256]; - Fl_Box *m_OutputLabel[NUM_OUTPUTS]; - Fl_Button *m_OutputButton[NUM_OUTPUTS]; - - //// Callbacks //// - inline void cb_Attach_i(Fl_Button* o, void* v); - static void cb_Attach(Fl_Button* o, void* v); - inline void cb_Detach_i(Fl_Button* o, void* v); - static void cb_Detach(Fl_Button* o, void* v); - inline void cb_OutputConnect_i(Fl_Button* o, void* v); - static void cb_OutputConnect(Fl_Button* o, void* v); - inline void cb_InputConnect_i(Fl_Button* o, void* v); - static void cb_InputConnect(Fl_Button* o, void* v); + std::vector m_OutputName; + std::vector m_OutputLabel; + std::vector m_OutputButton; + + void RemoveInput() ; + void RemoveOutput() ; + + void AddInput() ; + void AddOutput() ; + + //// inline Callbacks //// + inline void cb_Add_i(Fl_Button* o); + inline void cb_Remove_i(Fl_Button* o); + inline void cb_Attach_i(Fl_Button* o); + inline void cb_Detach_i(Fl_Button* o); + inline void cb_OutputConnect_i(Fl_Button* o); + inline void cb_InputConnect_i(Fl_Button* o); + + //// Static Callbacks //// + static void cb_Add(Fl_Button* o, JackPluginGUI* v) {v->cb_Add_i(o);} + static void cb_Remove(Fl_Button* o, JackPluginGUI* v) {v->cb_Remove_i(o);} + static void cb_Attach(Fl_Button* o, JackPluginGUI* v) {v->cb_Attach_i(o);} + static void cb_Detach(Fl_Button* o, JackPluginGUI* v) {v->cb_Detach_i(o);} + static void cb_OutputConnect(Fl_Button* o, JackPluginGUI* v) {v->cb_OutputConnect_i(o);} + static void cb_InputConnect(Fl_Button* o, JackPluginGUI* v) {v->cb_InputConnect_i(o);} }; #endif