/*
 * This software is released under GPL. If you don't know what that is
 * immediately point your webbrowser to  http://www.gnu.org and read
 * all about it.
 *
 * The short version: You can modify the sources for your own purposes
 * but you must include the new sources if you distribute a derived work.
 *
 * (C) 2002, 2003, 2004, 2005 Jens M Andreasen <ja@linux.nu>
 *
 *
 *
 *
 *    (
 *     )
 *   c[]
 *
 *
 */ 

//static char * widget_theme = 0; // NADA!
static char * widget_theme = "/usr/share/themes/Crux/gtk-2.0/gtkrc";
//static char * widget_theme = "/home/jens/.themes/g5-ish/gtk-2.0/gtkrc";

#include <unistd.h>
#include <string.h>
#include <stdio.h>

#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>

//#include "interface.h"
#include "mx44.h"
#include <math.h>
// hint_t groups
#define MISC 0
#define ENV1 1 /* time  */
#define ENV2 2 /* level */
#define ENV3 3 /* other */
#define MOD1 4 /* phase */
#define MOD2 5 /* amplitude */
#define FREQ 6
#define BIAS 7

#define DELAY 8
#define DIST 9
#define LFO 10

extern Mx44state * mx44;
extern int mx44running;
extern Mx44patch * mx44patch; // Stored patches
extern unsigned char* mx44patchNo;// index of patch in use
extern Mx44patch* mx44tmpPatch; // copy of patch in use.


static int midichannel = 0;
static int group,bank,patch;
typedef struct _hint
{
  int op;
  int group;
  int index;
  float min;
  float max;
  char * spinlabel;
  
}hint_t;
static   GtkWidget *window1;

static struct mx44patch_edit
{
  GtkWidget *pm[4][4]; // [destination] [source]
  GtkWidget *am[4][4];
  GtkWidget *mix[4][2]; // [op] [level/balance]
  
  
  GtkWidget *env_level[4][8]; // [op] [stage]
  GtkWidget *env_time[4][8];
  
  GtkWidget *wheelbutton[4][2];
  
  GtkWidget *od[4][8];
  GtkWidget *od_group[4];
  GtkWidget *wawebutton[4];
  GtkWidget *lowpassbutton[4];
  GtkWidget *waweshapebutton[4];
  GtkWidget *phasefollowkeybutton[4];
  GtkWidget *magicbutton[4];

  GtkWidget *harmonic[4];
  GtkWidget *detune[4];
  GtkWidget *intonation[4][2];

  
  GtkWidget *velocityfollow[4];
  // key bias
  GtkWidget *breakpoint[4];    // [op]
  GtkWidget *keybias[4][2];    // [op][hi/lo value]
  // env keyfollow
  GtkWidget *keyfollow[4][2]; // [op][attack/sustain-loop]
  // key velocity
  GtkWidget *velocity[4]; // [op]
  
  GtkWidget *phase[4][2]; // [op][offset/velocityfollow]
  
  //GtkWidget  *mod_delay; // delay for am/pm
  //GtkWidget  *mod_keyfollow; // keyfollow
  //GtkWidget  *delay_table;
  //GtkWidget  *
  //GtkWidget  *
  //GtkWidget  *
  //  GtkWidget *spinbutton[4];
  // GtkWidget *spinlabel[4];
  
  
  GtkWidget *common_spinbutton;
  GtkWidget *common_spinlabel;
  GtkWidget *common_oplabel;
  
  GtkWidget *monobutton;
  GtkWidget *lfo[6];
  GtkWidget *lfo_button[2];

  
  GtkWidget *window;
  GtkWidget *table[4];
  GtkWidget *canvas;
  int op;
  
}ed;
static int wn;

static char *op_label[]={"Op 1","Op 2","Op 3","Op 4",NULL};

static int patch_change =1;
static
void set_value(GtkRange* range,double value)
{
  if(range)
    {
      GtkAdjustment *adj = gtk_range_get_adjustment(range);
      gtk_adjustment_set_value(adj,value);
    }
  
}
static GtkWidget *patchname;
static GtkWidget *patch_group_1;
static GtkWidget *patch_group_2;
static GtkComboBox *bank_entry;
static GtkComboBox *patch_entry;
static GtkObject *midichannel_spinner_adj;


volatile struct 
{
  Mx44patch *tmp;
  int channel ;
  int number;
} newpatch;


static 
void set_widgets(Mx44patch *tmp_patch,int channel ,int patchNumber)
{
  int i, op;

  patch_change = 1;
  
  if(midichannel == -1)
    {
      midichannel = channel;
      gtk_adjustment_set_value((GtkAdjustment*)midichannel_spinner_adj,midichannel+1);
    }
  //if(midichannel != channel)    return;
  
  tmp_patch = tmp_patch + channel;
  
  
   if( patchNumber != -1)
     {
      group = patchNumber >= 64;
      bank  = (patchNumber & 0x03F)>>3;
      patch = patchNumber & 0x07;
      
      gtk_combo_box_set_active((GtkComboBox*)bank_entry,bank);
      
      gtk_combo_box_set_active((GtkComboBox*)patch_entry,patch);
      
      if(group)
	g_signal_emit_by_name(patch_group_2,"clicked");
      //gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (patch_group_2), TRUE);
      else
	g_signal_emit_by_name(patch_group_1,"clicked");
      //gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (patch_group_1), TRUE);
      
      
      
    }

   //set_value((GtkRange*)ed.mod_delay , tmp_patch->mod_delay/320.0); 
   gtk_entry_set_text (GTK_ENTRY (patchname), tmp_patch->name);
   //printf("name: %s\n", tmp_patch->name);
   for(op = 0; op < 4; ++op)
    {
      
      for(i=0; i < 4; ++i) 
	{
	  set_value((GtkRange*)ed.pm[op][i] , tmp_patch->pm[op][i]/320.0);
	  set_value((GtkRange*)ed.am[op][i] , tmp_patch->am[op][i]/320.0);
	}
      set_value((GtkRange*)ed.mix[op][0] , tmp_patch->mix[op][0]/320.0); 
      set_value((GtkRange*)ed.mix[op][1] , tmp_patch->mix[op][1]/177.0); 
      
      for(i=0; i < 8; ++i) 
	{
	  set_value((GtkRange*)ed.env_level[op][i] , tmp_patch->env_level[op][i]/80.0);
	  set_value((GtkRange*)ed.env_time[op][i] , tmp_patch->env_time[op][i]/320.0);
	}
      
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.od[op][tmp_patch->od[op]&0x07]), TRUE);
      set_value((GtkRange*)ed.harmonic[op] , tmp_patch->harmonic[op]/128.0);

      //if(tmp_patch->detune[op] <0)
      set_value((GtkRange*)ed.detune[op] , tmp_patch->detune[op]/100.0);
      //else
      //set_value((GtkRange*)ed.detune[op] , pow(tmp_patch->detune[op],1.0/3.0)/3.2);
      set_value((GtkRange*)ed.intonation[op][0] , tmp_patch->intonation[op][0]/327.6);
      set_value((GtkRange*)ed.intonation[op][1] , tmp_patch->intonation[op][1]/327.6);
      
      set_value((GtkRange*)ed.velocityfollow[op] , tmp_patch->velocityfollow[op]/320.0);
      set_value((GtkRange*)ed.breakpoint[op] , tmp_patch->breakpoint[op]);
      set_value((GtkRange*)ed.keybias[op][1] , -sqrt(tmp_patch->keybias[op][0]));
      set_value((GtkRange*)ed.keybias[op][0] , -sqrt(tmp_patch->keybias[op][1]));
      set_value((GtkRange*)ed.keyfollow[op][0] , tmp_patch->keyfollow[op][0]/320.0);
      set_value((GtkRange*)ed.keyfollow[op][1] , tmp_patch->keyfollow[op][1]/320.0);
      set_value((GtkRange*)ed.velocity[op] , tmp_patch->velocity[op]/320.0);
      set_value((GtkRange*)ed.phase[op][0] , tmp_patch->phase[op][0]/320.0);
      set_value((GtkRange*)ed.phase[op][1] , tmp_patch->phase[op][1]/320.0);
      
      if(tmp_patch->button[op]&WAWEBUTTON)
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.wawebutton[op]), TRUE);
      else
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.wawebutton[op]), FALSE);
      
      if(tmp_patch->button[op]&WHEELBUTTON)
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.wheelbutton[op][0]), TRUE);
      else
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.wheelbutton[op][0]), FALSE);

      if(tmp_patch->button[op]&LOWPASSBUTTON)
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.lowpassbutton[op]), TRUE);
      else
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.lowpassbutton[op]), FALSE);
      
      if(tmp_patch->button[op]&WAWESHAPEBUTTON)
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.waweshapebutton[op]), TRUE);
      else
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.waweshapebutton[op]), FALSE);

      if(tmp_patch->button[op]&PHASEFOLLOWKEYBUTTON)
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.phasefollowkeybutton[op]), TRUE);
      else
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.phasefollowkeybutton[op]), FALSE);
      
      if(tmp_patch->button[op]&MAGICBUTTON)
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.magicbutton[op]), TRUE);
      else
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.magicbutton[op]), FALSE);

    }
   for(i = 0;i<6;++i)
     set_value((GtkRange*)ed.lfo[i] , tmp_patch->lfo[i]/320.0);

   for(i = 0;i<2;++i)
    if(tmp_patch->lfo_button[i])
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.lfo_button[i]), TRUE);
    else
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.lfo_button[i]), FALSE);
   
   if(mx44->monomode[channel])
     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.monobutton), TRUE);
   else
     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ed.monobutton), FALSE);
   
   patch_change = 0;
}

void setwidgets(Mx44patch *tmp_patch,int channel ,int patchNumber)
{
  //  printf("channel: %d midichannel: %d\n",channel,midichannel);
  if(channel == midichannel)
    {
      newpatch.tmp = tmp_patch;
      newpatch.channel = channel;
    }
}

static
int check_patch(void* data)
{

  if(mx44->patchNo[midichannel] != newpatch.number)
    {
      //puts("check_patch");
      newpatch.number = mx44->patchNo[midichannel];
      set_widgets(newpatch.tmp, newpatch.channel, newpatch.number);
      
    }
  return 1;
}
// unique widget names
static char * name_n()
{
  static int n =0;
  char tmp[64]; 
  sprintf(tmp,"%s%d","widget_",n++);  
  return strdup(tmp);
}
static
void line(GtkWidget *table,int x,int y,int width,int height)
{
  char*name;
  GtkWidget *line = gtk_hseparator_new ();
  name = name_n();
  gtk_widget_set_name (line, name);
  gtk_widget_ref (line);
  gtk_object_set_data_full (GTK_OBJECT (ed.window), name, line,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (line);
  gtk_table_attach (GTK_TABLE (table), line, x, x+width, y, y+height,
                    (GtkAttachOptions) (GTK_FILL),
                    (GtkAttachOptions) (GTK_FILL), 0, 0);

}
static
GtkWidget *label(GtkWidget *table,int x,int y,int width,char*text)
{
  GtkWidget *label = gtk_label_new (text);
  
  text = name_n();
  gtk_widget_set_name (label, text);
  gtk_widget_ref (label);
  gtk_object_set_data_full (GTK_OBJECT (table), text, label,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (label);
  gtk_table_attach (GTK_TABLE (table), label, x,x+width, y, y+1,
                    (GtkAttachOptions) (GTK_FILL),
                    (GtkAttachOptions) (0), 0, 0);
  gtk_widget_set_sensitive (label, FALSE);
  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

  return label;
}
static  GtkAdjustment *spin_adj;
static
int  on_focus( GtkRange *range, GdkEvent *event, hint_t* hint)
{
  GtkAdjustment *adj  = gtk_range_get_adjustment(range);
  if(patch_change)
    return 0;
  if(spin_adj != adj)
    {
      spin_adj = adj;
      /*
	gtk_label_set_text((GtkLabel*)ed.spinlabel[hint->op],hint->spinlabel);
	gtk_spin_button_set_adjustment( (GtkSpinButton*)ed.spinbutton[hint->op], adj);
	gtk_spin_button_set_value ((GtkSpinButton*)ed.spinbutton[hint->op],adj->value);    
	
      */
      gtk_label_set_text((GtkLabel*)ed.common_spinlabel,hint->spinlabel);
      if(hint->op <0)
	gtk_label_set_text((GtkLabel*)ed.common_oplabel,"Mx44");
      else
	gtk_label_set_text((GtkLabel*)ed.common_oplabel,op_label[hint->op]);
      gtk_spin_button_set_adjustment( (GtkSpinButton*)ed.common_spinbutton, adj);
      gtk_spin_button_set_value ((GtkSpinButton*)ed.common_spinbutton,adj->value);    
    }
  return 0;
}
static
int  on_range( GtkRange *range, GdkEvent *event, hint_t* hint)
{ 
  if(patch_change)
    return 1;
  on_focus(range,event,hint);
  gtk_widget_grab_focus((GtkWidget*)ed.common_spinbutton); 
  
  return 0;
}
static
void on_value_changed( GtkAdjustment *adj, hint_t* hint)
{
  double value = adj->value;
  if(patch_change)
    return;
  if(spin_adj != adj)
    {
      spin_adj = adj;
      /*
	gtk_label_set_text((GtkLabel*)ed.spinlabel[hint->op],hint->spinlabel);
	gtk_spin_button_set_adjustment( (GtkSpinButton*)ed.spinbutton[hint->op],
	adj);
      */
      //gtk_label_set_text((GtkLabel*)ed.common_spinlabel,hint->spinlabel);
      //gtk_spin_button_set_adjustment( (GtkSpinButton*)ed.common_spinbutton,adj);
    }
  
  switch(hint->group)
    {
    case MISC:
      if(hint->index == 0) // phase init
	{
	  mx44tmpPatch[ midichannel ].phase[hint->op][0]
	    = value * 320 ;
	}
      else if(hint->index == 1) // phase velocity
	{
	  mx44tmpPatch[ midichannel ].phase[hint->op][1]
	    = value * 320 ;
	}
      else if(hint->index == 2) // velocity sensitivity
	{
	  mx44tmpPatch[ midichannel ].velocity[hint->op]
	    = value * 320 ;
	}
      else if(hint->index == 3) // output volume
	{
	  mx44tmpPatch[ midichannel ].mix[hint->op][0]
	    = value * 320 ;
	}
      else if(hint->index == 4)  // output balance
	{
	  mx44tmpPatch[ midichannel ].mix[hint->op][1]
	    = value * 177 ;
	}
      break;
    case ENV1: // envelope time
      {
	mx44tmpPatch[ midichannel ].env_time[hint->op][hint->index]
	  = value * 320 ;
	break;
      }
    case ENV2: // envelope level
      {
	mx44tmpPatch[ midichannel ].env_level[hint->op][hint->index]
	  = value * 80;
	break;
      }
    case ENV3:
      if(hint->index == 0) // attacktime velocityfollow
	{
	  mx44tmpPatch[ midichannel ].velocityfollow[hint->op]
	    = value * 320 ;
	}
      else if(hint->index == 1) // attack/release keyfollow
	{
	  mx44tmpPatch[ midichannel ].keyfollow[hint->op][0]
	    = value * 320 ;
	}
      else if(hint->index == 2) // sustainloop keyfollow
	{
	  mx44tmpPatch[ midichannel ].keyfollow[hint->op][1]
	    = value * 320 ;
	}

      break;
    case FREQ:
      if(hint->index == 0) // frequency course
	{
	  mx44tmpPatch[ midichannel ].harmonic[hint->op]
	    = value * 128 ; 
	}
      else if(hint->index == 2) // frequency offset
	{
	  mx44tmpPatch[ midichannel ].detune[hint->op]
	    = value * 100;
	}
      else if(hint->index == 3) // intonation amount
	{
	  mx44tmpPatch[ midichannel ].intonation[hint->op][0]
	    = value * 327.6 ; 
	}
      else if(hint->index == 4) // intonation decay
	{
	  mx44tmpPatch[ midichannel ].intonation[hint->op][1]
	    = value * 327.6 ; 
	}
      break;
    case BIAS:
      if(hint->index == 0) // breakpoint
	{
	  mx44tmpPatch[ midichannel ].breakpoint[hint->op]
	    = value;
	}
      else if(hint->index == 1) // bias low
	{
	  mx44tmpPatch[ midichannel ].keybias[hint->op][1]
	    = value * value;
	}
      else if(hint->index == 2) // bias low
	{
	  mx44tmpPatch[ midichannel ].keybias[hint->op][0]
	    = value * value;
	}
      break;
    case MOD1:
      mx44tmpPatch[ midichannel ].pm[hint->op][hint->index] 
	= value * 320;
      break;
    case MOD2:
      mx44tmpPatch[ midichannel ].am[hint->op][hint->index] 
	= value * 320;
      break;
    case DELAY:
      puts("no delay yet");
      break;
    case DIST:
      puts("no overdrive yet");

      break;
    case LFO:

      mx44tmpPatch[ midichannel ].lfo[hint->index] 
	= value * 320;
      //puts("no LFO yet");
      //printf("index: %f\n",value * 320);//hint->index);

      break;
    }

}
/*
static
void on_delay( GtkAdjustment *adj, hint_t* hint)
{
  double value = adj->value;
  printf("delay: %f\n",value);
  switch(((int)hint))
    {
    case 0:
      mx44tmpPatch[ midichannel ].mod_delay = value * 320;
      break;
      
    case 1:
      mx44tmpPatch[ midichannel ].mod_keyfollow = value * 320;
      break;
    }
}
*/
static
GtkWidget *scale(GtkWidget *table,int x,int y,int width,int height,
		  float min, float max,int op,int group,int groupindex,char*help)
{
  GtkAdjustment *adj;
  GtkWidget *widget;
  hint_t *hint = malloc(sizeof(hint_t));


  char*name = name_n();
  
  hint->spinlabel=help;
  hint->op = op;
  hint->group = group;
  hint->index = groupindex;
  hint->min = min;
  hint->max = max;
  
  adj = (GtkAdjustment*)gtk_adjustment_new (0, min, max, 0.01, 
						   1.0, 0.0);

  g_signal_connect (adj, "value_changed",
		    GTK_SIGNAL_FUNC(on_value_changed), hint);
  

  if(width > height)
    {
      //widget = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj));
      widget = gtk_hscale_new (GTK_ADJUSTMENT (adj));
    }
  else
    {
      //widget = gtk_vscrollbar_new (GTK_ADJUSTMENT (adj));
      widget = gtk_vscale_new (GTK_ADJUSTMENT (adj));
      gtk_range_set_inverted ((GtkRange*)widget, 1);
    }
  //*
  g_signal_connect (widget, "enter_notify_event",
		    GTK_SIGNAL_FUNC (on_range), hint);
  g_signal_connect (widget, "focus_in_event",
  	    GTK_SIGNAL_FUNC (on_focus), hint);
  g_signal_connect (widget, "button_release_event",
		    GTK_SIGNAL_FUNC (on_range), hint);
  //*/
  gtk_widget_set_name (widget,name);
  gtk_widget_ref (widget);
  gtk_object_set_data_full (GTK_OBJECT (ed.window),name, widget,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (widget);
  gtk_table_attach (GTK_TABLE (table), widget, x, x+width, y, y+height,
                    (GtkAttachOptions) (GTK_EXPAND|GTK_FILL),
                    (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0);
  gtk_scale_set_draw_value (GTK_SCALE (widget), FALSE);
  return widget;
}

static
void mk_envelope(GtkWidget *table,int x,int y,int op,char*name)
{
  int h = 8;
  int w = 0;
  int i;
  int index = 0;
  int size = 6;
  char*time_help[]={"  attack time 1","  attack time 2","  attack time 3","  attack time 4",
		    "  sustainloop time 1","  sustainloop time 2",
		    "  release time 1","  release time 2"};
  char*level_help[]={"  startlevel","  attack level 1","  attack level 2","  attack level 3",
		     "  sustainloop level 1","  sustainloop level 2",
		     "  release level 1","  release level 2"};

  for(i = 0;i<4;++i,--h,++w)
    {
      //printf("index: %d\n",index);
      ed.env_time[op][index] = scale(table,x+i+1,y+h,size-1,1,
				     0,100,op,ENV1,index,time_help[index]);
      if(i)
	ed.env_level[op][index] = scale(table,x+i+size-1,y+h+1,1,size -2,
					0,100,op,ENV2,index,level_help[index]);
      else
	ed.env_level[op][index] = scale(table,x,y+h,1,size -2,
					0,100,op,ENV2,index,level_help[index]);
    
      index++;
    }

  label(table,h-1,i,size+3,name);

  while(h-->0)
    {
      ++i;
      //printf("index: %d\n",index);
      ed.env_time[op][index] = scale(table,x+i+1,y+h,size-1,1,
				       0,100,op,ENV1,index,time_help[index ]);

      if(h>1)
	ed.env_level[op][index] = scale(table,x+i+size-1,y+h+1,1,size -2,
					  0,100,op,ENV2,index,level_help[index ]);
      else if(h == 1)
	ed.env_level[op][index+1] = scale(table,x+i+size,y+h,1,size -2,
					  0,100,op,ENV2,index+1,level_help[index ]);
      index++;
    }

  //label(ed.table[wn],6+x,14+y,5,"  Velocity");
  ed.velocityfollow[op] = scale(table,
				  6+x,12+y,3,1,
				  0,100,op,ENV3,0,"  attacktime velocityfollow");
  label(ed.table[op],9+x,10+y,4,"Keyfollow");
  ed.keyfollow[op][0] = scale(table,
				9+x,9+y,3,1,
				0,100,op,ENV3,1,"  attack/release keyfollow");
  ed.keyfollow[op][1] = scale(table,
				10+x,8+y,3,1,
				0,100,op,ENV3,2,"  sustainloop keyfollow");
}
/*
static
GtkWidget *mk_delay_table(void)
{ 
  GtkAdjustment *adj;
  GtkWidget *widget;
  GtkWidget *table;
  table = gtk_table_new (2, 8, FALSE);
  gtk_widget_ref (table);
  gtk_object_set_data_full (GTK_OBJECT (window1), "delay_table", table,
			      (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (table);
  
  
  adj = (GtkAdjustment*)gtk_adjustment_new (0, 0, 100, 0.01, 
					    1.0, 0.0);
  g_signal_connect (adj, "value_changed",
		    GTK_SIGNAL_FUNC(on_delay), NULL);

  widget = gtk_hscale_new (GTK_ADJUSTMENT (adj));
  
    g_signal_connect (widget, "enter_notify_event",
                      GTK_SIGNAL_FUNC (on_delay), NULL);
    g_signal_connect (widget, "focus_in_event",
                      GTK_SIGNAL_FUNC (on_delay), NULL);
    g_signal_connect (widget, "button_release_event",
                      GTK_SIGNAL_FUNC (on_delay), NULL);
  
 gtk_object_set_data_full (GTK_OBJECT (ed.window),"delay", widget,
                            (GtkDestroyNotify) gtk_widget_unref);

  
  gtk_widget_set_name (widget,"mod_delay");
  gtk_widget_ref (widget);
  gtk_widget_show (widget);
  gtk_table_attach (GTK_TABLE (table), widget, 1, 3, 1, 2,
                    (GtkAttachOptions) (GTK_EXPAND|GTK_FILL),
                    (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0);
  gtk_scale_set_draw_value (GTK_SCALE (widget), FALSE);
  ed.mod_delay = widget;

  adj = (GtkAdjustment*)gtk_adjustment_new (0, 0, 100, 0.01, 
					    1.0, 0.0);
  g_signal_connect (adj, "value_changed",
		    GTK_SIGNAL_FUNC(on_delay), NULL+1);

 widget = gtk_hscale_new (GTK_ADJUSTMENT (adj));
 gtk_object_set_data_full (GTK_OBJECT (ed.window),"delay", widget,
                            (GtkDestroyNotify) gtk_widget_unref);

  
  gtk_widget_set_name (widget,"mod_delay");
  gtk_widget_ref (widget);
  gtk_widget_show (widget);
  gtk_table_attach (GTK_TABLE (table), widget, 4, 6, 1, 2,
                    (GtkAttachOptions) (GTK_EXPAND|GTK_FILL),
                    (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0);
  gtk_scale_set_draw_value (GTK_SCALE (widget), FALSE);
  ed.mod_keyfollow = widget;
  return table;
}
*/

static
void mk_patchbay(GtkWidget *table,int x,int y,int op,char*name)
{
  int i;
  char*am_help[]={"  op 1 amplitude modulation","  op 2 amplitude modulation",
		  "  op 3 amplitude modulation","  op 4 amplitude modulation"};
  char*pm_help[]={"  op 1 phase modulation","  op 2 phase modulation",
		  "  op 3 phase modulation","  op 4 phase modulation"};
  for(i = 0;i<8;++i)
    {
      int x2=0;
      char*name;
      GtkWidget *line = gtk_vseparator_new ();

      if(i&2)
	{
	  x2 = 2;
	}

      if(i&1)
	{
	  ed.am[op][i>>1] = scale(table,x+x2,y+i,4,1,
				  -100,100,op,MOD2,i>>1,am_help[i>>1]);
	}
      else
	{
	  name = name_n();
	  gtk_widget_set_name (line, name);
	  gtk_widget_ref (line);
	  gtk_object_set_data_full (GTK_OBJECT (ed.window), name, line,
				    (GtkDestroyNotify) gtk_widget_unref);

	  gtk_table_attach (GTK_TABLE (table), line, x+x2+1, x+x2+3, y+i-(i==0), y+2+i,
			    (GtkAttachOptions) (GTK_FILL),
			    (GtkAttachOptions) (GTK_FILL), 0, 0);
	  ed.pm[op][i>>1] = scale(table,x+x2,y+i,4,1,
				  -100,100,op,MOD1,i>>1,pm_help[i>>1]);
	  gtk_widget_show (line);

	}
    }
  label(table,x,y+2,2," fm");
  label(table,x,y+3,2," am");
}


static
GtkWidget* tab_label(GtkWidget *window,char *name)
{
  GtkWidget *label;
  label = gtk_label_new (name);
  gtk_widget_ref (label);
  gtk_object_set_data_full (GTK_OBJECT (window), name_n(), label,
			    (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (label);
  return label;
}
static
void on_od_clicked (GtkButton *button,
		    void*  user_data)
{
  int value = ((int)user_data)&0x0F;
  int op = ((int)user_data)>>4;
  mx44tmpPatch[ midichannel ].od[op] = value;

}

static
void on_lfo_button_clicked (GtkToggleButton *button,
		    void*  user_data)
{

  if(button == (GtkToggleButton*)ed.lfo_button[0])
    mx44tmpPatch[ midichannel ].lfo_button[0] = gtk_toggle_button_get_active(button); 
  else if(button == (GtkToggleButton*)ed.lfo_button[1])
    mx44tmpPatch[ midichannel ].lfo_button[1] = gtk_toggle_button_get_active(button); 

}
static
void on_button_clicked (GtkToggleButton *button,
		    void*  user_data)
{
  int op = ((int)user_data)&0x0F;
  int number = ((int)user_data)>>4;
  char b = mx44tmpPatch[ midichannel ].button[op];

  if(gtk_toggle_button_get_active(button)) 
    {
      mx44tmpPatch[ midichannel ].button[op] = b |number;
    } 
  else 
    {
      mx44tmpPatch[ midichannel ].button[op] = b &(~number);
    }
}
static int saving;
static
void  patch_changed(void)
{
  int midipatch = group*64+bank*8+patch;
  if(midipatch < 0 || midipatch > 127)
    return;
  mx44patchNo [midichannel] = midipatch;
  newpatch.number = midipatch;
  if(patch_change)
    return;

  if(!saving)
    if(midichannel != -1)
      {

	//puts("patch_changed");
	
	mx44tmpPatch[midichannel] = mx44patch[midipatch];
	
	set_widgets(mx44tmpPatch,midichannel,-1);
      }
}
static
void on_patch_group_1_clicked (GtkButton *button,
			       void*  user_data)
{
  group = 0;
  patch_changed();
}
static
void on_patch_group_2_clicked (GtkButton *button,
			       void* user_data)
{
  group = 1;
  patch_changed();
}
static
int on_bank_entry_changed (GtkComboBox *combo,
			   void* user_data)
{
  /*
  char* txt = gtk_editable_get_chars(editable,0,50);
  if(*txt)
    {
      bank = txt[1] - 'A';
      patch_changed();
    }
  */
  bank = gtk_combo_box_get_active(combo);
  patch_changed();
  return 0;
}
static
int on_patch_entry_changed (GtkComboBox *combo,
			    void* user_data)
{
  /*
  char* txt = gtk_editable_get_chars(editable,0,50);
  if(*txt)
    {
      patch = txt[1] - '1';
      patch_changed();
    }
  */
  patch = gtk_combo_box_get_active(combo);
  patch_changed();
  return 0;
}

GtkToggleButton *savebutton;
static
void on_save_button_toggled (GtkToggleButton *togglebutton,
			     void* user_data)
{

  if(gtk_toggle_button_get_active(togglebutton))
    saving = TRUE;
  else
    {
      if(savebutton)
	{
	  printf("patch: %i channel %i\n",mx44patchNo [midichannel] ,midichannel);
	  strcpy( mx44tmpPatch[midichannel].name,gtk_entry_get_text((GtkEntry*) patchname ));
	  mx44patch[mx44patchNo[midichannel]] = mx44tmpPatch[midichannel];
	}
      
      saving = FALSE;
    }

  savebutton = togglebutton;

}

static 
void on_esc_save_button_pressed (GtkButton *button,
				 void* user_data)
{
  GtkToggleButton *sb = savebutton;
  savebutton = 0;
  if(sb)
    gtk_toggle_button_set_active(sb,FALSE);
}


static
void on_monobutton_toggled (GtkToggleButton *togglebutton,
			     void* user_data)
{
  mx44->monomode[midichannel] = gtk_toggle_button_get_active(togglebutton);
}
static
int on_ch_combo( GtkComboBox *combo, void* user_data)
{
  midichannel = gtk_combo_box_get_active(combo);
  set_widgets(mx44tmpPatch,midichannel,mx44patchNo[midichannel]);
  newpatch.number = mx44->patchNo[midichannel];
  return 0;
}

static
GtkWidget* create_window (int unused)
{

  GtkWidget  *frame,*basetable = 0;
  char *name;
    //  char *win_label[]={"Mx44:1","Mx44:2","Mx44:3","Mx44:4",NULL};

  wn = 0;


  name = name_n();

  ed.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  window1=ed.window;
  gtk_widget_set_name (ed.window, name);
  gtk_object_set_data (GTK_OBJECT (ed.window), name, ed.window);
  gtk_container_set_border_width (GTK_CONTAINER (ed.window), 2);


  gtk_window_set_title (GTK_WINDOW (ed.window), "Mx44");
  
  g_signal_connect (ed.window, "destroy",
		    GTK_SIGNAL_FUNC(gtk_main_quit),
		    NULL);

  {
    GtkWidget *patch_table,*fx_table;

    void *bank_combo;
    void *patch_combo;

    GtkWidget *save_button;

    GtkWidget *esc_save_button;

    GtkWidget *ch_combo;
    GSList *patchgroup_group = NULL;

    GtkTooltips *tooltips;

    tooltips = gtk_tooltips_new ();


    basetable = gtk_table_new (3, 4, FALSE);
    gtk_widget_ref (basetable);
    gtk_widget_show(basetable);


    patch_table = gtk_table_new (1, 67, TRUE);
    gtk_widget_ref (patch_table);
    gtk_object_set_data_full (GTK_OBJECT (window1), "patch_table", patch_table,
			      (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (patch_table);
    
    gtk_table_attach (GTK_TABLE (basetable),
		      patch_table, 0,2, 1, 2,
		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
		      (GtkAttachOptions) (GTK_FILL), 0, 0);

    
    patch_group_1 = gtk_radio_button_new (patchgroup_group);
    patchgroup_group = gtk_radio_button_group (GTK_RADIO_BUTTON (patch_group_1));
    gtk_widget_ref (patch_group_1);
    gtk_object_set_data_full (GTK_OBJECT (window1), "patch_group_1", patch_group_1,
			      (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (patch_group_1);

    gtk_table_attach (GTK_TABLE (patch_table), patch_group_1, 1, 3, 0, 1,
		      (GtkAttachOptions) (GTK_FILL),
		      (GtkAttachOptions) (0), 0, 0);
    gtk_tooltips_set_tip (tooltips, patch_group_1, "patch group 1", NULL);
    
    patch_group_2 = gtk_radio_button_new (patchgroup_group);
    patchgroup_group = gtk_radio_button_group (GTK_RADIO_BUTTON (patch_group_2));
    gtk_widget_ref (patch_group_2);
    gtk_object_set_data_full (GTK_OBJECT (window1), "patch_group_2", patch_group_2,
			      (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (patch_group_2);
    gtk_table_attach (GTK_TABLE (patch_table), patch_group_2, 3, 5, 0, 1,
		      (GtkAttachOptions) (GTK_FILL),
		      (GtkAttachOptions) (0), 0, 0);

    gtk_tooltips_set_tip (tooltips, patch_group_2, "patch group 2", NULL);
    

    bank_combo = gtk_combo_box_new_text ();
    gtk_widget_ref (bank_combo);
    gtk_object_set_data_full (GTK_OBJECT (window1), "bank_combo", bank_combo,
			      (GtkDestroyNotify) gtk_widget_unref);
    gtk_tooltips_set_tip (tooltips, bank_combo, "bank selection", NULL);
    gtk_widget_show (bank_combo);
    gtk_table_attach (GTK_TABLE (patch_table), bank_combo, 5, 9, 0, 1,
		      (GtkAttachOptions) (GTK_EXPAND),
		      (GtkAttachOptions) (0), 0, 0);
    //gtk_widget_set_usize (bank_combo, 45, 25);
    //gtk_container_set_border_width (GTK_CONTAINER (bank_combo), 5);
    GTK_WIDGET_SET_FLAGS (bank_combo, GTK_CAN_FOCUS);
    gtk_combo_box_append_text (GTK_COMBO_BOX (bank_combo), "A");
    gtk_combo_box_append_text (GTK_COMBO_BOX (bank_combo), "B");
    gtk_combo_box_append_text (GTK_COMBO_BOX (bank_combo), "C");
    gtk_combo_box_append_text (GTK_COMBO_BOX (bank_combo), "D");
    gtk_combo_box_append_text (GTK_COMBO_BOX (bank_combo), "E");
    gtk_combo_box_append_text (GTK_COMBO_BOX (bank_combo), "F");
    gtk_combo_box_append_text (GTK_COMBO_BOX (bank_combo), "G");
    gtk_combo_box_append_text (GTK_COMBO_BOX (bank_combo), "H");
    gtk_combo_box_set_active  (GTK_COMBO_BOX (bank_combo), 0);
    
    bank_entry = bank_combo;
    
    patch_combo = gtk_combo_box_new_text ();
    gtk_widget_ref (patch_combo);
    gtk_object_set_data_full (GTK_OBJECT (window1), "patch_combo", patch_combo,
			      (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (patch_combo);
    gtk_table_attach (GTK_TABLE (patch_table), patch_combo, 9, 13, 0, 1,
		      (GtkAttachOptions) (GTK_EXPAND),
		      (GtkAttachOptions) (0), 0, 0);

    gtk_combo_box_append_text (GTK_COMBO_BOX (patch_combo), "1");
    gtk_combo_box_append_text (GTK_COMBO_BOX (patch_combo), "2");
    gtk_combo_box_append_text (GTK_COMBO_BOX (patch_combo), "3");
    gtk_combo_box_append_text (GTK_COMBO_BOX (patch_combo), "4");
    gtk_combo_box_append_text (GTK_COMBO_BOX (patch_combo), "5");
    gtk_combo_box_append_text (GTK_COMBO_BOX (patch_combo), "6");
    gtk_combo_box_append_text (GTK_COMBO_BOX (patch_combo), "7");
    gtk_combo_box_append_text (GTK_COMBO_BOX (patch_combo), "8");
    gtk_combo_box_set_active  (GTK_COMBO_BOX (patch_combo), 0);
    
    patch_entry = patch_combo;

    //gtk_tooltips_set_tip (tooltips, patch_combo, "patch selection", NULL);




    patchname = gtk_entry_new_with_max_length (31);
    gtk_widget_ref (patchname);
    gtk_object_set_data_full (GTK_OBJECT (window1), "patchname", patchname,
			      (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (patchname);
    gtk_table_attach (GTK_TABLE (patch_table), patchname, 13, 27, 0, 1,
		      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
		      (GtkAttachOptions) (0), 2, 7);
    
    save_button = gtk_toggle_button_new_with_label ("SAVE");
    gtk_widget_ref (save_button);
    gtk_object_set_data_full (GTK_OBJECT (window1), "save_button", save_button,
			      (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (save_button);
    gtk_table_attach (GTK_TABLE (patch_table), save_button, 27, 31, 0, 1,
                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
		      (GtkAttachOptions) (0), 0, 0);
    gtk_tooltips_set_tip (tooltips, save_button,
			  "select patch to save in, then release button", NULL);
    
   
    /* FIXME!
    ed.delay_table = mk_delay_table();
    gtk_table_attach (GTK_TABLE (patch_table), ed.delay_table, 0, 8, 1, 2,
		      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
		      (GtkAttachOptions) (0), 2, 7);
    */

    
    esc_save_button = gtk_button_new_with_label ("Esc");
    gtk_widget_ref (esc_save_button);
    gtk_object_set_data_full (GTK_OBJECT (window1), "esc_save_button", esc_save_button,
			      (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (esc_save_button);
    gtk_table_attach (GTK_TABLE (patch_table), esc_save_button, 31, 34, 0, 1,
		      (GtkAttachOptions) (GTK_FILL),
		      (GtkAttachOptions) (0), 0, 0);
    gtk_tooltips_set_tip (tooltips, esc_save_button, "cancel save procedure", NULL);

    //--

    ed.common_oplabel = tab_label(ed.window, "Mx44");
    gtk_label_set_justify (GTK_LABEL (ed.common_oplabel), GTK_JUSTIFY_LEFT);
    gtk_misc_set_alignment (GTK_MISC (ed.common_oplabel), 0, 0.5);
    gtk_widget_set_size_request (ed.common_oplabel ,20, -1);
    gtk_table_attach (GTK_TABLE (patch_table),
    	    ed.common_oplabel, 36,39, 0, 1,
    	    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
    	    (GtkAttachOptions) (GTK_FILL), 0, 0);
    gtk_widget_show(ed.common_oplabel);

 
    ed.common_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (NULL), 1, 2);
    gtk_widget_ref(ed.common_spinbutton);
    gtk_spin_button_set_numeric ((GtkSpinButton*)ed.common_spinbutton,1 );
    gtk_entry_set_alignment ((GtkEntry*)ed.common_spinbutton,1 );
    gtk_widget_set_size_request (ed.common_spinbutton ,50, -1);
    gtk_widget_show (ed.common_spinbutton);
    gtk_table_attach (GTK_TABLE (patch_table), ed.common_spinbutton, 39, 44, 0, 1,
		      (GtkAttachOptions) (GTK_FILL),
		      (GtkAttachOptions) (0), 0, 0);
    
    
    ed.common_spinlabel = tab_label(ed.window, "    (C) Jens M Andreasen, 2005");
    gtk_label_set_justify (GTK_LABEL (ed.common_spinlabel), GTK_JUSTIFY_LEFT);
    gtk_misc_set_alignment (GTK_MISC (ed.common_spinlabel), 0, 0.5);
    gtk_widget_set_size_request (ed.common_spinlabel ,60, -1);
    gtk_table_attach (GTK_TABLE (patch_table),
    	    ed.common_spinlabel, 44,59, 0, 1,
    	    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
    	    (GtkAttachOptions) (GTK_FILL), 0, 0);
    gtk_widget_show(ed.common_spinlabel);
    
    // ----

    ed.monobutton = gtk_toggle_button_new_with_label ("M");



    gtk_widget_ref (ed.monobutton);
    gtk_object_set_data_full (GTK_OBJECT (window1), "monobutton", ed.monobutton,
			      (GtkDestroyNotify) gtk_widget_unref);
#if 0
    gtk_widget_show (ed.monobutton);
    gtk_table_attach (GTK_TABLE (patch_table), ed.monobutton, 58, 60, 0, 1,
		      (GtkAttachOptions) (GTK_FILL),
		      (GtkAttachOptions) (0), 0, 0);
    gtk_tooltips_set_tip (tooltips, ed.monobutton, "midi mono mode", NULL);
    gtk_widget_modify_text(ed.monobutton,GTK_STATE_PRELIGHT,&col);
#endif
    // ----

    ch_combo = gtk_combo_box_new_text ();
    gtk_widget_ref (ch_combo);
    gtk_object_set_data_full (GTK_OBJECT (window1), "ch_combo", ch_combo,
			      (GtkDestroyNotify) gtk_widget_unref);
    //gtk_tooltips_set_tip (tooltips, ch_combo, "bank selection", NULL);
    gtk_widget_show (ch_combo);
    gtk_table_attach (GTK_TABLE (patch_table), ch_combo, 61, 67, 0, 1,
		      (GtkAttachOptions) (GTK_EXPAND),
		      (GtkAttachOptions) (0), 0, 0);
    //gtk_widget_set_usize (bank_combo, 45, 25);
    //gtk_container_set_border_width (GTK_CONTAINER (ch_combo), 5);
    GTK_WIDGET_SET_FLAGS (ch_combo, GTK_CAN_FOCUS);
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 1");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 2");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 3");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 4");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 5");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 6");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 7");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 8");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch 9");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch10");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch11");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch12");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch13");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch14");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch15");
    gtk_combo_box_append_text (GTK_COMBO_BOX (ch_combo), "Ch16");
    gtk_combo_box_set_active  (GTK_COMBO_BOX (ch_combo), 0);


    g_signal_connect (ch_combo, "changed",
		      GTK_SIGNAL_FUNC (on_ch_combo),NULL);

    
    g_signal_connect (bank_combo, "changed",
		      GTK_SIGNAL_FUNC (on_bank_entry_changed),
		      NULL);
    g_signal_connect (patch_entry, "changed",
		      GTK_SIGNAL_FUNC (on_patch_entry_changed),
		      NULL);
    g_signal_connect (save_button, "toggled",
		      GTK_SIGNAL_FUNC (on_save_button_toggled),
		      NULL);
    g_signal_connect (esc_save_button, "clicked",
		      GTK_SIGNAL_FUNC (on_esc_save_button_pressed),
		      NULL);

    g_signal_connect (ed.monobutton, "toggled",
		      GTK_SIGNAL_FUNC (on_monobutton_toggled),
		      NULL);

    g_signal_connect (patch_group_1, "pressed",
		      GTK_SIGNAL_FUNC (on_patch_group_1_clicked),
		      NULL);
    g_signal_connect (patch_group_2, "pressed",
		      GTK_SIGNAL_FUNC (on_patch_group_2_clicked),
		      NULL);
    

    gtk_widget_grab_focus((GtkWidget*)ed.common_spinbutton);     
    
    {
      GtkWidget *widget;
      widget = gtk_frame_new(NULL);
      gtk_frame_set_shadow_type( GTK_FRAME(widget), GTK_SHADOW_NONE);
      gtk_container_set_border_width (GTK_CONTAINER (widget), 2);      
      gtk_widget_show(widget);
  
      //gtk_container_set_border_width (GTK_CONTAINER (ed.table[ed.op]), 6);
      

      fx_table = gtk_table_new (35,6, TRUE);
      gtk_widget_ref (fx_table);
      gtk_object_set_data_full (GTK_OBJECT (window1), "fx_table", fx_table,
				(GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_show (fx_table);
      gtk_container_set_border_width (GTK_CONTAINER (fx_table), 3);
      gtk_container_add (GTK_CONTAINER (widget), fx_table);
      gtk_table_attach (GTK_TABLE (basetable),
			widget, 2,3, 0, 3,
			(GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
			(GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
      
#if 0
      label(fx_table,0,0,4,"Delay");
      
      widget = scale(fx_table,
		     0,1,1,4,
		     0,100,-1,DELAY,0,"  // delay time");
      gtk_widget_set_size_request (widget, 18, 18);

      scale(fx_table,
	    1,1,1,4,
	    0,100,-1,DELAY,1,"  // delay spread");

      scale(fx_table,
	    2,1,1,4,
	    0,100,-1,DELAY,2,"  // delay feedback");

      scale(fx_table,
	    3,1,1,4,
	    0,100,-1,DELAY,3,"  // delay LFO modulation");

      scale(fx_table,
	    5,1,1,4,
	    0,100,-1,DELAY,4,"  // delay amount");


      label(fx_table,0,7,4,"Overdrive");

      widget=scale(fx_table,
		   1,8,4,1,
		   0,100,-1,DIST,0,"  // overdrive / distortion");
      gtk_widget_set_size_request (widget, 18, 18);
#else
      {
	int i;
	for (i=0;i < 7;++i)
	  line(fx_table,1,1+i,4,1);
      }
#endif


      label(fx_table,0,10,4,"LFO");

      ed.lfo[0] = scale(fx_table,
			2,15,1,4,
			0,100,-1,LFO,0,"  LFO rate 1");
      ed.lfo[1] = scale(fx_table,
			3,15,1,4,
			0,100,-1,LFO,1,"  LFO rate 2");
      ed.lfo[2] = scale(fx_table,
			4,13,1,4,
			0,100,-1,LFO,2,"  LFO amount 1");
      ed.lfo[3] = scale(fx_table,
			5,12,1,4,
			0,100,-1,LFO,3,"  LFO amount 2");
      ed.lfo[4] = scale(fx_table,
			0,12,5,1,
			0,100,-1,LFO,4,"  LFO time 1");
      ed.lfo[5] = scale(fx_table,
			1,11,5,1,
			0,100,-1,LFO,5,"  LFO time 2");

      label(fx_table,1,13,3," Sync");
      label(fx_table,1,14,3," Wheel");
      
      
      //-------------

      widget = gtk_check_button_new();
      gtk_widget_ref(widget);
      gtk_object_set_data_full (GTK_OBJECT (window1), "loopbutton", widget,
				(GtkDestroyNotify) gtk_widget_unref);
      
      g_signal_connect (widget, "clicked",
			GTK_SIGNAL_FUNC (on_lfo_button_clicked),
			NULL);
      
      gtk_widget_show(widget);
      gtk_table_attach (GTK_TABLE (fx_table), widget, 0, 1, 13, 14,
			(GtkAttachOptions) (GTK_SHRINK),
			(GtkAttachOptions) (GTK_SHRINK), 0, 0);
      gtk_widget_set_size_request (widget, 18, 18);

      ed.lfo_button[0] = widget;
      //-------------

      widget = gtk_check_button_new();
      gtk_widget_ref(widget);
      gtk_object_set_data_full (GTK_OBJECT (window1), "touchbutton", widget,
				(GtkDestroyNotify) gtk_widget_unref);
      /*
      g_signal_connect (ed.wheelbutton[ed.op][0], "clicked",
			GTK_SIGNAL_FUNC (on_button_clicked),
			(NULL+(WHEELBUTTON<<4))+ed.op);
      */
      g_signal_connect (widget, "clicked",
			GTK_SIGNAL_FUNC (on_lfo_button_clicked),
			NULL+1);
      gtk_widget_show(widget);
      gtk_table_attach (GTK_TABLE (fx_table), widget, 0, 1, 14, 15,
			(GtkAttachOptions) (GTK_SHRINK),
			(GtkAttachOptions) (GTK_SHRINK), 0, 0);
      gtk_widget_set_size_request (widget, 18, 18);

      ed.lfo_button[1] = widget;
      //---------------
#if 0
      label(fx_table,0,22,4,"Arpeggio  ...");

      label(fx_table,0,28,4,"Key Zone  ...");
#else
      {
	int i;
	for (i=0;i < 12;++i)
	  line(fx_table,1,22+i,4,1);
      }
#endif
    }
  }


  gtk_container_add (GTK_CONTAINER (ed.window), basetable);


  for(ed.op = 0;op_label[ed.op];++ed.op)  
    {
      
      

      name = name_n();
      ed.table[ed.op] = gtk_table_new (15, 22, TRUE);
      
      
      gtk_widget_set_name (ed.table[ed.op], name);
      gtk_widget_ref (ed.table[ed.op]);
      
      gtk_object_set_data_full (GTK_OBJECT (ed.window), name, ed.table[ed.op],
				(GtkDestroyNotify) gtk_widget_unref);
      
      
      mk_envelope(ed.table[ed.op],0,0,ed.op,"Envelope  time / level");

      label(ed.table[ed.op],13,7,3," Wheel");


      ed.wheelbutton[ed.op][0] = gtk_check_button_new();
      gtk_widget_ref(ed.wheelbutton[ed.op][0]);
      gtk_object_set_data_full (GTK_OBJECT (window1), "wheelbutton", ed.wheelbutton[ed.op][0] ,
				(GtkDestroyNotify) gtk_widget_unref);
      g_signal_connect (ed.wheelbutton[ed.op][0], "clicked",
			GTK_SIGNAL_FUNC (on_button_clicked),
			(NULL+(WHEELBUTTON<<4))+ed.op);
      gtk_widget_show(ed.wheelbutton[ed.op][0]);
      gtk_table_attach (GTK_TABLE (ed.table[ed.op]), ed.wheelbutton[ed.op][0], 12, 13, 7, 8,
			(GtkAttachOptions) (GTK_SHRINK),
			(GtkAttachOptions) (GTK_SHRINK), 0, 0);
      gtk_widget_set_size_request (ed.wheelbutton[ed.op][0], 18, 18);
      
      

      
      label(ed.table[ed.op],0,1,4,"Keybias");
      ed.breakpoint[ed.op] = scale(ed.table[ed.op],
				0,0,5,1,
				0,128,ed.op,BIAS,0, "  bias breakpoint");
      ed.keybias[ed.op][0] = scale(ed.table[ed.op],
				0,2,1,4,
				-100,0,ed.op,BIAS,1,"  bias low");
      ed.keybias[ed.op][1] = scale(ed.table[ed.op],
				1,2,1,4,
				-100,0,ed.op,BIAS,2,"  bias high");


      
      label(ed.table[ed.op],0,14,2,"Phase");
      ed.phase[ed.op][0] = scale(ed.table[ed.op],
			    2,11,1,4,
			      0,100,ed.op,MISC,0,"  phase init");
      ed.phase[ed.op][1] = scale(ed.table[ed.op],
			      3,11,1,4,
			      0,100,ed.op,MISC,1,"  phase velocity / keyfollow");
      
      label(ed.table[ed.op],6,14,3,"Velocity");
      line(ed.table[ed.op],4,12,2,1);
      ed.velocity[ed.op] = scale(ed.table[ed.op],
			      4,10,2,5,
			      -100,100,ed.op,MISC,2,"  velocity sensitivity");

      label(ed.table[ed.op],12,13,2,"Out");
      ed.mix[ed.op][0] = scale(ed.table[ed.op],
			       13,9,2,5,
			       0,100,ed.op,MISC,3,"  output volume");
      ed.mix[ed.op][1] = scale(ed.table[ed.op],
			       12,14,4,1,
			       -180,180,ed.op,MISC,4,"  output balance");
                  
      {
	int x;
  
	for(x=0;x<8;++x)
	  {
	    ed.od[ed.op][x] = gtk_radio_button_new ((void*)ed.od_group[ed.op]);
	    ed.od_group[ed.op] = (void*)gtk_radio_button_group (GTK_RADIO_BUTTON (ed.od[ed.op][x]));
	    gtk_widget_ref (ed.od[ed.op][x]);
	    gtk_object_set_data_full (GTK_OBJECT (window1), "wawe 0", ed.od[ed.op][x],
				      (GtkDestroyNotify) gtk_widget_unref);
	    gtk_widget_show (ed.od[ed.op][x]);

	    if(x <4)
	      gtk_table_attach (GTK_TABLE (ed.table[ed.op]), ed.od[ed.op][x],x+ 15, x+16, 0, 1,
				(GtkAttachOptions) (GTK_SHRINK),
				(GtkAttachOptions) (GTK_SHRINK), 0, 0);
	    else
	      gtk_table_attach (GTK_TABLE (ed.table[ed.op]), ed.od[ed.op][x],x+ 14, x+15, 1, 2,
				(GtkAttachOptions) (GTK_SHRINK),
				(GtkAttachOptions) (GTK_SHRINK), 0, 0);

	    gtk_widget_set_size_request (ed.od[ed.op][x], 18, 18);
	    g_signal_connect (ed.od[ed.op][x], "clicked",
			      GTK_SIGNAL_FUNC (on_od_clicked),
			      (NULL+x)+(ed.op<<4));

	  }

	ed.wawebutton[ed.op] = gtk_check_button_new();
	gtk_widget_ref(ed.wawebutton[ed.op]);
	gtk_widget_show(ed.wawebutton[ed.op]);
	gtk_object_set_data_full (GTK_OBJECT (window1), "complex", ed.wawebutton[ed.op] ,
				  (GtkDestroyNotify) gtk_widget_unref);
	gtk_table_attach (GTK_TABLE (ed.table[ed.op]),	ed.wawebutton[ed.op] ,20, 21, 0, 1,
			  (GtkAttachOptions) (GTK_SHRINK),
			  (GtkAttachOptions) (GTK_SHRINK), 0, 0);
	gtk_widget_set_size_request (ed.wawebutton[ed.op], 18, 18);

	g_signal_connect (ed.wawebutton[ed.op], "clicked",
			  GTK_SIGNAL_FUNC (on_button_clicked),
			  (NULL+(WAWEBUTTON<<4))+ed.op);
	

	ed.lowpassbutton[ed.op] = gtk_check_button_new();
	gtk_widget_ref(ed.lowpassbutton[ed.op]);
	gtk_widget_show(ed.lowpassbutton[ed.op]);
	gtk_object_set_data_full (GTK_OBJECT (window1), "lowpass", ed.lowpassbutton[ed.op] ,
				  (GtkDestroyNotify) gtk_widget_unref);
	gtk_table_attach (GTK_TABLE (ed.table[ed.op]),	ed.lowpassbutton[ed.op] ,21, 22, 0, 1,
			  (GtkAttachOptions) (GTK_SHRINK),
			  (GtkAttachOptions) (GTK_SHRINK), 0, 0);
	gtk_widget_set_size_request (ed.lowpassbutton[ed.op], 18, 18);
	
	g_signal_connect (ed.lowpassbutton[ed.op], "clicked",
			  GTK_SIGNAL_FUNC (on_button_clicked),
			  (NULL+(LOWPASSBUTTON<<4))+ed.op);
	

	ed.waweshapebutton[ed.op] = gtk_check_button_new();
	gtk_widget_ref(ed.waweshapebutton[ed.op]);
	gtk_widget_show(ed.waweshapebutton[ed.op]);
	gtk_object_set_data_full (GTK_OBJECT (window1), "waweshape", ed.waweshapebutton[ed.op] ,
				  (GtkDestroyNotify) gtk_widget_unref);
	gtk_table_attach (GTK_TABLE (ed.table[ed.op]),	ed.waweshapebutton[ed.op] ,14, 15, 0, 2,
			  (GtkAttachOptions) (GTK_SHRINK),
			  (GtkAttachOptions) (GTK_SHRINK), 0, 0);
	gtk_widget_set_size_request (ed.waweshapebutton[ed.op], 18, 18);
	
	g_signal_connect (ed.waweshapebutton[ed.op], "clicked",
			  GTK_SIGNAL_FUNC (on_button_clicked),
			  (NULL+(WAWESHAPEBUTTON<<4))+ed.op);
	

	ed.phasefollowkeybutton[ed.op] = gtk_check_button_new();
	gtk_widget_ref(ed.phasefollowkeybutton[ed.op]);
	gtk_widget_show(ed.phasefollowkeybutton[ed.op]);
	gtk_object_set_data_full (GTK_OBJECT (window1), "complex", ed.phasefollowkeybutton[ed.op] ,
				  (GtkDestroyNotify) gtk_widget_unref);
	gtk_table_attach (GTK_TABLE (ed.table[ed.op]),	ed.phasefollowkeybutton[ed.op] ,3, 4, 10, 11,
			  (GtkAttachOptions) (GTK_SHRINK),
			  (GtkAttachOptions) (GTK_SHRINK), 0, 0);
	gtk_widget_set_size_request (ed.phasefollowkeybutton[ed.op], 18, 18);

	g_signal_connect (ed.phasefollowkeybutton[ed.op], "clicked",
			  GTK_SIGNAL_FUNC (on_button_clicked),
			  (NULL+(PHASEFOLLOWKEYBUTTON<<4))+ed.op);

	
	ed.magicbutton[ed.op] = gtk_check_button_new();
	gtk_widget_ref(ed.magicbutton[ed.op]);
	gtk_widget_show(ed.magicbutton[ed.op]);
	gtk_object_set_data_full (GTK_OBJECT (window1), "magic", ed.magicbutton[ed.op] ,
				  (GtkDestroyNotify) gtk_widget_unref);
	gtk_table_attach (GTK_TABLE (ed.table[ed.op]),	ed.magicbutton[ed.op] ,21, 22, 2, 3,
			  (GtkAttachOptions) (GTK_SHRINK),
			  (GtkAttachOptions) (GTK_SHRINK), 0, 0);
	gtk_widget_set_size_request (ed.magicbutton[ed.op], 18, 18);
	
	g_signal_connect (ed.magicbutton[ed.op], "clicked",
			  GTK_SIGNAL_FUNC (on_button_clicked),
			  (NULL+(MAGICBUTTON<<4))+ed.op);
	

	//label(ed.table[ed.op],15,1,3," Wawe &");

	label(ed.table[ed.op],16,2,4," Oscillator");
	ed.harmonic[ed.op] = scale(ed.table[ed.op],
				   16,4,5,2,
				   0,100,ed.op,FREQ,0,"  frequency multiplyer");
	
	line(ed.table[ed.op],21,4,1,2);
	ed.detune[ed.op] = scale(ed.table[ed.op],
				 21,3,1,4,
				 -100,100,ed.op,FREQ,2,"  frequency offset");
    
	line(ed.table[ed.op],15,3,1,2);
	ed.intonation[ed.op][0] = scale(ed.table[ed.op],
					15,2,1,4,
					-100,100,ed.op,FREQ,3,"  intonation amount");
	ed.intonation[ed.op][1] = scale(ed.table[ed.op],
					16,3,4,2,
					0,100,ed.op,FREQ,4,"  intonation decay");
  
      }

      mk_patchbay(ed.table[ed.op],16,7,ed.op,"Modulation");
      
      /*
      line(ed.table[ed.op],9,15,16,1);
      
      ed.spinlabel[ed.op] = label(ed.table[ed.op],13,16,12,
				  "  (C) Jens M Andreasen, 2004");
      
      adj = (GtkAdjustment*)gtk_adjustment_new (100, 0, 100, 0.01, 1, 1);
      ed.spinbutton[ed.op] = 
	gtk_spin_button_new (GTK_ADJUSTMENT ( adj ), 1, 2);
      gtk_spin_button_set_numeric ((GtkSpinButton*)ed.spinbutton[ed.op],1 );
      gtk_entry_set_alignment ((GtkEntry*)ed.spinbutton[ed.op],1 );
      name = name_n();
      gtk_widget_set_name (ed.spinbutton[ed.op], name);
      gtk_widget_ref (ed.spinbutton[ed.op]);
      
      gtk_object_set_data_full (GTK_OBJECT (ed.window[wn]), name, ed.spinbutton[ed.op],
                            (GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_set_size_request (ed.spinbutton[ed.op] ,60, -1);
      gtk_widget_show (ed.spinbutton[ed.op]);
      gtk_table_attach (GTK_TABLE (ed.table[ed.op]), ed.spinbutton[ed.op], 9, 13, 15, 17,
			GTK_FILL,
			0, 0, 0);
      */
      /* Create a Frame */
      frame = gtk_frame_new(NULL);
      //      gtk_container_add(GTK_CONTAINER(notebook), frame);
      
      switch(ed.op)
	{
	case 0:
	  gtk_table_attach (GTK_TABLE (basetable), frame, 
			    0,1, 
			    0,1,
			    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
			    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
	  break;
	case 1:
	  gtk_table_attach (GTK_TABLE (basetable), frame, 
			    1,2, 
			    0,1,
			    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
			    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
	  break;
	case 2:
	  gtk_table_attach (GTK_TABLE (basetable), frame, 
			    0,1 , 
			    2,3,
			    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
			    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
	  break;
	case 3:
	  gtk_table_attach (GTK_TABLE (basetable), frame, 
			    1,2, 
			    2,3,
			    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
			    (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
	}
      
      /* Set the style of the frame */
      gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
      gtk_container_set_border_width (GTK_CONTAINER (frame), 2);      
      gtk_widget_show(frame);
  
      gtk_container_set_border_width (GTK_CONTAINER (ed.table[ed.op]), 6);
      gtk_container_add (GTK_CONTAINER (frame), ed.table[ed.op]);
      gtk_widget_show (ed.table[ed.op]);

    }

  
  //set_widgets(mx44tmpPatch,midichannel,mx44patchNo[midichannel]);
  gtk_widget_show(window1);
  
  return NULL;
}

int
main_interface (int argc, char *argv[])
{

  gtk_set_locale ();

  gtk_rc_add_default_file (widget_theme);
  gtk_init (&argc, &argv);

  create_window (0);
  set_widgets(mx44tmpPatch,0,mx44patchNo[0]);  
  g_timeout_add (50,
		 check_patch,
		 NULL);

  gtk_main ();
  return 0;
}

//main (int argc, char *argv[]) {return main_interface(argc,argv);}
