@@ -1,6 +1,6 @@ | |||
****** SpiralSynthModular ****** | |||
Last changed Tuesday 6-January-2004. | |||
Last changed Tuesday 11-March-2004. | |||
SpiralSynthModular is open source software, distributed under the General | |||
Public License (GPL). See the file COPYING. | |||
@@ -109,13 +109,9 @@ Samplerate = 44100 - Sets the samplerate | |||
*** Trying it out without installing *** | |||
You can try SpiralSynthModular out by following the following steps. | |||
1. Run the script ./createlinks to create a dummy plugin directory in your source | |||
directory | |||
2. To run use the command: | |||
./spiralsynthmodular --PluginPath /path/to/your/ssm/source/links | |||
You can try SpiralSynthModular by running the script ./test-run | |||
which creates a dummy plugin directory in your source directory | |||
and runs SpiralSynthModular using these uninstalled plugins. | |||
Disclaimer: | |||
@@ -30,7 +30,7 @@ char** SpiralPlugin_GetIcon() { return SpiralIcon_xpm; } | |||
int SpiralPlugin_GetID() { return 123; } | |||
string SpiralPlugin_GetGroupName() { return "Control"; } | |||
string SpiralPlugin_GetGroupName() { return "InputOutput"; } | |||
} | |||
@@ -25,45 +25,46 @@ | |||
using namespace std; | |||
extern "C" { | |||
SpiralPlugin* SpiralPlugin_CreateInstance() { | |||
return new MixerPlugin; | |||
} | |||
char** SpiralPlugin_GetIcon() { | |||
return SpiralIcon_xpm; | |||
} | |||
int SpiralPlugin_GetID() { | |||
return 0x0007; | |||
} | |||
string SpiralPlugin_GetGroupName() { | |||
return "Amps/Mixers"; | |||
} | |||
SpiralPlugin* SpiralPlugin_CreateInstance() { return new MixerPlugin; } | |||
char** SpiralPlugin_GetIcon() { return SpiralIcon_xpm; } | |||
int SpiralPlugin_GetID() { return 0x0007; } | |||
string SpiralPlugin_GetGroupName() { return "Amps/Mixers"; } | |||
} | |||
/////////////////////////////////////////////////////// | |||
MixerPlugin::MixerPlugin() : | |||
m_NumChannels(0) | |||
m_NumChannels(4) | |||
{ | |||
int c; | |||
m_Version = 2; | |||
m_PluginInfo.Name = "Mixer"; | |||
m_PluginInfo.Width = 80; | |||
m_PluginInfo.Height = 140; | |||
m_PluginInfo.Height = 150; | |||
for (c=0; c<MAX_CHANNELS; c++) { | |||
m_ChannelVal[c] = 1.0f; | |||
m_GUIArgs.inPeak[c] = false; | |||
} | |||
m_GUIArgs.Peak = false; | |||
CreatePorts (); | |||
for (int n=0; n<MAX_CHANNELS; n++) m_ChannelVal[n] = 1.0f; | |||
m_PluginInfo.NumInputs = m_NumChannels; | |||
m_PluginInfo.NumOutputs = 1; | |||
for (c=1; c<=m_NumChannels; c++) AddInputTip (c); | |||
m_PluginInfo.PortTips.push_back ("Output"); | |||
m_AudioCH->Register ("Value", &m_GUIArgs.Value); | |||
m_AudioCH->Register ("Num", &m_GUIArgs.Num); | |||
m_AudioCH->Register ("Peak", &m_GUIArgs.Peak, ChannelHandler::OUTPUT); | |||
m_AudioCH->RegisterData ("inPeak", ChannelHandler::OUTPUT, m_GUIArgs.inPeak, MAX_CHANNELS * sizeof (bool)); | |||
} | |||
MixerPlugin::~MixerPlugin() { | |||
} | |||
void MixerPlugin::AddInputTip (int Channel) { | |||
char t[256]; | |||
sprintf (t, "Input %d", Channel); | |||
m_PluginInfo.PortTips.push_back (t); | |||
} | |||
PluginInfo &MixerPlugin::Initialise (const HostInfo *Host) { | |||
return SpiralPlugin::Initialise (Host); | |||
} | |||
@@ -75,9 +76,12 @@ SpiralGUIType *MixerPlugin::CreateGUI() { | |||
void MixerPlugin::Execute () { | |||
// Mix the inputs | |||
for (int n=0; n<m_HostInfo->BUFSIZE; n++) { | |||
float out = 0.0; | |||
for (int c=0; c<m_NumChannels; c++) | |||
out += (GetInput (c, n) * m_ChannelVal[c]); | |||
float in, out = 0.0; | |||
for (int c=0; c<m_NumChannels; c++) { | |||
in = GetInput (c, n) * m_ChannelVal[c]; | |||
m_GUIArgs.inPeak[c] = (in > 1.0); | |||
out += in; | |||
} | |||
SetOutput (0, n, out); | |||
m_GUIArgs.Peak = (out > 1.0); | |||
} | |||
@@ -86,48 +90,56 @@ void MixerPlugin::Execute () { | |||
void MixerPlugin::ExecuteCommands() { | |||
if (m_AudioCH->IsCommandWaiting()) { | |||
switch (m_AudioCH->GetCommand()) { | |||
case SETCH: | |||
case SETMIX: | |||
m_ChannelVal[m_GUIArgs.Num] = m_GUIArgs.Value; | |||
break; | |||
case SETNUM: | |||
SetChannels (m_GUIArgs.Num); | |||
case ADDCHAN: | |||
AddChannel (); | |||
break; | |||
case REMOVECHAN: | |||
RemoveChannel (); | |||
break; | |||
} | |||
} | |||
} | |||
void MixerPlugin::SetChannels (int n) { | |||
// once to clear the connections with the current info | |||
// do we need this???? | |||
UpdatePluginInfoWithHost(); | |||
// Things can get a bit confused deleting and adding inputs so we just chuck away all the ports... | |||
RemoveAllInputs (); | |||
RemoveAllOutputs (); | |||
m_PluginInfo.NumInputs = 0; | |||
m_PluginInfo.NumOutputs = 0; | |||
void MixerPlugin::SetChannels (int num) { | |||
// This is only used on loading, so we don't care that it clears all the inputs first | |||
UpdatePluginInfoWithHost(); // once to clear the connections with the current info | |||
RemoveAllInputs(); | |||
m_PluginInfo.PortTips.clear (); | |||
// ... and then create some new ones | |||
CreatePorts (n, true); | |||
// do the actual update | |||
UpdatePluginInfoWithHost (); | |||
m_PluginInfo.NumInputs = num; | |||
m_NumChannels = num; | |||
for (int c=1; c<=m_NumChannels; c++) { | |||
AddInput (); | |||
AddInputTip (c); | |||
} | |||
m_PluginInfo.PortTips.push_back ("Output"); | |||
UpdatePluginInfoWithHost (); // do the actual update | |||
} | |||
void MixerPlugin::CreatePorts (int n, bool AddPorts) { | |||
// default values n = 4 AddPorts = false | |||
int c; | |||
m_PluginInfo.NumInputs = n; | |||
m_NumChannels = n; | |||
char t[256]; | |||
for (c=1; c<=n; c++) { | |||
sprintf (t, "Input %d", c); | |||
m_PluginInfo.PortTips.push_back (t); | |||
} | |||
m_PluginInfo.NumOutputs = 1; | |||
void MixerPlugin::AddChannel (void) { | |||
UpdatePluginInfoWithHost(); // once to clear the connections with the current info | |||
m_PluginInfo.NumInputs++; | |||
m_NumChannels++; | |||
AddInput (); | |||
vector<std::string>::iterator i = m_PluginInfo.PortTips.end(); | |||
m_PluginInfo.PortTips.erase (--i); | |||
AddInputTip (m_NumChannels); | |||
m_PluginInfo.PortTips.push_back ("Output"); | |||
if (AddPorts) { | |||
for (c=0; c<m_PluginInfo.NumInputs; c++) AddInput(); | |||
AddOutput(); | |||
} | |||
UpdatePluginInfoWithHost (); // do the actual update | |||
} | |||
void MixerPlugin::RemoveChannel (void) { | |||
UpdatePluginInfoWithHost(); // once to clear the connections with the current info | |||
m_PluginInfo.NumInputs--; | |||
m_NumChannels--; | |||
vector<std::string>::iterator i = m_PluginInfo.PortTips.end(); | |||
m_PluginInfo.PortTips.erase (--i); | |||
m_PluginInfo.PortTips.erase (--i); | |||
m_PluginInfo.PortTips.push_back ("Output"); | |||
RemoveInput(); | |||
UpdatePluginInfoWithHost (); // do the actual update | |||
} | |||
void MixerPlugin::StreamOut (ostream &s) { | |||
@@ -140,7 +152,7 @@ void MixerPlugin::StreamIn (istream &s) { | |||
int version, chans; | |||
s >> version; | |||
switch (version) { | |||
case 1: SetChannels (4); | |||
case 1: // needs default number of channels | |||
break; | |||
case 2: s >> chans; | |||
SetChannels (chans); | |||
@@ -35,19 +35,22 @@ class MixerPlugin : public SpiralPlugin { | |||
virtual void StreamIn(std::istream &s); | |||
// has to be defined in the plugin | |||
virtual void UpdateGUI() { Fl::check(); } | |||
enum GUICommands { NONE, SETCH, SETNUM }; | |||
enum GUICommands { NONE, SETMIX, ADDCHAN, REMOVECHAN }; | |||
struct GUIArgs { | |||
int Num; | |||
float Value; | |||
bool inPeak[MAX_CHANNELS]; | |||
bool Peak; | |||
}; | |||
float GetChannel (int n) { return m_ChannelVal[n]; } | |||
int GetChannels (void) { return m_NumChannels; } | |||
private: | |||
void CreatePorts (int n = 4, bool AddPorts = false); | |||
void AddChannel (void); | |||
void RemoveChannel (void); | |||
void AddInputTip (int Channel); | |||
GUIArgs m_GUIArgs; | |||
int m_NumChannels; | |||
void SetChannels (int n); | |||
void SetChannels (int num); | |||
float m_ChannelVal[MAX_CHANNELS]; | |||
}; | |||
@@ -22,21 +22,45 @@ | |||
using namespace std; | |||
const float default_slider_value = 1.0f; | |||
//////////////////////////////////////////// | |||
MixerPluginGUI::ChanGUI::ChanGUI (int ChanNum, MixerPluginGUI *p, Fl_Color SelColour) { | |||
m_SliderGroup = new Fl_Group (0, 0, 20, 108, ""); | |||
m_SliderGroup->user_data ((void *)p); | |||
m_PeakInd = new Fl_LED_Button (0, -8, 20, 20, ""); | |||
m_SliderGroup->add (m_PeakInd); | |||
m_Chan = new Fl_Slider (0, 8, 20, 100, ""); | |||
m_Chan->type (FL_VERT_NICE_SLIDER); | |||
m_Chan->box (FL_PLASTIC_DOWN_BOX); | |||
m_Chan->selection_color (SelColour); | |||
m_Chan->maximum (2); | |||
m_Chan->step (0.01); | |||
m_Chan->value (default_slider_value); | |||
m_Chan->labelsize (10); | |||
m_Chan->callback ((Fl_Callback*)MixerPluginGUI::cb_Chan, (void*)&Numbers[ChanNum]); | |||
m_SliderGroup->add(m_Chan); | |||
} | |||
//////////////////////////////////////////// | |||
MixerPluginGUI::MixerPluginGUI (int w, int h, MixerPlugin *o, ChannelHandler *ch, const HostInfo *Info) : | |||
SpiralPluginGUI (w, h, o, ch) | |||
{ | |||
m_GUIColour = (Fl_Color)Info->GUI_COLOUR; | |||
for (int n=0; n<MAX_CHANNELS; n++) Numbers[n]=n; | |||
m_MainPack = new Fl_Pack (0, 15, w, 100); | |||
for (int c=0; c<MAX_CHANNELS; c++) Numbers[c]=c; | |||
m_MainPack = new Fl_Pack (0, 15, w, 108); | |||
m_MainPack->type (FL_HORIZONTAL); | |||
add (m_MainPack); | |||
// start with four... | |||
AddChan(); AddChan(); AddChan(); AddChan(); | |||
m_Buttons = new Fl_Pack (0, 118, 62, 20); | |||
m_Buttons = new Fl_Pack (0, 126, 62, 20); | |||
m_Buttons->type (FL_HORIZONTAL); | |||
add (m_Buttons); | |||
@@ -61,41 +85,30 @@ SpiralPluginGUI (w, h, o, ch) | |||
} | |||
void MixerPluginGUI::AddChan (bool SendData, bool ResizeIt) { | |||
Fl_Slider *NewSlide = new Fl_Slider (0, 0, 20, 100, ""); | |||
NewSlide->user_data ((void*)(this)); | |||
NewSlide->type (FL_VERT_NICE_SLIDER); | |||
NewSlide->selection_color (m_GUIColour); | |||
NewSlide->box (FL_PLASTIC_DOWN_BOX); | |||
NewSlide->labelsize (10); | |||
NewSlide->maximum (2); | |||
NewSlide->step (0.01); | |||
NewSlide->value (1.0); | |||
int num = (int)m_SlidVec.size(); | |||
NewSlide->callback ((Fl_Callback*)cb_Chan, (void*)&Numbers[num]); | |||
m_MainPack->add (NewSlide); | |||
m_SlidVec.push_back (NewSlide); | |||
int num = (int)m_GUIVec.size(); | |||
ChanGUI *NewChan = new ChanGUI (num, this, m_GUIColour); | |||
m_GUIVec.push_back (NewChan); | |||
m_MainPack->add (NewChan->m_SliderGroup); | |||
if (SendData) { | |||
m_GUICH->Set ("Num", ++num); | |||
m_GUICH->SetCommand (MixerPlugin::SETNUM); | |||
m_GUICH->SetCommand (MixerPlugin::ADDCHAN); | |||
m_GUICH->Wait (); | |||
m_GUICH->Set ("Num", num); | |||
m_GUICH->Set ("Value", (float)(2.0f - NewSlide->value ())); | |||
m_GUICH->SetCommand(MixerPlugin::SETCH); | |||
m_GUICH->Set ("Num", ++num); | |||
m_GUICH->Set ("Value", (float)(2.0f - default_slider_value)); | |||
m_GUICH->SetCommand(MixerPlugin::SETMIX); | |||
m_GUICH->Wait (); | |||
} | |||
if (ResizeIt && num > 3) Resize (w()+20, h()); | |||
} | |||
void MixerPluginGUI::DeleteChan (bool SendData) { | |||
vector<Fl_Slider*>::iterator i = m_SlidVec.end (); | |||
vector<ChanGUI*>::iterator i = m_GUIVec.end(); | |||
i--; | |||
m_MainPack->remove (*i); | |||
m_MainPack->remove ((*i)->m_SliderGroup); | |||
delete *i; | |||
m_SlidVec.erase (i); | |||
int num = (int)m_SlidVec.size(); | |||
m_GUIVec.erase (i); | |||
int num = (int)m_GUIVec.size(); | |||
if (SendData) { | |||
m_GUICH->Set ("Num", num); | |||
m_GUICH->SetCommand (MixerPlugin::SETNUM); | |||
m_GUICH->SetCommand (MixerPlugin::REMOVECHAN); | |||
m_GUICH->Wait (); | |||
} | |||
if (num > 2) Resize (w()-20, h()); | |||
@@ -104,20 +117,24 @@ void MixerPluginGUI::DeleteChan (bool SendData) { | |||
void MixerPluginGUI::UpdateValues(SpiralPlugin *o) { | |||
MixerPlugin *Plugin = (MixerPlugin *)o; | |||
unsigned int chans = Plugin->GetChannels(); | |||
while (chans < m_SlidVec.size()) DeleteChan (false); | |||
while (chans > m_SlidVec.size()) AddChan (false, true); | |||
for (unsigned int n=0; n<chans; n++) | |||
m_SlidVec[n]->value (2.0f - Plugin->GetChannel (n)); | |||
while (chans < m_GUIVec.size()) DeleteChan (false); | |||
while (chans > m_GUIVec.size()) AddChan (false, true); | |||
for (unsigned int c=0; c<chans; c++) | |||
m_GUIVec[c]->m_Chan->value (2.0f - Plugin->GetChannel (c)); | |||
redraw(); | |||
} | |||
void MixerPluginGUI::Update () { | |||
if (m_GUICH->GetBool ("Peak")) m_PeakInd->value (true); | |||
m_GUICH->GetData ("inPeak", m_inPeak); | |||
for (unsigned int c=0; c<m_GUIVec.size(); c++) { | |||
if (m_inPeak[c]) m_GUIVec[c]->m_PeakInd->value (true); | |||
} | |||
} | |||
inline void MixerPluginGUI::cb_Add_i (Fl_Button* o, void* v) { | |||
m_PeakInd->value (false); | |||
if ((int)m_SlidVec.size() < MAX_CHANNELS) AddChan (true, true); | |||
if ((int)m_GUIVec.size() < MAX_CHANNELS) AddChan (true, true); | |||
} | |||
void MixerPluginGUI::cb_Add (Fl_Button* o, void* v) { | |||
@@ -126,7 +143,7 @@ void MixerPluginGUI::cb_Add (Fl_Button* o, void* v) { | |||
inline void MixerPluginGUI::cb_Delete_i (Fl_Button* o, void* v) { | |||
m_PeakInd->value (false); | |||
if (m_SlidVec.size() > 2) DeleteChan (); | |||
if (m_GUIVec.size() > 2) DeleteChan (); | |||
} | |||
void MixerPluginGUI::cb_Delete (Fl_Button* o, void* v) { | |||
@@ -134,29 +151,26 @@ void MixerPluginGUI::cb_Delete (Fl_Button* o, void* v) { | |||
} | |||
inline void MixerPluginGUI::cb_Chan_i (Fl_Slider* o, void* v) { | |||
// This line works fine | |||
// cerr << *(int*)(v) << endl << (float)(2.0f-o->value()) << endl; | |||
// The segfault comes when you do any of the following - don't know why | |||
int num = (*(int*)(v)); | |||
m_PeakInd->value (false); | |||
m_GUICH->Set("Num", (*(int*)(v))); | |||
m_GUIVec[num]->m_PeakInd->value (false); | |||
m_GUICH->Set("Num", num); | |||
m_GUICH->Set("Value", (float)(2.0f-o->value())); | |||
m_GUICH->SetCommand (MixerPlugin::SETCH); | |||
m_GUICH->SetCommand (MixerPlugin::SETMIX); | |||
} | |||
void MixerPluginGUI::cb_Chan(Fl_Slider* o, void* v) { | |||
// If you use user_data() instead of parent()->parent() you get a segfault - don't know why | |||
((MixerPluginGUI*)(o->parent()->parent()))->cb_Chan_i (o, v); | |||
((MixerPluginGUI*)(o->parent()->user_data()))->cb_Chan_i (o, v); | |||
} | |||
// you sometimes get a segfault on exit too - again - don't know why | |||
const string MixerPluginGUI::GetHelpText (const string &loc){ | |||
return string("") | |||
+ "A general purpose mixer.\n" | |||
+ "Useful for mixing CV values as well as mono audio\n" | |||
+ "signals.\n" | |||
+ "The LED indicates the the mixer output is at peak\n" | |||
+ "level, click on it, or change levels to reset it.\n" | |||
+ "The LEDs indicate the the mixer inputs or output is\n" | |||
+ "at peak level, click on them, or change appropriate\n" | |||
+ "levels to reset them.\n" | |||
+ "Add up to 16 channels using the '+' button.\n" | |||
+ "Use the '-' button to remove unwanted channels.\n"; | |||
} |
@@ -28,7 +28,8 @@ | |||
static int Numbers[MAX_CHANNELS]; | |||
class MixerPluginGUI : public SpiralPluginGUI { | |||
class MixerPluginGUI : public SpiralPluginGUI | |||
{ | |||
public: | |||
MixerPluginGUI (int w, int h, MixerPlugin *o, ChannelHandler *ch, const HostInfo *Info); | |||
virtual void UpdateValues(SpiralPlugin *o); | |||
@@ -36,9 +37,18 @@ class MixerPluginGUI : public SpiralPluginGUI { | |||
protected: | |||
const std::string GetHelpText(const std::string &loc); | |||
private: | |||
bool m_inPeak[MAX_CHANNELS]; | |||
class ChanGUI { | |||
public: | |||
ChanGUI (int ChanNum, MixerPluginGUI *p, Fl_Color SelColour); | |||
Fl_Group *m_SliderGroup; | |||
Fl_Slider *m_Chan; | |||
Fl_LED_Button *m_PeakInd; | |||
}; | |||
friend class ChanGUI; | |||
void AddChan (bool SendData = false, bool ResizeIt = false); | |||
void DeleteChan (bool SendData = true); | |||
std::vector<Fl_Slider*> m_SlidVec; | |||
std::vector<ChanGUI*> m_GUIVec; | |||
Fl_Pack *m_MainPack, *m_Buttons; | |||
Fl_Button *m_Add, *m_Delete; | |||
Fl_LED_Button *m_PeakInd; | |||
@@ -30,7 +30,7 @@ char** SpiralPlugin_GetIcon() { return SpiralIcon_xpm; } | |||
int SpiralPlugin_GetID() { return 0x0001; } | |||
string SpiralPlugin_GetGroupName() { return "Control"; } | |||
string SpiralPlugin_GetGroupName() { return "InputOutput"; } | |||
} | |||
/////////////////////////////////////////////////////// | |||
@@ -42,7 +42,7 @@ PLUGINLIST="AmpPlugin AnotherFilterPlugin BeatMatchPlugin ControllerPlugin \ | |||
CounterPlugin DelayPlugin DiskWriterPlugin DistributorPlugin EchoPlugin \ | |||
EnvFollowerPlugin EnvelopePlugin FilterPlugin FlipflopPlugin FormantFilterPlugin \ | |||
KeyboardPlugin LFOPlugin LogicPlugin MasherPlugin MatrixPlugin \ | |||
MeterPlugin MidiPlugin MixSwitchPlugin MixerPlugin MoogFilterPlugin NoisePlugin \ | |||
MeterPlugin MidiPlugin MixSwitchPlugin MixerPlugin MoogFilterPlugin MousePlugin NoisePlugin \ | |||
NoteSnapPlugin OperatorPlugin OscillatorPlugin OutputPlugin PoshSamplerPlugin \ | |||
RingModPlugin SVFilterPlugin SampleHoldPlugin ScopePlugin SeqSelectorPlugin \ | |||
SmoothPlugin SpiralLoopPlugin SplitSwitchPlugin SplitterPlugin StereoMixerPlugin \ | |||
@@ -239,6 +239,7 @@ SpiralSound/Plugins/MidiPlugin/Makefile | |||
SpiralSound/Plugins/MixSwitchPlugin/Makefile | |||
SpiralSound/Plugins/MixerPlugin/Makefile | |||
SpiralSound/Plugins/MoogFilterPlugin/Makefile | |||
SpiralSound/Plugins/MousePlugin/Makefile | |||
SpiralSound/Plugins/NoisePlugin/Makefile | |||
SpiralSound/Plugins/NoteSnapPlugin/Makefile | |||
SpiralSound/Plugins/OperatorPlugin/Makefile | |||
@@ -0,0 +1,20 @@ | |||
#!/bin/bash | |||
if [ $# -gt 0 ] ; then | |||
if ! [ -e links/$1.so ] ; then | |||
echo Creating link for $1 | |||
ln -s ../SpiralSound/Plugins/$1/$1.so links/$1.so | |||
fi | |||
else | |||
if ! [ -d links ] ; then | |||
if [ -e links ] ; then | |||
echo A file \"links\" alredy exists, can\'t create the directory | |||
exit | |||
fi | |||
mkdir links | |||
fi | |||
xargs -n 1 $0 < SpiralSound/PluginList.txt | |||
./spiralsynthmodular --PluginPath `pwd`/links/ | |||
fi | |||