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 
19 #include <stdio.h>
20 #include <limits.h>
21 #include <math.h>
22 
23 #include "JackPlugin.h"
24 #include "JackPluginGUI.h"
25 #include "SpiralIcon.xpm"
26 
27 using namespace std;
28 
29 int JackClient::JackProcessInstanceID = -1;
30 int JackPlugin::JackInstanceCount = 0;
31 
32 /////////////////////////////////////////////////////////////////////////////////////////////
JackProcess_i(jack_nframes_t nframes)33 inline void JackClient::JackProcess_i(jack_nframes_t nframes)
34 {
35 	SetBufferSize(nframes);
36 
37 	for (int n=0; n<GetJackInputCount(); n++)
38 	{
39 		if (jack_port_connected(m_InputPortMap[n]->Port))
40 		{
41 			sample_t *in = (sample_t *) jack_port_get_buffer(m_InputPortMap[n]->Port, nframes);
42 			memcpy (m_InputPortMap[n]->Buf, in, sizeof (sample_t) * GetBufferSize());
43 		}
44 	}
45 
46 	for (int n=0; n<GetJackOutputCount(); n++)
47 	{
48 		if (jack_port_connected(m_OutputPortMap[n]->Port))
49 		{
50 			if (m_OutputPortMap[n]->Buf)
51 			{
52 				sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes);
53 				memcpy (out, m_OutputPortMap[n]->Buf, sizeof (sample_t) * GetBufferSize());
54 			}
55 			else // no output availible, clear
56 			{
57 				sample_t *out = (sample_t *) jack_port_get_buffer(m_OutputPortMap[n]->Port, nframes);
58 				memset (out, 0, sizeof (sample_t) * GetBufferSize());
59 			}
60 		}
61 	}
62 
63 	if (RunCallback&&RunContext)
64 	{
65 		if (JackProcessInstanceID==-1)
66 			JackProcessInstanceID = m_JackInstanceID;
67 
68 		if (JackProcessInstanceID==m_JackInstanceID)
69 			RunCallback(RunContext,true);
70 	}
71 }
72 
73 /////////////////////////////////////////////////////////////////////////////////////////////
74 
SampleRateChange_i(jack_nframes_t nframes)75 inline void JackClient::SampleRateChange_i(jack_nframes_t nframes)
76 {
77 	SetSampleRate(nframes);
78 }
79 
80 /////////////////////////////////////////////////////////////////////////////////////////////
81 
JackShutdown_i()82 inline void JackClient::JackShutdown_i()
83 {
84 	cerr<<"Shutdown"<<endl;
85 
86 	SetAttached(false);
87 
88 	if (JackProcessInstanceID==m_JackInstanceID)
89 		JackProcessInstanceID = -1;
90 
91 	// tells ssm to go back to non callback mode
92 	RunCallback(RunContext, false);
93 }
94 
95 ///////////////////////////////////////////////////////
96 
JackClient()97 JackClient::JackClient()
98 {
99   m_JackInstanceID = 0;
100   m_Attached = false;
101   m_SampleRate = 0;
102   m_BufferSize = 0;
103   m_JackInputCount = 4;
104   m_JackOutputCount = 4;
105   m_Client=NULL;
106 }
107 
108 /////////////////////////////////////////////////////////////////////////////////////////////
109 
~JackClient()110 JackClient::~JackClient()
111 {
112    if (IsAttached()) Detach();
113 }
114 
115 /////////////////////////////////////////////////////////////////////////////////////////////
116 
AddInputPort(int NewPortNumber)117 void JackClient::AddInputPort(int NewPortNumber)
118 {
119   char Name[256];
120   JackPort *NewPort;
121 
122   if (!(m_Client)) return;
123 
124   NewPort = new JackPort;
125 
126   sprintf(Name,"In%d", NewPortNumber);
127 
128   NewPort->PortNo = NewPortNumber;
129   NewPort->Name=Name;
130   NewPort->Buf=NULL;
131   NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
132 
133   m_InputPortMap[NewPortNumber]=NewPort;
134 }
135 
AddOutputPort(int NewPortNumber)136 void JackClient::AddOutputPort(int NewPortNumber)
137 {
138   char Name[256];
139   JackPort *NewPort;
140 
141   if (!(m_Client)) return;
142 
143   NewPort = new JackPort;
144 
145   sprintf(Name,"Out%d", NewPortNumber);
146 
147   NewPort->PortNo = NewPortNumber;
148   NewPort->Name=Name;
149   NewPort->Buf=NULL;
150   NewPort->Port = jack_port_register (m_Client, Name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
151 
152   m_OutputPortMap[NewPortNumber]=NewPort;
153 }
154 
RemoveInputPort(int PortNumber)155 void JackClient::RemoveInputPort(int PortNumber)
156 {
157   char Name[256];
158   JackPort *OldPort;
159 
160   if (!(m_Client)) return;
161 
162   OldPort = m_InputPortMap[PortNumber];
163   m_InputPortMap[PortNumber] = NULL;
164   jack_port_unregister (m_Client, OldPort->Port);
165   delete OldPort;
166 }
167 
RemoveOutputPort(int PortNumber)168 void JackClient::RemoveOutputPort(int PortNumber)
169 {
170   char Name[256];
171   JackPort *OldPort;
172 
173   if (!(m_Client)) return;
174 
175   OldPort = m_OutputPortMap[PortNumber];
176   m_OutputPortMap[PortNumber] = NULL;
177   jack_port_unregister (m_Client, OldPort->Port);
178   delete OldPort;
179 }
180 
Attach()181 bool JackClient::Attach()
182 {
183 	char JackClientName[256];
184 
185 	if (m_Attached) return true;
186 
187 	sprintf(JackClientName,"SSM%d",GetJackInstanceID());
188 	if (!(m_Client = jack_client_new(JackClientName)))
189 	{
190 		cerr<<"jack server not running?"<<endl;
191 		return false;
192 	}
193 
194 	jack_set_process_callback(m_Client, JackProcess, this);
195 	jack_set_sample_rate_callback (m_Client, SampleRateChange, this);
196 	jack_on_shutdown (m_Client, JackShutdown, this);
197 
198 	// create the ports
199 	m_InputPortMap.clear();
200 	for (int n=0; n<GetJackInputCount(); n++)
201 	  AddInputPort(n);
202 
203 	m_OutputPortMap.clear();
204 	for (int n=0; n<GetJackOutputCount(); n++)
205 	  AddOutputPort(n);
206 
207 	// tell the JACK server that we are ready to roll
208 	if (jack_activate (m_Client))
209 	{
210 		cerr<<"cannot activate client"<<endl;
211 		return false;
212 	}
213 
214 	m_Attached=true;
215 
216 	cerr<<"connected to jack..."<<endl;
217 
218 	return true;
219 }
220 
221 /////////////////////////////////////////////////////////////////////////////////////////////
222 
Detach()223 void JackClient::Detach()
224 {
225 	if (m_Client)
226 	{
227 		cerr<<"Detaching from JACK"<<endl;
228 		jack_client_close(m_Client);
229 		m_Client=NULL;
230 		m_Attached=false;
231 	}
232 
233 	if (JackProcessInstanceID==m_JackInstanceID)
234 		JackProcessInstanceID = -1;
235 
236 	// tells ssm to go back to non callback mode
237 	RunCallback(RunContext, false);
238 }
239 
240 /////////////////////////////////////////////////////////////////////////////////////////////
241 
GetPortNames(vector<string> & InputNames,vector<string> & OutputNames)242 void JackClient::GetPortNames(vector<string> &InputNames, vector<string> &OutputNames)
243 {
244 	InputNames.clear();
245 	OutputNames.clear();
246 
247 	if (!m_Attached) return;
248 
249 	//Outputs first
250 	const char **PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsOutput);
251 
252 	int n=0;
253 	while(PortNameList[n]!=NULL)
254 	{
255 		OutputNames.push_back(PortNameList[n]);
256 		n++;
257 	}
258 
259 	delete PortNameList;
260 
261 	//Inputs second
262 	PortNameList=jack_get_ports(m_Client,NULL,NULL,JackPortIsInput);
263 
264 	n=0;
265 	while(PortNameList[n]!=NULL)
266 	{
267 		InputNames.push_back(PortNameList[n]);
268 		n++;
269 	}
270 
271 	delete PortNameList;
272 }
273 
274 /////////////////////////////////////////////////////////////////////////////////////////////
275 // Input means input of SSM, so this connects jack sources to the plugin outputs
ConnectInput(int n,const string & JackPort)276 void JackClient::ConnectInput(int n, const string &JackPort)
277 {
278 	if (!IsAttached()) return;
279 
280 	cerr<<"JackClient::ConnectInput: connecting source ["<<JackPort<<"] to dest ["<<m_InputPortMap[n]->Name<<"]"<<endl;
281 
282 	if (m_InputPortMap[n]->ConnectedTo!="")
283 	{
284 		if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
285 			cerr<<"JackClient::ConnectInput: cannot disconnect input port ["
286 				<<m_InputPortMap[n]->ConnectedTo<<"] from ["<<m_InputPortMap[n]->Name<<"]"<<endl;
287 	}
288 
289 	m_InputPortMap[n]->ConnectedTo = JackPort;
290 
291 	if (jack_connect (m_Client, JackPort.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
292 		cerr<<"JackClient::ConnectInput: cannot connect input port ["
293 			<<JackPort<<"] to ["<<m_InputPortMap[n]->Name<<"]"<<endl;
294 
295 	m_InputPortMap[n]->Connected=true;
296 }
297 
298 /////////////////////////////////////////////////////////////////////////////////////////////
299 // Output means output of SSM, so this connects plugin inputs to a jack destination
ConnectOutput(int n,const string & JackPort)300 void JackClient::ConnectOutput(int n, const string &JackPort)
301 {
302 	if (!IsAttached()) return;
303 	cerr<<"JackClient::ConnectOutput: connecting source ["<<m_OutputPortMap[n]->Name<<"] to dest ["<<JackPort<<"]"<<endl;
304 
305 	if (m_OutputPortMap[n]->ConnectedTo!="")
306 	{
307 		if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str()))
308 			cerr<<"JackClient::ConnectOutput: cannot disconnect output port ["
309 				<<m_OutputPortMap[n]->ConnectedTo<<"] from ["<<m_OutputPortMap[n]->Name<<"]"<<endl;
310 	}
311 
312 	m_OutputPortMap[n]->ConnectedTo = JackPort;
313 	if (jack_connect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), JackPort.c_str()))
314 		cerr<<"JackClient::ConnectOutput: cannot connect output port ["
315 			<<m_OutputPortMap[n]->Name<<"] to ["<<JackPort<<"]"<<endl;
316 	m_OutputPortMap[n]->Connected=true;
317 }
318 
319 /////////////////////////////////////////////////////////////////////////////////////////////
320 // Input means input of SSM, so this connects jack sources to the plugin outputs
DisconnectInput(int n)321 void JackClient::DisconnectInput(int n)
322 {
323 	if (!IsAttached()) return;
324 	cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;
325 
326 	if (m_InputPortMap[n]->ConnectedTo!="")
327 	{
328 		if (jack_disconnect (m_Client, m_InputPortMap[n]->ConnectedTo.c_str(), jack_port_name(m_InputPortMap[n]->Port)))
329 			cerr<<"JackClient::ConnectInput: cannot disconnect input port ["
330 				<<m_InputPortMap[n]->ConnectedTo<<"] from ["<<m_InputPortMap[n]->Name<<"]"<<endl;
331 	}
332 
333 	m_InputPortMap[n]->Connected=false;
334 }
335 
336 /////////////////////////////////////////////////////////////////////////////////////////////
337 // Output means output of SSM, so this connects plugin inputs to a jack destination
DisconnectOutput(int n)338 void JackClient::DisconnectOutput(int n)
339 {
340 	if (!IsAttached()) return;
341 	cerr<<"JackClient::DisconnectInput: Disconnecting input "<<n<<endl;
342 
343 	if (m_OutputPortMap[n]->ConnectedTo!="")
344 	{
345 		if (jack_disconnect (m_Client, jack_port_name(m_OutputPortMap[n]->Port), m_OutputPortMap[n]->ConnectedTo.c_str()))
346 			cerr<<"JackClient::ConnectOutput: cannot disconnect output port ["
347 				<<m_OutputPortMap[n]->ConnectedTo<<"] from ["<<m_OutputPortMap[n]->Name<<"]"<<endl;
348 	}
349 
350 	m_OutputPortMap[n]->Connected=false;
351 }
352 /////////////////////////////////////////////////////////////////////////////////////////////
353 
SetInputBuf(int ID,float * s)354 void JackClient::SetInputBuf(int ID, float* s)
355 {
356 	if(m_InputPortMap.find(ID)!=m_InputPortMap.end()) m_InputPortMap[ID]->Buf=s;
357 }
358 
359 /////////////////////////////////////////////////////////////////////////////////////////////
360 
SetOutputBuf(int ID,float * s)361 void JackClient::SetOutputBuf(int ID, float* s)
362 {
363 	if(m_OutputPortMap.find(ID)!=m_OutputPortMap.end()) m_OutputPortMap[ID]->Buf=s;
364 }
365 
366 /////////////////////////////////////////////////////////////////////////////////////////////
367 
368 extern "C" {
SpiralPlugin_CreateInstance()369 SpiralPlugin* SpiralPlugin_CreateInstance()
370 {
371 	return new JackPlugin;
372 }
373 
SpiralPlugin_GetIcon()374 char** SpiralPlugin_GetIcon()
375 {
376 	return SpiralIcon_xpm;
377 }
378 
SpiralPlugin_GetID()379 int SpiralPlugin_GetID()
380 {
381 	return 31;
382 }
383 
SpiralPlugin_GetGroupName()384 string SpiralPlugin_GetGroupName()
385 {
386 	return "InputOutput";
387 }
388 }
389 
390 ///////////////////////////////////////////////////////
391 
JackPlugin()392 JackPlugin::JackPlugin() :
393 m_UpdateNames(false),
394 m_Connected(false)
395 {
396         m_JackClient=new JackClient;
397 
398 	//clunky way to ensure unique JackID - JackInstanceCount is never dec
399 	//so new JackInstances per session always get a higher number even on
400 	//reload and new Patch
401 
402 	m_JackInstanceID = JackInstanceCount;
403 	JackInstanceCount++;
404 
405         m_JackClient->SetJackInstanceID(m_JackInstanceID);
406 
407 	// we are an output
408 	m_IsTerminal = true;
409 
410 	m_Version = 2;
411 
412 	m_PluginInfo.Name="Jack";
413 	m_PluginInfo.Width=225;
414 	m_PluginInfo.Height=230;
415 	m_PluginInfo.NumInputs=0;
416 	m_PluginInfo.NumOutputs=0;
417 
418      	m_PluginInfo.PortTips.clear();
419 
420      	m_PluginInfo.NumInputs = m_JackClient->GetJackOutputCount();
421 	m_GUIArgs.NumInputs = m_PluginInfo.NumInputs;
422 
423      	for (int n=0; n<m_JackClient->GetJackInputCount(); n++)
424      	{
425 		char Temp[256];
426 		sprintf(Temp,"SSM Input %d",n);
427 		m_PluginInfo.PortTips.push_back(Temp);
428      	}
429 
430      	m_PluginInfo.NumOutputs = m_JackClient->GetJackOutputCount();
431 	m_GUIArgs.NumOutputs = m_PluginInfo.NumOutputs;
432 
433 	for (int n=0; n<m_JackClient->GetJackOutputCount(); n++)
434 	{
435 		char Temp[256];
436 		sprintf(Temp,"SSM Output %d",n);
437 		m_PluginInfo.PortTips.push_back(Temp);
438 	}
439 
440 	m_AudioCH->Register("NumInputs",&m_GUIArgs.NumInputs);
441 	m_AudioCH->Register("NumOutputs",&m_GUIArgs.NumOutputs);
442 	m_AudioCH->RegisterData("Port",ChannelHandler::INPUT,&m_GUIArgs.Port,sizeof(m_GUIArgs.Port));
443 	m_AudioCH->Register("NumInputPortNames",&m_NumInputPortNames,ChannelHandler::OUTPUT);
444 	m_AudioCH->Register("NumOutputPortNames",&m_NumOutputPortNames,ChannelHandler::OUTPUT);
445 	m_AudioCH->RegisterData("InputPortNames",ChannelHandler::OUTPUT,&m_InputPortNames,sizeof(m_InputPortNames));
446 	m_AudioCH->RegisterData("OutputPortNames",ChannelHandler::OUTPUT,&m_OutputPortNames,sizeof(m_OutputPortNames));
447 	m_AudioCH->Register("UpdateNames",&m_UpdateNames,ChannelHandler::OUTPUT);
448 	m_AudioCH->Register("Connected",&m_Connected,ChannelHandler::OUTPUT);
449 }
450 
~JackPlugin()451 JackPlugin::~JackPlugin()
452 {
453 	if (m_JackClient)
454 	{
455 		m_JackClient->Detach();
456 		delete m_JackClient;
457 		m_JackClient=NULL;
458 	}
459 }
460 
Kill()461 bool JackPlugin::Kill()
462 {
463 	m_IsDead=true;
464 
465 	UpdatePluginInfoWithHost();
466 	RemoveAllInputs ();
467 	RemoveAllOutputs ();
468 	UpdatePluginInfoWithHost();
469 
470 	m_JackClient->Detach();
471 	delete m_JackClient;
472 	m_JackClient=NULL;
473 	return true;
474 }
475 
Initialise(const HostInfo * Host)476 PluginInfo &JackPlugin::Initialise(const HostInfo *Host)
477 {
478 	PluginInfo& Info= SpiralPlugin::Initialise(Host);
479 	host=Host;
480 
481 	m_JackClient->SetCallback(cb_Update,m_Parent);
482 
483 	return Info;
484 }
485 
CreateGUI()486 SpiralGUIType *JackPlugin::CreateGUI()
487 {
488 	return new JackPluginGUI(m_PluginInfo.Width,
489 						  m_PluginInfo.Height,
490 					      this,m_AudioCH,m_HostInfo);
491 }
492 
SetNumberPorts(int nInputs,int nOutputs)493 void  JackPlugin::SetNumberPorts (int nInputs, int nOutputs) {
494      UpdatePluginInfoWithHost();
495      RemoveAllInputs ();
496      RemoveAllOutputs ();
497      m_PluginInfo.NumInputs = 0;
498      m_PluginInfo.NumOutputs = 0;
499      m_PluginInfo.PortTips.clear ();
500      CreatePorts (nInputs, nOutputs, true);
501      UpdatePluginInfoWithHost ();
502 }
503 
CreatePorts(int nInputs,int nOutputs,bool AddPorts)504 void  JackPlugin::CreatePorts (int nInputs, int nOutputs, bool AddPorts) {
505     	m_PluginInfo.PortTips.clear();
506 
507     	m_PluginInfo.NumInputs = nInputs;
508      	m_JackClient->SetJackInputCount(nInputs);
509 
510      	for (int n=0; n<nInputs; n++)
511      	{
512 		char Temp[256];
513 		sprintf(Temp,"SSM Input %d",n);
514 		m_PluginInfo.PortTips.push_back(Temp);
515      	}
516 
517     	m_PluginInfo.NumOutputs = nOutputs;
518      	m_JackClient->SetJackOutputCount(nOutputs);
519 
520 	for (int n=0; n<nOutputs; n++)
521 	{
522 		char Temp[256];
523 		sprintf(Temp,"SSM Output %d",n);
524 		m_PluginInfo.PortTips.push_back(Temp);
525 	}
526 
527      if (AddPorts) {
528         for (int n=0; n<nInputs; n++) AddInput();
529         for (int n=0; n<nOutputs; n++) AddOutput();
530      }
531 
532  }
533 
Execute()534 void JackPlugin::Execute()
535 {
536 }
537 
ExecuteCommands()538 void JackPlugin::ExecuteCommands()
539 {
540 	if (m_IsDead) return;
541 
542         bool commandwaiting = m_AudioCH->IsCommandWaiting();
543         int command = (commandwaiting)?(int)m_AudioCH->GetCommand():0;
544 
545 	if (commandwaiting)
546 	{
547 		switch (command) {
548 			case SET_PORT_COUNT :
549 				SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs);
550                 }
551         }
552 
553 
554 	// we want to process this whether we are connected to stuff or not
555 	JackClient* pJack=m_JackClient;
556 
557 	// connect the buffers up if we are plugged into something
558 	for (int n=0; n<pJack->GetJackOutputCount(); n++)
559 	{
560 		if (InputExists(n))
561 		{
562 			pJack->SetOutputBuf(n,(float*)GetInput(n)->GetBuffer());
563 		}
564 		else
565 		{
566 			pJack->SetOutputBuf(n,NULL);
567 		}
568 	}
569 
570 	for (int n=0; n<pJack->GetJackInputCount(); n++)
571 	{
572 		if (OutputExists(n))
573 		{
574 			pJack->SetInputBuf(n,(float*)GetOutputBuf(n)->GetBuffer());
575 		}
576 		else
577 		{
578 			pJack->SetInputBuf(n,NULL);
579 		}
580   	}
581 
582 	if (commandwaiting)
583 	{
584 		switch (command)
585 		{
586 			case UPDATE_NAMES :
587 			{
588 				int c=0;
589 
590 			    std::vector<string> InputNames,OutputNames;
591 				GetPortNames(InputNames,OutputNames);
592 				for (vector<string>::iterator i=InputNames.begin();
593 					 i!=InputNames.end(); ++i)
594 				{
595 					strcpy(m_InputPortNames[c],i->c_str());
596 					c++;
597 				}
598 
599 				c=0;
600 
601 				for (std::vector<string>::iterator i=OutputNames.begin();
602 					 i!=OutputNames.end(); ++i)
603 				{
604 					strcpy(m_OutputPortNames[c],i->c_str());
605 					c++;
606 				}
607 
608 				m_NumInputPortNames=InputNames.size();
609 				m_NumOutputPortNames=OutputNames.size();
610 			}
611 			break;
612 
613 			case CHECK_PORT_CHANGES :
614 				if ((m_JackClient->IsAttached()) && (!m_JackClient->CheckingPortChanges)) {
615 					m_JackClient->CheckingPortChanges = true;
616 
617 					for (int n=0; n<m_PluginInfo.NumInputs; n++) {
618 						if (jack_port_connected(m_JackClient->m_OutputPortMap[n]->Port)!=m_JackClient->m_OutputPortMap[n]->Connected)
619 							m_JackClient->m_OutputPortsChanged.push_back(m_JackClient->m_OutputPortMap[n]);
620 
621 						if (jack_port_connected(m_JackClient->m_InputPortMap[n]->Port)!=m_JackClient->m_InputPortMap[n]->Connected)
622 							m_JackClient->m_InputPortsChanged.push_back(m_JackClient->m_InputPortMap[n]);
623 					}
624 
625 					m_JackClient->CheckingPortChanges = false;
626 				}
627 
628 			break;
629 			default : break;
630 		}
631 	}
632 	m_Connected=m_JackClient->IsAttached();
633 }
634 
StreamOut(ostream & s)635 void JackPlugin::StreamOut (ostream &s)
636 {
637 	s << m_Version << " " << m_GUIArgs.NumInputs << " " << m_GUIArgs.NumOutputs << " ";
638 }
639 
StreamIn(istream & s)640 void JackPlugin::StreamIn (istream &s)
641 {
642 	char Test;
643 	int Version, NumInputs, NumOutputs;
644 
645 	s.seekg (2, ios::cur );  //skip to next line
646 	Test = s.peek();         //peek first char
647 	s.seekg (-2, ios::cur ); //jump back to prior line
648 
649 	if ( (Test >= '0') && (Test <= '9') )
650 	{
651 		s >> Version;
652 	}
653 	else
654 	{
655 		//No Version, so use Version 1
656 		Version = 1;
657 	}
658 
659 	switch (Version)
660 	{
661 		case 2:
662 		{
663 			s >> NumInputs >> NumOutputs;
664 			m_GUIArgs.NumOutputs = min(max(NumOutputs, MIN_PORTS), MAX_PORTS);
665 			m_GUIArgs.NumInputs = min(max(NumInputs, MIN_PORTS), MAX_PORTS);
666 
667 			SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs);
668 		}
669 		break;
670 
671 		case 1:
672 		{
673 			//use original fixed defaults
674 			m_GUIArgs.NumInputs = 16;
675 			m_GUIArgs.NumOutputs = 16;
676 
677 			SetNumberPorts (m_GUIArgs.NumInputs, m_GUIArgs.NumOutputs);
678 		}
679 		break;
680 	}
681 }
682