| @@ -1,3 +1,16 @@ | |||||
| CVS 0.2.3 | |||||
| New plugin menu on canvas | |||||
| New mouse clicks Button 1 = Box select devices, Move devices | |||||
| Button 2 (Shift Button 1) = Drag Canvas, Multi select | |||||
| Button 3 (Ctrl Button 1) = Edit and Plugin menu, Multi Select | |||||
| Updated streamer - Now shows file name. | |||||
| New output CV that rises from 0 to 1 as stream plays | |||||
| Envelope update - Added a filter to smooth out clicks on very fast attack levels | |||||
| Scope and Meter have moved to the Input/Output group | |||||
| PoshSampler now has a button - ReTrigger, when this button is OFF, a sample cannot | |||||
| be retriggered until it has finished playing. | |||||
| Release 0.2.2 | Release 0.2.2 | ||||
| New GUI - less cluttered and more "traditional" toolbars. | New GUI - less cluttered and more "traditional" toolbars. | ||||
| @@ -14,7 +14,7 @@ | |||||
| * You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
| * along with this program; if not, write to the Free Software | * along with this program; if not, write to the Free Software | ||||
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||||
| */ | |||||
| */ | |||||
| #include <FL/Fl_Group.h> | #include <FL/Fl_Group.h> | ||||
| #include <FL/Fl_Output.h> | #include <FL/Fl_Output.h> | ||||
| @@ -36,8 +36,8 @@ class CanvasWire | |||||
| { | { | ||||
| public: | public: | ||||
| CanvasWire() { Clear(); } | CanvasWire() { Clear(); } | ||||
| void Clear() | |||||
| void Clear() | |||||
| { | { | ||||
| OutputPort=-1; | OutputPort=-1; | ||||
| OutputID=-1; | OutputID=-1; | ||||
| @@ -97,9 +97,9 @@ public: | |||||
| void ClearConnections(Fl_DeviceGUI* Device); | void ClearConnections(Fl_DeviceGUI* Device); | ||||
| void RemoveDevice(Fl_DeviceGUI* Device); | void RemoveDevice(Fl_DeviceGUI* Device); | ||||
| void Clear(); | void Clear(); | ||||
| void AddPluginName(const string &s, int ID) | |||||
| { m_PluginNameList.push_back(pair<string,int>(s,ID)); } | |||||
| GraphSort* GetGraph() { return &m_Graph; } | |||||
| void AddPluginName(const string &s, int ID); | |||||
| GraphSort* GetGraph() { return &m_Graph; } | |||||
| void Poll(); | void Poll(); | ||||
| @@ -131,10 +131,7 @@ public: | |||||
| data->redraw(); | data->redraw(); | ||||
| } | } | ||||
| static void EnablePaste(Fl_Canvas *data) | |||||
| { | |||||
| data->m_CanPaste=true; | |||||
| } | |||||
| static void EnablePaste(Fl_Canvas *data) { data->m_CanPaste=true; } | |||||
| bool HaveSelection() {return m_HaveSelection; } | bool HaveSelection() {return m_HaveSelection; } | ||||
| CanvasGroup Selection() { return m_Selection; } | CanvasGroup Selection() { return m_Selection; } | ||||
| @@ -146,102 +143,43 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| void PopupEditMenu (Fl_Group *group); | |||||
| void DrawSelection(); | void DrawSelection(); | ||||
| void CalculateSelection(); | void CalculateSelection(); | ||||
| void DrawWires(); | void DrawWires(); | ||||
| void ClearIncompleteWire(); | void ClearIncompleteWire(); | ||||
| void DrawIncompleteWire(); | void DrawIncompleteWire(); | ||||
| bool UserMakingConnection(); | bool UserMakingConnection(); | ||||
| Fl_DeviceGUI *FindDevice(int ID); | Fl_DeviceGUI *FindDevice(int ID); | ||||
| Fl_Image *m_BG; | |||||
| char *m_BGData; | |||||
| Fl_Image *m_BG; | |||||
| char *m_BGData; | |||||
| void (*cb_Connection)(Fl_Widget*, void*); | void (*cb_Connection)(Fl_Widget*, void*); | ||||
| void (*cb_Unconnect)(Fl_Widget*, void*); | void (*cb_Unconnect)(Fl_Widget*, void*); | ||||
| void (*cb_AddDevice)(Fl_Widget*, void*); | void (*cb_AddDevice)(Fl_Widget*, void*); | ||||
| void (*cb_Rename)(Fl_Widget*, void*); | void (*cb_Rename)(Fl_Widget*, void*); | ||||
| void (*cb_CutDeviceGroup)(Fl_Widget*, void*); | void (*cb_CutDeviceGroup)(Fl_Widget*, void*); | ||||
| void (*cb_CopyDeviceGroup)(Fl_Widget*, void*); | void (*cb_CopyDeviceGroup)(Fl_Widget*, void*); | ||||
| void (*cb_PasteDeviceGroup)(Fl_Widget*, void*); | void (*cb_PasteDeviceGroup)(Fl_Widget*, void*); | ||||
| void (*cb_MergePatch)(Fl_Widget*, void*); | void (*cb_MergePatch)(Fl_Widget*, void*); | ||||
| map<int,int> MapNewDeviceIds; | |||||
| map<int,int> MapNewDeviceIds; | |||||
| vector<CanvasWire> m_WireVec; | vector<CanvasWire> m_WireVec; | ||||
| CanvasWire m_IncompleteWire; | |||||
| bool m_ToolMenu, m_ButtonDown; | |||||
| int m_x,m_y,m_Selected; | |||||
| vector< pair<string,int> > m_PluginNameList; | |||||
| CanvasWire m_IncompleteWire; | |||||
| GraphSort m_Graph; | GraphSort m_Graph; | ||||
| int m_UpdateTimer; | |||||
| int m_DragX,m_DragY; | |||||
| bool m_HaveSelection, m_Selecting; | |||||
| int m_StartSelectX,m_StartSelectY; | |||||
| int m_EndSelectX,m_EndSelectY; | |||||
| CanvasGroup m_Selection; | |||||
| bool m_CanPaste; | |||||
| CanvasGroup m_Selection; | |||||
| bool m_CanPaste, m_HaveSelection, m_Selecting; | |||||
| int m_x, m_y, m_UpdateTimer, m_DragX, m_DragY; | |||||
| int m_StartSelectX, m_StartSelectY, m_EndSelectX,m_EndSelectY; | |||||
| friend istream &operator>>(istream &s, Fl_Canvas &o); | friend istream &operator>>(istream &s, Fl_Canvas &o); | ||||
| friend ostream &operator<<(ostream &s, Fl_Canvas &o); | friend ostream &operator<<(ostream &s, Fl_Canvas &o); | ||||
| void PopupEditMenu(Fl_Group *group); | |||||
| ///Inline Callbacks/// | |||||
| inline void cb_OnDrag_i(Fl_Widget* widget, int x,int y); | |||||
| inline void cb_OnDragClick_i(Fl_Widget* widget, int button,int shift_state) | |||||
| { | |||||
| if ((button==3) && ((shift_state & FL_CTRL) != 0)) | |||||
| { | |||||
| PopupEditMenu(widget->parent()); | |||||
| } | |||||
| if ((widget) && (button==1)) | |||||
| { | |||||
| int ID = ((Fl_DeviceGUI*)(widget->parent()))->GetID(); | |||||
| std::vector<int>::iterator device_iter = std::find(m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), ID); | |||||
| if (((shift_state & FL_SHIFT) != 0) || ((shift_state & FL_CTRL) != 0)) | |||||
| { | |||||
| if (m_HaveSelection) | |||||
| { | |||||
| if (device_iter != m_Selection.m_DeviceIds.end()) | |||||
| m_Selection.m_DeviceIds.erase(device_iter); | |||||
| else | |||||
| m_Selection.m_DeviceIds.push_back(ID); | |||||
| } | |||||
| else | |||||
| { | |||||
| m_Selection.Clear(); | |||||
| m_HaveSelection = true; | |||||
| m_Selection.m_DeviceIds.push_back(ID); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| m_Selection.Clear(); | |||||
| m_HaveSelection = true; | |||||
| m_Selection.m_DeviceIds.push_back(ID); | |||||
| } | |||||
| redraw(); | |||||
| } | |||||
| } | |||||
| inline void cb_DeleteDeviceGroup_i(); | |||||
| ///Static Callbacks/// | |||||
| static void cb_OnDrag_s(Fl_Widget* widget, int x,int y, void* data) { ((Fl_Canvas *)data)->cb_OnDrag_i(widget, x, y); } | |||||
| static void cb_OnDragClick_s(Fl_Widget* widget, int button,int shift_state, void* data) { ((Fl_Canvas *)data)->cb_OnDragClick_i(widget, button, shift_state); } | |||||
| static void cb_DeleteDeviceGroup(Fl_Widget* widget, void* data) { ((Fl_Canvas *)data)->cb_DeleteDeviceGroup_i(); } | |||||
| // Callbacks | |||||
| static void cb_OnDrag_s (Fl_Widget* widget, int x, int y, void* data); | |||||
| inline void cb_OnDrag_i (Fl_Widget* widget, int x,int y); | |||||
| static void cb_OnDragClick_s (Fl_Widget* widget, int button, int shift_state, void* data); | |||||
| inline void cb_OnDragClick_i(Fl_Widget* widget, int button,int shift_state); | |||||
| static void cb_DeleteDeviceGroup (Fl_Widget* widget, void* data); | |||||
| inline void cb_DeleteDeviceGroup_i(); | |||||
| static void cb_AddDeviceFromMenu (Fl_Widget* widget, void* data); | |||||
| inline void cb_AddDeviceFromMenu_i (Fl_Widget* widget, void* data); | |||||
| }; | }; | ||||
| istream &operator>>(istream &s, Fl_Canvas &o); | istream &operator>>(istream &s, Fl_Canvas &o); | ||||
| @@ -132,9 +132,9 @@ void DiskWriterPluginGUI::UpdateValues (SpiralPlugin *o) | |||||
| m_32bits->value(0); | m_32bits->value(0); | ||||
| m_24bits->value(0); | m_24bits->value(0); | ||||
| m_16bits->value(1); | m_16bits->value(1); | ||||
| } | |||||
| } | |||||
| } | } | ||||
| m_Stereo->value(Plugin->GetStereo()); | m_Stereo->value(Plugin->GetStereo()); | ||||
| redraw(); | redraw(); | ||||
| @@ -143,13 +143,28 @@ void DiskWriterPluginGUI::UpdateValues (SpiralPlugin *o) | |||||
| //// Callbacks //// | //// Callbacks //// | ||||
| inline void DiskWriterPluginGUI::cb_Open_i(Fl_Button* o) | inline void DiskWriterPluginGUI::cb_Open_i(Fl_Button* o) | ||||
| { | |||||
| { | |||||
| if (o->value()) | if (o->value()) | ||||
| { | { | ||||
| char *fn=fl_file_chooser("Pick a Wav file to save to", "*.wav", NULL); | char *fn=fl_file_chooser("Pick a Wav file to save to", "*.wav", NULL); | ||||
| char t[256]; | |||||
| sprintf(t,"%s",fn); | |||||
| // On Mon, 2004-05-17 at 20:53, Bernd Breitenbach wrote: | |||||
| // When you click the open button and click cancel right afterwards it crashes. | |||||
| // Attached you find a patch for it. | |||||
| // I would call it a work around not a solution, because you can't have filenames that exceeds | |||||
| // 256 chars. | |||||
| // A real solution requires a more flexible implementation of ChannelHandler::RegisterData | |||||
| // On Mon, 17 May 2004 13:59:23 Dave Griffiths wrote: | |||||
| // That's a difficult one. We can't use new/malloc as it's for use on the realtime thread | |||||
| // (although in practice, ssm breaks this rule quite a lot :/ ) | |||||
| // A solution would be to use a custom allocator, with constant timing | |||||
| // - or a ringbuffer mechanism I think... | |||||
| char t[256]; | |||||
| strcpy (t, fn); | |||||
| //sprintf(t,"%s",fn); | |||||
| if (fn && fn!="") | if (fn && fn!="") | ||||
| { | { | ||||
| m_GUICH->SetData("Filename",(void*)t); | m_GUICH->SetData("Filename",(void*)t); | ||||
| @@ -168,34 +183,34 @@ inline void DiskWriterPluginGUI::cb_Open_i(Fl_Button* o) | |||||
| } | } | ||||
| inline void DiskWriterPluginGUI::cb_Record_i(Fl_Button* o) | inline void DiskWriterPluginGUI::cb_Record_i(Fl_Button* o) | ||||
| { | |||||
| if (o->value()) | |||||
| { | |||||
| if (o->value()) | |||||
| { | { | ||||
| m_GUICH->SetCommand(DiskWriterPlugin::RECORD); | m_GUICH->SetCommand(DiskWriterPlugin::RECORD); | ||||
| } | |||||
| else | |||||
| } | |||||
| else | |||||
| { | { | ||||
| m_GUICH->SetCommand(DiskWriterPlugin::STOP); | m_GUICH->SetCommand(DiskWriterPlugin::STOP); | ||||
| } | |||||
| } | |||||
| } | } | ||||
| inline void DiskWriterPluginGUI::cb_16bits_i(Fl_Button* o) | inline void DiskWriterPluginGUI::cb_16bits_i(Fl_Button* o) | ||||
| { | |||||
| { | |||||
| m_GUICH->Set("BitsPerSample",16); | m_GUICH->Set("BitsPerSample",16); | ||||
| } | } | ||||
| inline void DiskWriterPluginGUI::cb_24bits_i(Fl_Button* o) | inline void DiskWriterPluginGUI::cb_24bits_i(Fl_Button* o) | ||||
| { | |||||
| { | |||||
| m_GUICH->Set("BitsPerSample",24); | m_GUICH->Set("BitsPerSample",24); | ||||
| } | } | ||||
| inline void DiskWriterPluginGUI::cb_32bits_i(Fl_Button* o) | inline void DiskWriterPluginGUI::cb_32bits_i(Fl_Button* o) | ||||
| { | |||||
| { | |||||
| m_GUICH->Set("BitsPerSample",32); | m_GUICH->Set("BitsPerSample",32); | ||||
| } | } | ||||
| inline void DiskWriterPluginGUI::cb_Stereo_i(Fl_Button* o) | inline void DiskWriterPluginGUI::cb_Stereo_i(Fl_Button* o) | ||||
| { | |||||
| { | |||||
| m_GUICH->Set("Stereo",o->value()); | m_GUICH->Set("Stereo",o->value()); | ||||
| } | } | ||||
| @@ -460,7 +460,6 @@ SpiralWindowType *SynthModular::CreateWindow() | |||||
| m_TopWindow->resizable(m_CanvasScroll); | m_TopWindow->resizable(m_CanvasScroll); | ||||
| m_Canvas = new Fl_Canvas(-5000, -5000, 10000, 10000, ""); | m_Canvas = new Fl_Canvas(-5000, -5000, 10000, 10000, ""); | ||||
| m_Canvas->user_data ((void*)(this)); | |||||
| m_Canvas->type(1); | m_Canvas->type(1); | ||||
| m_Canvas->box(FL_FLAT_BOX); | m_Canvas->box(FL_FLAT_BOX); | ||||
| m_Canvas->labeltype(FL_ENGRAVED_LABEL); | m_Canvas->labeltype(FL_ENGRAVED_LABEL); | ||||
| @@ -596,39 +595,43 @@ void SynthModular::LoadPlugins (string pluginPath) { | |||||
| //NewButton->color(SpiralInfo::GUICOL_Button); | //NewButton->color(SpiralInfo::GUICOL_Button); | ||||
| //NewButton->selection_color(SpiralInfo::GUICOL_Button); | //NewButton->selection_color(SpiralInfo::GUICOL_Button); | ||||
| the_group->add (NewButton); | the_group->add (NewButton); | ||||
| string PluginName=*i; | |||||
| // we need to keep tooltips stored outside their widgets - widgets just have a pointer | |||||
| // I haven't done anything about cleaning up these strings - which may cause memory leaks? | |||||
| // But m_DeviceVec - which, I assume, would be used to keep track of / clean up the dynamicly | |||||
| // created NewButton widgets isn't cleaned up either, so we might have 2 memory leaks | |||||
| // involved? - but then again, they might be automatically deallocated because they're | |||||
| // in another widget, in which case there's just one memory leak to deal with. (andy) | |||||
| string* PluginName = new string (*i); | |||||
| // find the first slash, if there is one, and get rid of everything before and including it | // find the first slash, if there is one, and get rid of everything before and including it | ||||
| unsigned int p = PluginName.find ('/'); | |||||
| if (p < PluginName.length()) PluginName.erase (0, p); | |||||
| unsigned int p = PluginName->find ('/'); | |||||
| if (p < PluginName->length()) PluginName->erase (0, p); | |||||
| // find last . and get rid of everything after and including it | // find last . and get rid of everything after and including it | ||||
| p = PluginName.rfind ('.'); | |||||
| unsigned int l = PluginName.length (); | |||||
| if (p < l) PluginName.erase (p, l); | |||||
| NewButton->tooltip (PluginName.c_str()); | |||||
| p = PluginName->rfind ('.'); | |||||
| unsigned int l = PluginName->length (); | |||||
| if (p < l) PluginName->erase (p, l); | |||||
| NewButton->tooltip (PluginName->c_str()); | |||||
| // Slashes have significance to the menu widgets, remove them from the GroupName | // Slashes have significance to the menu widgets, remove them from the GroupName | ||||
| while ((p = GroupName.find ('/')) < PluginName.length()) | |||||
| while ((p = GroupName.find ('/')) < PluginName->length()) | |||||
| GroupName = GroupName.replace (p, 1, " and "); | GroupName = GroupName.replace (p, 1, " and "); | ||||
| string MenuEntry = "Plugins/" + GroupName + "/" + PluginName; | |||||
| string MenuEntry = "Plugins/" + GroupName + "/" + *PluginName; | |||||
| m_MainMenu->add (MenuEntry.c_str(), 0, cb_NewDeviceFromMenu, &Numbers[ID], 0); | m_MainMenu->add (MenuEntry.c_str(), 0, cb_NewDeviceFromMenu, &Numbers[ID], 0); | ||||
| //MenuEntry = "Help/" + MenuEntry; | |||||
| //m_MainMenu->add (MenuEntry.c_str(), 0, NULL, &Numbers[ID], 0); | |||||
| // andy preston | |||||
| // my next step would be to add the plugins to Andrew's right-click menu | |||||
| // to free up the middle button | |||||
| m_Canvas->AddPluginName (PluginName, PluginManager::Get()->GetPlugin(ID)->ID); | |||||
| // when help is working better - this will put the plugins into the help menu | |||||
| // MenuEntry = "Help/" + MenuEntry; | |||||
| // m_MainMenu->add (MenuEntry.c_str(), 0, NULL, &Numbers[ID], 0); | |||||
| // Add the plugins to the canvas menu | |||||
| m_Canvas->AddPluginName (MenuEntry, PluginManager::Get()->GetPlugin(ID)->ID); | |||||
| // this overwrites the widget's user_data with that specified for the callback | // this overwrites the widget's user_data with that specified for the callback | ||||
| // so we can't use it for other purposes | // so we can't use it for other purposes | ||||
| NewButton->callback ((Fl_Callback*)cb_NewDevice, &Numbers[ID]); | NewButton->callback ((Fl_Callback*)cb_NewDevice, &Numbers[ID]); | ||||
| NewButton->show(); | NewButton->show(); | ||||
| // Nothing else ever touches m_DeviceVec - is this right??? (andy) | |||||
| m_DeviceVec.push_back (NewButton); | m_DeviceVec.push_back (NewButton); | ||||
| the_group->redraw(); | the_group->redraw(); | ||||
| // m_NextPluginButton++; | // m_NextPluginButton++; | ||||
| Fl::check(); | Fl::check(); | ||||
| splashtext->label (PluginName.c_str()); | |||||
| splashtext->label (PluginName->c_str()); | |||||
| Splash->redraw(); | Splash->redraw(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1415,12 +1418,13 @@ void SynthModular::cb_NewDevice (Fl_Button *o, void *v) { | |||||
| // (Plugin Canvas Menu) | // (Plugin Canvas Menu) | ||||
| inline void SynthModular::cb_NewDeviceFromCanvasMenu_i(Fl_Canvas* o, void* v) | |||||
| { | |||||
| AddDevice(*((int*)v),*((int*)v+1),*((int*)v+2)); | |||||
| inline void SynthModular::cb_NewDeviceFromCanvasMenu_i (Fl_Canvas* o, void* v) { | |||||
| AddDevice(*((int*)v),*((int*)v+1),*((int*)v+2)); | |||||
| } | |||||
| void SynthModular::cb_NewDeviceFromCanvasMenu(Fl_Canvas* o, void* v) { | |||||
| ((SynthModular*)(o->user_data()))->cb_NewDeviceFromCanvasMenu_i(o,v); | |||||
| } | } | ||||
| void SynthModular::cb_NewDeviceFromCanvasMenu(Fl_Canvas* o, void* v) | |||||
| {((SynthModular*)(o->user_data()))->cb_NewDeviceFromCanvasMenu_i(o,v);} | |||||
| ///////////////////////////////// | ///////////////////////////////// | ||||
| @@ -63,7 +63,7 @@ public: | |||||
| class Fl_ToolButton : public Fl_Button | class Fl_ToolButton : public Fl_Button | ||||
| { | { | ||||
| public: | public: | ||||
| Fl_ToolButton(int x, int y, int w, int h, const char *n=NULL) : | |||||
| Fl_ToolButton(int x, int y, int w, int h, const char *n=NULL) : | |||||
| Fl_Button(x,y,w,h,n) {} | Fl_Button(x,y,w,h,n) {} | ||||
| virtual void draw() { draw_label(); } | virtual void draw() { draw_label(); } | ||||
| }; | }; | ||||
| @@ -72,7 +72,7 @@ class DeviceGroup | |||||
| { | { | ||||
| public: | public: | ||||
| DeviceGroup() { devicecount = 0; } | DeviceGroup() { devicecount = 0; } | ||||
| int devicecount; | int devicecount; | ||||
| fstream devices; | fstream devices; | ||||
| map<int,int> m_DeviceIds;//old ID, new ID | map<int,int> m_DeviceIds;//old ID, new ID | ||||
| @@ -98,13 +98,13 @@ public: | |||||
| void FreezeAll() | void FreezeAll() | ||||
| { | { | ||||
| m_CH.Set("Frozen",true); | |||||
| m_CH.Set("Frozen",true); | |||||
| m_CH.Wait(); | m_CH.Wait(); | ||||
| } | } | ||||
| void ThawAll() | void ThawAll() | ||||
| { | { | ||||
| m_CH.Set("Frozen",false); | |||||
| m_CH.Set("Frozen",false); | |||||
| } | } | ||||
| void PauseAudio() | void PauseAudio() | ||||
| @@ -121,7 +121,7 @@ public: | |||||
| { | { | ||||
| if (! m_ResetingAudioThread) | if (! m_ResetingAudioThread) | ||||
| { | { | ||||
| FreezeAll(); | |||||
| FreezeAll(); | |||||
| m_ResetingAudioThread = true; | m_ResetingAudioThread = true; | ||||
| @@ -175,7 +175,6 @@ private: | |||||
| inline void cb_NewComment_i(Fl_Button* o, void* v); | inline void cb_NewComment_i(Fl_Button* o, void* v); | ||||
| static void cb_NewComment(Fl_Button* o, void* v); | static void cb_NewComment(Fl_Button* o, void* v); | ||||
| // File menu - and associated buttons, etc. | // File menu - and associated buttons, etc. | ||||
| inline void cb_New_i (Fl_Widget *o, void *v); | inline void cb_New_i (Fl_Widget *o, void *v); | ||||
| static void cb_New (Fl_Widget *o, void *v); | static void cb_New (Fl_Widget *o, void *v); | ||||