/* ZynAddSubFX - a software synthesizer EnvelopeFreeEdit.cpp - Envelope Edit View Copyright (C) 2016 Mark McCurry This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include "EnvelopeFreeEdit.h" #include "../Misc/Util.h" #include #include #include #include #include using namespace zyncarla; EnvelopeFreeEdit::EnvelopeFreeEdit(int x,int y, int w, int h, const char *label) :Fl_Box(x,y,w,h,label), Fl_Osc_Widget(this) { pair=NULL; currentpoint=-1; cpx=0; lastpoint=-1; } void EnvelopeFreeEdit::init(void) { oscRegister("Penvpoints"); oscRegister("Penvdt"); oscRegister("Penvval"); oscRegister("Penvsustain"); //register for non-bulk types for(int i=0; icreateLink(loc+string("Penvdt") + to_s(i), this); osc->createLink(loc+string("Penvval") + to_s(i), this); } } void EnvelopeFreeEdit::OSC_raw(const char *msg) { const char *args = rtosc_argument_string(msg); if(strstr(msg,"Penvpoints") && !strcmp(args, "i")) { Penvpoints = rtosc_argument(msg, 0).i; } else if(strstr(msg,"Penvdt") && !strcmp(args, "b")) { rtosc_blob_t b = rtosc_argument(msg, 0).b; assert(b.len == MAX_ENVELOPE_POINTS); memcpy(Penvdt, b.data, MAX_ENVELOPE_POINTS); } else if(strstr(msg,"Penvval") && !strcmp(args, "b")) { rtosc_blob_t b = rtosc_argument(msg, 0).b; assert(b.len == MAX_ENVELOPE_POINTS); memcpy(Penvval, b.data, MAX_ENVELOPE_POINTS); } else if(strstr(msg, "Penvval") && !strcmp(args, "c")) { const char *str = strstr(msg, "Penvval"); int id = atoi(str+7); assert(0 <= id && id < MAX_ENVELOPE_POINTS); Penvval[id] = rtosc_argument(msg, 0).i; } else if(strstr(msg, "Penvdt") && !strcmp(args, "c")) { const char *str = strstr(msg, "Penvdt"); int id = atoi(str+6); assert(0 <= id && id < MAX_ENVELOPE_POINTS); Penvdt[id] = rtosc_argument(msg, 0).i; } else if(strstr(msg,"Penvsustain") && !strcmp(args, "i")) { Penvsustain = rtosc_argument(msg, 0).i; } redraw(); do_callback(); } void EnvelopeFreeEdit::setpair(Fl_Box *pair_) { pair=pair_; } int EnvelopeFreeEdit::getpointx(int n) const { const int lx=w()-10; int npoints=Penvpoints; float sum=0; for(int i=1; iPfreemode==0) // env->converttofree(); const int npoints=Penvpoints; if (active_r()) fl_color(FL_BLACK); else fl_color(90,90,90); if (!active_r()) currentpoint=-1; fl_rectf(ox,oy,lx,ly); //Margins ox+=5;oy+=5;lx-=10;ly-=10; //draw the lines fl_color(FL_GRAY); const int midline = oy+ly*(1-64.0/127); fl_line_style(FL_SOLID); fl_line(ox+2,midline,ox+lx-2,midline); //draws the evelope points and lines Fl_Color alb=FL_WHITE; if (!active_r()) alb=fl_rgb_color(180,180,180); fl_color(alb); int oldxx=0,xx=0,oldyy=0,yy=getpointy(0); fl_rectf(ox-3,oy+yy-3,6,6); for (int i=1; i=0){ fl_color(FL_CYAN); fl_rectf(ox+getpointx(lastpoint)-5,oy+getpointy(lastpoint)-5,10,10); } //draw the sustain position if(Penvsustain>0){ fl_color(FL_YELLOW); xx=getpointx(Penvsustain); fl_line(ox+xx,oy+0,ox+xx,oy+ly); } //Show the envelope duration and the current line duration fl_font(FL_HELVETICA|FL_BOLD,10); float time=0.0; if (currentpoint<=0 && (!ctrldown||lastpoint <= 0)){ fl_color(alb); for(int i=1; i=0){ snprintf((char *)&tmpstr,20,"%d", Penvval[lastpoint]); fl_draw(tmpstr,ox+lx-20,oy+ly-23,20,10,FL_ALIGN_RIGHT,NULL,0); } } } int EnvelopeFreeEdit::handle(int event) { const int x_=Fl::event_x()-x(); const int y_=Fl::event_y()-y(); static Fl_Widget *old_focus; int key, old_mod_state; switch(event) { case FL_ENTER: old_focus=Fl::focus(); Fl::focus(this); // Otherwise the underlying window seems to regrab focus, // and I can't see the KEYDOWN action. return 1; case FL_LEAVE: Fl::focus(old_focus); break; case FL_KEYDOWN: case FL_KEYUP: key = Fl::event_key(); if (key==FL_Alt_L || key==FL_Alt_R) { altdown = (event==FL_KEYDOWN); redraw(); if (pair!=NULL) pair->redraw(); } if (key==FL_Control_L || key==FL_Control_R){ ctrldown = (event==FL_KEYDOWN); redraw(); if (pair!=NULL) pair->redraw(); } break; case FL_PUSH: currentpoint=getnearest(x_,y_); cpx=x_; cpy=y_; cpdt=Penvdt[currentpoint]; cpval=Penvval[currentpoint]; lastpoint=currentpoint; redraw(); if (pair) pair->redraw(); return 1; case FL_RELEASE: currentpoint=-1; redraw(); if (pair) pair->redraw(); return 1; case FL_MOUSEWHEEL: if (Fl::event_buttons()) return 1; if (lastpoint>=0) { int delta = Fl::event_dy() * (Fl::event_shift() ? 4 : 1); if (!ctrldown) { int ny = Penvval[lastpoint] - delta; ny = ny < 0 ? 0 : ny > 127 ? 127 : ny; Penvval[lastpoint] = ny; oscWrite(to_s("Penvval")+to_s(lastpoint), "c", ny); oscWrite("Penvval",""); } else if (lastpoint > 0) { int newdt = Penvdt[lastpoint] - delta; newdt = newdt < 0 ? 0 : newdt > 127 ? 127 : newdt; Penvdt[lastpoint] = newdt; oscWrite(to_s("Penvdt")+to_s(lastpoint), "c", newdt); oscWrite("Penvdt",""); } redraw(); if (pair!=NULL) pair->redraw(); return 1; } case FL_DRAG: if (currentpoint>=0){ old_mod_state = mod_state; mod_state = ctrldown << 1 | altdown; if (old_mod_state != mod_state) { cpx=x_; cpy=y_; cpdt=Penvdt[currentpoint]; cpval=Penvval[currentpoint]; old_mod_state = mod_state; } if (!altdown || !ctrldown) { const int dy=(int)((cpy-y_)/3.0); const int newval=limit(cpval+dy, 0, 127); Penvval[currentpoint]=newval; oscWrite(to_s("Penvval")+to_s(currentpoint), "c", newval); oscWrite("Penvval",""); } if (!altdown || ctrldown) { const int dx=(int)((x_-cpx)*0.1); const int newdt=limit(cpdt+dx,0,127); if(currentpoint!=0) Penvdt[currentpoint]=newdt; else Penvdt[currentpoint]=0; oscWrite(to_s("Penvdt")+to_s(currentpoint), "c", newdt); oscWrite("Penvdt",""); } redraw(); if(pair) pair->redraw(); return 1; } } // Needed to propagate undo/redo keys. return 0; } void EnvelopeFreeEdit::update(void) { oscWrite("Penvpoints"); oscWrite("Penvdt"); oscWrite("Penvval"); oscWrite("Penvsustain"); } void EnvelopeFreeEdit::rebase(std::string new_base) { osc->renameLink(loc+"Penvpoints", new_base+"Penvpoints", this); osc->renameLink(loc+"Penvdt", new_base+"Penvdt", this); osc->renameLink(loc+"Penvval", new_base+"Penvval", this); osc->renameLink(loc+"Penvsustain", new_base+"Penvsustain", this); for(int i=0; irenameLink(loc+dt, new_base+dt, this); osc->renameLink(loc+val, new_base+val, this); } loc = new_base; update(); }