#include "snd.h"

static void W_info_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
#if HAVE_XmHTML
  snd_help((snd_state *)clientData,"Minibuffer","#panelayout");
#else
  snd_help((snd_state *)clientData,"Minibuffer",get_info_help());
#endif
}

static void W_play_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
#if HAVE_XmHTML
  snd_help((snd_state *)clientData,"Play","#play");
#else
  snd_help((snd_state *)clientData,"Play",get_play_help());
#endif
}

static char info_sep_help[] =
"When reading a very large file, Snd tries to\n\
keep an overview at hand of the channels so\n\
that you can move around quickly in very large\n\
data sets; when first read in, these overviews\n\
are set underway, and when they are finally\n\
ready for use, the line after the file name\n\
appears.  If you try to zoom out to a large\n\
view before the separator line appears, the\n\
graphics update process may be slow.\n\
";

static void W_info_sep_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"Name Separator",info_sep_help);
}

static char amp_help[] = 
"This scrollbar controls the amplitude\n\
at which the sound is played.  Click the\n\
amp label to return to 1.0. Control-Click\n\
returns to the previous value.\n\
";

static void W_amp_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"Amp",amp_help);
}

static char srate_help[] =
"This scrollbar controls the sampling rate\n\
at which the sound is played.  The arrow\n\
controls the direction (forwards or backwards)\n\
of playback.  Label clicks behave as with amp.\n\
";

static void W_srate_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
#if HAVE_XmHTML
  snd_help((snd_state *)clientData,"Srate","#speed");
#else
  ssnd_help((snd_state *)clientData,"Srate",srate_help,"\n",get_speed_menu_help(),NULL);
#endif
}

static char srate_arrow_help[] = 
"This button determines which direction\n\
the sound file is played.  When pointing\n\
to the right, the sound is played forwards;\n\
to the left, backwards.\n\
";

static void W_srate_arrow_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"Srate Arrow",srate_arrow_help);
}

static char expand_help[] =
"This scrollbar controls the tempo at which\n\
the sound is played back, using granular\n\
synthesis. The expand button must be down\n\
to get any expansion. Label clicks as in amp.\n\
";

static void W_expand_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
#if HAVE_XmHTML
  snd_help((snd_state *)clientData,"Expand","#expand");
#else
  ssnd_help((snd_state *)clientData,"Expand",expand_help,"\n",get_expand_menu_help(),NULL);
#endif
}

static void W_expand_button_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"Expand Button","This button turns on expansion\n");
}

static char contrast_help[] =
"This scrollbar controls the amount of\n\
'contrast enhancement' applied during\n\
playback.  The contrast button must be\n\
down to get any effect.  Label clicks as in amp.\n\
";

static void W_contrast_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
#if HAVE_XmHTML
  snd_help((snd_state *)clientData,"Contrast","#contrast");
#else
  ssnd_help((snd_state *)clientData,"Contrast",contrast_help,"\n",get_contrast_menu_help(),NULL);
#endif
}

static void W_contrast_button_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"Contrast Button","This button turns on contrast enhancement\n");
}

static char revscl_help[] =
"This scrollbar controls the amount of the\n\
sound that is fed into the reverberator.\n\
The reverb button must be down to get any\n\
reverb during playback.  Label clicks as in amp.\n\
";

static void W_revscl_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
#if HAVE_XmHTML
  snd_help((snd_state *)clientData,"Reverb amount","#reverb");
#else
  ssnd_help((snd_state *)clientData,"Reverb amount",revscl_help,"\n",get_reverb_menu_help(),NULL);
#endif
}

static char revlen_help[] =
"This scrollbar controls the lengths of\n\
the various delay lines in the reverb.\n\
It only takes effect when the reverb is\n\
created, that is, only when the play\n\
operation starts from silence.  Label clicks\n\
as in amp.\n\
";

static void W_revlen_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
#if HAVE_XmHTML
  snd_help((snd_state *)clientData,"Reverb length","#reverb");
#else
  ssnd_help((snd_state *)clientData,"Reverb length",revlen_help,"\n",get_reverb_menu_help(),NULL);
#endif
}

static void W_reverb_button_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,"Reverb Button","This button turns on reverberation\n");
}

static char filter_help[] =
"The Snd filter is an FIR filter of arbitrary\n\
order.  You specify the filter you want by\n\
defining the frequency response as an envelope\n\
in the 'env' window; set the desired order in\n\
the 'order' window; then turn it on by pushing\n\
the filter button at the right.  The filter\n\
design algorithm uses frequency sampling.\n\
The higher the order, the closer the filter\n\
can approximate the envelope you draw.\n\
You can also specify the filter coefficients\n\
in a file of floats, then load them into the\n\
Snd filter by typing the file name in the\n\
filter envelope text window.\n\
";

static void W_filter_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,"Filter",filter_help);
} 

static char filter_order_help[] =
"The filter order determines how closely\n\
the filter approximates the frequency response\n\
curve you drew in the 'env' window.\n\
";

static void W_filter_order_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,"Filter Order",filter_order_help);
}

static char filter_envelope_help[] =
"The filter envelope is a line-segment\n\
description of the frequency response\n\
you want.  It consists of a sequence of\n\
x,y pairs; normally the x axis goes\n\
from 0 to .5 or 0 to 1.0.  For example,\n\
a low-pass filter envelope could be:\n\
0.0 1.0 .25 1.0 .5 0.0 1.0 0.0\n\
";

static void W_filter_envelope_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,"Filter Envelope",filter_envelope_help);
}

static void W_filter_button_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,"Filter Button","This button turns on the filter\n");
}

static void W_sync_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "Sync Button",
"This button causes edit operations on one\n\
channel to be applied to all channels at the\n\
same time.\n\
");
}

static void W_combine_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "Combine Button",
"This button causes all channels to be\n\
displayed in one window, sharing the various\n\
channel controls.  Two extra scrollbars on\n\
the right provide scroll and zoom for the\n\
overall set of channel graphs. The default\n\
multichannel display style can be set in\n\
the Snd initialization file by setting\n\
the variable combine-channels.\n\
");
}

static void W_record_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "Record",
"The Record button causes Snd to rememeber\n\
any settings or changes to the settings within\n\
the control panel while the sound is playing.\n\
You can subsequently replay that 'take' by pressing\n\
the Replay button, and save it as an edit to\n\
the file with the Apply button.\n\
");
}

static void W_replay_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "Replay",
"The Replay button replays the last\n\
recorded run (see Record) of the current\n\
sound.\n\
");
}

static void W_apply_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "Apply",
"The Apply button saves the last recorded\n\
run over the current file (see Record) as\n\
an edit of the current file.\n\
");
}

static void W_set_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "Save",
"The 'Save' button saves the current control\n\
panel state for a subsequent 'Restore'.\n\
");
}

static void W_reset_Help_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "Restore",
"The 'Restore' button returns the control\n\
panel to the state at the time of the\n\
last 'Save', or the initial state if there\n\
has been no 'Save'.\n\
");
}

static void W_name_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
	   "Minibuffer",
"This portion of the snd display has several\n\
parts: the sound file name, with an asterisk if\n\
the file has unsaved edits; a minibuffer for\n\
various expression evaluations; a sync button\n\
that causes operations on one channel to be\n\
applied to all channels; and a play button\n\
that causes the sound to be played.  The\n\
lower portion of the pane, normally hidden,\n\
contains a variety of sound manipulation\n\
controls that can be applied while it is\n\
playing:\n\
\n\
    file name, followed by a separator\n\
\n",
info_sep_help,
"\n\n\
    minibuffer, sync, and play buttons\n\
    amplitude scrollbar\n\
\n",
amp_help,
"\n\n\
    srate scrollbar\n\
\n",
srate_help,
"\n\
    srate arrow button\n\
\n",
srate_arrow_help,
"\n\n\
    expand scrollbar and button\n\
\n",
expand_help,
"\n\n\
    contrast scrollbar and button\n\
\n",
contrast_help,
"\n\n\
    reverb amount scrollbar\n\
\n",
revscl_help,
"\n\
    reverb length scrollbar\n\
\n",
revlen_help,
"\n\n\
    filter section\n\
\n",
filter_help,
"\n\
    filter order text window\n\
\n",
filter_order_help,
"\n\
    filter envelope window\n\
\n",
filter_envelope_help,
NULL);
}

#if OVERRIDE_TOGGLE
/* Metrolink Motif defines control-button1 to be "take focus" */
static char ToggleTrans2[] =
       "c<Btn1Down>:   ArmAndActivate()\n";
static XtTranslations toggleTable2 = NULL;

void override_toggle_translation(Widget w)
{
  if (!toggleTable2) toggleTable2 = XtParseTranslationTable(ToggleTrans2);
  XtOverrideTranslations(w,toggleTable2);
}
#endif

Widget snd_widget(snd_info *sp, int w)
{ 
  Widget *ws;
  if ((sp) && (sp->sgx))
    {
      ws = ((snd_context *)(sp->sgx))->snd_widgets;
      if (ws) return(ws[w]);
    }
  return(NULL);
}

#define SND_TXT_BUF_SIZE 256
static char snd_txt_buf[SND_TXT_BUF_SIZE];

int sound_unlock_ctrls(snd_info *sp, void *ptr)
{
  XtManageChild(snd_widget(sp,W_snd_ctrls));
  XtVaSetValues(snd_widget(sp,W_snd_ctrls),XmNpaneMinimum,1,NULL);
  return(0);
}

int sound_lock_ctrls(snd_info *sp, void *ptr)
{
  snd_state *ss;
  ss = (snd_state *)(sp->state);
  XtUnmanageChild(snd_widget(sp,W_snd_ctrls));
  XtVaSetValues(snd_widget(sp,W_snd_ctrls),XmNpaneMinimum,ss->ctrls_height,NULL);
  return(0);
}

static char *short_sound_format (int format)
{
  switch (format)
    {
    case snd_16_linear: case snd_16_linear_little_endian: case snd_16_unsigned: case snd_16_unsigned_little_endian: return("short"); break;
    case snd_8_mulaw: return("mulaw"); break;
    case snd_8_linear: return("byte"); break;
    case snd_32_float: case snd_32_float_little_endian: case snd_32_vax_float: return("float"); break;
    case snd_32_linear: case snd_32_linear_little_endian: return("int"); break;
    case snd_8_alaw: return("alaw"); break;
    case snd_8_unsigned: return("char"); break;
    case snd_24_linear: case snd_24_linear_little_endian: return("24-bit"); break;
    case snd_64_double: case snd_64_double_little_endian: return("double"); break;
    case snd_12_linear: case snd_12_linear_little_endian: case snd_12_unsigned: case snd_12_unsigned_little_endian: return("12-bit"); break;
    default: return(snd_string_unknown); break;
    }
}

static char link_file[128];
static char *linked_file(char *link_name)
{
  int bytes;
#ifndef VMS
  bytes = readlink(link_name,link_file,128);
  if (bytes > 0)
    {
      link_file[bytes] = 0;
      return(link_file);
    }
  else return("?");
#else
  return("?");
#endif
}

static char timebuf[64];

static void W_name_Click_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  char *str;
  file_info *hdr;
  float dur;
  int linked = 0;
  snd_info *sp = (snd_info *)clientData;
  if (sp)
    {
      hdr = sp->hdr;
      if (hdr)
	{
	  linked = is_link(sp->fullname);
	  dur = (float)(hdr->samples)/(float)(hdr->chans * hdr->srate);
	  str = (char *)calloc(256,sizeof(char));
#if (!defined(BEOS)) && (!defined(HAVE_CONFIG_H)) || defined(HAVE_STRFTIME)
	  strftime(timebuf,64,"%d-%b-%y %H:%M",localtime(&(sp->write_date)));
#else
	  sprintf(timebuf,"");
#endif
	  sprintf(str,"%d, %d chan%s, %.3f sec%s, %s:%s, %s%s%s%s",
		  hdr->srate,
		  hdr->chans,
		  ((hdr->chans > 1) ? "s" : ""),
		  dur,
		  ((dur == 1.0) ? "" : "s"),
		  sound_type_name(hdr->type),
		  short_sound_format(hdr->format),
		  timebuf,
		  (linked) ? ", (link to " : "",
		  (linked) ? linked_file(sp->fullname) : "",
		  (linked) ? ")" : "");
	  report_in_minibuffer(sp,str);
	  free(str);
	}
    }
}

static char number_one[5]={'1',snd_string_decimal,'0','0','\0'};
static char number_zero[5]={'0',snd_string_decimal,'0','0','\0'};
static char semitone_one[5]={' ',' ',' ','0','\0'};
static char ratio_one[5]={' ','1','/','1','\0'};

static char amp_number_buffer[5]={'1',snd_string_decimal,'0','0','\0'};

int snd_amp_to_int(float amp)
{
  int val;
  if (amp <= 0.0)
    val = 0;
  else
    {
      val = round(amp / (float)(SCROLLBAR_LINEAR_MULT));
      if (val > SCROLLBAR_LINEAR_MAX)
	{
	  val = round((log(amp)*((float)SCROLLBAR_MAX*.2)) + SCROLLBAR_MID);
	}
    }
  return(val);
}

void snd_amp_changed(snd_info *sp, int val)
{
  char *sfs;
  if (val == 0) 
    sp->amp = 0.0;
  else 
    {
      if (val < SCROLLBAR_LINEAR_MAX)
	sp->amp = (float)val * SCROLLBAR_LINEAR_MULT;
      else sp->amp = exp((float)(val-SCROLLBAR_MID)/((float)SCROLLBAR_MAX*.2));
    }
  sfs=prettyf(sp->amp,2);
  fill_number(sfs,amp_number_buffer);
  make_name_label(snd_widget(sp,W_snd_amp_number),amp_number_buffer);
  if (sp->recording) record_amp_change(sp,val,sp->amp);
  free(sfs);
}

static void W_amp_Click_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  XButtonEvent *ev;
  int val;
  snd_context *sx;
  sx = sp->sgx;
  ev = (XButtonEvent *)(cb->event);
  if (ev->state & (snd_ControlMask | snd_MetaMask)) val = sp->last_amp; else val = 50;
  snd_amp_changed(sp,val);
  XtVaSetValues(sx->snd_widgets[W_snd_amp],XmNvalue,val,NULL);
}

static void W_amp_Drag_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_amp_changed((snd_info *)clientData,((XmScrollBarCallbackStruct *)callData)->value);
}

static void W_amp_ValueChanged_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  sp->last_amp = cb->value;
  snd_amp_changed(sp,cb->value);
}



static char srate_number_buffer[5]={'1',snd_string_decimal,'0','0','\0'};

int snd_srate_to_int(float val)
{
  if (val > 0.0)
    return(round(450.0 + 150.0 * log(val)));
  else return(0);
}

void snd_srate_changed(snd_info *sp, int ival)
{
  snd_state *ss;
  ss = sp->state;
  sp->srate = srate_changed(ival,srate_number_buffer,speed_style(ss),speed_tones(ss));
  make_name_label(snd_widget(sp,W_snd_srate_number),srate_number_buffer);
  if (sp->recording) record_speed_change(sp,ival,sp->srate);
}

static void W_srate_Click_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  XButtonEvent *ev;
  int val;
  snd_context *sx;
  sx = sp->sgx;
  ev = (XButtonEvent *)(cb->event);
  if (ev->state & (snd_ControlMask | snd_MetaMask)) val = sp->last_srate; else val = 450;
  snd_srate_changed(sp,val);
  XtVaSetValues(sx->snd_widgets[W_snd_srate],XmNvalue,val,NULL);
}

static void W_srate_Drag_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_srate_changed((snd_info *)clientData,((XmScrollBarCallbackStruct *)callData)->value);
}

static void W_srate_ValueChanged_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  sp->last_srate = cb->value;
  snd_srate_changed(sp,cb->value);
}

void toggle_direction_arrow(snd_info *sp, int state)
{
  XmToggleButtonSetState(snd_widget(sp,W_snd_srate_arrow),state,TRUE);
}



static char expand_number_buffer[5]={'1',snd_string_decimal,'0','0','\0'};

int snd_expand_to_int(float ep)
{
  int val;
  val = ep/.0009697;
  if (val>100) val = round(450+150*log(ep));
  return(val);
}

void snd_expand_changed(snd_info *sp, int val)
{
  char *sfs;
  if (val < 100)
    sp->expand = (float)val * .0009697;
  else sp->expand = exp((float)(val-450)/150.0);
  sfs=prettyf(sp->expand,2);
  fill_number(sfs,expand_number_buffer);
  make_name_label(snd_widget(sp,W_snd_expand_number),expand_number_buffer);
  if ((sp->recording) && (sp->expanding)) record_expand_change(sp,val,sp->expand);
  free(sfs);
}

static void W_expand_Click_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  XButtonEvent *ev;
  int val;
  snd_context *sx;
  sx = sp->sgx;
  ev = (XButtonEvent *)(cb->event);
  if (ev->state & (snd_ControlMask | snd_MetaMask)) val = sp->last_expand; else val = 450;
  snd_expand_changed(sp,val);
  XtVaSetValues(sx->snd_widgets[W_snd_expand],XmNvalue,val,NULL);
}

static void W_expand_Drag_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_expand_changed((snd_info *)clientData,((XmScrollBarCallbackStruct *)callData)->value);
}

static void W_expand_ValueChanged_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  sp->last_expand = cb->value;
  snd_expand_changed(sp,cb->value);
}

static void Expand_button_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData; 
  snd_info *sp = (snd_info *)clientData;
  ss = sp->state;
  sp->expanding = cb->set;
  if (!(ss->using_schemes)) XmChangeColor(snd_widget(sp,W_snd_expand),(Pixel)((sp->expanding) ? ((ss->sgx)->scale) : ((ss->sgx)->main)));
}

void toggle_expand_button(snd_info *sp, int state)
{
  XmToggleButtonSetState(snd_widget(sp,W_snd_expand_button),state,TRUE);
}



static char contrast_number_buffer[5]={'0',snd_string_decimal,'0','0','\0'};

int snd_contrast_to_int(float val)
{
  return(round(val*10));
}

void snd_contrast_changed(snd_info *sp, int val)
{
  char *sfs;
  sp->contrast = (float)val/10.0;
  sfs=prettyf(sp->contrast,2);
  fill_number(sfs,contrast_number_buffer);
  make_name_label(snd_widget(sp,W_snd_contrast_number),contrast_number_buffer);
  if ((sp->recording) && (sp->contrasting)) record_contrast_change(sp,val,sp->contrast);
  free(sfs);
}

static void W_contrast_Click_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  XButtonEvent *ev;
  int val;
  snd_context *sx;
  sx = sp->sgx;
  ev = (XButtonEvent *)(cb->event);
  if (ev->state & (snd_ControlMask | snd_MetaMask)) val = sp->last_contrast; else val = 0;
  snd_contrast_changed(sp,val);
  XtVaSetValues(sx->snd_widgets[W_snd_contrast],XmNvalue,val,NULL);
}

static void W_contrast_Drag_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_contrast_changed((snd_info *)clientData,((XmScrollBarCallbackStruct *)callData)->value);
}

static void W_contrast_ValueChanged_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  sp->last_contrast = cb->value;
  snd_contrast_changed(sp,cb->value);
}

static void Contrast_button_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  ss = sp->state;
  sp->contrasting = cb->set;
  if (!(ss->using_schemes)) XmChangeColor(snd_widget(sp,W_snd_contrast),(Pixel)((sp->contrasting) ? ((ss->sgx)->scale) : ((ss->sgx)->main)));
}

void toggle_contrast_button(snd_info *sp, int state)
{
  XmToggleButtonSetState(snd_widget(sp,W_snd_contrast_button),state,TRUE);
}



static char revscl_number_buffer[7]={'0',snd_string_decimal,'0','0','0','0','\0'};
static char number_long_zero[7]={'0',snd_string_decimal,'0','0','0','0','\0'};

int snd_revscl_to_int(float val)
{
  return(round(pow(val,0.333)*60.0));
}

void snd_revscl_changed(snd_info *sp, int val)
{
  char *fs,*ps,*sfs;
  int i,j;
  sp->revscl = cube((float)val/60.0);
  sfs=prettyf(sp->revscl,3);
  fs=sfs;
  ps=(char *)(revscl_number_buffer);
  j=strlen(fs);
  if (j>6) j=6;
  if (j<6) 
    {
      revscl_number_buffer[5]='0';
      revscl_number_buffer[4]='0'; 
      revscl_number_buffer[3]='0';
      revscl_number_buffer[2]='0'; 
      revscl_number_buffer[1]=snd_string_decimal;
    }
  for (i=0;i<j;i++) (*ps++) = (*fs++);
  make_name_label(snd_widget(sp,W_snd_revscl_number),revscl_number_buffer);
  if ((sp->recording) && (sp->reverbing)) record_reverb_change(sp,val,sp->revscl);
  free(sfs);
}

static void W_revscl_Click_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  XButtonEvent *ev;
  int val;
  snd_context *sx;
  sx = sp->sgx;
  ev = (XButtonEvent *)(cb->event);
  if (ev->state & (snd_ControlMask | snd_MetaMask)) val = sp->last_revscl; else val = 0;
  snd_revscl_changed(sp,val);
  XtVaSetValues(sx->snd_widgets[W_snd_revscl],XmNvalue,val,NULL);
}


static void W_revscl_Drag_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_revscl_changed((snd_info *)clientData,((XmScrollBarCallbackStruct *)callData)->value);
}

static void W_revscl_ValueChanged_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  sp->last_revscl = cb->value;
  snd_revscl_changed(sp,cb->value);
}



static char revlen_number_buffer[5]={'1',snd_string_decimal,'0','0','\0'};

int snd_revlen_to_int(float val)
{
  return(round(val*20.0));
}

void snd_revlen_changed(snd_info *sp, int val)
{
  char *sfs;
  sp->revlen = (float)val/20.0;
  sfs=prettyf(sp->revlen,2);
  fill_number(sfs,revlen_number_buffer);
  make_name_label(snd_widget(sp,W_snd_revlen_number),revlen_number_buffer);
  free(sfs);
}

static void W_revlen_Click_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  XButtonEvent *ev;
  int val;
  snd_context *sx;
  sx = sp->sgx;
  ev = (XButtonEvent *)(cb->event);
  if (ev->state & (snd_ControlMask | snd_MetaMask)) val = sp->last_revlen; else val = 20;
  snd_revlen_changed(sp,val);
  XtVaSetValues(sx->snd_widgets[W_snd_revlen],XmNvalue,val,NULL);
}

static void W_revlen_Drag_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_revlen_changed((snd_info *)clientData,((XmScrollBarCallbackStruct *)callData)->value);
}

static void W_revlen_ValueChanged_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)callData;
  snd_info *sp = (snd_info *)clientData;
  sp->last_revlen = cb->value;
  snd_revlen_changed(sp,cb->value);
}



static void Reverb_button_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  ss = sp->state;
  sp->reverbing = cb->set;
  if (!(ss->using_schemes))
    {
      XmChangeColor(snd_widget(sp,W_snd_revlen),(Pixel)((sp->reverbing) ? ((ss->sgx)->scale) : ((ss->sgx)->main)));
      XmChangeColor(snd_widget(sp,W_snd_revscl),(Pixel)((sp->reverbing) ? ((ss->sgx)->scale) : ((ss->sgx)->main)));
    }
}

void toggle_reverb_button(snd_info *sp, int state)
{
  XmToggleButtonSetState(snd_widget(sp,W_snd_reverb_button),state,TRUE);
}

static void Filter_button_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  sp->filtering = cb->set;
}

void toggle_filter_button(snd_info *sp, int state)
{
  XmToggleButtonSetState(snd_widget(sp,W_snd_filter_button),state,TRUE);
}

void filter_order_changed(snd_info *sp, int order)
{
  char *fltorder;
  fltorder = (char *)calloc(4,sizeof(char));
  sprintf(fltorder,"%d",order);
  XmTextSetString(snd_widget(sp,W_snd_filter_order),fltorder);
  sp->filter_order = order;
  free(fltorder);
}

void filter_env_changed(snd_info *sp, env *e)
{
  /* turn e back into a string for textfield widget */
  XmTextSetString(snd_widget(sp,W_snd_filter),env_to_string(e));
}

static void filter_textfield_deactivate(snd_info *sp)
{
  chan_info *active_chan;
  Widget graph;
  active_chan = current_channel(sp);
  graph = chan_widget(active_chan,W_chn_graph);
  if ((XmIsTraversable(graph)) && (XmGetVisibility(graph) != XmVISIBILITY_FULLY_OBSCURED))
    XmProcessTraversal(graph,XmTRAVERSE_CURRENT);
}

static void Filter_Order_activate_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  char *str;
  int order;
  snd_info *sp = (snd_info *)clientData;
  str = XmTextGetString(w);
  if ((str) && (*str))
    {
      sscanf(str,"%d",&order);
      sp->filter_order = order;
    }
  filter_textfield_deactivate(sp);
}

/* TODO: fft-filter (i.e. envelope window superimposed on spectrum) */

static env *load_filter_coeffs(char *file)
{
  /* assumed to be a file of bare floats in machine byte order */
  int len,fd,bytes;
  float *data;
  env *e;
  fd = open(file,O_RDONLY,0);
  if (fd == -1) return(NULL);
  bytes = lseek(fd,0L,2);
  len = bytes/4;
  if (len < 2) {close(fd); return(NULL);}
  lseek(fd,0L,0);
  data = (float *)calloc(len,sizeof(float));
  read(fd,(unsigned char *)data,len*4);
  e = make_envelope(data,len);
  close(fd);
  free(data);
  return(e);
}

static void Filter_activate_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* make an envelope out of the data */
  snd_info *sp = (snd_info *)clientData;
  char *str;
  int end_of_text,err;
  str = XmTextGetString(w);
  while ((str) && (isspace(*str))) str++;
  if (isalpha(*str))
    {
      sp->filter_is_envelope = 0;
      sp->filter_env = load_filter_coeffs(str);
      if (!(sp->filter_env))
	{
	  end_of_text = XmTextGetLastPosition(w);
	  XmTextInsert(w,end_of_text," ");
	  XmTextInsert(w,end_of_text+1,snd_string_not_found);
	}
    }
  else
    {
      sp->filter_is_envelope = 1;
      sp->filter_env = scan_envelope_and_report_error(sp,XmTextGetString(w),&err);
    }
  filter_textfield_deactivate(sp);
}

/* ---------------- reflect control panel slider/button defaults ---------------- */

static void reflect_control_panel_defaults(snd_state *ss, snd_info *sp)
{
  float spdf;
  int val;
  toggle_expand_button(sp,default_expanding(ss));
  toggle_reverb_button(sp,default_reverbing(ss));
  toggle_contrast_button(sp,default_contrasting(ss));
  toggle_filter_button(sp,default_filtering(ss));
  snd_revlen_changed(sp,snd_revlen_to_int(default_reverb_length(ss)));
  snd_revscl_changed(sp,snd_revscl_to_int(default_reverb_scale(ss)));
  snd_expand_changed(sp,snd_expand_to_int(default_expand(ss)));
  snd_amp_changed(sp,snd_amp_to_int(default_amp(ss)));
  if (default_speed(ss) < 0.0)
    {
      spdf = -(default_speed(ss));
      sp->play_direction = -1;
    }
  else
    {
      spdf = (default_speed(ss));
      sp->play_direction = 1;
    }
  val = snd_srate_to_int(spdf);
  snd_srate_changed(sp,val);
  XtVaSetValues(snd_widget(sp,W_snd_srate),XmNvalue,val,NULL);
  toggle_direction_arrow(sp,(sp->play_direction == -1)); /* true here means reversed playback */
  snd_contrast_changed(sp,snd_contrast_to_int(default_contrast(ss)));
  XtVaSetValues(snd_widget(sp,W_snd_amp),XmNvalue,snd_amp_to_int(default_amp(ss)),NULL);
  XtVaSetValues(snd_widget(sp,W_snd_expand),XmNvalue,snd_expand_to_int(default_expand(ss)),NULL);
  XtVaSetValues(snd_widget(sp,W_snd_contrast),XmNvalue,snd_contrast_to_int(default_contrast(ss)),NULL);
  XtVaSetValues(snd_widget(sp,W_snd_revlen),XmNvalue,snd_revlen_to_int(default_reverb_length(ss)),NULL);
  XtVaSetValues(snd_widget(sp,W_snd_revscl),XmNvalue,snd_revscl_to_int(default_reverb_scale(ss)),NULL);
  filter_order_changed(sp,default_filter_order(ss));
}

void set_play_button(snd_info *sp, int val)
{
  XmToggleButtonSetState(snd_widget(sp,W_snd_play),val,FALSE);
  set_file_browser_play_button(sp->shortname,val);
}

static void Play_button_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_info *sp = (snd_info *)clientData;
  chan_info *cp;
  snd_state *ss;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  int i;
  XButtonEvent *ev;
  ev = (XButtonEvent *)(cb->event);
  if (sp->playing) 
    {
      if (sp->cursor_follows_play)
	{
	  for (i=0;i<sp->nchans;i++)
	    {
	      cp = sp->chans[i];
	      cp->original_cursor = cp->cursor;
	    }
	}
      stop_playing(sp->playing);
    }
  if (!(sp->cursor_follows_play))         /* can be set in init file */
    sp->cursor_follows_play = (ev->state & (snd_ControlMask | snd_MetaMask));
  set_file_browser_play_button(sp->shortname,cb->set);
  goto_graph(any_selected_channel(sp));
  if (cb->set) 
    {
      ss = sp->state;
      XtVaSetValues(w,XmNselectColor,((sp->cursor_follows_play) ? ((ss->sgx)->mixpix) : ((ss->sgx)->text)),NULL);
      start_playing(sp,0);
    }
}

typedef struct {int pausing; snd_state *ss;} pause_data;

static int set_play_button_pause(snd_info *sp, void *ptr)
{
  pause_data *pd = (pause_data *)ptr;
  snd_state *ss;
  Widget w;
  if (sp->playing)
    {
      ss = pd->ss;
      w = snd_widget(sp,W_snd_play);
      if (pd->pausing)
	XtVaSetValues(w,XmNselectColor,(ss->sgx)->red,NULL);
      else XtVaSetValues(w,XmNselectColor,((sp->cursor_follows_play) ? ((ss->sgx)->mixpix) : ((ss->sgx)->text)),NULL);
    }
  return(0);
}

void play_button_pause(snd_state *ss, int pausing)
{
  pause_data *pd;
  pd = (pause_data *)calloc(1,sizeof(pause_data));
  pd->pausing = pausing;
  pd->ss = ss;
  map_over_sounds(ss,set_play_button_pause,(void *)pd);
  free(pd);
}


static void Play_arrow_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  int dir;
  dir = cb->set;
  if (dir) sp->play_direction = -1; else sp->play_direction = 1;
  if (sp->recording) record_direction_change(sp,dir,sp->play_direction);
}

void syncb(snd_info *sp, int on)
{
  sp->syncing = on;
  XmToggleButtonSetState(snd_widget(sp,W_snd_sync),on,FALSE);
}

static void Sync_button_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  chan_info *cp;
  sp->syncing = cb->set;
  cp = any_selected_channel(sp);
  goto_graph(cp);
  if (sp->syncing) 
    {
      apply_x_axis_change(cp->axis,cp,sp);
      /* also sync up cursors -- 15-May-97 */
      cursor_moveto(cp,cp->cursor);
    }
}

void combineb(snd_info *sp, int val)
{
  switch (val)
    {
    case CHANNELS_SEPARATE: separate_sound(sp); break; /* snd-xchn.c -> change_channel_style */
    case CHANNELS_COMBINED: combine_sound(sp); break;
    case CHANNELS_SUPERIMPOSED: superimpose_sound(sp); break;
    }
}

static void Combine_button_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* click if set unsets, click if unset->combine, ctrl-click->superimpose */
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  XButtonEvent *ev;
  int val;
  ev = (XButtonEvent *)(cb->event);
  if (cb->set)
    {
      if (ev->state & (snd_ControlMask | snd_MetaMask)) 
	val = CHANNELS_SUPERIMPOSED;
      else val = CHANNELS_COMBINED;
    }
  else val = CHANNELS_SEPARATE;
  combineb(sp,val);
}


static Boolean xrun_amp_env (XtPointer sp)
{
  /* this extra step is needed to get around various X-isms */
  return(run_amp_env((snd_info *)sp));
}

void start_amp_env(snd_info *sp, int anew)
{
  /* fire up work proc for amp env */
  Widget info_sep;
  snd_state *ss;
  snd_context *sgx;
  ss = sp->state;
  if (subsampling(ss))
    {
      sgx = sp->sgx;
      if (!(sgx->env_in_progress))
	{
	  info_sep = snd_widget(sp,W_snd_info_sep);
	  if (info_sep) XtVaSetValues(info_sep,XmNseparatorType,XmNO_LINE,NULL);
	  sp->env_anew = anew;
	  sgx->env_in_progress = XtAppAddWorkProc(XtWidgetToApplicationContext(main_PANE(sp)),xrun_amp_env,(XtPointer)sp);
	}
    }
}

void signal_amp_env_done(snd_info *sp)
{
  Widget info_sep;
  info_sep = snd_widget(sp,W_snd_info_sep);
  if (info_sep) XtVaSetValues(info_sep,XmNseparatorType,XmSHADOW_ETCHED_IN,NULL);
  alert_enved_amp_env(sp);
}

void remove_amp_env(snd_info *sp)
{
  /* assume someone else is dealing with the arrays */
  snd_context *sgx;
  sgx = sp->sgx;
  if (sgx->env_in_progress)
    {
      signal_amp_env_done(sp);
      XtRemoveWorkProc(sgx->env_in_progress);
      sgx->env_in_progress = 0;
    }
}

void remove_apply(snd_info *sp)
{
  snd_context *sgx;
  if ((sp) && (sgx = sp->sgx) && (sgx->apply_in_progress))
    {
      XtRemoveWorkProc(sgx->apply_in_progress);
      sgx->apply_in_progress = 0;
    }
}

static void Info_activate_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* can be response to various things */
  snd_info *sp = (snd_info *)clientData;
  snd_state *ss;
  XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *)callData;
  XKeyEvent *ev;
  KeySym keysym;
  ev = (XKeyEvent *)(cb->event);
  keysym = XKeycodeToKeysym(XtDisplay(w),(int)(ev->keycode),(ev->state & ShiftMask) ? 1 : 0);
  ss = sp->state;
  ss->mx_sp = sp; 
  snd_info_activate(sp,keysym);
}

static void Record_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* merge (record) changes in ctrl state into current state */
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  sp->recording = cb->set;
  if (sp->recording) 
    {
      initialize_record(sp);
      XmToggleButtonSetState(snd_widget(sp,W_snd_apply),FALSE,TRUE);
    }
}

static void Replay_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* run dac using current ctrls state (and envs, if any)
   * if any changes made (and record on), merge them into current state 
   */
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  sp->replaying = cb->set;
  if (sp->replaying) 
    {
      initialize_replay(sp);
      XmToggleButtonSetState(snd_widget(sp,W_snd_apply),FALSE,TRUE);
    }
  /* assume play explicit (may want to set several of these before starting) */
}

static Boolean xrun_apply(XtPointer sp)
{
  return(apply_controls((void *)sp));
}

static void Apply_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* create temp file of run over current file using the current (saved) ctrls state */
  snd_info *sp = (snd_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  snd_context *sgx;
  sgx = sp->sgx;
  sp->applying = cb->set;
  if (sp->applying) 
    {
      XmToggleButtonSetState(snd_widget(sp,W_snd_replay),FALSE,TRUE);
      XmToggleButtonSetState(snd_widget(sp,W_snd_record),FALSE,TRUE);
      sgx->apply_in_progress = XtAppAddWorkProc(XtWidgetToApplicationContext(main_PANE(sp)),xrun_apply,(XtPointer)make_apply_state(sp));
    }
  else 
    {
      stop_applying(sp);
    }
}

/* apply is only safe if the DAC is currently inactive and remains safe only
 * if all other apply buttons are locked out (and play).
 */

static int lockapply(snd_info *sp, void *up) 
{
  if (sp != up) XtSetSensitive(snd_widget(sp,W_snd_apply),FALSE);
  return(0);
}

void lock_apply(snd_state *ss, snd_info *sp)
{
  /* if playing or applying, set other applys to insensitive */
  map_over_sounds(ss,lockapply,(void *)sp);
}

static int lockplay(snd_info *sp, void *up) 
{
  XtSetSensitive(snd_widget(sp,W_snd_replay),FALSE);
  XtSetSensitive(snd_widget(sp,W_snd_record),FALSE);
  XtSetSensitive(snd_widget(sp,W_snd_play),FALSE);
  return(0);
}

void lock_play_and_record(snd_state *ss, snd_info *sp)
{
  /* if applying, set plays, records, and replays to insensitive */
  map_over_sounds(ss,lockplay,(void *)sp);
}

static int unlockapply(snd_info *sp, void *up) 
{
  if (sp != up) XtSetSensitive(snd_widget(sp,W_snd_apply),TRUE);
  return(0);
}

void unlock_apply(snd_state *ss,snd_info *sp)
{
  map_over_sounds(ss,unlockapply,(void *)sp);
}

static int unlockplay(snd_info *sp, void *up) 
{
  XtSetSensitive(snd_widget(sp,W_snd_replay),TRUE);
  XtSetSensitive(snd_widget(sp,W_snd_record),TRUE);
  XtSetSensitive(snd_widget(sp,W_snd_play),TRUE);
  return(0);
}

void unlock_play_and_record(snd_state *ss,snd_info *sp)
{
  map_over_sounds(ss,unlockplay,(void *)sp);
}

static int cant_write(char *name)
{
  return((access(name,W_OK)) != 0);
}

static void Set_Callback(Widget w,XtPointer clientData,XtPointer callData) {save_control_state((snd_info *)clientData);}
static void Reset_Callback(Widget w,XtPointer clientData,XtPointer callData) {restore_control_state((snd_info *)clientData);}

static void add_sound_callbacks(Widget *sw, XtPointer sps)
{
  int i;
  snd_info *sp;
  chan_info *cp;
  snd_state *ss;
  sp=(snd_info *)sps;
  ss=(snd_state *)(sp->state);
  XtAddCallback(sw[W_snd_play],XmNvalueChangedCallback,Play_button_Callback,sps);
  XtAddCallback(sw[W_snd_name],XmNactivateCallback,W_name_Click_Callback,sps);
  XtAddCallback(sw[W_snd_amp_label],XmNactivateCallback,W_amp_Click_Callback,sps);
  XtAddCallback(sw[W_snd_srate_label],XmNactivateCallback,W_srate_Click_Callback,sps);
  XtAddCallback(sw[W_snd_contrast_label],XmNactivateCallback,W_contrast_Click_Callback,sps);
  XtAddCallback(sw[W_snd_expand_label],XmNactivateCallback,W_expand_Click_Callback,sps);
  XtAddCallback(sw[W_snd_revscl_label],XmNactivateCallback,W_revscl_Click_Callback,sps);
  XtAddCallback(sw[W_snd_revlen_label],XmNactivateCallback,W_revlen_Click_Callback,sps);
  XtAddCallback(sw[W_snd_srate_arrow],XmNvalueChangedCallback,Play_arrow_Callback,sps);
  XtAddCallback(sw[W_snd_expand_button],XmNvalueChangedCallback,Expand_button_Callback,sps);
  XtAddCallback(sw[W_snd_contrast_button],XmNvalueChangedCallback,Contrast_button_Callback,sps);
  XtAddCallback(sw[W_snd_reverb_button],XmNvalueChangedCallback,Reverb_button_Callback,sps);
  XtAddCallback(sw[W_snd_filter_button],XmNvalueChangedCallback,Filter_button_Callback,sps);
  XtAddCallback(sw[W_snd_info],XmNactivateCallback,Info_activate_Callback,sps);
  XtAddCallback(sw[W_snd_filter_order],XmNactivateCallback,Filter_Order_activate_Callback,sps);
  XtAddCallback(sw[W_snd_filter],XmNactivateCallback,Filter_activate_Callback,sps);
  XtAddCallback(sw[W_snd_sync],XmNvalueChangedCallback,Sync_button_Callback,sps);
  if (sp->nchans > 1) XtAddCallback(sw[W_snd_combine],XmNvalueChangedCallback,Combine_button_Callback,sps);
  XtAddCallback(sw[W_snd_record],XmNvalueChangedCallback,Record_Callback,sps);
  XtAddCallback(sw[W_snd_replay],XmNvalueChangedCallback,Replay_Callback,sps);
  XtAddCallback(sw[W_snd_apply],XmNvalueChangedCallback,Apply_Callback,sps);
  XtAddCallback(sw[W_snd_set],XmNactivateCallback,Set_Callback,sps);
  XtAddCallback(sw[W_snd_reset],XmNactivateCallback,Reset_Callback,sps);
  for (i=0;i<sp->nchans;i++)
    {
      cp=sp->chans[i];
      add_chan_callbacks(cp);
    }
}

static void remove_sound_callbacks(snd_info *sp, XtPointer sps)
{
  snd_context *sx;
  Widget *sw;
  snd_state *ss;
  ss = (snd_state *)(sp->state);
  sx = sp->sgx;
  sw = sx->snd_widgets;
  XtRemoveCallback(sw[W_snd_play],XmNvalueChangedCallback,Play_button_Callback,sps);
  XtRemoveCallback(sw[W_snd_amp_label],XmNactivateCallback,W_amp_Click_Callback,sps);
  XtRemoveCallback(sw[W_snd_srate_label],XmNactivateCallback,W_srate_Click_Callback,sps);
  XtRemoveCallback(sw[W_snd_contrast_label],XmNactivateCallback,W_contrast_Click_Callback,sps);
  XtRemoveCallback(sw[W_snd_expand_label],XmNactivateCallback,W_expand_Click_Callback,sps);
  XtRemoveCallback(sw[W_snd_revscl_label],XmNactivateCallback,W_revscl_Click_Callback,sps);
  XtRemoveCallback(sw[W_snd_revlen_label],XmNactivateCallback,W_revlen_Click_Callback,sps);
  XtRemoveCallback(sw[W_snd_srate_arrow],XmNvalueChangedCallback,Play_arrow_Callback,sps);
  XtRemoveCallback(sw[W_snd_expand_button],XmNvalueChangedCallback,Expand_button_Callback,sps);
  XtRemoveCallback(sw[W_snd_contrast_button],XmNvalueChangedCallback,Contrast_button_Callback,sps);
  XtRemoveCallback(sw[W_snd_reverb_button],XmNvalueChangedCallback,Reverb_button_Callback,sps);
  XtRemoveCallback(sw[W_snd_filter_button],XmNvalueChangedCallback,Filter_button_Callback,sps);
  XtRemoveCallback(sw[W_snd_info],XmNactivateCallback,Info_activate_Callback,sps);
  XtRemoveCallback(sw[W_snd_filter_order],XmNactivateCallback,Filter_Order_activate_Callback,sps);
  XtRemoveCallback(sw[W_snd_filter],XmNactivateCallback,Filter_activate_Callback,sps);
  XtRemoveCallback(sw[W_snd_sync],XmNvalueChangedCallback,Sync_button_Callback,sps);
  if (sp->nchans > 1) XtRemoveCallback(sw[W_snd_combine],XmNvalueChangedCallback,Combine_button_Callback,sps);
  XtRemoveCallback(sw[W_snd_record],XmNvalueChangedCallback,Record_Callback,sps);
  XtRemoveCallback(sw[W_snd_replay],XmNvalueChangedCallback,Replay_Callback,sps);
  XtRemoveCallback(sw[W_snd_apply],XmNvalueChangedCallback,Apply_Callback,sps);
  XtRemoveCallback(sw[W_snd_set],XmNactivateCallback,Set_Callback,sps);
  XtRemoveCallback(sw[W_snd_reset],XmNactivateCallback,Reset_Callback,sps);
}

/* bitmaps for the playback direction arrow */
static unsigned char speed_r_bits[] = {
   0x00, 0x04, 0x10, 0x08, 0x00, 0x10, 0x04, 0x20, 0x00, 0x40, 0xa5, 0xbf,
   0x00, 0x40, 0x04, 0x20, 0x00, 0x10, 0x10, 0x08, 0x00, 0x04, 0x00, 0x00};
static unsigned char speed_l_bits[] = {
   0x20, 0x00, 0x10, 0x08, 0x08, 0x00, 0x04, 0x20, 0x02, 0x00, 0xfd, 0xa5,
   0x02, 0x00, 0x04, 0x20, 0x08, 0x00, 0x10, 0x08, 0x20, 0x00, 0x00, 0x00};

#if HAVE_XPM
#include <X11/xpm.h>
/* XPM icon for lock (read-only file) */

static char * mini_lock_xpm[] = {
"16 14 6 1",
" 	c None s None",
".	c gray50",
"X	c black",
"o	c white",
"O	c yellow",
"-      c ivory2",
"------.XXX.-----",
"-----X.ooo.X----",
"----..oXXXo..---",
"----XoX...XoX---",
"----XoX.--XoX.--",
"----XoX.--XoX.--",
"---XXXXXXXXXXX--",
"---XOOOOOOOOOX.-",
"---XO.......OX.-",
"---XOOOOOOOOOX.-",
"---XO.......OX.-",
"---XOOOOOOOOOX.-",
"---XXXXXXXXXXX.-",
"----...........-"};

static Pixmap mini_lock;
static int mini_lock_allocated = 0;

static char * mini_bomb_xpm[] = {
"16 14 7 1",
" 	c None s None",
".	c black",
"X	c gray50",
"o	c gray85",
"O	c red",
"#	c white",
"-      c ivory2",
"-------...------",
"------.---.-----",
"-----.-----.----",
"----...-----.---",
"---.....----.---",
"--.X#o...----.--",
"-X.#X....X---.--",
"-..oX.....---O-O",
"-.......O.-O-OO-",
"-......Xo.--OOO-",
"-X.....X.X--O---",
"--.......-------",
"---X...X--------",
"----------------"};

static Pixmap mini_bomb;

void snd_file_lock_icon(snd_info *sp, int on)
{
  if (mini_lock) XtVaSetValues(snd_widget(sp,W_snd_name_icon),XmNlabelPixmap,(on) ? mini_lock : XmUNSPECIFIED_PIXMAP,NULL);
  /* these Pixmaps can be null if the colormap is screwed up */
}

void snd_file_bomb_icon(snd_info *sp, int on)
{
  if (mini_bomb) XtVaSetValues(snd_widget(sp,W_snd_name_icon),XmNlabelPixmap,(on) ? mini_bomb : XmUNSPECIFIED_PIXMAP,NULL);
}

#else
void snd_file_lock_icon(snd_info *sp, int on) {}
void snd_file_bomb_icon(snd_info *sp, int on) {if (on) report_in_minibuffer(sp,snd_string_file_has_changed);}
#endif

snd_info *add_sound_window (char *filename, snd_state *state)
{  
  snd_info *sp,*osp;
  file_info *hdr;
  Widget *sw;
  XmString s1;
  int snd_slot,nchans,make_widgets,i,k,need_colors,n,old_chans;
  Arg args[32];
  char *old_name = NULL;
  Dimension app_y,app_dy,screen_y,chan_min_y;
  /* these dimensions are used to try to get a reasonable channel graph size without falling off the screen bottom */
  Pixmap rb,lb;
  XGCValues v;
  int depth;
  int samples_per_channel;
  Widget form;
  snd_context *sx;
  snd_slot = find_free_sound_slot(state); /* expands sound list if needed */
  snd_IO_error = snd_no_error;
  errno = 0;
  hdr = make_file_info(filename,state);
  if (!hdr) return(NULL);
  if (state->pending_change) 
    {
      old_name = filename;
      filename = state->pending_change;
      state->pending_change = NULL;
    }
  nchans = hdr->chans;
  samples_per_channel = hdr->samples/nchans;

  XtVaGetValues(main_SHELL(state),XmNy,&app_y,XmNheight,&app_dy,NULL);
  screen_y = DisplayHeight(main_DISPLAY(state),main_SCREEN(state));
  app_dy = (screen_y - app_y - app_dy - 20*nchans);
  chan_min_y = (Dimension)(app_dy/(Dimension)nchans);
  if (chan_min_y > (Dimension)(state->channel_min_height)) chan_min_y = state->channel_min_height; else if (chan_min_y < 5) chan_min_y = 5;
  if (state->sounds[snd_slot]) /* we're trying to re-use an old, inactive set of widgets and whatnot */
    {
      osp = state->sounds[snd_slot];
      old_chans = osp->allocated_chans;
    }
  else old_chans = 0;
  make_widgets = (state->sounds[snd_slot] == NULL);
  state->sounds[snd_slot] = make_snd_info(state->sounds[snd_slot],state,filename,hdr,snd_slot);
  sp = state->sounds[snd_slot];
  sp->inuse = 1;
  sx = sp->sgx;
  sw = sx->snd_widgets;
  if ((!make_widgets) && (old_chans < nchans))
    {
      for (i=old_chans;i<nchans;i++) add_channel_window(sp,i,state,chan_min_y,1,NULL,WITH_FW_BUTTONS);
    }

  if (make_widgets)
    {
      need_colors = (!(state->using_schemes));

      n=0;      
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNallowResize,TRUE); n++;
      XtSetArg(args[n],XmNsashIndent,CHANNEL_SASH_INDENT); n++;

      /* if (mumble_style(state) == CHANNELS_HORIZONTAL) {XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;} */
      /* this doesn't work yet because the control panel is screwed up when trying to display itself horizontally */
      /* Perhaps another layer of panes? */

      if (state->listening) {XtSetArg(args[n],XmNpositionIndex,snd_slot); n++;}
#if (!(PANED_WINDOWS_BUGGY))
      sw[W_snd_pane] = XtCreateManagedWidget("snd-pane",xmPanedWindowWidgetClass,sound_PANE(state),args,n);
#else
      sw[W_snd_pane] = XtCreateManagedWidget("snd-pane",xmRowColumnWidgetClass,sound_PANE(state),args,n);
#endif
      XtAddCallback(sw[W_snd_pane],XmNhelpCallback,W_name_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_pane],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      /* if user clicks in controls, then starts typing, try to send key events to current active channel */
      /* all widgets in the control-pane that would otherwise intercept the key events get this event handler */

      for (i=0;i<nchans;i++) add_channel_window(sp,i,state,chan_min_y,0,NULL,WITH_FW_BUTTONS);
      
      n=0;      
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNpaneMinimum,state->ctrls_height); n++;
      XtSetArg(args[n],XmNpaneMaximum,state->ctrls_height); n++;
      sw[W_snd_ctrls] = XtCreateManagedWidget ("snd-ctrls",xmFormWidgetClass,sw[W_snd_pane],args,n);

      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      sw[W_snd_name_form] = XtCreateManagedWidget("snd-name-form",xmFormWidgetClass,sw[W_snd_ctrls],args,n);
      XtAddCallback(sw[W_snd_name_form],XmNhelpCallback,W_name_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_name_form],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);

      n=0;      
      s1=XmStringCreateLtoR(shortname(sp),XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_high_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
      sw[W_snd_name] = XtCreateManagedWidget ("snd-name",xmPushButtonWidgetClass,sw[W_snd_name_form],args,n);
      XtAddCallback(sw[W_snd_name],XmNhelpCallback,W_name_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_name],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);

      n=0;      
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_name]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelType,XmPIXMAP); n++;
      XtSetArg(args[n],XmNlabelPixmap,XmUNSPECIFIED_PIXMAP); n++;
      sw[W_snd_name_icon] = XtCreateManagedWidget("snd-info-icon",xmLabelWidgetClass,sw[W_snd_name_form],args,n);
#if HAVE_XPM
      if (!mini_lock_allocated)
	{ 
	  Pixmap shape1,shape2; 
	  XpmAttributes attributes; 
	  int scr;
	  Display *dp;
	  Drawable wn;
	  dp = XtDisplay(sw[W_snd_name]);
	  wn = XtWindow(sw[W_snd_name]);
	  scr = DefaultScreen(dp);
	  XtVaGetValues(sw[W_snd_name],XmNdepth,&attributes.depth,XmNcolormap,&attributes.colormap,NULL);
	  attributes.visual = DefaultVisual(dp,scr);
	  attributes.valuemask = XpmDepth | XpmColormap | XpmVisual;
	  XpmCreatePixmapFromData(dp,wn,mini_lock_xpm,&mini_lock,&shape1,&attributes);
	  XpmCreatePixmapFromData(dp,wn,mini_bomb_xpm,&mini_bomb,&shape2,&attributes);
	  mini_lock_allocated = 1;
      }
#endif

      n=0;      
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNbottomWidget,sw[W_snd_name]); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_name_icon]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
      XtSetArg(args[n],XmNwidth,20); n++; /* was 40 */
      XtSetArg(args[n],XmNseparatorType,XmSHADOW_ETCHED_IN); n++;
      sw[W_snd_info_sep] = XtCreateManagedWidget ("snd-info-sep",xmSeparatorWidgetClass,sw[W_snd_name_form],args,n);
      XtAddCallback(sw[W_snd_info_sep],XmNhelpCallback,W_info_sep_Help_Callback,state);

      n=0;
      s1=XmStringCreate("     ","button_font");
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNbottomWidget,sw[W_snd_info_sep]); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_info_sep]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNfontList,button_FONT(state)); n++;
      sw[W_snd_info_label] = XtCreateManagedWidget ("snd-info-label",xmLabelWidgetClass,sw[W_snd_name_form],args,n);
      XtAddCallback(sw[W_snd_info_label],XmNhelpCallback,W_info_Help_Callback,state);
      XmStringFree(s1);

      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_info_label]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNfontList,bold_button_FONT(state)); n++;
      XtSetArg(args[n],XmNresizeWidth,TRUE); n++;
      XtSetArg(args[n],XmNmarginHeight,1); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNcolumns,30); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      sw[W_snd_info] = sndCreateTextFieldWidget(state,"snd-info",sw[W_snd_name_form],args,n,TRUE);
      XtAddCallback(sw[W_snd_info],XmNhelpCallback,W_info_Help_Callback,state);

      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
#if NEED_TOGGLE_SIZE
      XtSetArg(args[n],XmNmarginHeight,TOGGLE_MARGIN); n++;
      XtSetArg(args[n],XmNmarginTop,TOGGLE_MARGIN); n++;
#endif
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNfontList,button_FONT(state)); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_play] = XtCreateManagedWidget(snd_string_play,xmToggleButtonWidgetClass,sw[W_snd_name_form],args,n);
      XtAddCallback(sw[W_snd_play],XmNhelpCallback,W_play_Help_Callback,state);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_play]);
#endif

      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
#if NEED_TOGGLE_SIZE
      XtSetArg(args[n],XmNmarginHeight,TOGGLE_MARGIN); n++;
      XtSetArg(args[n],XmNmarginTop,TOGGLE_MARGIN); n++;
#endif
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_play]); n++;
      XtSetArg(args[n],XmNfontList,button_FONT(state)); n++;
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_sync] = XtCreateManagedWidget(snd_string_sync,xmToggleButtonWidgetClass,sw[W_snd_name_form],args,n);
      XtAddCallback(sw[W_snd_sync],XmNhelpCallback,W_sync_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_sync],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_sync]);
#endif

      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNbottomWidget,sw[W_snd_sync]); n++;
#if NEED_TOGGLE_SIZE
      XtSetArg(args[n],XmNmarginHeight,TOGGLE_MARGIN); n++;
      XtSetArg(args[n],XmNmarginTop,TOGGLE_MARGIN); n++;
#endif
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_sync]); n++;
      XtSetArg(args[n],XmNfontList,button_FONT(state)); n++;
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_combine] = XtCreateManagedWidget(snd_string_unite,xmToggleButtonWidgetClass,sw[W_snd_name_form],args,n);
      XtAddCallback(sw[W_snd_combine],XmNhelpCallback,W_combine_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_combine],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_combine]);
#endif

      n=0;
      XtVaSetValues(sw[W_snd_ctrls],XmNskipAdjust,TRUE,NULL);

      /* tried a dial widget here, but it didn't seem to fit and was harder to manipulate and read than a scale */
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_name_form]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNmargin,LINE_MARGIN); n++;
      XtSetArg(args[n],XmNheight,LINE_MARGIN); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      sw[W_snd_amp_separator] = XtCreateManagedWidget ("snd-amp-sep",xmSeparatorWidgetClass,sw[W_snd_ctrls],args,n);
      XtAddCallback(sw[W_snd_amp_separator],XmNhelpCallback,W_amp_Help_Callback,state);

      n=0;      
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_amp_separator]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      sw[W_snd_amp_form] = XtCreateManagedWidget ("snd-amp",xmFormWidgetClass,sw[W_snd_ctrls],args,n);
      XtAddEventHandler(sw[W_snd_amp_form],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);

      n=0;      
      /* AMP */
      s1=XmStringCreateLtoR(snd_string_amp_p,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
      sw[W_snd_amp_label] = XtCreateManagedWidget ("amp-label",xmPushButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_amp_label],XmNhelpCallback,W_amp_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_amp_label],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_amp_label]);
#endif

      n=0;
      s1=XmStringCreateLtoR(number_one,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_amp_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_amp_label]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      sw[W_snd_amp_number] = XtCreateManagedWidget ("amp-number",xmLabelWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_amp_number],XmNhelpCallback,W_amp_Help_Callback,state);
      XmStringFree(s1);

      n=0;      
      if (need_colors) n = background_scale_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_amp_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_amp_number]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNmaximum,SCROLLBAR_MAX); n++;
      XtSetArg(args[n],XmNvalue,SCROLLBAR_MID); n++;
      XtSetArg(args[n],XmNdragCallback,make_callback_list(W_amp_Drag_Callback,(XtPointer)sp)); n++;
      XtSetArg(args[n],XmNvalueChangedCallback,make_callback_list(W_amp_ValueChanged_Callback,(XtPointer)sp)); n++;
      sw[W_snd_amp] = XtCreateManagedWidget("amp",xmScrollBarWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_amp],XmNhelpCallback,W_amp_Help_Callback,state);

      n=0;
      /* SRATE */
      s1=XmStringCreateLtoR(snd_string_speed,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_amp_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++; 
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
      sw[W_snd_srate_label] = XtCreateManagedWidget ("srate-label",xmPushButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_srate_label],XmNhelpCallback,W_srate_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_srate_label],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_srate_label]);
#endif

      n=0;
      switch (speed_style(state))
	{
	case SPEED_AS_RATIO: s1=XmStringCreateLtoR(ratio_one,XmFONTLIST_DEFAULT_TAG); break;
	case SPEED_AS_SEMITONE: s1=XmStringCreateLtoR(semitone_one,XmFONTLIST_DEFAULT_TAG); break;
	default: s1=XmStringCreateLtoR(number_one,XmFONTLIST_DEFAULT_TAG); break;
	}
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_srate_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_srate_label]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++; 
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      sw[W_snd_srate_number] = XtCreateManagedWidget ("srate-number",xmLabelWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_srate_number],XmNhelpCallback,W_srate_Help_Callback,state);
      XmStringFree(s1);

      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_srate_label]); n++;
      XtSetArg(args[n],XmNindicatorOn,FALSE); n++;
      XtSetArg(args[n],XmNlabelType,XmPIXMAP); n++;
      XtSetArg(args[n],XmNmarginHeight,0); n++;
      XtSetArg(args[n],XmNmarginWidth,0); n++;
      XtSetArg(args[n],XmNmarginTop,0); n++;
      XtSetArg(args[n],XmNtopOffset,0); n++;
      sw[W_snd_srate_arrow] = XtCreateManagedWidget("dir",xmToggleButtonWidgetClass,sw[W_snd_amp_form],args,n);
      form = sw[W_snd_srate_arrow];
      rb = XCreateBitmapFromData(XtDisplay(form),RootWindowOfScreen(XtScreen(form)),speed_r_bits,16,12);
      lb = XCreateBitmapFromData(XtDisplay(form),RootWindowOfScreen(XtScreen(form)),speed_l_bits,16,12);
      XtVaGetValues(form,XmNforeground,&v.foreground,XmNbackground,&v.background,XmNdepth,&depth,NULL);
      sx->speed_gc = XtGetGC(form,GCForeground | GCBackground,&v);
      sx->speed_r = XCreatePixmap(XtDisplay(form),RootWindowOfScreen(XtScreen(form)),16,12,depth);
      sx->speed_l = XCreatePixmap(XtDisplay(form),RootWindowOfScreen(XtScreen(form)),16,12,depth);
      XCopyPlane(XtDisplay(form),rb,sx->speed_r,sx->speed_gc,0,0,16,12,0,0,1);
      XCopyPlane(XtDisplay(form),lb,sx->speed_l,sx->speed_gc,0,0,16,12,0,0,1);
      XFreePixmap(XtDisplay(form),rb);
      XFreePixmap(XtDisplay(form),lb);
      XtVaSetValues(form,XmNselectPixmap,sx->speed_l,XmNlabelPixmap,sx->speed_r,NULL);
      /* pretty damn tedious -- we can't use the bare pixmap because X dies sputtering incomprehensible jargon */
      XtAddCallback(sw[W_snd_srate_arrow],XmNhelpCallback,W_srate_arrow_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_srate_arrow],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_srate_arrow]);
#endif

      n=0;
      if (need_colors) n = background_scale_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_srate_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_srate_number]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_srate_arrow]); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNmaximum,1000); n++;
      XtSetArg(args[n],XmNvalue,450); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNdragCallback,make_callback_list(W_srate_Drag_Callback,(XtPointer)sp)); n++;
      XtSetArg(args[n],XmNvalueChangedCallback,make_callback_list(W_srate_ValueChanged_Callback,(XtPointer)sp)); n++;
      sw[W_snd_srate] = XtCreateManagedWidget("srate",xmScrollBarWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_srate],XmNhelpCallback,W_srate_Help_Callback,state);

      n=0;
      /* EXPAND */
      s1=XmStringCreateLtoR(snd_string_expand,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_srate_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
      sw[W_snd_expand_label] = XtCreateManagedWidget ("expand-label",xmPushButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_expand_label],XmNhelpCallback,W_expand_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_expand_label],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_expand_label]);
#endif
      
      n=0;
      s1=XmStringCreateLtoR(number_one,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_expand_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_expand_label]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      sw[W_snd_expand_number] = XtCreateManagedWidget ("expand-number",xmLabelWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_expand_number],XmNhelpCallback,W_expand_Help_Callback,state);
      XmStringFree(s1);
      
      n=0;
      s1=XmStringCreateLtoR("",XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_expand_label]); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNmarginWidth,0); n++;
      XtSetArg(args[n],XmNtopOffset,1); n++;
      XtSetArg(args[n],XmNspacing,0); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
#if NEED_TOGGLE_SIZE
      XtSetArg(args[n],XmNindicatorSize,TOGGLE_SIZE); n++;
#endif
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_expand_button] = XtCreateManagedWidget("expoff",xmToggleButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_expand_button],XmNhelpCallback,W_expand_button_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_expand_button],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_expand_button]);
#endif

      n=0;
      if (need_colors) n = background_main_color(args,n,state); /* was scale */
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_expand_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_expand_number]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_expand_button]); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNmaximum,1000); n++;
      XtSetArg(args[n],XmNvalue,450); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNdragCallback,make_callback_list(W_expand_Drag_Callback,(XtPointer)sp)); n++;
      XtSetArg(args[n],XmNvalueChangedCallback,make_callback_list(W_expand_ValueChanged_Callback,(XtPointer)sp)); n++;
      sw[W_snd_expand] = XtCreateManagedWidget("",xmScrollBarWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_expand],XmNhelpCallback,W_expand_Help_Callback,state);

      /* CONTRAST */
      n=0;
      s1=XmStringCreateLtoR(snd_string_contrast,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_expand_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
      sw[W_snd_contrast_label] = XtCreateManagedWidget ("contrast-label",xmPushButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_contrast_label],XmNhelpCallback,W_contrast_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_contrast_label],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_contrast_label]);
#endif
      
      n=0;
      s1=XmStringCreateLtoR(number_zero,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_contrast_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_contrast_label]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      sw[W_snd_contrast_number] = XtCreateManagedWidget ("contrast-number",xmLabelWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_contrast_number],XmNhelpCallback,W_contrast_Help_Callback,state);
      XmStringFree(s1);
      
      n=0;
      s1=XmStringCreateLtoR("",XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_contrast_label]); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNmarginWidth,0); n++;
      XtSetArg(args[n],XmNtopOffset,1); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNspacing,0); n++;
#if NEED_TOGGLE_SIZE
      XtSetArg(args[n],XmNindicatorSize,TOGGLE_SIZE); n++;
#endif
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_contrast_button] = XtCreateManagedWidget("conoff",xmToggleButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_contrast_button],XmNhelpCallback,W_contrast_button_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_contrast_button],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_contrast_button]);
#endif

      n=0;
      if (need_colors) n = background_main_color(args,n,state); /* was scale */
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_contrast_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_contrast_number]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_contrast_button]); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNvalue,0); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNdragCallback,make_callback_list(W_contrast_Drag_Callback,(XtPointer)sp)); n++;
      XtSetArg(args[n],XmNvalueChangedCallback,make_callback_list(W_contrast_ValueChanged_Callback,(XtPointer)sp)); n++;
      sw[W_snd_contrast] = XtCreateManagedWidget("",xmScrollBarWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_contrast],XmNhelpCallback,W_contrast_Help_Callback,state);

      /* REVERB */
      /* REVSCL */
      n=0;
      s1=XmStringCreateLtoR(snd_string_reverb,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_contrast_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
      sw[W_snd_revscl_label] = XtCreateManagedWidget ("revscl-label",xmPushButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_revscl_label],XmNhelpCallback,W_revscl_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_revscl_label],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_revscl_label]);
#endif
      
      n=0;
      s1=XmStringCreateLtoR(number_long_zero,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_revscl_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_revscl_label]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      sw[W_snd_revscl_number] = XtCreateManagedWidget ("revscl-number",xmLabelWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_revscl_number],XmNhelpCallback,W_revscl_Help_Callback,state);
      XmStringFree(s1);
      
      n=0;
      if (need_colors) n = background_main_color(args,n,state); /* was scale */
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_revscl_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_revscl_number]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNrightPosition,60); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNvalue,0); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNdragCallback,make_callback_list(W_revscl_Drag_Callback,(XtPointer)sp)); n++;
      XtSetArg(args[n],XmNvalueChangedCallback,make_callback_list(W_revscl_ValueChanged_Callback,(XtPointer)sp)); n++;
      sw[W_snd_revscl] = XtCreateManagedWidget("",xmScrollBarWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_revscl],XmNhelpCallback,W_revscl_Help_Callback,state);

      /* REVOFF */
      n=0;
      s1=XmStringCreateLtoR("",XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_revscl_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_contrast_button]); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNmarginWidth,0); n++;
      XtSetArg(args[n],XmNtopOffset,1); n++;
      XtSetArg(args[n],XmNspacing,0); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
#if NEED_TOGGLE_SIZE
      XtSetArg(args[n],XmNindicatorSize,TOGGLE_SIZE); n++;
#endif
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_reverb_button] = XtCreateManagedWidget("revoff",xmToggleButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_reverb_button],XmNhelpCallback,W_reverb_button_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_reverb_button],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_reverb_button]);
#endif


      /* REVLEN */
      n=0;
      s1=XmStringCreateLtoR(snd_string_len,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_revscl]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNleftPosition,60); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
      sw[W_snd_revlen_label] = XtCreateManagedWidget("revlen-label",xmPushButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_revlen_label],XmNhelpCallback,W_revlen_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_revlen_label],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_revlen_label]);
#endif

      n=0;
      s1=XmStringCreateLtoR(number_one,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_revlen_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_revlen_label]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      sw[W_snd_revlen_number] = XtCreateManagedWidget("revlen-number",xmLabelWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_revlen_number],XmNhelpCallback,W_revlen_Help_Callback,state);
      XmStringFree(s1);

      n=0;
      if (need_colors) n = background_main_color(args,n,state); /* was scale */
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_revlen_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_revlen_number]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_reverb_button]); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNvalue,20); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNdragCallback,make_callback_list(W_revlen_Drag_Callback,(XtPointer)sp)); n++;
      XtSetArg(args[n],XmNvalueChangedCallback,make_callback_list(W_revlen_ValueChanged_Callback,(XtPointer)sp)); n++;
      sw[W_snd_revlen] = XtCreateManagedWidget("",xmScrollBarWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_revlen],XmNhelpCallback,W_revlen_Help_Callback,state);


      /* FILTER */
      n=0;
      s1=XmStringCreateLtoR(snd_string_filter_order,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_revscl_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      XtSetArg(args[n],XmNshadowThickness,0); n++;
      XtSetArg(args[n],XmNhighlightThickness,0); n++;
      XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
      sw[W_snd_filter_label] = XtCreateManagedWidget ("filter-label",xmLabelWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_filter_label],XmNhelpCallback,W_filter_Help_Callback,state);
      XmStringFree(s1);

      /* filter order */
      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      /* XtSetArg(args[n],XmNfontList,bold_button_FONT(state)); n++; */
      XtSetArg(args[n],XmNresizeWidth,FALSE); n++;
      XtSetArg(args[n],XmNcolumns,3); n++;
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_filter_label]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_filter_label]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      sw[W_snd_filter_order] = sndCreateTextFieldWidget(state,"filter-order",sw[W_snd_amp_form],args,n,TRUE);
      XmTextSetString(sw[W_snd_filter_order],"  2");
      XtAddCallback(sw[W_snd_filter_order],XmNhelpCallback,W_filter_order_Help_Callback,state);

      n=0;
      s1=XmStringCreateLtoR(snd_string_env_p,XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_filter_order]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_filter_order]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
      sw[W_snd_filter_env] = XtCreateManagedWidget ("filter-env",xmLabelWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_filter_env],XmNhelpCallback,W_filter_envelope_Help_Callback,state);
      XmStringFree(s1);

      n=0;
      s1=XmStringCreateLtoR("",XmFONTLIST_DEFAULT_TAG);
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_filter_env]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_reverb_button]); n++;
      XtSetArg(args[n],XmNheight,16); n++;
      XtSetArg(args[n],XmNmarginWidth,0); n++;
      XtSetArg(args[n],XmNtopOffset,2); n++;
      XtSetArg(args[n],XmNspacing,0); n++;
      XtSetArg(args[n],XmNlabelString,s1); n++; 
#if NEED_TOGGLE_SIZE
      XtSetArg(args[n],XmNindicatorSize,TOGGLE_SIZE); n++;
#endif
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_filter_button] = XtCreateManagedWidget("fltoff",xmToggleButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_filter_button],XmNhelpCallback,W_filter_button_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_filter_button],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
      XmStringFree(s1);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_filter_button]);
#endif

      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNfontList,bold_button_FONT(state)); n++;
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_filter_env]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sw[W_snd_filter_env]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sw[W_snd_filter_button]); n++;
      XtSetArg(args[n],XmNmarginHeight,CONTROLS_MARGIN); n++;
      sw[W_snd_filter] = sndCreateTextFieldWidget(state,"filter-window",sw[W_snd_amp_form],args,n,TRUE);
      XtAddCallback(sw[W_snd_filter],XmNhelpCallback,W_filter_envelope_Help_Callback,state);

      /* RECORD SEPARATOR */
      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_filter]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNmargin,LINE_MARGIN); n++;
      XtSetArg(args[n],XmNheight,LINE_MARGIN); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      sw[W_snd_record_sep] = XtCreateManagedWidget("snd-rec-sep",xmSeparatorWidgetClass,sw[W_snd_amp_form],args,n);

      #define LEFT_SPACE 3
      #define INTER_SPACE 30

      /* RECORD */
      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_record_sep]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNleftPosition,LEFT_SPACE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_record] = XtCreateManagedWidget(snd_string_Record,xmToggleButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_record],XmNhelpCallback,W_record_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_record],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_record]);
#endif

      /* REPLAY */
      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_record]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNleftPosition,LEFT_SPACE + INTER_SPACE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_replay] = XtCreateManagedWidget(snd_string_Replay,xmToggleButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_replay],XmNhelpCallback,W_replay_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_replay],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_replay]);
#endif

      /* APPLY */
      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_replay]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNleftPosition,LEFT_SPACE + 2*INTER_SPACE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_apply] = XtCreateManagedWidget(snd_string_Apply,xmToggleButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_apply],XmNhelpCallback,W_apply_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_apply],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);
#if OVERRIDE_TOGGLE
      override_toggle_translation(sw[W_snd_apply]);
#endif

      /* SET */
      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNfontList,button_FONT(state)); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_record_sep]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNleftPosition,90); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_set] = XtCreateManagedWidget(snd_string_s,xmPushButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_set],XmNhelpCallback,W_set_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_set],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);

      /* RESET */
      n=0;
      if (need_colors) n = background_main_color(args,n,state);
      XtSetArg(args[n],XmNfontList,button_FONT(state)); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sw[W_snd_record_sep]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNleftPosition,95); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      if (!(state->using_schemes)) {XtSetArg(args[n],XmNselectColor,(state->sgx)->text); n++;}
      sw[W_snd_reset] = XtCreateManagedWidget(snd_string_r,xmPushButtonWidgetClass,sw[W_snd_amp_form],args,n);
      XtAddCallback(sw[W_snd_reset],XmNhelpCallback,W_reset_Help_Callback,state);
      XtAddEventHandler(sw[W_snd_reset],KeyPressMask,FALSE,graph_key_press,(XtPointer)sp);

    } /* new sound state */
  else
    { /* re-manage currently inactive chan */
      XtVaSetValues(sw[W_snd_ctrls],XmNpaneMinimum,state->ctrls_height,NULL);
      for (i=0;i<NUM_SND_WIDGETS;i++)
	if ((sw[i]) && (!XtIsManaged(sw[i]))) 
	  XtManageChild(sw[i]);
      for (k=0;k<nchans;k++) 
	add_channel_window(sp,k,state,chan_min_y,0,NULL,WITH_FW_BUTTONS);
      make_name_label(sw[W_snd_name],shortname(sp));
      XtVaSetValues(sw[W_snd_ctrls],XmNpaneMinimum,1,NULL);
    }
  if (sp->nchans == 1) 
    {
      XmToggleButtonSetState(snd_widget(sp,W_snd_combine),FALSE,FALSE);
      XtUnmanageChild(snd_widget(sp,W_snd_combine));
    }
  add_sound_data(filename,sp,state);
  add_sound_callbacks(sw,(XtPointer)sp);
  reflect_control_panel_defaults(state,sp); /* expects active callbacks */
  snd_file_lock_icon(sp,(state->viewing || (cant_write(sp->fullname)))); /* sp->read_only not set yet */
  if (samples_per_channel > 100000) start_amp_env(sp,0);
  state->pending_open = NULL;
  if (state->pending_change)
    {
      sprintf(snd_txt_buf,"(translated %s)",old_name);
      report_in_minibuffer(sp,snd_txt_buf);
    }
  if (!(state->using_schemes)) map_over_children(sound_PANE(state),color_sashes,(void *)state);
  if (!(auto_resize(state))) normalize_all_sounds(state);
  return(sp);
}

void snd_info_cleanup(snd_info *sp)
{
  Widget w;
  int i;
  if ((sp) && (sp->sgx) && (snd_widget(sp,W_snd_sync)))
    {
      XtVaSetValues(snd_widget(sp,W_snd_sync),XmNset,FALSE,NULL);
      XtVaSetValues(snd_widget(sp,W_snd_expand_button),XmNset,FALSE,NULL);
      XtVaSetValues(snd_widget(sp,W_snd_contrast_button),XmNset,FALSE,NULL);
      XtVaSetValues(snd_widget(sp,W_snd_srate_arrow),XmNset,FALSE,NULL);
      XtVaSetValues(snd_widget(sp,W_snd_filter_button),XmNset,FALSE,NULL);
      XtVaSetValues(snd_widget(sp,W_snd_reverb_button),XmNset,FALSE,NULL);
      XmToggleButtonSetState(snd_widget(sp,W_snd_combine),FALSE,FALSE);
      sp->combining = CHANNELS_SEPARATE; 
      remove_sound_callbacks(sp,(XtPointer)sp);
      for (i=NUM_SND_WIDGETS-1;i>=0;i--)
	{
	  w = snd_widget(sp,i);
	  if ((w) && (XtIsManaged(w))) XtUnmanageChild(w);
	}
    }
}

void unlock_ctrls(snd_info *sp) {XtVaSetValues(snd_widget(sp,W_snd_ctrls),XmNpaneMinimum,1,NULL);}

static void replay_amp_callback(XtPointer clientData, XtIntervalId *id) {replay_amp((void *)clientData);}
void call_replay_amp(snd_state *ss, XtPointer ap,int time) {XtAppAddTimeOut(main_APP(ss),time,replay_amp_callback,ap);}

static void replay_speed_callback(XtPointer clientData, XtIntervalId *id) {replay_speed((void *)clientData);}
void call_replay_speed(snd_state *ss, XtPointer ap,int time) {XtAppAddTimeOut(main_APP(ss),time,replay_speed_callback,ap);}

static void replay_expand_callback(XtPointer clientData, XtIntervalId *id) {replay_expand((void *)clientData);}
void call_replay_expand(snd_state *ss, XtPointer ap,int time) {XtAppAddTimeOut(main_APP(ss),time,replay_expand_callback,ap);}

static void replay_contrast_callback(XtPointer clientData, XtIntervalId *id) {replay_contrast((void *)clientData);}
void call_replay_contrast(snd_state *ss, XtPointer ap,int time) {XtAppAddTimeOut(main_APP(ss),time,replay_contrast_callback,ap);}

static void replay_reverb_callback(XtPointer clientData, XtIntervalId *id) {replay_reverb((void *)clientData);}
void call_replay_reverb(snd_state *ss, XtPointer ap,int time) {XtAppAddTimeOut(main_APP(ss),time,replay_reverb_callback,ap);}

static void replay_direction_callback(XtPointer clientData, XtIntervalId *id) {replay_direction((void *)clientData);}
void call_replay_direction(snd_state *ss, XtPointer ap,int time) {XtAppAddTimeOut(main_APP(ss),time,replay_direction_callback,ap);}

void set_apply_button(snd_info *sp, int val) {XmToggleButtonSetState(snd_widget(sp,W_snd_apply),val,FALSE);}


void normalize_sound(snd_state *ss, snd_info *sp, snd_info *osp, chan_info *ncp)
{
  /* make sp look ok, squeezing others if needed; called only if normalize_on_open(ss) */
  /* if there's already enough (i.e. ss->channel_min_height), just return */
  /* this is used in goto_next_graph and goto_previous_graph (snd-chn.c) to open windows that are currently squeezed shut */
  float val,size,high,low;
  Dimension chan_y;
  int *wid;
  Widget *cw;
  Widget wcp;
  chan_info *cp;
  chan_context *cx;

  if ((!ss) || (!sp) || (!(normalize_on_open(ss)))) return;
  if (sound_style(ss) != SOUNDS_HORIZONTAL)
    {
      /* several attempts to be fancy here just made a mess of the display */
      cx = ncp->cgx;
      cw = cx->chan_widgets;
      XtVaGetValues(cw[W_chn_main_window],XmNheight,&chan_y,NULL);
      if (chan_y < (Dimension)(ss->channel_min_height>>1)) 
	{
	  wid = (int *)calloc(1,sizeof(int));
	  (*wid) = (ss->channel_min_height>>1) + 10;
	  channel_lock_pane(ncp,(void *)wid);
	  channel_open_pane(ncp,NULL);
	  channel_unlock_pane(ncp,NULL);
	}
    }
  else
    {
      cx = ncp->cgx;
      cw = cx->chan_widgets;
      XtVaGetValues(cw[W_chn_main_window],XmNwidth,&chan_y,NULL);
      if (chan_y < 200)
	{
	  XtUnmanageChild(cw[W_chn_main_window]);
	  XtVaSetValues(cw[W_chn_main_window],XmNwidth,200,NULL);
	  XtManageChild(cw[W_chn_main_window]);
	}
    }
  if (sp->combining == CHANNELS_COMBINED)
    {
      cp = any_selected_channel(sp);
      high = (float)(sp->nchans - cp->chan)/(float)sp->nchans;
      low = high - 1.0/(float)sp->nchans;
      cp = sp->chans[0];
      wcp = chan_widget(cp,W_chn_gsy);
      val = (float)get_raw_value(wcp)/(float)(SCROLLBAR_MAX);
      size = (float)get_raw_size(wcp)/(float)(SCROLLBAR_MAX);
      if ((val > low) || ((val+size) < high))
	{
	  val = low;
	  if ((val+size) > 1.0) val = 1.0 - size;
	  set_raw_value(wcp,val*SCROLLBAR_MAX);
	  gsy_changed(val*SCROLLBAR_MAX,cp);
	}
    }
}

