@@ -38,8 +38,10 @@ m_UpdateTimer(0) | |||
{ | |||
m_IncompleteWire.OutputChild=-1; | |||
m_IncompleteWire.OutputPort=-1; | |||
m_IncompleteWire.OutputTerminal=false; | |||
m_IncompleteWire.InputChild=-1; | |||
m_IncompleteWire.InputPort=-1; | |||
m_IncompleteWire.InputTerminal=false; | |||
m_BG=NULL; | |||
m_BGData=NULL; | |||
@@ -364,6 +366,7 @@ void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value | |||
m_IncompleteWire.OutputChild=ChildNum; | |||
m_IncompleteWire.OutputPort=Port; | |||
m_IncompleteWire.OutputID=Device->GetID(); | |||
m_IncompleteWire.OutputTerminal=Device->IsTerminal(); | |||
} | |||
else | |||
{ | |||
@@ -378,6 +381,7 @@ void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value | |||
m_IncompleteWire.InputChild=ChildNum; | |||
m_IncompleteWire.InputPort=Port; | |||
m_IncompleteWire.InputID=Device->GetID(); | |||
m_IncompleteWire.InputTerminal=Device->IsTerminal(); | |||
} | |||
else | |||
{ | |||
@@ -392,7 +396,8 @@ void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value | |||
// send the connect callback | |||
cb_Connection(this,(void*)&m_IncompleteWire); | |||
m_Graph.AddConnection(m_IncompleteWire.OutputID,m_IncompleteWire.InputID); | |||
m_Graph.AddConnection(m_IncompleteWire.OutputID,m_IncompleteWire.OutputTerminal, | |||
m_IncompleteWire.InputID,m_IncompleteWire.InputTerminal); | |||
// Turn on both ports | |||
Fl_DeviceGUI* ODGUI = (Fl_DeviceGUI*)(child(m_IncompleteWire.OutputChild)); | |||
@@ -557,30 +562,65 @@ istream &operator>>(istream &s, Fl_Canvas &o) | |||
{ | |||
int NumWires; | |||
s>>NumWires; | |||
for(int n=0; n<NumWires; n++) | |||
// my bad, didn't version this stream - remove one day... | |||
if (NumWires==-1) | |||
{ | |||
CanvasWire NewWire; | |||
int version; | |||
s>>version; | |||
s>>NumWires; | |||
s>>NewWire.OutputID; | |||
s>>NewWire.OutputChild; | |||
s>>NewWire.OutputPort; | |||
s>>NewWire.InputID; | |||
s>>NewWire.InputChild; | |||
s>>NewWire.InputPort; | |||
o.m_WireVec.push_back(NewWire); | |||
// Notify connection by callback | |||
o.cb_Connection(&o,(void*)&NewWire); | |||
o.m_Graph.AddConnection(NewWire.OutputID,NewWire.InputID); | |||
for(int n=0; n<NumWires; n++) | |||
{ | |||
CanvasWire NewWire; | |||
// Turn on both ports | |||
((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->AddConnection(NewWire.OutputPort+ | |||
((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->GetInfo()->NumInputs); | |||
((Fl_DeviceGUI*)(o.child(NewWire.InputChild)))->AddConnection(NewWire.InputPort); | |||
} | |||
s>>NewWire.OutputID; | |||
s>>NewWire.OutputChild; | |||
s>>NewWire.OutputPort; | |||
s>>NewWire.OutputTerminal; | |||
s>>NewWire.InputID; | |||
s>>NewWire.InputChild; | |||
s>>NewWire.InputPort; | |||
s>>NewWire.InputTerminal; | |||
o.m_WireVec.push_back(NewWire); | |||
// Notify connection by callback | |||
o.cb_Connection(&o,(void*)&NewWire); | |||
o.m_Graph.AddConnection(NewWire.OutputID,NewWire.OutputTerminal,NewWire.InputID,NewWire.InputTerminal); | |||
// Turn on both ports | |||
((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->AddConnection(NewWire.OutputPort+ | |||
((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->GetInfo()->NumInputs); | |||
((Fl_DeviceGUI*)(o.child(NewWire.InputChild)))->AddConnection(NewWire.InputPort); | |||
} | |||
} | |||
else | |||
{ | |||
for(int n=0; n<NumWires; n++) | |||
{ | |||
CanvasWire NewWire; | |||
s>>NewWire.OutputID; | |||
s>>NewWire.OutputChild; | |||
s>>NewWire.OutputPort; | |||
s>>NewWire.InputID; | |||
s>>NewWire.InputChild; | |||
s>>NewWire.InputPort; | |||
o.m_WireVec.push_back(NewWire); | |||
// Notify connection by callback | |||
o.cb_Connection(&o,(void*)&NewWire); | |||
o.m_Graph.AddConnection(NewWire.OutputID,false,NewWire.InputID,false); | |||
// Turn on both ports | |||
((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->AddConnection(NewWire.OutputPort+ | |||
((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->GetInfo()->NumInputs); | |||
((Fl_DeviceGUI*)(o.child(NewWire.InputChild)))->AddConnection(NewWire.InputPort); | |||
} | |||
} | |||
return s; | |||
} | |||
@@ -588,6 +628,9 @@ istream &operator>>(istream &s, Fl_Canvas &o) | |||
ostream &operator<<(ostream &s, Fl_Canvas &o) | |||
{ | |||
int version=0; | |||
s<<-1<<" "<<version<<" "; | |||
s<<o.m_WireVec.size()<<endl; | |||
for(vector<CanvasWire>::iterator i=o.m_WireVec.begin(); | |||
@@ -596,9 +639,11 @@ ostream &operator<<(ostream &s, Fl_Canvas &o) | |||
s<<i->OutputID<<" "; | |||
s<<i->OutputChild<<" "; | |||
s<<i->OutputPort<<" "; | |||
s<<i->OutputTerminal<<" "; | |||
s<<i->InputID<<" "; | |||
s<<i->InputChild<<" "; | |||
s<<i->InputPort<<endl; | |||
s<<i->InputPort<<" "; | |||
s<<i->InputTerminal<<endl; | |||
} | |||
return s; | |||
@@ -40,18 +40,22 @@ public: | |||
OutputChild=-1; | |||
OutputPort=-1; | |||
OutputID=-1; | |||
OutputTerminal=false; | |||
InputChild=-1; | |||
InputPort=-1; | |||
InputID=-1; | |||
InputTerminal=false; | |||
DelMe=false; | |||
} | |||
int OutputID; | |||
int OutputChild; | |||
int OutputPort; | |||
bool OutputTerminal; | |||
int InputID; | |||
int InputChild; | |||
int InputPort; | |||
bool InputTerminal; | |||
bool DelMe; | |||
}; | |||
@@ -51,13 +51,14 @@ int Fl_PortButton::handle(int event) | |||
return 1; | |||
} | |||
Fl_DeviceGUI::Fl_DeviceGUI(const DeviceGUIInfo& Info, Fl_Group *PW, Fl_Pixmap *Icon) : | |||
Fl_DeviceGUI::Fl_DeviceGUI(const DeviceGUIInfo& Info, Fl_Group *PW, Fl_Pixmap *Icon, bool Terminal) : | |||
Fl_Group(Info.XPos, Info.YPos, Info.Width+(PortGroupWidth*2), Info.Height+TitleBarHeight, ""), | |||
m_PluginWindow(NULL), | |||
m_Icon(NULL), | |||
m_Name(Info.Name), | |||
m_ID(-1), | |||
m_DelMe(false) | |||
m_DelMe(false), | |||
m_IsTerminal(Terminal) | |||
{ | |||
for (int n=0; n<512; n++) Numbers[n]=n; | |||
@@ -79,7 +79,7 @@ struct DeviceGUIInfo | |||
class Fl_DeviceGUI : public Fl_Group | |||
{ | |||
public: | |||
Fl_DeviceGUI(const DeviceGUIInfo& Info, Fl_Group *PW, Fl_Pixmap *Icon); | |||
Fl_DeviceGUI(const DeviceGUIInfo& Info, Fl_Group *PW, Fl_Pixmap *Icon, bool Terminal=false); | |||
virtual int handle(int event); | |||
virtual void draw(); | |||
@@ -107,6 +107,9 @@ public: | |||
virtual void Clear(); | |||
int GetPortType(int n) { return m_Info.PortTypes[n]; } | |||
// do we belong to a plugin that is an output? | |||
bool IsTerminal() { return m_IsTerminal; } | |||
protected: | |||
DeviceGUIInfo m_Info; | |||
@@ -127,6 +130,7 @@ private: | |||
string m_Name; | |||
int m_ID; | |||
bool m_DelMe; | |||
bool m_IsTerminal; | |||
}; | |||
#endif |
@@ -48,16 +48,34 @@ void GraphSort::Sort() | |||
// walk back from all the roots | |||
m_Sorted.clear(); | |||
list<int> RootNodes; | |||
bool FoundRoot=false; | |||
for (map<int,Node>::iterator i=m_Graph.begin(); | |||
i!=m_Graph.end(); i++) | |||
{ | |||
// if there are no outputs, this must be a root | |||
if (i->second.Outputs.empty()) | |||
{ | |||
FoundRoot=true; | |||
RecursiveWalk(i->first); | |||
} | |||
} | |||
// no roots found - try looking for a terminal node and recursing from | |||
// there, this makes circular graphs work. | |||
if (!FoundRoot) | |||
{ | |||
for (map<int,Node>::iterator i=m_Graph.begin(); | |||
i!=m_Graph.end(); i++) | |||
{ | |||
// if there are no outputs, this must be a root | |||
if (i->second.IsTerminal) | |||
{ | |||
RecursiveWalk(i->first); | |||
} | |||
} | |||
} | |||
#ifdef GRAPHSORT_TRACE | |||
for(list<int>::iterator i=m_Sorted.begin(); | |||
i!=m_Sorted.end(); i++) | |||
@@ -121,12 +139,13 @@ void GraphSort::Dump() | |||
} | |||
} | |||
void GraphSort::AddConnection(int SID, int DID) | |||
void GraphSort::AddConnection(int SID, bool STerminal, int DID, bool DTerminal) | |||
{ | |||
map<int,Node>::iterator si=m_Graph.find(SID); | |||
if (si==m_Graph.end()) | |||
{ | |||
Node newnode; | |||
newnode.IsTerminal = STerminal; | |||
m_Graph[SID]=newnode; | |||
#ifdef GRAPHSORT_TRACE | |||
cerr<<"added "<<SID<<endl; | |||
@@ -137,6 +156,7 @@ void GraphSort::AddConnection(int SID, int DID) | |||
if (di==m_Graph.end()) | |||
{ | |||
Node newnode; | |||
newnode.IsTerminal = DTerminal; | |||
m_Graph[DID]=newnode; | |||
#ifdef GRAPHSORT_TRACE | |||
cerr<<"added "<<DID<<endl; | |||
@@ -34,7 +34,7 @@ public: | |||
~GraphSort(); | |||
const list<int> &GetSortedList(); | |||
void Sort(); | |||
void AddConnection(int SID, int DID); | |||
void AddConnection(int SID, bool STerminal, int DID, bool DTerminal); | |||
void RemoveConnection(int SID, int DID); | |||
void Clear(); | |||
void Dump(); | |||
@@ -43,6 +43,7 @@ public: | |||
{ | |||
list<int> Inputs; | |||
list<int> Outputs; | |||
bool IsTerminal; | |||
}; | |||
private: | |||
@@ -81,6 +81,7 @@ inline void FilterPluginGUI::cb_Cutoff_i(Fl_Slider* o, void* v) | |||
float value=100.0f-o->value(); | |||
m_GUICH->Set("Cutoff",(float)(value*value)+10.0f); | |||
} | |||
void FilterPluginGUI::cb_Cutoff(Fl_Slider* o, void* v) | |||
{ ((FilterPluginGUI*)(o->parent()))->cb_Cutoff_i(o,v); } | |||
@@ -99,3 +100,10 @@ inline void FilterPluginGUI::cb_RevResonance_i(Fl_Button* o, void* v) | |||
void FilterPluginGUI::cb_RevResonance(Fl_Button* o, void* v) | |||
{ ((FilterPluginGUI*)(o->parent()))->cb_RevResonance_i(o,v); } | |||
const string FilterPluginGUI::GetHelpText(const string &loc){ | |||
return string("") | |||
+ "The standard SpiralSynth filter, based on the (zxforms design).\n" | |||
+ "Quite a meaty sound - low pass only, nice for bass modulations.\n" | |||
+ "With variable emphasis/cutoff CV's.\n\n" | |||
+ "It's also pretty fast, and well tested in SpiralSynth."; | |||
} |
@@ -36,6 +36,9 @@ public: | |||
virtual void UpdateValues(SpiralPlugin *o); | |||
protected: | |||
const string GetHelpText(const string &loc); | |||
private: | |||
Fl_Group *GUIFilterGroup; | |||
@@ -154,7 +154,7 @@ int JackClient::Process(jack_nframes_t nframes, void *o) | |||
} | |||
} | |||
} | |||
if(RunCallback&&RunContext) | |||
{ | |||
// do the work | |||
@@ -345,6 +345,9 @@ m_Connected(false) | |||
{ | |||
m_RefCount++; | |||
// we are an output | |||
m_IsTerminal = true; | |||
m_PluginInfo.Name="Jack"; | |||
m_PluginInfo.Width=200; | |||
m_PluginInfo.Height=325; | |||
@@ -390,7 +393,7 @@ PluginInfo &JackPlugin::Initialise(const HostInfo *Host) | |||
PluginInfo& Info= SpiralPlugin::Initialise(Host); | |||
host=Host; | |||
JackClient::Get()->SetCallback(cb_Update,m_Parent); | |||
if (m_RefCount==1) JackClient::Get()->SetCallback(cb_Update,m_Parent); | |||
return Info; | |||
} | |||
@@ -409,6 +412,11 @@ 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(); | |||
@@ -71,3 +71,12 @@ inline void MoogFilterPluginGUI::cb_Resonance_i(Fl_Knob* o, void* v) | |||
{ m_GUICH->Set("Resonance",(float)(o->value())); } | |||
void MoogFilterPluginGUI::cb_Resonance(Fl_Knob* o, void* v) | |||
{ ((MoogFilterPluginGUI*)(o->parent()))->cb_Resonance_i(o,v); } | |||
const string MoogFilterPluginGUI::GetHelpText(const string &loc){ | |||
return string("") | |||
+ "Classic moog filter. Very different sound to the other filters,\n" | |||
+ "needless to say, very squelchy. As well as lowpass, band and high\n" | |||
+ "pass are simultaneously calculated too. The emphasis can be pushed\n" | |||
+ "into self oscillation (careful of the speakers). In this way, it\n" | |||
+ "can be used to generate sinewave oscillations."; | |||
} |
@@ -36,6 +36,9 @@ public: | |||
virtual void UpdateValues(SpiralPlugin *o); | |||
protected: | |||
const string GetHelpText(const string &loc); | |||
private: | |||
Fl_Group *GUIFilterGroup; | |||
@@ -372,3 +372,19 @@ void OscillatorPluginGUI::cb_pop(Fl_Button* o, void* v) { | |||
((OscillatorPluginGUI*)(o->parent()))->cb_pop_i(o,v); | |||
} | |||
const string OscillatorPluginGUI::GetHelpText(const string &loc){ | |||
return string("") | |||
+ "The Oscillator generates raw waveforms from CV controls. Three wave \n" | |||
+ "shapes are included, Square wave, Triangle wave and white noise.\n\n" | |||
+ "In the square and triangle shapes, the Frequency CV controls the pitch \n" | |||
+ "of the signal generated, and the pulsewidth turns the squarewave into \n" | |||
+ "a pulse wave of varying harmonics, and the triangle wave into a sawtooth,\n" | |||
+ "or reverse sawtooth wave.\n\n" | |||
+ "The sample & hold CV changes the time between samples with the white noise.\n" | |||
+ "This is usful for making the Oscillator into a random CV generator.\n\n" | |||
+ "The plugin window allows you to select the wave shape, set the octave and\n" | |||
+ "fine tune the frequency. There are also controls to set the pulsewidth,\n" | |||
+ "sample and hold manually, and control the modulation depth of the input CV's.\n\n" | |||
+ "The frequency can be set extremely low on this oscillator, so you can use\n" | |||
+ "it as an LFO for controlling other plugins."; | |||
} |
@@ -37,6 +37,9 @@ public: | |||
virtual void UpdateValues(SpiralPlugin *o); | |||
protected: | |||
const string GetHelpText(const string &loc); | |||
private: | |||
Fl_Check_Button *ShapeSquare; | |||
@@ -87,7 +87,10 @@ OutputPlugin::OutputPlugin() : | |||
m_Volume(1.0f) | |||
{ | |||
m_RefCount++; | |||
// we are an output. | |||
m_IsTerminal=true; | |||
m_PluginInfo.Name="OSS"; | |||
m_PluginInfo.Width=100; | |||
m_PluginInfo.Height=100; | |||
@@ -80,3 +80,17 @@ inline void SVFilterPluginGUI::cb_Reset_i(Fl_Button* o, void* v) | |||
{ } | |||
void SVFilterPluginGUI::cb_Reset(Fl_Button* o, void* v) | |||
{ ((SVFilterPluginGUI*)(o->parent()))->cb_Reset_i(o,v); } | |||
const string SVFilterPluginGUI::GetHelpText(const string &loc){ | |||
return string("") | |||
+ "A State Variable Filter. First thing to say is, it's a bit\n" | |||
+ "broken. Seems to generate glitchy noise when the cutoff is \n" | |||
+ "modulated. Possibly a range bug on the cutoff too.\n" | |||
+ "On the other hand, I like some of the noises it seems to\n" | |||
+ "make, so it's here anyway (I'll fix it some day).\n\n" | |||
+ "Works pretty well at band,high and peaking useful for creating\n" | |||
+ "some different sounds.\n\n" | |||
+ "Note: Comes with a reset button, so if you break it pushing\n" | |||
+ "the emphasis up too high, you can reset the cooeficients\n" | |||
+ "(which fixes it)."; | |||
} |
@@ -36,6 +36,9 @@ public: | |||
virtual void UpdateValues(SpiralPlugin *o); | |||
protected: | |||
const string GetHelpText(const string &loc); | |||
private: | |||
Fl_Group *GUIFilterGroup; | |||
@@ -30,6 +30,7 @@ SpiralPlugin::SpiralPlugin() | |||
cb_Update=NULL; | |||
m_Parent=NULL; | |||
m_HostID=-1; | |||
m_IsTerminal=false; | |||
m_AudioCH = new ChannelHandler; | |||
} | |||
@@ -104,6 +104,8 @@ public: | |||
void SetParent(void *s) { m_Parent=s; } | |||
void UpdateChannelHandler(); | |||
// is the plugin connected to an external device (oss/alsa/jack) | |||
bool IsTerminal() { return m_IsTerminal; } | |||
ChannelHandler *GetChannelHandler() { return m_AudioCH; } | |||
@@ -153,6 +155,8 @@ protected: | |||
// tell the engine that we are taking control of the | |||
// timing for output. | |||
void (*cb_Blocking)(void*o ,bool m); | |||
bool m_IsTerminal; | |||
private: | |||
@@ -21,6 +21,8 @@ | |||
#include <FL/fl_draw.h> | |||
#include <FL/fl_draw.H> | |||
#include <FL/Fl_Multiline_Output.h> | |||
#include <FL/Fl_Text_Display.h> | |||
#include <FL/Fl_Text_Buffer.h> | |||
static const int GUI_COLOUR = 154; | |||
static const int GUIBG_COLOUR = 144; | |||
@@ -83,14 +85,15 @@ inline void SpiralPluginGUI::cb_Help_i(Fl_Button* o, void* v) | |||
{ | |||
int w=300,h=200; | |||
m_HelpWin = new Fl_Double_Window(w,h,"Help"); | |||
Fl_Multiline_Output* text= new Fl_Multiline_Output(0,0,w,h); | |||
text->value(GetHelpText(SpiralInfo::LOCALE).c_str()); | |||
Fl_Text_Display* text = new Fl_Text_Display(0,0,10,10); | |||
text->buffer(new Fl_Text_Buffer); | |||
text->insert(GetHelpText(SpiralInfo::LOCALE).c_str()); | |||
text->textsize(10); | |||
text->set_output(); | |||
m_HelpWin->add(text); | |||
m_HelpWin->resizable(text); | |||
m_HelpWin->show(); | |||
text->size(w,h); // hack to get the text widget to appear??? | |||
} | |||
else | |||
{ | |||
@@ -504,3 +504,17 @@ void WaveTablePluginGUI::cb_pop(Fl_Button* o, void* v) { | |||
((WaveTablePluginGUI*)o->parent())->cb_pop_i(o,v); | |||
} | |||
const string WaveTablePluginGUI::GetHelpText(const string &loc){ | |||
return string("") | |||
+ "The WaveTable plugin is a fast multifunction oscillator with a variety \n" | |||
+ "of wave shapes:\n" | |||
+ "Sine, Square, Saw, Reverse Saw, Triangle, Two pulse shapes and an inverse\n" | |||
+ "sinewave.\n\n" | |||
+ "These wave shapes are internally represented as samples, rather than\n" | |||
+ "being continually calculated like the conventional oscillator. This \n" | |||
+ "makes the plugin fast, but restricts the modulations you can do on the\n" | |||
+ "wave forms (no pulsewidth).\n\n" | |||
+ "The oscillator can be pitched very low for use as a LFO CV generator,\n" | |||
+ "using any of the supported wave shapes. User wave shapes are planned,\n" | |||
+ "so you will be able to load your own samples in."; | |||
} |
@@ -36,6 +36,9 @@ public: | |||
virtual void UpdateValues(SpiralPlugin* o); | |||
protected: | |||
const string GetHelpText(const string &loc); | |||
private: | |||
Fl_Check_Button *ShapeSquare; | |||
@@ -49,7 +49,7 @@ void XFadePluginGUI::UpdateValues(SpiralPlugin *o) | |||
inline void XFadePluginGUI::cb_Mix_i(Fl_Slider* o, void* v) | |||
{ | |||
m_GUICH->Set("Mix",o->value()); | |||
m_GUICH->Set("Mix",(float)o->value()); | |||
} | |||
void XFadePluginGUI::cb_Mix(Fl_Slider* o, void* v) | |||
{ ((XFadePluginGUI*)(o->parent()))->cb_Mix_i(o,v); } | |||
@@ -567,7 +567,7 @@ DeviceWin* SynthModular::NewDeviceWin(int n, int x, int y) | |||
Info.XPos = x; //TOOLBOX_WIDTH+(rand()%400); | |||
Info.YPos = y; //rand()%400; | |||
nlw->m_DeviceGUI = new Fl_DeviceGUI(Info, temp, Pix); | |||
nlw->m_DeviceGUI = new Fl_DeviceGUI(Info, temp, Pix, nlw->m_Device->IsTerminal()); | |||
m_Canvas->add(nlw->m_DeviceGUI); | |||
m_Canvas->redraw(); | |||