From 17ec1deb74e2e934dc11fb4d9a2f8c6cef34c5a7 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 9 Jul 2007 20:45:58 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r7949, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/moonlib/; revision=7950 --- gamme.c | 558 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 558 insertions(+) create mode 100644 gamme.c (limited to 'gamme.c') diff --git a/gamme.c b/gamme.c new file mode 100644 index 0000000..d4ddd01 --- /dev/null +++ b/gamme.c @@ -0,0 +1,558 @@ +/* +Copyright (C) 2002 Antoine Rousseau + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#include +#include +#include +#include "g_canvas.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ gamme ----------------------------- */ +#define BACKGROUND "-fill grey" +#define BACKGROUNDCOLOR "grey" + +#ifndef PD_VERSION_MINOR +#define PD_VERSION_MINOR 32 +#endif + +#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER) +#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT) +#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL) + + +#define DEFAULTSIZE 15 +#define DEFAULTWIDTH 90 +#define DEFAULTHEIGHT 40 + +#define DEFAULTCOLOR "black" +#define BLACKCOLOR "black" +#define WHITECOLOR "white" +#define SELBLACKCOLOR "gold" +#define SELWHITECOLOR "yellow" + + +static t_class *gamme_class; + +static char *NoteNames[]= + { "C","C#","D","D#","E","F","F#","G","G#","A","A#","B" }; +static char NoteColPos[]= + { 1,-1,2,-2,3,4,-4,5,-5,6,-6,7 }; +static char Whites[]={0,2,4,5,7,9,11}; +static char Blacks[]={1,3,6,8,10}; +static char BlacksWhites[]={1,3,6,8,10,0,2,4,5,7,9,11}; +static char WhitesBlacks[]={0,2,4,5,7,9,11,1,3,6,8,10}; + +#define ISWHITE(x) (NoteColPos[x]>0) +#define ISBLACK(x) (!ISWHITE(x)) + +#define te_xpos te_xpix +#define te_ypos te_ypix + +typedef struct _gamme +{ + t_object x_obj; + t_outlet *x_out_n; /*gives the number of selected notes when change occurs*/ + t_outlet *x_out_note; /*gives the number and new value of the changed notes when change occurs*/ + t_glist * x_glist; + int x_width; + int x_height; + char x_n; + char x_notes[12]; + char x_on_notes[12]; +} t_gamme; + +/* widget helper functions */ + + +#define INTERSPACE 0.02 +#define NOTEWIDTH ((1-INTERSPACE*6.0)/7.0) +#define BLACK1st ((NOTEWIDTH+INTERSPACE)/2.0) +#define BLACKH 0.6 +static void note_get_rel_rect(int x, float *xp1, float *yp1, float *xp2, float *yp2) +{ + int cp=NoteColPos[x]; + + *xp1=(abs(cp)-1)*(NOTEWIDTH+INTERSPACE) + (cp<0)*BLACK1st; + *xp2=*xp1+NOTEWIDTH; + + *yp1=0; + *yp2=cp<0?BLACKH:1; +} + +static int get_touched_note(float x, float y) +{ + int i,j; + float xp1,xp2,yp1,yp2; + + for(j=0;j<12;j++) { + i=BlacksWhites[j]; + note_get_rel_rect(i,&xp1,&yp1,&xp2,&yp2); + if((x>=xp1)&&(x<=xp2)&&(y>=yp1)&&(y<=yp2)) + return i; + } + /*post("gamme::get_touched_note note not found: x=%f y=%f",x,y);*/ + return -1; +} + +static void draw_inlets(t_gamme *x, t_glist *glist, int firsttime, int nin, int nout) +{ + int n = nout; + int nplus, i; + int xpos=text_xpix(&x->x_obj, glist); + int ypos=text_ypix(&x->x_obj, glist); + + nplus = (n == 1 ? 1 : n-1); + for (i = 0; i < n; i++) + { + int onset = xpos + (x->x_width - IOWIDTH) * i / nplus; + if (firsttime) + sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xo%d\n", + glist_getcanvas(glist), + onset, ypos + x->x_height - 1, + onset + IOWIDTH, ypos + x->x_height, + x, i); + else + sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n", + glist_getcanvas(glist), x, i, + onset, ypos + x->x_height - 1, + onset + IOWIDTH, ypos + x->x_height); + } + n = nin; + nplus = (n == 1 ? 1 : n-1); + for (i = 0; i < n; i++) + { + int onset = xpos + (x->x_width - IOWIDTH) * i / nplus; + if (firsttime) + sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xi%d\n", + glist_getcanvas(glist), + onset, ypos, + onset + IOWIDTH, ypos + 1, + x, i); + else + sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n", + glist_getcanvas(glist), x, i, + onset, ypos, + onset + IOWIDTH, ypos + 1); + + } +} + +void gamme_drawme(t_gamme *x, t_glist *glist, int firsttime) +{ + int i,j; + float x1,y1,x2,y2; + int xi1,yi1,xi2,yi2; + char *color; + int xpos=text_xpix(&x->x_obj, glist); + int ypos=text_ypix(&x->x_obj, glist); + + if (firsttime) { + sys_vgui(".x%x.c create rectangle \ +%d %d %d %d -tags %xS "BACKGROUND"\n", + glist_getcanvas(glist), + xpos, ypos, + xpos + x->x_width, ypos + x->x_height, + x); + + } + else { + sys_vgui(".x%x.c coords %xS \ +%d %d %d %d\n", + glist_getcanvas(glist), x, + xpos, ypos, + xpos + x->x_width, ypos + x->x_height); + } + + for(j=0;j<12;j++){ + i=WhitesBlacks[j]; + note_get_rel_rect(i,&x1,&y1,&x2,&y2); + xi1=xpos + x->x_width*x1; + xi2=xpos + x->x_width*x2; + yi1=ypos + x->x_height*y1; + yi2=ypos + x->x_height*y2; + + if (firsttime) { + color=x->x_notes[i]? (ISWHITE(i)?SELWHITECOLOR:SELBLACKCOLOR): + (ISWHITE(i)?WHITECOLOR:BLACKCOLOR); + sys_vgui(".x%x.c create rectangle \ +%d %d %d %d -tags %x%s -fill %s\n", + glist_getcanvas(glist),xi1,yi1,xi2,yi2, + x,NoteNames[i],color); + } + else { + sys_vgui(".x%x.c coords %x%s \ +%d %d %d %d\n", + glist_getcanvas(glist),x,NoteNames[i],xi1,yi1,xi2,yi2); + } + } + + draw_inlets(x, glist, firsttime, 1,3); + +} + +void gamme_erase(t_gamme* x,t_glist* glist) +{ + int n; + t_canvas *canvas=glist_getcanvas(glist); + + sys_vgui(".x%x.c delete %xS\n",canvas, x); + + for(n=0;n<12;n++) + sys_vgui(".x%x.c delete %x%s\n",canvas,x,NoteNames[n]); + + n = 1; + while (n--) { + sys_vgui(".x%x.c delete %xi%d\n",canvas,x,n); + } + n = 3; + while (n--) { + sys_vgui(".x%x.c delete %xo%d\n",canvas,x,n); + } +} + + + +/* ------------------------ gamme widgetbehaviour----------------------------- */ + + +static void gamme_getrect(t_gobj *z, t_glist *glist, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + t_gamme *x = (t_gamme *)z; + int width, height; + t_gamme* s = (t_gamme*)z; + + + width = s->x_width; + height = s->x_height; + *xp1 = text_xpix(&x->x_obj, glist); + *yp1 = text_ypix(&x->x_obj, glist); + *xp2 = *xp1 + width; + *yp2 = *yp1 + height; +} + +static void gamme_displace(t_gobj *z, t_glist *glist, + int dx, int dy) +{ + t_gamme *x = (t_gamme *)z; + x->x_obj.te_xpos += dx; + x->x_obj.te_ypos += dy; + gamme_drawme(x, glist, 0); + canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x); +} + +static void gamme_select(t_gobj *z, t_glist *glist, int state) +{ + t_gamme *x = (t_gamme *)z; + sys_vgui(".x%x.c itemconfigure %xS -fill %s\n", glist, + x, (state? "blue" : BACKGROUNDCOLOR)); +} + + +static void gamme_activate(t_gobj *z, t_glist *glist, int state) +{ +/* t_text *x = (t_text *)z; + t_rtext *y = glist_findrtext(glist, x); + if (z->g_pd != gatom_class) rtext_activate(y, state);*/ +} + +static void gamme_delete(t_gobj *z, t_glist *glist) +{ + t_text *x = (t_text *)z; + canvas_deletelinesfor(glist, x); +} + + +static void gamme_vis(t_gobj *z, t_glist *glist, int vis) +{ + t_gamme* s = (t_gamme*)z; + if (vis) + gamme_drawme(s, glist, 1); + else + gamme_erase(s,glist); +} + +/* can we use the normal text save function ?? */ + +static void gamme_save(t_gobj *z, t_binbuf *b) +{ + t_gamme *x = (t_gamme *)z; + char *c=x->x_notes; + + binbuf_addv(b, "ssiisiiiiiiiiiiiiii", gensym("#X"),gensym("obj"), + (t_int)x->x_obj.te_xpos, (t_int)x->x_obj.te_ypos, + gensym("gamme"),x->x_width,x->x_height, + c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9],c[10],c[11]); + binbuf_addv(b, ";"); +} + +void gamme_getn(t_gamme *x) +{ + outlet_float(x->x_out_n,x->x_n); +} + +void gamme_out_changed(t_gamme *x,int note) +{ + t_atom ats[2]; + SETFLOAT(&ats[0],note); + SETFLOAT(&ats[1],x->x_notes[note]); + + outlet_list(x->x_out_note,0,2,ats); +} + +inline float my_mod(float x,int n) +{ + float y=fmod(x,n); + return y<0?y+n:y; +} + +#define my_div(x,y) (floor(x/y)) +#define tonotei(x) (my_mod(rint(x),12U)) + +void gamme_set(t_gamme *x,t_floatarg note,t_floatarg on) +{ + unsigned int i,notei=tonotei(note),changed=0; + char *color; + t_canvas *canvas=glist_getcanvas(x->x_glist); + + + if(x->x_notes[notei]!=on) changed=1; + if(on<0) x->x_notes[notei]=!(x->x_notes[notei]); + else x->x_notes[notei]=on; + if(changed) gamme_out_changed(x,notei); + + color=x->x_notes[notei]?(ISWHITE(notei)?SELWHITECOLOR:SELBLACKCOLOR): + (ISWHITE(notei)?WHITECOLOR:BLACKCOLOR); + + if(glist_isvisible(x->x_glist)) + sys_vgui(".x%x.c itemconfigure %x%s -fill %s\n", canvas, + x, NoteNames[notei],color); + + x->x_n=0; + for(i=0;i<12;i++) if(x->x_notes[i]) x->x_on_notes[(int)(x->x_n++)]=i; + gamme_getn(x); +} + +#define getnote(n) \ + (my_div(n,(int)x->x_n)*12+x->x_on_notes[(int)my_mod(n,x->x_n)]) +void gamme_get(t_gamme *x,t_floatarg ref_octave,t_floatarg note) +{ + int no0,no1,ni0,ni1,n0,n1,n; + float xn,xx,nn; + + if(!x->x_n) return; + no0=floor(note); + no1=ceil(note); + xx=note-no0; + + nn=getnote((float)no0)*(1-xx)+getnote((float)(no0+1))*xx+ref_octave*12; + n=getnote((float)no0)+ref_octave*12; + outlet_float(x->x_obj.ob_outlet,nn); +} + +static void gamme_click(t_gamme *x, t_floatarg xpos, t_floatarg ypos, + t_floatarg shift, t_floatarg ctrl, t_floatarg alt) +{ + int note; + int x0=text_xpix(&x->x_obj, x->x_glist); + int y0=text_ypix(&x->x_obj, x->x_glist); + + note=get_touched_note( + (xpos-x0)/x->x_width, + (ypos-y0)/x->x_height); + + if(note>=0) gamme_set(x,note,!x->x_notes[note]); +} + +static int gamme_newclick(t_gobj *z, struct _glist *glist, + int xpix, int ypix, int shift, int alt, int dbl, int doit) +{ + t_gamme* x = (t_gamme *)z; + + if(doit) + { + gamme_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, + 0, (t_floatarg)alt); + } + return (1); +} + +void gamme_float(t_gamme *x,t_floatarg f) +{ + unsigned int notei=tonotei(f); + + /*post("notei=%d",notei);*/ + if(x->x_notes[notei]) + outlet_float(x->x_obj.ob_outlet,f); +} + +void gamme_round(t_gamme *x,t_floatarg f,t_floatarg round) +{ + unsigned int notei=tonotei(f); + int imin=floor(f),imax=ceil(f); + float norm; + + if(!x->x_n) return; + + while(!x->x_notes[(int)my_mod((imin),12U)]) imin--; + while(!x->x_notes[(int)my_mod((imax),12U)]) imax++; + + /*post("min: %d max: %d",imin,imax);*/ + + if((imin!=imax)&&round) { + round*=round; + norm=(f-imin)/(imax-imin)*2-1; + norm=norm/sqrt(1+round*norm*norm)*sqrt(1+round)/2+.5; + f=norm*(imax-imin)+imin; + } + outlet_float(x->x_obj.ob_outlet,f); +} + +void gamme_setall(t_gamme *x,t_symbol *s, int argc, t_atom *argv) +{ + int i=0,err=0; + + if(argc==12) + { + for(i=0;i<12;i++) err+=!IS_A_FLOAT(argv,i); + if(!err) for(i=0;i<12;i++) gamme_set(x,i,atom_getfloat(&argv[i])); + } +} + +void gamme_getall(t_gamme *x) +{ + int i=0; + + for(i=0;i<12;i++) gamme_out_changed(x,i); + gamme_getn(x); +} + +extern int sys_noloadbang; +static void gamme_loadbang(t_gamme *x) +{ + int i; + + if(sys_noloadbang) return; + for(i=0;i<12;i++) gamme_out_changed(x,i); + gamme_getn(x); +} + +void gamme_size(t_gamme* x,t_floatarg w,t_floatarg h) { + x->x_width = w; + x->x_height = h; + gamme_drawme(x, x->x_glist, 0); +} + +t_widgetbehavior gamme_widgetbehavior; + +static void gamme_setwidget(void) +{ + gamme_widgetbehavior.w_getrectfn = gamme_getrect; + gamme_widgetbehavior.w_displacefn = gamme_displace; + gamme_widgetbehavior.w_selectfn = gamme_select; + gamme_widgetbehavior.w_activatefn = gamme_activate; + gamme_widgetbehavior.w_deletefn = gamme_delete; + gamme_widgetbehavior.w_visfn = gamme_vis; + gamme_widgetbehavior.w_clickfn = gamme_newclick; + //gamme_widgetbehavior.w_propertiesfn = NULL; + //gamme_widgetbehavior.w_savefn = gamme_save; +} + + +static void *gamme_new(t_symbol *s, int argc, t_atom *argv) +{ + int i=0,err=0; + + t_gamme *x = (t_gamme *)pd_new(gamme_class); + + x->x_glist = (t_glist*) canvas_getcurrent(); + x->x_width = DEFAULTWIDTH; + x->x_height = DEFAULTHEIGHT; + outlet_new(&x->x_obj, &s_float); + x->x_out_n=outlet_new(&x->x_obj, &s_float); + x->x_out_note=outlet_new(&x->x_obj, &s_float); + + x->x_n=0; + for(i=0;i<12;i++) x->x_notes[i]=0; + for(i=0;i<12;i++) x->x_on_notes[i]=0; + + if((argc>1)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)) + { + if(atom_getfloat(&argv[0])) x->x_width = atom_getfloat(&argv[0]); + if(atom_getfloat(&argv[1])) x->x_height = atom_getfloat(&argv[1]); + + if(argc==14) + { + for(i=0;i<12;i++) err+=(!IS_A_FLOAT(argv,i+2)); + if(!err) { + for(i=0;i<12;i++) if(x->x_notes[i]=atom_getfloat(&argv[i+2])) + x->x_on_notes[(int)(x->x_n++)]=i; + /*gamme_set(x,i,atom_getfloat(&argv[i+2]));gamme_getn(x);*/ + } + else post("gamme_new : error in creation arguments"); + } + /*if(argc==14) gamme_setall(x,s,argc-2,&argv[2]);*/ + } + + return (x); +} + +void gamme_setup(void) +{ + post("gamme_setup"); + gamme_class = class_new(gensym("gamme"), (t_newmethod)gamme_new, 0, + sizeof(t_gamme),0, A_GIMME,0); + + class_addfloat(gamme_class,gamme_float); + + class_addmethod(gamme_class, (t_method)gamme_click, gensym("click"), + A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + + class_addmethod(gamme_class, (t_method)gamme_size, gensym("size"), + A_FLOAT, A_FLOAT, 0); + + class_addmethod(gamme_class, (t_method)gamme_set, gensym("set"), + A_FLOAT, A_FLOAT, 0); + + class_addmethod(gamme_class, (t_method)gamme_get, gensym("get"), + A_FLOAT, A_FLOAT, 0); + + class_addmethod(gamme_class, (t_method)gamme_round, gensym("round"), + A_FLOAT, A_FLOAT, 0); + + class_addmethod(gamme_class, (t_method)gamme_setall, gensym("setall"), + A_GIMME, 0); + + class_addmethod(gamme_class, (t_method)gamme_getall, gensym("getall"), 0); + + class_addmethod(gamme_class, (t_method)gamme_getn, gensym("getn"), 0); + + /*class_addmethod(gamme_class, (t_method)gamme_loadbang, gensym("loadbang"), 0);*/ + + + gamme_setwidget(); + class_setwidget(gamme_class,&gamme_widgetbehavior); + class_setsavefn(gamme_class, gamme_save); + +} + + -- cgit v1.2.1