@@ -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 | |||
New GUI - less cluttered and more "traditional" toolbars. | |||
@@ -14,7 +14,7 @@ | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
*/ | |||
*/ | |||
#include <FL/Fl_Group.h> | |||
#include <FL/Fl_Output.h> | |||
@@ -36,8 +36,8 @@ class CanvasWire | |||
{ | |||
public: | |||
CanvasWire() { Clear(); } | |||
void Clear() | |||
void Clear() | |||
{ | |||
OutputPort=-1; | |||
OutputID=-1; | |||
@@ -97,9 +97,9 @@ public: | |||
void ClearConnections(Fl_DeviceGUI* Device); | |||
void RemoveDevice(Fl_DeviceGUI* Device); | |||
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(); | |||
@@ -131,10 +131,7 @@ public: | |||
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; } | |||
CanvasGroup Selection() { return m_Selection; } | |||
@@ -146,102 +143,43 @@ public: | |||
} | |||
private: | |||
void PopupEditMenu (Fl_Group *group); | |||
void DrawSelection(); | |||
void CalculateSelection(); | |||
void DrawWires(); | |||
void ClearIncompleteWire(); | |||
void DrawIncompleteWire(); | |||
bool UserMakingConnection(); | |||
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_Unconnect)(Fl_Widget*, void*); | |||
void (*cb_AddDevice)(Fl_Widget*, void*); | |||
void (*cb_Rename)(Fl_Widget*, void*); | |||
void (*cb_CutDeviceGroup)(Fl_Widget*, void*); | |||
void (*cb_CopyDeviceGroup)(Fl_Widget*, void*); | |||
void (*cb_PasteDeviceGroup)(Fl_Widget*, void*); | |||
void (*cb_MergePatch)(Fl_Widget*, void*); | |||
map<int,int> MapNewDeviceIds; | |||
map<int,int> MapNewDeviceIds; | |||
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; | |||
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 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); | |||
@@ -132,9 +132,9 @@ void DiskWriterPluginGUI::UpdateValues (SpiralPlugin *o) | |||
m_32bits->value(0); | |||
m_24bits->value(0); | |||
m_16bits->value(1); | |||
} | |||
} | |||
} | |||
m_Stereo->value(Plugin->GetStereo()); | |||
redraw(); | |||
@@ -143,13 +143,28 @@ void DiskWriterPluginGUI::UpdateValues (SpiralPlugin *o) | |||
//// Callbacks //// | |||
inline void DiskWriterPluginGUI::cb_Open_i(Fl_Button* o) | |||
{ | |||
{ | |||
if (o->value()) | |||
{ | |||
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!="") | |||
{ | |||
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) | |||
{ | |||
if (o->value()) | |||
{ | |||
if (o->value()) | |||
{ | |||
m_GUICH->SetCommand(DiskWriterPlugin::RECORD); | |||
} | |||
else | |||
} | |||
else | |||
{ | |||
m_GUICH->SetCommand(DiskWriterPlugin::STOP); | |||
} | |||
} | |||
} | |||
inline void DiskWriterPluginGUI::cb_16bits_i(Fl_Button* o) | |||
{ | |||
{ | |||
m_GUICH->Set("BitsPerSample",16); | |||
} | |||
inline void DiskWriterPluginGUI::cb_24bits_i(Fl_Button* o) | |||
{ | |||
{ | |||
m_GUICH->Set("BitsPerSample",24); | |||
} | |||
inline void DiskWriterPluginGUI::cb_32bits_i(Fl_Button* o) | |||
{ | |||
{ | |||
m_GUICH->Set("BitsPerSample",32); | |||
} | |||
inline void DiskWriterPluginGUI::cb_Stereo_i(Fl_Button* o) | |||
{ | |||
{ | |||
m_GUICH->Set("Stereo",o->value()); | |||
} | |||
@@ -460,7 +460,6 @@ SpiralWindowType *SynthModular::CreateWindow() | |||
m_TopWindow->resizable(m_CanvasScroll); | |||
m_Canvas = new Fl_Canvas(-5000, -5000, 10000, 10000, ""); | |||
m_Canvas->user_data ((void*)(this)); | |||
m_Canvas->type(1); | |||
m_Canvas->box(FL_FLAT_BOX); | |||
m_Canvas->labeltype(FL_ENGRAVED_LABEL); | |||
@@ -596,39 +595,43 @@ void SynthModular::LoadPlugins (string pluginPath) { | |||
//NewButton->color(SpiralInfo::GUICOL_Button); | |||
//NewButton->selection_color(SpiralInfo::GUICOL_Button); | |||
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 | |||
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 | |||
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 | |||
while ((p = GroupName.find ('/')) < PluginName.length()) | |||
while ((p = GroupName.find ('/')) < PluginName->length()) | |||
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); | |||
//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 | |||
// so we can't use it for other purposes | |||
NewButton->callback ((Fl_Callback*)cb_NewDevice, &Numbers[ID]); | |||
NewButton->show(); | |||
// Nothing else ever touches m_DeviceVec - is this right??? (andy) | |||
m_DeviceVec.push_back (NewButton); | |||
the_group->redraw(); | |||
// m_NextPluginButton++; | |||
Fl::check(); | |||
splashtext->label (PluginName.c_str()); | |||
splashtext->label (PluginName->c_str()); | |||
Splash->redraw(); | |||
} | |||
} | |||
@@ -1415,12 +1418,13 @@ void SynthModular::cb_NewDevice (Fl_Button *o, void *v) { | |||
// (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 | |||
{ | |||
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) {} | |||
virtual void draw() { draw_label(); } | |||
}; | |||
@@ -72,7 +72,7 @@ class DeviceGroup | |||
{ | |||
public: | |||
DeviceGroup() { devicecount = 0; } | |||
int devicecount; | |||
fstream devices; | |||
map<int,int> m_DeviceIds;//old ID, new ID | |||
@@ -98,13 +98,13 @@ public: | |||
void FreezeAll() | |||
{ | |||
m_CH.Set("Frozen",true); | |||
m_CH.Set("Frozen",true); | |||
m_CH.Wait(); | |||
} | |||
void ThawAll() | |||
{ | |||
m_CH.Set("Frozen",false); | |||
m_CH.Set("Frozen",false); | |||
} | |||
void PauseAudio() | |||
@@ -121,7 +121,7 @@ public: | |||
{ | |||
if (! m_ResetingAudioThread) | |||
{ | |||
FreezeAll(); | |||
FreezeAll(); | |||
m_ResetingAudioThread = true; | |||
@@ -175,7 +175,6 @@ private: | |||
inline void cb_NewComment_i(Fl_Button* o, void* v); | |||
static void cb_NewComment(Fl_Button* o, void* v); | |||
// File menu - and associated buttons, etc. | |||
inline void cb_New_i (Fl_Widget *o, void *v); | |||
static void cb_New (Fl_Widget *o, void *v); | |||