#include "snd.h"

#if HAVE_GUILE

/* entire file on this switch 
 * has replacements for some funcs also found in snd-clm.c 
 * need simple way to redirect gh_display output 
 * might be nice to have a data-hook 
 * or hooks into anything (i.e. before/after/around methods) 
 * 
 * src by chan src-env
 * user-defined zoom focus?
 * last-command (key)
 *
 * add to control panel:
 *   add-control control-button-hook control-slider-hook control-hook (called by dac function) remove-control
 *   would need tie into snd-apply.c snd-dac.c
 *   need label digits?
 *
 * dialog window manipulations (via winvar + setxy etc)
 * direct data access from dynamically loaded c modules?
 * direct access to drawingarea widgets (for user-generated graphics)
 * mark color, section color, graph color
 *
 *   graph-cursor 
 */

/* save-state internal functions:
 *
 * several functions are intended for the use of the state saver (and aren't in snd.html).
 * since the edit history needs to remember what user-action caused a given edit, the
 *   internal calls have an added argument "origin" -- this is the same as ed->origin
 *   throughout snd-edits.c; also the data in each case is integer, not float.
 *
 *   set-int-samples (samp samps origin vector snd chn)
 *   insert-int-samples (samp samps origin vector snd chn)
 *   delete-int-samples (samp samps origin snd chn)
 *
 * The mark saver calls restore-marks -- see snd-marks.c.
 * The region saver calls restore-region -- see snd-clip.c
 */

static snd_state *state = NULL;
static char name_buf[256];
static char *gh_print(SCM result, int in_list);

static char *sanitize(char *errstr)
{
  int i,len;
  len = snd_strlen(errstr);
  for (i=0;i<len;i++) if (errstr[i] == '%') errstr[i]='~'; /* SGI fprintf tries to interpret imbedded %S which causes bus errors! */
  return(errstr);
}

static SCM clm_handler(void *data, SCM tag, SCM throw_args) /* error handler */
{
  int i,len;
  SCM el;
  snd_info *sp;
  char *str;
  len = gh_list_length(throw_args);
  sprintf(name_buf,"error: ");
  for (i=0;i<len;i++)
    {
      el = scm_list_ref(throw_args,gh_int2scm(i));
      if ((el) && (el != SCM_UNDEFINED) && (!(gh_boolean_p(el))))
	{
	  str = gh_print(el,0);
	  strcat(name_buf,str);
	  strcat(name_buf," ");
	  free(str);
	}
    }
  if (data) strcat(name_buf,(char *)data);
  if (state->mx_sp)
    {
      sp = state->mx_sp;
      clear_minibuffer_prompt(sp);
      report_in_minibuffer(sp,name_buf);
    }
  if (state->listening)
    {
      state->result_printout = 1;
      snd_append_command(state,name_buf);
    }
  else 
    if (!(state->mx_sp))
      fprintf(stderr,sanitize(name_buf));
  return(SCM_BOOL_F);
}

static SCM eval_str_wrapper(void *data, SCM jmpbuf)
{
  return(gh_eval_str(data));
}

static SCM eval_file_wrapper(void *data, SCM jmpbuf)
{
  SCM tmp;
  tmp = gh_eval_file(data);
  return(tmp);
}

static void gd_set(char *name,float val) 
{
  sprintf(name_buf,"(set! %s %f)",name,val); 
  scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,name_buf,clm_handler,name_buf);
}

static void gi_set(char *name,int val) 
{
  sprintf(name_buf,"(set! %s %d)",name,val); 
  scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,name_buf,clm_handler,name_buf);
}

static void gs_set(char *name,char *val) 
{
  if ((val) && (*val))
    sprintf(name_buf,"(set! %s \"%s\")",name,val);
  else sprintf(name_buf,"(set! %s \"\")",name);
  scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,name_buf,clm_handler,name_buf);
}

#if 0
static float gd_get(char *name)
{
  SCM val;
  val = gh_lookup(name);
  if (val == SCM_UNDEFINED) fprintf(stderr," %s is undefined!\n",name);
  if (gh_number_p(val)) return(gh_scm2double(val));
  return(0.0);
}

static int gi_get(char *name)
{
  SCM val;
  val = gh_lookup(name);
  if (val == SCM_UNDEFINED) fprintf(stderr," %s is undefined!\n",name);
  if (gh_number_p(val)) return(gh_scm2int(val));
  if (val == SCM_BOOL_T) return(1);
  if (val == SCM_BOOL_F) return(0);
  return(0); /* ? */
}

static char *gs_get(char *name)
{
  SCM val;
  val = gh_lookup(name);
  if (val == SCM_UNDEFINED) fprintf(stderr," %s is undefined!\n",name);
  if (gh_string_p(val)) return(gh_scm2newstr(val,0));
  return(NULL);
}
#endif

static int int_or_zero(SCM n)
{
  if (gh_number_p(n))
    return(gh_scm2int(n));
  return(0);
}

static int int_or_one(SCM n)
{
  if (gh_number_p(n))
    return(gh_scm2int(n));
  return(1);
}

static int bool_int_or_one(SCM n)
{
  if (gh_number_p(n))
    return(gh_scm2int(n));
  else
    if (n == SCM_BOOL_F) 
      return(0);
  return(1);
}

static char *gh_print(SCM result, int in_list)
{
  char *newbuf = NULL,*str = NULL,*str1 = NULL;
  int i,len,ilen,savelen,savectr,slen;
  if (gh_boolean_p(result))
    {
      newbuf = (char *)calloc(8,sizeof(char));
      sprintf(newbuf,"%s",(gh_scm2bool(result)) ? "#t" : "#f");
    }
  else
    if (gh_number_p(result))
      {
	if (gh_exact_p(result))
	  {
	    newbuf = (char *)calloc(32,sizeof(char));
	    sprintf(newbuf,"%d",gh_scm2int(result));
	  }
	else 
	  {
	    newbuf = (char *)calloc(32,sizeof(char));
	    sprintf(newbuf,"%.4f",(float)gh_scm2double(result));
	  }
      }
    else
      if (gh_string_p(result))
	{
	  len=0;
	  str = gh_scm2newstr(result,&len);
	  newbuf = (char *)calloc(len+8,sizeof(char));
	  sprintf(newbuf,"\"%s\"",str);
	  free(str);
	}
      else
	if (gh_char_p(result))
	  {
	    newbuf = (char *)calloc(8,sizeof(char));
	    sprintf(newbuf,"%c",gh_scm2char(result));
	  }
	else
	  if (gh_symbol_p(result))
	    newbuf = gh_symbol2newstr(result,NULL);
	  else
	    if ((gh_list_p(result)) || (gh_vector_p(result)))
	      {
		if (gh_vector_p(result)) 
		  len = gh_vector_length(result);
		else len = gh_list_length(result);
		if (len>print_length(state)) ilen=print_length(state); else ilen=len;
		newbuf = (char *)calloc(128,sizeof(char));
		savelen = 128;
		savectr = 3;
		if (gh_vector_p(result)) 
		  sprintf(newbuf,"#("); 
		else 
		  if (in_list == 0)
		    sprintf(newbuf,"'(");
		  else sprintf(newbuf,"(");
		for (i=0;i<ilen;i++)
		  {
		    if (gh_vector_p(result)) 
		      str = gh_print(gh_vref(result,gh_int2scm(i)),0);
		    else str = gh_print(scm_list_ref(result,gh_int2scm(i)),1);
		    if ((str) && (*str)) 
		      {
			slen = strlen(str);
			if ((slen+savectr+1) >= savelen)
			  {
			    savelen += 128;
			    newbuf = (char *)realloc(newbuf,savelen * sizeof(char));
			  }
			if (i != 0) {strcat(newbuf," "); savectr++;}
			strcat(newbuf,str);
			savectr+=slen;
		      }
		    if (str) free(str);
		  }
		if (savectr+8 > savelen) newbuf = (char *)realloc(newbuf,(savectr+8) * sizeof(char));
		if (len != ilen) strcat(newbuf," ...");
		strcat(newbuf,")");
	      }
	    else
	      if (gh_pair_p(result))
		{
		  str = gh_print(gh_car(result),0);
		  str1 = gh_print(gh_cdr(result),0);
		  len = snd_strlen(str) + snd_strlen(str1) + 8;
		  newbuf = (char *)calloc(len,sizeof(char));
		  sprintf(newbuf,"(%s . %s)",str,str1);
		  if (str) free(str);
		  if (str1) free(str1);
		}
	      else
		if (gh_procedure_p(result))
		  {
		    newbuf = (char *)calloc(16,sizeof(char));
		    sprintf(newbuf,"<func>"); /* where is the function name?? */
		  }
		else
		  {
		    newbuf = (char *)calloc(8,sizeof(char));
		    sprintf(newbuf,"nil");
		  }
  return(newbuf);
}

static SCM gh_new_procedure0_3 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,0,3,0));} /* not provided by gh_funcs.c */
static SCM gh_new_procedure0_4 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,0,4,0));}
static SCM gh_new_procedure1_3 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,1,3,0));}
static SCM gh_new_procedure1_4 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,1,4,0));}
static SCM gh_new_procedure1_5 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,1,5,0));}
static SCM gh_new_procedure1_7 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,1,7,0));}
static SCM gh_new_procedure0_5 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,0,5,0));}
static SCM gh_new_procedure3_2 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,3,2,0));}
static SCM gh_new_procedure4_2 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,4,2,0));}
static SCM gh_new_procedure9_0 (char *proc_name,SCM (*fn)()) {return(gh_new_procedure(proc_name,fn,9,0,0));}

int clm_doit(snd_state *ss, char *buf, int from_clm)
{
  /* scm_set_current_output_port? */
  snd_info *sp = NULL;
  SCM result;
  char *str = NULL;
  result = scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,buf,clm_handler,buf);
  str = gh_print(result,0);
  if (from_clm)
    { /* fix up #t and #f for common lisp */
      if (result == SCM_BOOL_T)
	write(ss->to_clm,"T",2);
      else
	{
	  if (result == SCM_BOOL_F)
	    write(ss->to_clm,"NIL",4);
	  else write(ss->to_clm,str,snd_strlen(str)+1);
	}
    }
  else
    {
      if (ss->mx_sp)
	{
	  sp = ss->mx_sp;
	  clear_minibuffer_prompt(sp);
	  report_in_minibuffer(sp,str);
	}
      if (ss->listening)
	{
	  snd_append_command(ss,buf);
	  ss->result_printout = 1;
	  snd_append_command(ss,str);
	}
    }
  if (str) free(str);
  return(0);
}

int clm_just_doit(snd_state *ss, char *buf)
{
  SCM result;
  char *str;
  result = scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,buf,clm_handler,buf);
  str = gh_print(result,0);
  ss->result_printout = 1;
  snd_append_command(ss,str);
  if (str) free(str);
  return(0);
}

static char init_file_buffer[128];

void snd_load_init_file(snd_state *ss)
{
  /* look for ".snd" on the home directory, and load it using the lisp-like CLM syntax given above */
  int fd;
  char *str;
  if (ss->init_file)
    {
      str = ss->init_file;
      if ((*str) == '~')
	{
	  strcpy(init_file_buffer,getenv("HOME"));
	  strcat(init_file_buffer,++str);
	}
      else strcpy(init_file_buffer,ss->init_file);
      fd = open(init_file_buffer,O_RDONLY,0);
      if (fd != -1) 
	{
	  close(fd);
	  scm_internal_catch(SCM_BOOL_T,eval_file_wrapper,init_file_buffer,clm_handler,NULL);
	  fflush(stdout);
	}
    }
}

int snd_load_file(snd_state *ss,char *filename)
{
  int fd;
  char *str,*saved_buf;
  str=filename;
  saved_buf = NULL;
  if ((*str) == '~')
    {
      strcpy(init_file_buffer,getenv("HOME"));
      strcat(init_file_buffer,++str);
    }
  else strcpy(init_file_buffer,str);
  fd = open(init_file_buffer,O_RDONLY,0);
  if (fd != -1) 
    {
      close(fd);
      scm_internal_catch(SCM_BOOL_T,eval_file_wrapper,init_file_buffer,clm_handler,NULL);
      fflush(stdout);
      return(0);
    }
  return(-1);
}


static SCM g_ask_before_overwrite(void) {return(gh_int2scm(ask_before_overwrite(state)));}
static SCM g_set_ask_before_overwrite(SCM val) {set_ask_before_overwrite(state,bool_int_or_one(val)); return(val);}
static SCM g_auto_resize(void) {return(gh_int2scm(auto_resize(state)));}
static SCM g_set_auto_resize(SCM val) {set_auto_resize(state,bool_int_or_one(val)); reflect_resize(state); return(val);}
static SCM g_channel_style(void) {return(gh_int2scm(channel_style(state)));}
static SCM g_set_channel_style(SCM style) {set_channel_style(state,gh_scm2int(style)); return(style);}
static SCM g_color_cutoff(void) {return(gh_double2scm(color_cutoff(state)));}
static SCM g_set_color_cutoff(SCM val) {set_color_cutoff(state,gh_scm2double(val)); return(val);}
static SCM g_color_inverted(void) {return(gh_int2scm(color_inverted(state)));}
static SCM g_set_color_inverted(SCM val) {set_color_inverted(state,bool_int_or_one(val)); return(val);}
static SCM g_color_scale(void) {return(gh_double2scm(color_scale(state)));}
static SCM g_set_color_scale(SCM val) {set_color_scale(state,gh_scm2double(val)); return(val);}
static SCM g_default_amp(void) {return(gh_double2scm(default_amp(state)));}
static SCM g_set_default_amp(SCM val) {set_default_amp(state,gh_scm2double(val)); return(val);}
static SCM g_default_contrast(void) {return(gh_double2scm(default_contrast(state)));}
static SCM g_set_default_contrast(SCM val) {set_default_contrast(state,gh_scm2double(val)); return(val);}
static SCM g_default_contrast_amp(void) {return(gh_double2scm(default_contrast_amp(state)));}
static SCM g_set_default_contrast_amp(SCM val) {set_default_contrast_amp(state,gh_scm2double(val)); return(val);}
static SCM g_default_contrasting(void) {return(gh_int2scm(default_contrasting(state)));}
static SCM g_set_default_contrasting(SCM val) {set_default_contrasting(state,bool_int_or_one(val)); return(val);}
static SCM g_default_expand(void) {return(gh_double2scm(default_expand(state)));}
static SCM g_set_default_expand(SCM val) {set_default_expand(state,gh_scm2double(val)); return(val);}
static SCM g_default_expand_hop(void) {return(gh_double2scm(default_expand_hop(state)));}
static SCM g_set_default_expand_hop(SCM val) {set_default_expand_hop(state,gh_scm2double(val)); return(val);}
static SCM g_default_expand_length(void) {return(gh_double2scm(default_expand_length(state)));}
static SCM g_set_default_expand_length(SCM val) {set_default_expand_length(state,gh_scm2double(val)); return(val);}
static SCM g_default_expand_ramp(void) {return(gh_double2scm(default_expand_ramp(state)));}
static SCM g_set_default_expand_ramp(SCM val) {set_default_expand_ramp(state,gh_scm2double(val)); return(val);}
static SCM g_default_expanding(void) {return(gh_int2scm(default_expanding(state)));}
static SCM g_set_default_expanding(SCM val) {set_default_expanding(state,bool_int_or_one(val)); return(val);}
static SCM g_default_filter_order(void) {return(gh_int2scm(default_filter_order(state)));}
static SCM g_set_default_filter_order(SCM val) {set_default_filter_order(state,gh_scm2int(val)); return(val);}
static SCM g_default_filtering(void) {return(gh_int2scm(default_filtering(state)));}
static SCM g_set_default_filtering(SCM val) {set_default_filtering(state,bool_int_or_one(val)); return(val);}
static SCM g_default_output_type(void) {return(gh_int2scm(default_output_type(state)));}
static SCM g_set_default_output_type(SCM val) {set_default_output_type(state,gh_scm2int(val)); return(val);}
static SCM g_default_reverb_feedback(void) {return(gh_double2scm(default_reverb_feedback(state)));}
static SCM g_set_default_reverb_feedback(SCM val) {set_default_reverb_feedback(state,gh_scm2double(val)); return(val);}
static SCM g_default_reverb_length(void) {return(gh_double2scm(default_reverb_length(state)));}
static SCM g_set_default_reverb_length(SCM val) {set_default_reverb_length(state,gh_scm2double(val)); return(val);}
static SCM g_default_reverb_lowpass(void) {return(gh_double2scm(default_reverb_lowpass(state)));}
static SCM g_set_default_reverb_lowpass(SCM val) {set_default_reverb_lowpass(state,gh_scm2double(val)); return(val);}
static SCM g_default_reverb_scale(void) {return(gh_double2scm(default_reverb_scale(state)));}
static SCM g_set_default_reverb_scale(SCM val) {set_default_reverb_scale(state,gh_scm2double(val)); return(val);}
static SCM g_default_reverbing(void) {return(gh_int2scm(default_reverbing(state)));}
static SCM g_set_default_reverbing(SCM val) {set_default_reverbing(state,bool_int_or_one(val)); return(val);}
static SCM g_default_speed(void) {return(gh_double2scm(default_speed(state)));}
static SCM g_set_default_speed(SCM val) {set_default_speed(state,gh_scm2double(val)); return(val);}
static SCM g_dot_size(void) {return(gh_int2scm(dot_size(state)));}
static SCM g_set_dot_size(SCM size) {set_dot_size(state,gh_scm2int(size)); return(size);}
static SCM g_enved_base(void) {return(gh_double2scm(enved_base(state)));}
static SCM g_set_enved_base(SCM val) {set_enved_base(state,gh_scm2double(val)); return(val);}
static SCM g_enved_clipping(void) {return(gh_int2scm(enved_clipping(state)));}
static SCM g_set_enved_clipping(SCM on) {set_enved_clipping(state,bool_int_or_one(on)); return(on);}
static SCM g_enved_exping(void) {return(gh_int2scm(enved_exping(state)));}
static SCM g_set_enved_exping(SCM val) {set_enved_exping(state,bool_int_or_one(val)); return(val);}
static SCM g_enved_target(void) {return(gh_int2scm(enved_target(state)));}
static SCM g_set_enved_target(SCM val) {set_enved_target(state,bool_int_or_one(val)); return(val);}
static SCM g_enved_waving(void) {return(gh_int2scm(enved_waving(state)));}
static SCM g_set_enved_waving(SCM val) {set_enved_waving(state,bool_int_or_one(val)); return(val);}
static SCM g_eps_file(void) {return(gh_str02scm(eps_file(state)));}
static SCM g_set_eps_file(SCM val) {set_eps_file(state,gh_scm2newstr(val,0)); return(val);}
static SCM g_fft_beta(void) {return(gh_double2scm(fft_beta(state)));}
static SCM g_set_fft_beta(SCM val) {set_fft_beta(state,gh_scm2double(val)); return(val);}
static SCM g_fft_log_frequency(void) {return(gh_int2scm(fft_log_frequency(state)));}
static SCM g_set_fft_log_frequency(SCM on) {set_fft_log_frequency(state,bool_int_or_one(on)); return(on);}
static SCM g_fft_log_magnitude(void) {return(gh_int2scm(fft_log_magnitude(state)));}
static SCM g_set_fft_log_magnitude(SCM on) {set_fft_log_magnitude(state,bool_int_or_one(on)); return(on);}
static SCM g_fft_size(void) {return(gh_int2scm(fft_size(state)));}
static SCM g_set_fft_size(SCM val) {set_fft_size(state,gh_scm2int(val)); return(val);}
static SCM g_fft_style(void) {return(gh_int2scm(fft_style(state)));}
static SCM g_set_fft_style(SCM val) {set_fft_style(state,gh_scm2int(val)); return(val);}
static SCM g_fft_window(void) {return(gh_int2scm(fft_window(state)));}
static SCM g_set_fft_window(SCM val) {set_fft_window(state,gh_scm2int(val)); return(val);}
static SCM g_filter_env_order(void) {return(gh_int2scm(filter_env_order(state)));}
static SCM g_set_filter_env_order(SCM val) {set_filter_env_order(state,gh_scm2int(val)); return(val);}
static SCM g_fit_data_on_open(void) {return(gh_int2scm(fit_data_on_open(state)));}
static SCM g_set_fit_data_on_open(SCM val) {set_fit_data_on_open(state,bool_int_or_one(val)); return(val);}
static SCM g_graph_style(void) {return(gh_int2scm(graph_style(state)));}
static SCM g_set_graph_style(SCM style) {set_graph_style(state,gh_scm2int(style)); return(style);}
static SCM g_initial_x0(void) {return(gh_double2scm(initial_x0(state)));}
static SCM g_set_initial_x0(SCM val) {set_initial_x0(state,gh_scm2double(val)); return(val);}
static SCM g_initial_x1(void) {return(gh_double2scm(initial_x1(state)));}
static SCM g_set_initial_x1(SCM val) {set_initial_x1(state,gh_scm2double(val)); return(val);}
static SCM g_initial_y0(void) {return(gh_double2scm(initial_y0(state)));}
static SCM g_set_initial_y0(SCM val) {set_initial_y0(state,gh_scm2double(val)); return(val);}
static SCM g_initial_y1(void) {return(gh_double2scm(initial_y1(state)));}
static SCM g_set_initial_y1(SCM val) {set_initial_y1(state,gh_scm2double(val)); return(val);}
static SCM g_line_size(void) {return(gh_int2scm(line_size(state)));}
static SCM g_set_line_size(SCM val) {set_line_size(state,gh_scm2int(val)); return(val);}
static SCM g_mix_amp_scaler(void) {return(gh_double2scm(get_mix_amp_scaler()));}
static SCM g_set_mix_amp_scaler(SCM val) {set_mix_amp_scaler(gh_scm2double(val)); return(val);}
static SCM g_mix_duration_brackets(void) {return(gh_int2scm(mix_duration_brackets(state)));}
static SCM g_set_mix_duration_brackets(SCM val) {set_mix_duration_brackets(state,bool_int_or_one(val)); return(val);}
static SCM g_mix_speed_scaler(void) {return(gh_double2scm(get_mix_speed_scaler()));}
static SCM g_set_mix_speed_scaler(SCM val) {set_mix_speed_scaler(gh_scm2double(val)); return(val);}
static SCM g_mix_tempo_scaler(void) {return(gh_double2scm(get_mix_tempo_scaler()));}
static SCM g_set_mix_tempo_scaler(SCM val) {set_mix_tempo_scaler(gh_scm2double(val)); return(val);}
static SCM g_mixer_group_max_out_chans(void) {return(gh_int2scm(mixer_group_max_out_chans(state)));}
static SCM g_set_mixer_group_max_out_chans(SCM val) {set_mixer_group_max_out_chans(state,gh_scm2int(val)); return(val);}
static SCM g_mixer_groups(void) {return(gh_int2scm(mixer_groups(state)));}
static SCM g_set_mixer_groups(SCM val) {set_mixer_groups(state,gh_scm2int(val)); return(val);}
static SCM g_movies(void) {return(gh_int2scm(movies(state)));}
static SCM g_set_movies(SCM val) {set_movies(state,bool_int_or_one(val)); return(val);}
static SCM g_normalize_fft(void) {return(gh_int2scm(normalize_fft(state)));}
static SCM g_set_normalize_fft(SCM val) {set_normalize_fft(state,bool_int_or_one(val)); return(val);}
static SCM g_normalize_on_open(void) {return(gh_int2scm(normalize_on_open(state)));}
static SCM g_set_normalize_on_open(SCM val) {set_normalize_on_open(state,bool_int_or_one(val)); return(val);}
static SCM g_prefix_arg(void) {return(gh_int2scm(prefix_arg(state)));}
static SCM g_set_prefix_arg(SCM val) {set_prefix_arg(state,gh_scm2int(val)); return(val);}
static SCM g_print_length(void) {return(gh_int2scm(print_length(state)));}
static SCM g_set_print_length(SCM val) {set_print_length(state,gh_scm2int(val)); return(val);}
static SCM g_raw_chans(void) {return(gh_int2scm(raw_chans(state)));}
static SCM g_set_raw_chans(SCM val) {set_raw_chans(state,gh_scm2int(val)); return(val);}
static SCM g_raw_format(void) {return(gh_int2scm(raw_format(state)));}
static SCM g_set_raw_format(SCM val) {set_raw_format(state,gh_scm2int(val)); return(val);}
static SCM g_raw_srate(void) {return(gh_int2scm(raw_srate(state)));}
static SCM g_set_raw_srate(SCM val) {set_raw_srate(state,gh_scm2int(val)); return(val);}
static SCM g_raw_type(void) {return(gh_int2scm(raw_type(state)));}
static SCM g_set_raw_type(SCM val) {set_raw_type(state,gh_scm2int(val)); return(val);}
static SCM g_recorder_autoload(void) {return(gh_int2scm(recorder_autoload(state)));}
static SCM g_set_recorder_autoload(SCM val) {set_autoload(state,bool_int_or_one(val)); return(val);}
static SCM g_recorder_buffer_size(void) {return(gh_int2scm(recorder_buffer_size(state)));}
static SCM g_set_recorder_buffer_size(SCM val) {in_set_recorder_buffer_size(state,gh_scm2int(val)); return(val);}
static SCM g_recorder_file(void) {return(gh_str02scm(recorder_file(state)));}
static SCM g_set_recorder_file(SCM val) {in_set_recorder_file(state,gh_scm2newstr(val,0)); return(val);}
static SCM g_recorder_in_format(void) {return(gh_int2scm(recorder_in_format(state)));}
static SCM g_set_recorder_in_format(SCM val) {in_set_recorder_in_format(state,gh_scm2int(val)); return(val);}
static SCM g_recorder_out_chans(void) {return(gh_int2scm(recorder_out_chans(state)));}
static SCM g_set_recorder_out_chans(SCM val) {in_set_recorder_out_chans(state,gh_scm2int(val)); return(val);}
static SCM g_recorder_out_format(void) {return(gh_int2scm(recorder_out_format(state)));}
static SCM g_set_recorder_out_format(SCM val) {in_set_recorder_out_format(state,gh_scm2int(val)); return(val);}
static SCM g_recorder_srate(void) {return(gh_int2scm(recorder_srate(state)));}
static SCM g_set_recorder_srate(SCM val) {in_set_recorder_srate(state,gh_scm2int(val)); return(val);}
static SCM g_reverb_decay(void) {return(gh_double2scm(reverb_decay(state)));}
static SCM g_set_reverb_decay(SCM val) {set_reverb_decay(state,gh_scm2double(val)); return(val);}
static SCM g_save_state_on_exit(void) {return(gh_int2scm(save_state_on_exit(state)));}
static SCM g_set_save_state_on_exit(SCM val) {set_save_state_on_exit(state,bool_int_or_one(val)); return(val);}
static SCM g_session_file(void) {return(gh_str02scm(session_file(state)));}
static SCM g_set_session_file(SCM val) {set_session_file(state,gh_scm2newstr(val,0)); return(val);}
static SCM g_show_fft_peaks(void) {return(gh_int2scm(show_fft_peaks(state)));}
static SCM g_set_show_fft_peaks(SCM val) {set_show_fft_peaks(state,bool_int_or_one(val)); return(val);}
static SCM g_show_marks(void) {return(gh_int2scm(show_marks(state)));}
static SCM g_set_show_marks(SCM on) {set_show_marks(state,bool_int_or_one(on)); return(on);}
static SCM g_show_mix_consoles(void) {return(gh_int2scm(show_mix_consoles(state)));}
static SCM g_set_show_mix_consoles(SCM on) {set_show_mix_consoles(state,bool_int_or_one(on)); return(on);}
static SCM g_show_y_zero(void) {return(gh_int2scm(show_y_zero(state)));}
static SCM g_set_show_y_zero(SCM on) {set_show_y_zero(state,bool_int_or_one(on)); return(on);}
static SCM g_sinc_width(void) {return(gh_int2scm(sinc_width(state)));}
static SCM g_set_sinc_width(SCM val) {set_sinc_width(state,gh_scm2int(val)); return(val);}
static SCM g_spectro_color(void) {return(gh_int2scm(spectro_color(state)));}
static SCM g_set_spectro_color(SCM val) {set_spectro_color(state,gh_scm2int(val)); return(val);}
static SCM g_spectro_cutoff(void) {return(gh_double2scm(spectro_cutoff(state)));}
static SCM g_set_spectro_cutoff(SCM val) {set_spectro_cutoff(state,gh_scm2double(val)); return(val);}
static SCM g_spectro_hop(void) {return(gh_int2scm(spectro_hop(state)));}
static SCM g_set_spectro_hop(SCM val) {set_spectro_hop(state,gh_scm2int(val)); return(val);}
static SCM g_spectro_x_angle(void) {return(gh_double2scm(spectro_x_angle(state)));}
static SCM g_set_spectro_x_angle(SCM val) {set_spectro_x_angle(state,gh_scm2double(val)); return(val);}
static SCM g_spectro_x_scale(void) {return(gh_double2scm(spectro_x_scale(state)));}
static SCM g_set_spectro_x_scale(SCM val) {set_spectro_x_scale(state,gh_scm2double(val)); return(val);}
static SCM g_spectro_y_angle(void) {return(gh_double2scm(spectro_y_angle(state)));}
static SCM g_set_spectro_y_angle(SCM val) {set_spectro_y_angle(state,gh_scm2double(val)); return(val);}
static SCM g_spectro_y_scale(void) {return(gh_double2scm(spectro_y_scale(state)));}
static SCM g_set_spectro_y_scale(SCM val) {set_spectro_y_scale(state,gh_scm2double(val)); return(val);}
static SCM g_spectro_z_angle(void) {return(gh_double2scm(spectro_z_angle(state)));}
static SCM g_set_spectro_z_angle(SCM val) {set_spectro_z_angle(state,gh_scm2double(val)); return(val);}
static SCM g_spectro_z_scale(void) {return(gh_double2scm(spectro_z_scale(state)));}
static SCM g_set_spectro_z_scale(SCM val) {set_spectro_z_scale(state,gh_scm2double(val)); return(val);}
static SCM g_speed_style(void) {return(gh_int2scm(speed_style(state)));}
static SCM g_set_speed_style(SCM speed) {activate_speed_in_menu(state,gh_scm2int(speed)); return(speed);}
static SCM g_speed_tones(void) {return(gh_int2scm(speed_tones(state)));}
static SCM g_set_speed_tones(SCM val) {set_speed_tones(state,gh_scm2int(val)); return(val);}
static SCM g_subsampling(void) {return(gh_int2scm(subsampling(state)));}
static SCM g_set_subsampling(SCM on) {set_subsampling(state,bool_int_or_one(on)); map_over_chans(state,update_graph,NULL); return(on);}
static SCM g_temp_dir(void) {return(gh_str02scm(temp_dir(state)));}
static SCM g_set_temp_dir(SCM val) {set_temp_dir(state,gh_scm2newstr(val,0)); return(val);}
#if HAVE_XmHTML
  static SCM g_html_dir(void) {return(gh_str02scm(html_dir(state)));}
  static SCM g_set_html_dir(SCM val) {set_html_dir(state,gh_scm2newstr(val,0)); return(val);}
#endif
static SCM g_transform_type(void) {return(gh_int2scm(transform_type(state)));}
static SCM g_set_transform_type(SCM val) {set_transform_type(state,gh_scm2int(val)); return(val);}
static SCM g_use_raw_defaults(void) {return(gh_int2scm(use_raw_defaults(state)));}
static SCM g_set_use_raw_defaults(SCM val) {set_use_raw_defaults(state,bool_int_or_one(val)); return(val);}
static SCM g_verbose_cursor(void) {return(gh_int2scm(verbose_cursor(state)));}
static SCM g_set_verbose_cursor(SCM on) {set_verbose_cursor(state,bool_int_or_one(on)); return(on);}
static SCM g_vu_font(void) {return(gh_str02scm(vu_font(state)));}
static SCM g_set_vu_font(SCM val) {set_vu_font(state,gh_scm2newstr(val,0)); return(val);}
static SCM g_vu_font_size(void) {return(gh_double2scm(vu_font_size(state)));}
static SCM g_set_vu_font_size(SCM val) {set_vu_font_size(state,gh_scm2double(val)); return(val);}
static SCM g_vu_size(void) {return(gh_double2scm(vu_size(state)));}
static SCM g_set_vu_size(SCM val) {set_vu_size(state,gh_scm2double(val)); return(val);}
static SCM g_wavelet_type(void) {return(gh_int2scm(wavelet_type(state)));}
static SCM g_set_wavelet_type(SCM val) {set_wavelet_type(state,gh_scm2int(val)); return(val);}
static SCM g_wavo(void) {return(gh_int2scm(wavo(state)));}
static SCM g_set_wavo(SCM val) {set_wavo(state,bool_int_or_one(val)); return(val);}
static SCM g_wavo_hop(void) {return(gh_int2scm(wavo_hop(state)));}
static SCM g_set_wavo_hop(SCM val) {set_wavo_hop(state,gh_scm2int(val)); return(val);}
static SCM g_wavo_trace(void) {return(gh_int2scm(wavo_trace(state)));}
static SCM g_set_wavo_trace(SCM val) {set_wavo_trace(state,gh_scm2int(val)); return(val);}
static SCM g_set_window_height(SCM height) {set_snd_window_height(state,gh_scm2int(height)); return(height);}
static SCM g_set_window_width(SCM width) {set_snd_window_width(state,gh_scm2int(width)); return(width);}
static SCM g_window_x(void) {return(gh_int2scm(window_x(state)));}
static SCM g_set_window_x(SCM val) {set_window_x(state,gh_scm2int(val)); return(val);}
static SCM g_window_y(void) {return(gh_int2scm(window_y(state)));}
static SCM g_set_window_y(SCM val) {set_window_y(state,gh_scm2int(val)); return(val);}
static SCM g_x_axis_style(void) {return(gh_int2scm(x_axis_style(state)));}
static SCM g_set_x_axis_style(SCM val) {set_x_axis_style(state,gh_scm2int(val)); return(val);}
static SCM g_xmax(void) {return(gh_double2scm(xmax(state)));}
static SCM g_set_xmax(SCM val) {set_xmax(state,gh_scm2double(val)); return(val);}
static SCM g_xmin(void) {return(gh_double2scm(xmin(state)));}
static SCM g_set_xmin(SCM val) {set_xmin(state,gh_scm2double(val)); return(val);}
static SCM g_ymax(void) {return(gh_double2scm(ymax(state)));}
static SCM g_set_ymax(SCM val) {set_ymax(state,gh_scm2double(val)); return(val);}
static SCM g_ymin(void) {return(gh_double2scm(ymin(state)));}
static SCM g_set_ymin(SCM val) {set_ymin(state,gh_scm2double(val)); return(val);}
static SCM g_zero_pad(void) {return(gh_int2scm(zero_pad(state)));}
static SCM g_set_zero_pad(SCM val) {set_zero_pad(state,bool_int_or_one(val)); return(val);}
static SCM g_zoom_focus_style(void) {return(gh_int2scm(zoom_focus_style(state)));}
static SCM g_set_zoom_focus_style(SCM focus) {activate_focus_menu(state,gh_scm2int(focus)); return(focus);}
static SCM g_set_just_sounds(SCM on) {toggle_just_sounds(bool_int_or_one(on)); return(on);}
static SCM g_edit_history_width(void) {return(gh_int2scm(edit_history_width(state)));}
static SCM g_set_edit_history_width(SCM val) {set_edit_history_width(state,gh_scm2int(val)); return(val);}

static SCM g_recorder_gain (SCM num) {return(gh_double2scm(read_record_state(AUDIO_GAINS,gh_scm2int(num),0)));}
static SCM g_recorder_in_amp (SCM in, SCM out) {return(gh_double2scm(read_record_state(REC_IN_AMPS,gh_scm2int(in),gh_scm2int(out))));}
static SCM g_recorder_out_amp (SCM num) {return(gh_double2scm(read_record_state(REC_OUT_AMPS,gh_scm2int(num),0)));}
static SCM g_set_recorder_gain (SCM num, SCM amp) {write_record_state(AUDIO_GAINS,gh_scm2int(num),0,gh_scm2double(amp)); return(amp);}
static SCM g_set_recorder_in_amp (SCM in, SCM out, SCM amp) {write_record_state(REC_IN_AMPS,gh_scm2int(in),gh_scm2int(out),gh_scm2double(amp)); return(amp);}
static SCM g_set_recorder_out_amp (SCM num, SCM amp) {write_record_state(REC_OUT_AMPS,gh_scm2int(num),0,gh_scm2double(amp)); return(amp);}

static SCM g_snd_print(void) {snd_print(state,eps_file(state),1); return(SCM_BOOL_F);}
static SCM g_snd_version(void) {return(gh_str02scm(SND_VERSION));}
static SCM g_snd_save_state(SCM filename) {if (save_state(state,gh_scm2newstr(filename,NULL)) == -1) return(SCM_BOOL_F); else return(filename);}
static SCM g_snd_save_macros(void) {save_macros(state); return(SCM_BOOL_F);}
static SCM g_snd_max_sounds(void) {return(gh_int2scm(state->max_sounds));}
static SCM g_snd_normalize_view(void) {normalize_all_sounds(state); return(SCM_BOOL_F);}
static SCM g_snd_window_width(void) {return(gh_int2scm(snd_window_width(state)));}
static SCM g_snd_window_height(void) {return(gh_int2scm(snd_window_height(state)));}
static SCM g_snd_show_listener(void) {if (state->listening != 1) handle_listener(state); return(SCM_BOOL_F);}
static SCM g_snd_hide_listener(void) {if (state->listening == 1) handle_listener(state); return(SCM_BOOL_F);}

static SCM g_override_data_location(SCM loc) 
{
  if (gh_number_p(loc)) 
    c_snd_header_override_data_location(gh_scm2int(loc)); 
  else c_snd_header_dont_override_data_location(); 
  return(loc);
}

static SCM g_override_data_format(SCM frm) 
{
  if (gh_number_p(frm)) 
    c_snd_header_override_sound_format(gh_scm2int(frm)); 
  else c_snd_header_dont_override_sound_format(); 
  return(frm);
}

static SCM g_override_data_size(SCM over) 
{
  if (over == SCM_BOOL_F) 
    c_snd_header_dont_override_data_size(); 
  else c_snd_header_override_data_size(); 
  return(over);
}

static SCM g_snd_exit(void) 
{
  if (dont_exit(state)) return(SCM_BOOL_T);
  snd_exit_cleanly(state); 
  exit(1); 
  return(SCM_BOOL_F);
}

static snd_info *get_sp(SCM scm_snd_n)
{
  int snd_n;
  if (gh_number_p(scm_snd_n))
    {
      snd_n = gh_scm2int(scm_snd_n);
      if ((snd_n < state->max_sounds) && (snd_ok(state->sounds[snd_n])))
	return(state->sounds[snd_n]);
      /* else return nil because user asked for specific sound and it's closed or non-existent */
    }
  else return(any_selected_sound(state));
  return(NULL);
}

static chan_info *get_cp(SCM scm_snd_n, SCM scm_chn_n)
{
  snd_info *sp;
  int chn_n;
  sp = get_sp(scm_snd_n);
  if (sp) 
    {
      if (gh_number_p(scm_chn_n))
	chn_n = gh_scm2int(scm_chn_n);
      else
	if (sp->selected_channel != NO_SELECTION) 
	  chn_n = sp->selected_channel;
	else chn_n = 0;
      if (chn_n < sp->nchans) return(sp->chans[chn_n]);
    }
  return(NULL);
}

#define SYNCF 0
#define UNITEF 1
#define READONLYF 2
#define NCHANSF 3
#define CONTRASTINGF 4
#define EXPANDINGF 5
#define REVERBINGF 6
#define FILTERINGF 7
#define FILTERORDERF 8
#define OKF 10
#define SRATEF 11
#define DATAFORMATF 12
#define DATALOCATIONF 13
#define HEADERTYPEF 14
#define CONTROLPANELSAVEF 15
#define CONTROLPANELRESTOREF 16
#define SELECTEDCHANNELF 17
#define COMMENTF 18
#define FILENAMEF 19
#define SHORTFILENAMEF 20
#define CLOSEF 21
#define UPDATEF 22
#define SAVEF 23
#define CURSORFOLLOWSPLAYF 24
#define SHOWCONTROLSF 25
#define SAVEMARKSF 26

static SCM sp_iread(SCM snd_n, int fld)
{
  snd_info *sp;
  sp = get_sp(snd_n);
  if (sp) 
    switch (fld)
      {
      case SYNCF: if (sp->syncing) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case UNITEF: return(gh_int2scm(sp->combining)); break;
      case READONLYF: if (sp->read_only) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case NCHANSF: return(gh_int2scm(sp->nchans)); break;
      case EXPANDINGF: if (sp->expanding) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case CONTRASTINGF: if (sp->contrasting) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case REVERBINGF: if (sp->reverbing) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case FILTERINGF: if (sp->filtering) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case FILTERORDERF: return(gh_int2scm(sp->filter_order)); break;
      case OKF: if (snd_ok(sp)) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case SRATEF: return(gh_int2scm((sp->hdr)->srate)); break;
      case DATAFORMATF: return(gh_cons(gh_int2scm((sp->hdr)->format),gh_str02scm(sound_format_name((sp->hdr)->format)))); break;
      case HEADERTYPEF: return(gh_cons(gh_int2scm((sp->hdr)->type),gh_str02scm(sound_type_name((sp->hdr)->type)))); break;
      case DATALOCATIONF: return(gh_int2scm((sp->hdr)->data_location)); break;
      case CONTROLPANELSAVEF: save_control_state(sp); break;
      case CONTROLPANELRESTOREF: restore_control_state(sp); break;
      case SELECTEDCHANNELF: if (sp->selected_channel != NO_SELECTION) return(gh_int2scm(sp->selected_channel)); break;
      case FILENAMEF: return(gh_str02scm(sp->fullname)); break;
      case SHORTFILENAMEF: return(gh_str02scm(sp->shortname)); break;
      case COMMENTF: return(gh_str02scm(sound_comment(sp->fullname))); break;
      case CLOSEF: snd_close_file(sp,state); break;
      case SAVEF: save_edits(sp,NULL); break;
      case UPDATEF: snd_update(state,sp); break;
      case CURSORFOLLOWSPLAYF: if (sp->cursor_follows_play) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case SHOWCONTROLSF: if (control_panel_open(sp)) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case SAVEMARKSF: save_marks(sp); break;
    }
  return(SCM_BOOL_F);
}

static SCM sp_iwrite(SCM snd_n, SCM val, int fld)
{
  snd_info *sp;
  int ival;
  sp = get_sp(snd_n);
  if (sp)
    {
      ival = bool_int_or_one(val);
      switch (fld)
	{
	case SYNCF: syncb(sp,ival); break;
	case UNITEF: combineb(sp,ival); break;
	case READONLYF: sp->read_only = ival; snd_file_lock_icon(sp,ival); break;
	case EXPANDINGF: toggle_expand_button(sp,ival); break;
	case CONTRASTINGF: toggle_contrast_button(sp,ival); break;
	case REVERBINGF: toggle_reverb_button(sp,ival); break;
	case FILTERINGF: toggle_filter_button(sp,ival); break;
	case FILTERORDERF: filter_order_changed(sp,ival); break;
	case CURSORFOLLOWSPLAYF: sp->cursor_follows_play = ival; break;
	case SHOWCONTROLSF: if (ival) sound_show_ctrls(sp); else sound_hide_ctrls(sp); break;
	}
    }
  return(val);
}

static SCM g_snd_ok(SCM snd_n) {return(sp_iread(snd_n,OKF));}
static SCM g_snd_syncing(SCM snd_n) {return(sp_iread(snd_n,SYNCF));}
static SCM g_snd_set_syncing(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,SYNCF));}
static SCM g_snd_uniting(SCM snd_n) {return(sp_iread(snd_n,UNITEF));}
static SCM g_snd_set_uniting(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,UNITEF));}
static SCM g_snd_read_only(SCM snd_n) {return(sp_iread(snd_n,READONLYF));}
static SCM g_snd_set_read_only(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,READONLYF));}
static SCM g_snd_channels(SCM snd_n) {return(sp_iread(snd_n,NCHANSF));}
static SCM g_snd_srate(SCM snd_n) {return(sp_iread(snd_n,SRATEF));}
static SCM g_snd_data_location(SCM snd_n) {return(sp_iread(snd_n,DATALOCATIONF));}
static SCM g_snd_data_format(SCM snd_n) {return(sp_iread(snd_n,DATAFORMATF));}
static SCM g_snd_header_type(SCM snd_n) {return(sp_iread(snd_n,HEADERTYPEF));}
static SCM g_snd_contrasting(SCM snd_n) {return(sp_iread(snd_n,CONTRASTINGF));}
static SCM g_snd_set_contrasting(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,CONTRASTINGF));}
static SCM g_snd_expanding(SCM snd_n) {return(sp_iread(snd_n,EXPANDINGF));}
static SCM g_snd_set_expanding(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,EXPANDINGF));}
static SCM g_snd_reverbing(SCM snd_n) {return(sp_iread(snd_n,REVERBINGF));}
static SCM g_snd_set_reverbing(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,REVERBINGF));}
static SCM g_snd_filtering(SCM snd_n) {return(sp_iread(snd_n,FILTERINGF));}
static SCM g_snd_set_filtering(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,FILTERINGF));}
static SCM g_snd_filter_order(SCM snd_n) {return(sp_iread(snd_n,FILTERORDERF));}
static SCM g_snd_set_filter_order(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,FILTERORDERF));}
static SCM g_snd_control_panel_save(SCM snd_n) {return(sp_iread(snd_n,CONTROLPANELSAVEF));}
static SCM g_snd_control_panel_restore(SCM snd_n) {return(sp_iread(snd_n,CONTROLPANELRESTOREF));}
static SCM g_snd_selected_channel(SCM snd_n) {return(sp_iread(snd_n,SELECTEDCHANNELF));}
static SCM g_snd_file_name(SCM snd_n) {return(sp_iread(snd_n,FILENAMEF));}
static SCM g_snd_short_file_name(SCM snd_n) {return(sp_iread(snd_n,SHORTFILENAMEF));}
static SCM g_snd_comment(SCM snd_n) {return(sp_iread(snd_n,COMMENTF));}
static SCM g_snd_close(SCM snd_n) {return(sp_iread(snd_n,CLOSEF));}
static SCM g_snd_update(SCM snd_n) {return(sp_iread(snd_n,UPDATEF));}
static SCM g_snd_save(SCM snd_n) {return(sp_iread(snd_n,SAVEF));}
static SCM g_snd_cursor_follows_play(SCM snd_n) {return(sp_iread(snd_n,CURSORFOLLOWSPLAYF));}
static SCM g_snd_set_cursor_follows_play(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,CURSORFOLLOWSPLAYF));}
static SCM g_snd_showing_controls(SCM snd_n) {return(sp_iread(snd_n,SHOWCONTROLSF));}
static SCM g_snd_set_show_controls(SCM on, SCM snd_n) {return(sp_iwrite(snd_n,on,SHOWCONTROLSF));}
static SCM g_snd_save_marks(SCM snd_n) {return(sp_iread(snd_n,SAVEMARKSF));}

static SCM g_snd_save_envelopes(SCM filename)
{
  char *name = NULL;
  FILE *fd;
  if (gh_string_p(filename)) 
    name = gh_scm2newstr(filename,NULL);
  else name = "envs.save";
  fd = fopen(name,"w");
  if (gh_string_p(filename)) free(name);
  if (fd)
    {
      save_envelope_editor_state(state,fd);
      fclose(fd);
      return(filename);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_save_options(SCM filename)
{
  char *name = NULL;
  FILE *fd;
  if (gh_string_p(filename)) 
    {
      name = gh_scm2newstr(filename,NULL);
      fd = fopen(name,"w");
      if (fd) 
	{
	  save_snd_state_options(state,fd);
	  fclose(fd);
	}
      free(name);
      return(filename);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_select_sound(SCM snd_n)
{
  int val;
  snd_info *osp,*sp;
  if (gh_number_p(snd_n))
    val = gh_scm2int(snd_n);
  else val = 0;
  sp = state->sounds[val];
  if (snd_ok(sp))
    {
      osp = any_selected_sound(state);
      select_sound(state,sp);
      normalize_sound(state,sp,osp,sp->chans[0]);
      goto_graph(sp->chans[0]);
    }
  map_over_chans(state,update_graph,NULL);
  return(snd_n);
}

static SCM g_snd_select_channel(SCM chn_n)
{
  snd_info *sp;
  int chan;
  if (gh_number_p(chn_n))
    chan = gh_scm2int(chn_n);
  else chan = 0;
  sp = any_selected_sound(state);
  if ((sp) && (chan < sp->nchans)) select_channel(sp,chan);
  return(chn_n);
}

#define AMPF 0
#define CONTRASTF 1
#define CONTRASTAMPF 2
#define EXPANDF 3
#define EXPANDLENGTHF 4
#define EXPANDRAMPF 5
#define EXPANDHOPF 6
#define SPEEDF 7
#define REVERBLENGTHF 8
#define REVERBFEEDBACKF 9
#define REVERBSCALEF 10
#define REVERBLOWPASSF 11

static SCM sp_fread(SCM snd_n, int fld)
{
  snd_info *sp;
  sp = get_sp(snd_n);
  if (sp) 
    switch (fld)
      {
      case AMPF: return(gh_double2scm(sp->amp)); break;
      case CONTRASTF: return(gh_double2scm(sp->contrast)); break;
      case CONTRASTAMPF: return(gh_double2scm(sp->contrast_amp)); break;
      case EXPANDF: return(gh_double2scm(sp->expand)); break;
      case EXPANDLENGTHF: return(gh_double2scm(sp->local_explen)); break;
      case EXPANDRAMPF: return(gh_double2scm(sp->local_exprmp)); break;
      case EXPANDHOPF: return(gh_double2scm(sp->local_exphop)); break;
      case SPEEDF: if (sp->play_direction == -1) return(gh_double2scm(-(sp->srate))); else return(gh_double2scm(sp->srate)); break;
      case REVERBLENGTHF: return(gh_double2scm(sp->revlen)); break;
      case REVERBFEEDBACKF: return(gh_double2scm(sp->local_revfb)); break;
      case REVERBSCALEF: return(gh_double2scm(sp->revscl)); break;
      case REVERBLOWPASSF: return(gh_double2scm(sp->local_revlp)); break;
    }
  return(SCM_BOOL_F);
}

static SCM sp_fwrite(SCM snd_n, SCM val, int fld)
{
  snd_info *sp;
  float fval;
  int dir;
  sp = get_sp(snd_n);
  if ((sp) && (gh_number_p(val)))
    {
      fval = gh_scm2double(val);
      switch (fld)
	{
	case AMPF: snd_amp_changed(sp,set_raw_value(snd_widget(sp,W_snd_amp),snd_amp_to_int(fval))); break;
	case CONTRASTF: snd_contrast_changed(sp,set_raw_value(snd_widget(sp,W_snd_contrast),snd_contrast_to_int(fval))); break;
	case CONTRASTAMPF: sp->contrast_amp = fval; break;
	case EXPANDF: snd_expand_changed(sp,set_raw_value(snd_widget(sp,W_snd_expand),snd_expand_to_int(fval))); break;
	case EXPANDLENGTHF: sp->local_explen = fval; break;
	case EXPANDRAMPF: sp->local_exprmp = fval; break;
	case EXPANDHOPF: sp->local_exphop = fval; break;
	case SPEEDF: 
	  if (fval > 0.0) dir=1; else dir=-1;
	  snd_srate_changed(sp,set_raw_value(snd_widget(sp,W_snd_srate),snd_srate_to_int(dir*fval))); 
	  toggle_direction_arrow(sp,(dir == -1));
	  break;
	case REVERBLENGTHF: snd_revlen_changed(sp,set_raw_value(snd_widget(sp,W_snd_revlen),snd_revlen_to_int(fval))); break;
	case REVERBFEEDBACKF: sp->local_revfb = fval; break;
	case REVERBSCALEF: snd_revscl_changed(sp,set_raw_value(snd_widget(sp,W_snd_revscl),snd_revscl_to_int(fval))); break;
	case REVERBLOWPASSF: sp->local_revlp = fval; break;
	}
    }
  return(val);
}

static SCM g_snd_amp(SCM snd_n) {return(sp_fread(snd_n,AMPF));}
static SCM g_snd_set_amp(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,AMPF));}
static SCM g_snd_contrast(SCM snd_n) {return(sp_fread(snd_n,CONTRASTF));}
static SCM g_snd_set_contrast(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,CONTRASTF));}
static SCM g_snd_contrast_amp(SCM snd_n) {return(sp_fread(snd_n,CONTRASTAMPF));}
static SCM g_snd_set_contrast_amp(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,CONTRASTAMPF));}
static SCM g_snd_expand(SCM snd_n) {return(sp_fread(snd_n,EXPANDF));}
static SCM g_snd_set_expand(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,EXPANDF));}
static SCM g_snd_expand_length(SCM snd_n) {return(sp_fread(snd_n,EXPANDLENGTHF));}
static SCM g_snd_set_expand_length(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,EXPANDLENGTHF));}
static SCM g_snd_expand_ramp(SCM snd_n) {return(sp_fread(snd_n,EXPANDRAMPF));}
static SCM g_snd_set_expand_ramp(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,EXPANDRAMPF));}
static SCM g_snd_expand_hop(SCM snd_n) {return(sp_fread(snd_n,EXPANDHOPF));}
static SCM g_snd_set_expand_hop(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,EXPANDHOPF));}
static SCM g_snd_speed(SCM snd_n) {return(sp_fread(snd_n,SPEEDF));}
static SCM g_snd_set_speed(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,SPEEDF));}
static SCM g_snd_reverb_length(SCM snd_n) {return(sp_fread(snd_n,REVERBLENGTHF));}
static SCM g_snd_set_reverb_length(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,REVERBLENGTHF));}
static SCM g_snd_reverb_feedback(SCM snd_n) {return(sp_fread(snd_n,REVERBFEEDBACKF));}
static SCM g_snd_set_reverb_feedback(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,REVERBFEEDBACKF));}
static SCM g_snd_reverb_scale(SCM snd_n) {return(sp_fread(snd_n,REVERBSCALEF));}
static SCM g_snd_set_reverb_scale(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,REVERBSCALEF));}
static SCM g_snd_reverb_lowpass(SCM snd_n) {return(sp_fread(snd_n,REVERBLOWPASSF));}
static SCM g_snd_set_reverb_lowpass(SCM on, SCM snd_n) {return(sp_fwrite(snd_n,on,REVERBLOWPASSF));}

#define FFTF 0
#define WAVEF 1
#define LENGTHF 2
#define CURSORF 3
#define MARKSF 4
#define MAXAMPF 5
#define GRAPHINGF 6
#define LOSAMPF 7
#define HISAMPF 8
#define PEAKSF 9

static SCM cp_iread(SCM snd_n, SCM chn_n, int fld)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    switch(fld)
      {
      case FFTF: if (cp->ffting) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case WAVEF: if (cp->waving) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case CURSORF: return(gh_int2scm(cp->cursor)); break;
      case LENGTHF: return(gh_int2scm(current_ed_samples(cp))); break;
      case MARKSF: if (cp->marks) return(gh_int2scm(1+(cp->mark_ctr[cp->edit_ctr]))); else return(gh_int2scm(0)); break;
      case MAXAMPF: return(gh_double2scm(get_maxamp(state,cp->sound,cp))); break;
      case GRAPHINGF: if (cp->lisp_graphing) return(SCM_BOOL_T); else return(SCM_BOOL_F); break;
      case LOSAMPF: if (cp->axis) return(gh_int2scm((cp->axis)->losamp)); break;
      case HISAMPF: if (cp->axis) return(gh_int2scm((cp->axis)->hisamp)); break;
      case PEAKSF: display_fft_peaks(cp); break;
      }
  return(SCM_BOOL_F);
}

static SCM cp_iwrite(SCM snd_n, SCM chn_n, SCM on, int fld)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      switch (fld)
	{
	case FFTF: fftb(cp,bool_int_or_one(on)); update_graph(cp,NULL); break;
	case WAVEF: waveb(cp,bool_int_or_one(on)); update_graph(cp,NULL); break;
	case CURSORF: cp->cursor_on = 1; handle_cursor(cp,cursor_moveto(cp,int_or_one(on))); break;
	case GRAPHINGF: 
	  cp->lisp_graphing = bool_int_or_one(on); 
	  if (!(cp->lisp_graphing)) gs_set("graph-hook",NULL);
	  update_graph(cp,NULL); 
	  break;
	case LOSAMPF: clm_left_axis(cp,int_or_zero(on)); break;
	case HISAMPF: clm_right_axis(cp,int_or_one(on)); break;
	}
    }
  return(on);
}

static SCM g_snd_ffting(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,FFTF));}
static SCM g_snd_set_ffting(SCM on, SCM snd_n, SCM chn_n) {return(cp_iwrite(snd_n,chn_n,on,FFTF));}
static SCM g_snd_waving(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,WAVEF));}
static SCM g_snd_set_waving(SCM on, SCM snd_n, SCM chn_n) {return(cp_iwrite(snd_n,chn_n,on,WAVEF));}
static SCM g_snd_graphing(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,GRAPHINGF));}
static SCM g_snd_set_graphing(SCM on, SCM snd_n, SCM chn_n) {return(cp_iwrite(snd_n,chn_n,on,GRAPHINGF));}
static SCM g_snd_cursor(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,CURSORF));}
static SCM g_snd_set_cursor(SCM on, SCM snd_n, SCM chn_n) {return(cp_iwrite(snd_n,chn_n,on,CURSORF));}
static SCM g_snd_length(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,LENGTHF));}
static SCM g_snd_marks(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,MARKSF));}
static SCM g_snd_maxamp(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,MAXAMPF));}
static SCM g_snd_peaks(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,PEAKSF));}

static SCM g_snd_left_sample(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,LOSAMPF));}
static SCM g_snd_set_left_sample(SCM on, SCM snd_n, SCM chn_n) {return(cp_iwrite(snd_n,chn_n,on,LOSAMPF));}
static SCM g_snd_right_sample(SCM snd_n, SCM chn_n) {return(cp_iread(snd_n,chn_n,HISAMPF));}
static SCM g_snd_set_right_sample(SCM on, SCM snd_n, SCM chn_n) {return(cp_iwrite(snd_n,chn_n,on,HISAMPF));}

static SCM g_snd_edits(SCM snd_n, SCM chn_n)
{ /* returns vector: (current edit (i.e. undo-able edits), redo-able edits) */
  chan_info *cp;
  int i;
  SCM vect;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      vect = gh_vector(gh_int2scm(2),gh_int2scm(cp->edit_ctr));
      for (i=cp->edit_ctr+1;i<cp->edit_size;i++)
	if (!(cp->edits[i])) break;
      gh_vset(vect,gh_int2scm(1),gh_int2scm(i-cp->edit_ctr-1));
      return(vect);
    }
  return(SCM_BOOL_F);
}

static SCM mark_to_index(chan_info *cp, mark **mps, mark *m)
{
  int i;
  for (i=0;i<=cp->mark_ctr[cp->edit_ctr];i++) 
    if (m==mps[i]) return(gh_int2scm(i));
  return(SCM_BOOL_F);
}

#define MARKSAMPLEF 0
#define MARKNAMEF 1
#define MARKFINDF 2
#define MARKADDF 3
#define MARKDELETEF 4

static SCM iread_mark(SCM snd_n, SCM chn_n, SCM ms_n, int fld)
{
  chan_info *cp;
  int msn = -1,i;
  mark *m;
  mark **mps;
  char *name = NULL;
  cp = get_cp(snd_n,chn_n);
  if ((cp) && ((cp->marks) || (fld == MARKADDF)))
    {
      if (gh_string_p(ms_n))
	name = gh_scm2newstr(ms_n,NULL);
      else msn = int_or_zero(ms_n);
      if (cp->marks) mps = cp->marks[cp->edit_ctr];
      switch (fld)
	{
	case MARKSAMPLEF: 
	  if (msn<=cp->mark_ctr[cp->edit_ctr]) return(gh_int2scm(mps[msn]->samp)); 
	  break;
	case MARKNAMEF: 
	  if (msn<=cp->mark_ctr[cp->edit_ctr])
	    {
	      m = mps[msn]; 
	      if (m->name) return(gh_str02scm(m->name)); 
	    }
	  break;
	case MARKFINDF:
	  for (i=0;i<=cp->mark_ctr[cp->edit_ctr];i++) 
	    if (((name) && (strcmp(name,mps[i]->name) == 0)) || (mps[i]->samp == msn)) return(gh_int2scm(i));
	  break;
	case MARKADDF:
	  m = add_mark(msn,NULL,cp);
	  update_graph(cp,NULL);
	  return(mark_to_index(cp,mps,m));
	  break;
	case MARKDELETEF:
	  if (msn<=cp->mark_ctr[cp->edit_ctr])
	    {
	      m = mps[msn];
	      delete_mark(m->samp,cp);
	    }
	  update_graph(cp,NULL);
	  break;
	}
    }
  return(SCM_BOOL_F);
}

static SCM iwrite_mark(SCM snd_n, SCM chn_n, SCM mark_n, SCM val, int fld)
{
  chan_info *cp;
  int n;
  mark *m;
  mark **mps;
  cp = get_cp(snd_n,chn_n);
  n = int_or_zero(mark_n);
  if ((cp) && (cp->marks) && (n<=cp->mark_ctr[cp->edit_ctr]))
    {
      mps = cp->marks[cp->edit_ctr];
      m = mps[n];
      switch (fld)
	{
	case MARKSAMPLEF: 
	  m->samp = gh_scm2int(val);
	  finish_moving_mark(cp,m); /* update and re-sort current mark list */
	  update_graph(cp,NULL);
	  return(mark_to_index(cp,mps,m));
	  break;
	case MARKNAMEF:
	  if (m->name) free(m->name);
	  m->name = gh_scm2newstr(val,NULL);
	  update_graph(cp,NULL);
	  break;
	}
    }
  return(val);
}

static SCM g_snd_mark_sample(SCM mark_n, SCM snd_n, SCM chn_n) {return(iread_mark(snd_n,chn_n,mark_n,MARKSAMPLEF));}
static SCM g_snd_set_mark_sample(SCM mark_n, SCM samp_n, SCM snd_n, SCM chn_n) {return(iwrite_mark(snd_n,chn_n,mark_n,samp_n,MARKSAMPLEF));}
static SCM g_snd_mark_name(SCM mark_n, SCM snd_n, SCM chn_n) {return(iread_mark(snd_n,chn_n,mark_n,MARKNAMEF));}
static SCM g_snd_set_mark_name(SCM mark_n, SCM name, SCM snd_n, SCM chn_n) {return(iwrite_mark(snd_n,chn_n,mark_n,name,MARKNAMEF));}
static SCM g_snd_find_mark(SCM samp_n, SCM snd_n, SCM chn_n) {return(iread_mark(snd_n,chn_n,samp_n,MARKFINDF));}
static SCM g_snd_add_mark(SCM samp_n, SCM snd_n, SCM chn_n) {return(iread_mark(snd_n,chn_n,samp_n,MARKADDF));}
static SCM g_snd_delete_mark(SCM samp_n, SCM snd_n, SCM chn_n) {return(iread_mark(snd_n,chn_n,samp_n,MARKDELETEF));}

static SCM g_snd_find_sound(SCM filename)
{
  /* scan active sounds looking for full then partial match, return index if found else nil */
  char *fname = NULL;
  snd_info *sp;
  if (gh_string_p(filename))
    {
      fname = gh_scm2newstr(filename,NULL);
      sp = find_sound(state,fname);
      if (fname) free(fname);
      if (sp) return(gh_int2scm(sp->index));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_set_x_bounds(SCM beg, SCM end, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) clm_x_axis(cp,gh_scm2double(beg),gh_scm2double(end));
  return(SCM_BOOL_F);
}

static SCM g_snd_set_y_bounds(SCM y0, SCM y1, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) clm_y_axis(cp,gh_scm2double(y0),gh_scm2double(y1));
  return(SCM_BOOL_F);
}

static SCM g_snd_set_y_limits(SCM low, SCM high, SCM which_graph, SCM snd_n, SCM chn_n)
{ /* experimental and doesn't work correctly yet */
  chan_info *cp;
  int grf;
  float y0,y1;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      grf = gh_scm2int(which_graph);
      y1 = gh_scm2double(high);
      y0 = gh_scm2double(low);
      if (grf == 0)
	clm_y_axis(cp,y0,y1);
      else
	if (grf == 1)
	  set_y_limits(cp,(cp->fft)->axis,y0,y1);
	else set_y_limits(cp,(cp->lisp_info)->axis,y0,y1);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_x_bounds(SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  axis_info *ap;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      ap = cp->axis;
      return(gh_cons(gh_double2scm(ap->x0),gh_double2scm(ap->x1)));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_y_bounds(SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  axis_info *ap;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      ap = cp->axis;
      return(gh_cons(gh_double2scm(ap->y0),gh_double2scm(ap->y1)));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_sample(SCM samp_n, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) return(gh_double2scm(sample(gh_scm2int(samp_n),cp)));
  return(SCM_BOOL_F);
}

static void add_zeros(chan_info *cp, int beg, int count)
{
  int *zeros;
  zeros = (int *)snd_calloc(cp->state,count,sizeof(int));
  insert_samples(beg,count,zeros,cp,"(zero-pad)");
  check_for_first_edit(cp);
  free(zeros);
}

static SCM g_snd_set_sample(SCM samp_n, SCM val, SCM snd_n, SCM chn_n)
{
  /* each call consitutes a separate edit from the undo/redo point-of-view */
  chan_info *cp;
  int curlen,beg;
  int ival[1];
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      curlen = current_ed_samples(cp);
      beg = gh_scm2int(samp_n);
      if (beg >= curlen) add_zeros(cp,curlen-1,beg-curlen+1);
      ival[0] = clm_sndfix * gh_scm2double(val);
      change_samples(beg,1,ival,cp,LOCK_MIXES,"(set-sample)");
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      return(val);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_samples(SCM samp_0, SCM samps, SCM snd_n, SCM chn_n)
{
  /* return the filled vector for scm to free? */
  chan_info *cp;
  int *ivals;
  int i,len,beg;
  SCM new_vect;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      beg = int_or_zero(samp_0);
      len = gh_scm2int(samps);
      ivals = load_samples(beg,len,cp);
      new_vect = gh_vector(samps,gh_double2scm(0.0));
      for (i=0;i<len;i++)
	gh_vset(new_vect,gh_int2scm(i),gh_double2scm(clm_sndflt * ivals[i]));
      free(ivals);
      return(new_vect);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_set_samples(SCM samp_0, SCM samps, SCM vect, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  int *ivals;
  int i,len,beg,curlen;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      beg = gh_scm2int(samp_0);
      len = gh_scm2int(samps);
      curlen = current_ed_samples(cp);
      if (beg >= curlen) add_zeros(cp,curlen-1,beg-curlen+1);      
      ivals = (int *)calloc(len,sizeof(int));
      for (i=0;i<len;i++)
	ivals[i] = clm_sndfix * gh_scm2double(gh_vref(vect,gh_int2scm(i)));
      change_samples(beg,len,ivals,cp,LOCK_MIXES,"(set-samples)");
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      free(ivals);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_set_int_samples(SCM samp_0, SCM samps, SCM origin, SCM vect, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  int *ivals;
  char *str;
  int i,len,beg;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      beg = gh_scm2int(samp_0);
      len = gh_scm2int(samps);
      ivals = (int *)calloc(len,sizeof(int));
      for (i=0;i<len;i++) ivals[i] = gh_scm2int(gh_vref(vect,gh_int2scm(i)));
      str = gh_scm2newstr(origin,NULL);
      change_samples(beg,len,ivals,cp,LOCK_MIXES,str);
      free(str);
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      free(ivals);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_clm_samples(SCM file)
{
  /* if file, find_sound else use currently selected sound.
   * write current contents as temp file
   * return temp file name to clm
   */
  char *filename;
  file_info *hdr;
  snd_info *sp = NULL;
  if (gh_string_p(file))
    {
      filename = gh_scm2newstr(file,NULL);
      sp = find_sound(state,filename);
      free(filename);
    }
  if (!sp) sp = any_selected_sound(state);
  if (sp)
    {
      filename = snd_tempnam(temp_dir(state),"snd_");
      hdr = sp->hdr;
      save_edits_2(sp,filename,hdr->type,hdr->format,hdr->srate,NULL);
      return(gh_str02scm(filename));
    }
  return(SCM_BOOL_F);
}

static SCM g_clm_snd_update(SCM data)
{
  char *file;
  snd_info *sp;
  if (gh_string_p(data))
    {
      file = gh_scm2newstr(data,NULL);
      sp = find_sound(state,file);
      if (sp)
	snd_update(state,sp);
      else snd_open_file(file,state);
      free(file);
    }
  return(data);
}

static SCM g_clm_snd_close(SCM data)
{
  char *file;
  snd_info *sp;
  if (gh_string_p(data))
    {
      file = gh_scm2newstr(data,NULL);
      sp = find_sound(state,file);
      if (sp) snd_close_file(sp,state);
      free(file);
    }
  return(data);
}

static SCM g_clm_snd_set_samples(SCM samp_0)
{
  chan_info *cp;
  int *ivals;
  int len,beg,curlen;
  cp = current_channel(state);
  if (cp)
    {
      beg = gh_scm2int(samp_0);
      curlen = current_ed_samples(cp);
      if (beg >= curlen) add_zeros(cp,curlen-1,beg-curlen+1);      
      ivals = clm_snd_data(state,&len);
      change_samples(beg,len,ivals,cp,LOCK_MIXES,"(clm-snd-set-samples)");
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      free(ivals);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_clm_snd_replace_samples(SCM tempf, SCM oldf)
{
  char *tempfile;
  snd_info *sp;
  SCM index;
  tempfile = gh_scm2newstr(tempf,NULL);
  index = g_snd_find_sound(oldf);
  if (gh_number_p(index)) 
    sp = state->sounds[gh_scm2int(index)];
  else sp = any_selected_sound(state);
  clm_snd_replace_samples(state,tempfile,sp);
  free(tempfile);
  return(SCM_BOOL_F);
}

static SCM g_clm_snd_samples(SCM sbeg, SCM slen)
{
  int *data;
  int beg,len;
  chan_info *cp;
  beg = gh_scm2int(sbeg);
  len = gh_scm2int(slen);
  cp = current_channel(state);
  if (cp)
    {
      data = load_samples(beg,len,cp);
      snd_clm_data(state,len,data);
      free(data);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_delete_sample(SCM samp_n, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      delete_samples(gh_scm2int(samp_n),1,cp,"(delete-sample)");
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_delete_samples(SCM samp_n, SCM samps, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      delete_samples(gh_scm2int(samp_n),gh_scm2int(samps),cp,"(delete-samples)");
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_delete_int_samples(SCM samp_n, SCM samps, SCM origin, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  char *str;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      str = gh_scm2newstr(origin,NULL);
      delete_samples(gh_scm2int(samp_n),gh_scm2int(samps),cp,str);
      free(str);
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_insert_sample(SCM samp_n, SCM val, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  int ival[1];
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      ival[0] = clm_sndfix * gh_scm2double(val);
      insert_samples(gh_scm2int(samp_n),1,ival,cp,"(insert-sample)");
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_insert_samples(SCM samp, SCM samps, SCM vect, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  int *ivals;
  int i,beg,len;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      beg = gh_scm2int(samp);
      len = gh_scm2int(samps);
      ivals = (int *)calloc(len,sizeof(int));
      for (i=0;i<len;i++) ivals[i] = clm_sndfix * gh_scm2double(gh_vref(vect,gh_int2scm(i)));
      insert_samples(beg,len,ivals,cp,"(insert-samples)");
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      free(ivals);
      return(gh_int2scm(len));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_insert_int_samples(SCM samp, SCM samps, SCM origin, SCM vect, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  int *ivals;
  char *str;
  int i,beg,len;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      beg = gh_scm2int(samp);
      len = gh_scm2int(samps);
      ivals = (int *)calloc(len,sizeof(int));
      for (i=0;i<len;i++) ivals[i] = gh_scm2int(gh_vref(vect,gh_int2scm(i)));
      str = gh_scm2newstr(origin,NULL);
      insert_samples(beg,len,ivals,cp,str);
      free(str);
      check_for_first_edit(cp);
      update_graph(cp,NULL);
      free(ivals);
      return(gh_int2scm(len));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_active_sounds(void)
{
  int i,num;
  num = 0;
  for (i=0;i<state->max_sounds;i++) if (snd_ok(state->sounds[i])) num++;
  return(gh_int2scm(num));
}

static SCM g_snd_undo(SCM ed_n, SCM snd_n, SCM chn_n) /* opt ed_n */
{ 
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      if (gh_number_p(ed_n))
	undo_EDIT(cp,gh_scm2int(ed_n));
      else undo_EDIT(cp,1);
      update_graph(cp,NULL);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_redo(SCM ed_n, SCM snd_n, SCM chn_n) /* opt ed_n */
{ 
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      if (gh_number_p(ed_n))
	redo_EDIT(cp,gh_scm2int(ed_n));
      else redo_EDIT(cp,1);
      update_graph(cp,NULL);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_insert_region(SCM reg_n, SCM snd_n, SCM chn_n) /* opt reg_n */
{ 
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) 
    {
      finish_keyboard_selection();
      if (gh_number_p(reg_n))
	paste_region(gh_scm2int(reg_n),cp,"(insert-region)");
      else paste_region(0,cp,"(insert-region)");
      update_graph(cp,NULL);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_insert_file(SCM file, SCM file_chn, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  char *filename;
  int nc,len,fchn;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      filename = complete_filename(gh_scm2newstr(file,NULL));
      nc = sound_chans(filename);
      if (nc != -1)
	{
	  len = sound_samples(filename)/nc;
	  fchn = int_or_zero(file_chn);
	  if (fchn < sound_chans(filename))
	    {
	      file_insert_samples(0,len,filename,cp,fchn,DONT_DELETE_ME,"(insert-sound)");
	      check_for_first_edit(cp);
	      update_graph(cp,NULL);
	      return(gh_int2scm(len));
	    }
	}
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_cut(void)
{ /* weird... */
  finish_keyboard_selection();
  if (region_ok(0))
    {
      delete_selection("(cut)");
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_selected_sound(void)
{
  if ((state->selected_sound != NO_SELECTION) && (snd_ok(state->sounds[state->selected_sound])))
    return(gh_int2scm(state->selected_sound));
  return(SCM_BOOL_F);
}

static SCM g_snd_report_in_minibuffer(SCM msg, SCM snd_n)
{
  snd_info *sp;
  char *str;
  sp = get_sp(snd_n);
  if (sp) 
    {
      str = gh_scm2newstr(msg,NULL);
      report_in_minibuffer(sp,str);
      free(str);
      return(msg);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_append_to_minibuffer(SCM msg, SCM snd_n)
{
  snd_info *sp;
  char *str;
  sp = get_sp(snd_n);
  if (sp) 
    {
      str = gh_scm2newstr(msg,NULL);
      append_to_minibuffer(sp,str);
      free(str);
      return(msg);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_open(SCM filename)
{ /* returns index of new sound if successful */
  char *fname;
  snd_info *sp;
  if (gh_string_p(filename))
    {
      fname = gh_scm2newstr(filename,NULL);
      sp = snd_open_file(fname,state);
      free(fname);
      if (sp) return(gh_int2scm(sp->index));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_open_alternate(SCM filename)
{ /* returns index of new sound if successful */
  char *fname;
  snd_info *sp;
  if (gh_string_p(filename))
    {
      sp = any_selected_sound(state);
      if (sp) snd_close_file(sp,state); /* should we ask about saving edits here? */
      fname = gh_scm2newstr(filename,NULL);
      sp = snd_open_file(fname,state);
      free(fname);
      if (sp) return(gh_int2scm(sp->index));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_view(SCM filename)
{
  char *fname;
  snd_info *sp;
  if (gh_string_p(filename))
    {
      fname = gh_scm2newstr(filename,NULL);
      state->viewing = 1;
      sp = snd_open_file(fname,state);
      state->viewing = 0;
      free(fname);
      if (sp) return(gh_int2scm(sp->index));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_save_as(SCM newfile, SCM index)
{ 
  snd_info *sp;
  file_info *hdr;
  char *fname;
  if ((gh_number_p(index)) && (gh_string_p(newfile)))
    {
      sp = get_sp(index);
      if (sp)
	{
	  fname = gh_scm2newstr(newfile,NULL);
	  hdr = sp->hdr;
	  save_edits_2(sp,fname,hdr->type,hdr->format,hdr->srate,NULL); /* last arg is comment */
	  free(fname);
	  return(newfile);
	}
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_revert(SCM index)
{ 
  snd_info *sp;
  int i;
  sp = get_sp(index);
  if (sp)
    {
      for (i=0;i<sp->nchans;i++) 
	{
	  revert_edits(sp->chans[i],NULL); 
	  update_graph(sp->chans[i],NULL);
	}
      reflect_file_revert_in_label(sp);
      reflect_file_revert_in_menu(state);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_new_file(SCM name) 
{
  snd_info *sp; 
  char *str;
  str = gh_scm2newstr(name,NULL);
  sp = snd_new_file(state,str); 
  free(str);
  if (sp) return(gh_int2scm(sp->index));
  return(SCM_BOOL_F);
}

static SCM g_snd_play(SCM samp_n, SCM snd_n, SCM chn_n) /* all chans if chn_n omitted, arbitrary file if snd_n is name */
{
  snd_info *sp;
  char *name;
  int samp = 0;
  if (gh_string_p(snd_n))
    {
      name = complete_filename(gh_scm2newstr(snd_n,NULL));
      sp = make_sound_readable(state,name,FALSE);
      if (sp)
	{
	  sp->shortname = filename_without_home_directory(name);
	  sp->fullname = NULL;
	  if (gh_number_p(chn_n)) samp = gh_scm2int(chn_n);
	  start_playing(sp,samp);
	  return(SCM_BOOL_T);
	}
    }
  else
    {
      sp = get_sp(snd_n);
      if (sp)
	{
	  if (gh_number_p(samp_n)) samp = gh_scm2int(samp_n);
	  if (!(gh_number_p(chn_n)))
	    start_playing(sp,samp);
	  else start_playing(get_cp(snd_n,chn_n),samp);
	  return(SCM_BOOL_T);
	}
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_stop(SCM snd_n)
{
  snd_info *sp;
  sp = get_sp(snd_n);
  if (sp) stop_playing(sp->playing);
  return(SCM_BOOL_F);
}

void add_or_edit_symbol(char *name, env *val)
{
  /* called from envelope editor -- pass new definition into scheme */
  SCM e;
  char *buf;
  buf = (char *)calloc(256,sizeof(char));
  e = gh_lookup(name);
  if ((e) && (e != SCM_BOOL_F) && (e != SCM_UNDEFINED) && (gh_list_p(e)))
    sprintf(buf,"(set! %s %s)",name,env_to_string(val));
  else sprintf(buf,"(define %s %s)",name,env_to_string(val));
  scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,buf,clm_handler,buf);
  free(buf);
}

env *name_to_env(char *str)
{
  /* called to see if str is a known envelope -- return its current value or nil if unknown */
  /* get str as list var and turn into env */
  SCM res,el;
  int i,len;
  float *data;
  res = gh_lookup(str);
  if (gh_list_p(res))
    {
      len = gh_list_length(res);
      data = (float *)calloc(len,sizeof(float));
      for (i=0;i<len;i++)
	{
	  el = scm_list_ref(res,gh_int2scm(i));
	  if (gh_number_p(el))
	    data[i] = gh_scm2double(el);
	  else data[i] = 0.0;
	}
      return(make_envelope(data,len));
    }
  return(NULL);
}

static SCM g_snd_save_defvar(SCM a)
{
  SCM res;
  char *name;
  name = gh_scm2newstr(a,0);
  res = gh_lookup(name);
  if (gh_list_p(res)) alert_envelope_editor(state,name,name_to_env(name));
  return(SCM_BOOL_F);
}

static SCM g_restore_marks(SCM size, SCM snd, SCM chn, SCM marklist)
{
  SCM lst,el,mlst;
  chan_info *cp;
  char *str;
  int i,j,list_size,in_size;
  cp = get_cp(snd,chn);
  if ((cp) && (!(cp->marks)))
    {
      cp->marks_size = gh_scm2int(size);
      cp->marks = (mark ***)calloc(cp->marks_size,sizeof(mark **));
      cp->mark_size = (int *)calloc(cp->marks_size,sizeof(int));
      cp->mark_ctr = (int *)calloc(cp->marks_size,sizeof(int));
      for (i=0;i<cp->marks_size;i++) cp->mark_ctr[i] = -1;
      list_size = gh_list_length(marklist);
      for (i=0;i<list_size;i++)
	{
	  lst = scm_list_ref(marklist,gh_int2scm(i));
	  cp->mark_size[i] = gh_scm2int(scm_list_ref(lst,gh_int2scm(0)));
	  cp->mark_ctr[i] = gh_scm2int(scm_list_ref(lst,gh_int2scm(1)));
          if (cp->mark_size[i] > 0)
	    {
	      mlst = scm_list_ref(lst,gh_int2scm(2));
	      cp->marks[i] = (mark **)calloc(cp->mark_size[i],sizeof(mark *));
	      in_size = gh_list_length(mlst);
	      for (j=0;j<in_size;j++)
		{
		  el = scm_list_ref(mlst,gh_int2scm(j));
		  if (gh_number_p(el))
		    {
                      if (gh_scm2int(el) != -1)
			cp->marks[i][j] = make_mark(gh_scm2int(el),NULL);
		    }
		  else 
		    {
		      if (!(gh_list_p(el))) fprintf(stderr,"not a list?? ");
		      str = gh_scm2newstr(scm_list_ref(el,gh_int2scm(0)),NULL);
		      cp->marks[i][j] = make_mark(gh_scm2int(scm_list_ref(el,gh_int2scm(1))),str);
		      free(str);
		    }
		}
	    }
	}
      return(SCM_BOOL_T);
    }
  else 
    if (cp->marks) fprintf(stderr,"there are marks here already!");
  return(SCM_BOOL_F);
}

static SCM g_snd_set_env_base(SCM name, SCM val) {return(gh_int2scm(set_env_base(gh_scm2newstr(name,NULL),gh_scm2double(val))));}
static SCM g_snd_update_graphs(void) {map_over_chans(state,update_graph,NULL); return(SCM_BOOL_F);}
static SCM g_snd_update_ffts(void) {map_over_chans(state,calculate_fft,NULL); return(SCM_BOOL_F);}

static SCM g_snd_region_length (SCM n) {return(gh_int2scm(region_len(int_or_zero(n))));}
static SCM g_snd_region_srate (SCM n) {return(gh_int2scm(region_srate(int_or_zero(n))));}
static SCM g_snd_region_chans (SCM n) {return(gh_int2scm(region_chans(int_or_zero(n))));}
static SCM g_snd_region_maxamp (SCM n) {return(gh_double2scm(region_maxamp(int_or_zero(n))));}
static SCM g_snd_select_region (SCM n) {select_region_and_update_browser(state,int_or_zero(n)); return(n);}
static SCM g_snd_delete_region (SCM n) {delete_region_and_update_browser(state,int_or_zero(n)); return(n);}

static SCM g_snd_protect_region (SCM n, SCM protect) {set_region_protect(gh_scm2int(n),gh_scm2int(protect)); return(protect);}
static SCM g_snd_regions(void) {return(gh_int2scm(snd_regions()));}
static SCM g_snd_play_region (SCM n) {play_region(state,int_or_zero(n),NULL); return(n);}

static SCM g_snd_make_region (SCM beg, SCM end, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) {define_region(cp,gh_scm2int(beg),gh_scm2int(end)); return(SCM_BOOL_T);}
  return(SCM_BOOL_F);
}

static SCM g_snd_save_region (SCM n, SCM filename) 
{
  char *name;
  name = gh_scm2newstr(filename,NULL);
  save_region(state,gh_scm2int(n),name);
  free(name);
  return(SCM_BOOL_F);
}

static SCM g_snd_mix_region(SCM chn_samp_n, SCM scaler, SCM reg_n, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) mix_region(int_or_zero(reg_n),cp,
		     (gh_number_p(chn_samp_n) ? (gh_scm2int(chn_samp_n)) : (cp->cursor)),
		     (gh_number_p(scaler) ? (gh_scm2double(scaler)) : 1.0));
  return(SCM_BOOL_F);
}

static SCM g_snd_region_sample(SCM samp_n, SCM reg_n, SCM chn_n)
{
  finish_keyboard_selection();
  return(gh_double2scm(region_sample(int_or_zero(reg_n),int_or_zero(chn_n),int_or_zero(samp_n))));
}

static SCM g_snd_region_samples(SCM beg_n, SCM num, SCM reg_n, SCM chn_n)
{
  SCM new_vect;
  float *data;
  int len,reg,i,chn;
  finish_keyboard_selection();
  reg = int_or_zero(reg_n);
  chn = int_or_zero(chn_n);
  if (chn < region_chans(reg))
    {
      len = int_or_zero(num);
      if (len == 0) len = region_len(reg);
      if (len > 0)
	{
	  new_vect = gh_vector(gh_int2scm(len),gh_double2scm(0.0));
	  data = (float *)calloc(len,sizeof(float));
	  region_samples(reg,chn,int_or_zero(beg_n),len,data);
	  for (i=0;i<len;i++) gh_vset(new_vect,gh_int2scm(i),gh_double2scm(data[i]));
	  free(data);
	  return(new_vect);
	}
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_group_ok(SCM n)
{
  if ((gh_number_p(n)) && (group_ok(state,gh_scm2int(n)))) return(SCM_BOOL_T);
  return(SCM_BOOL_F);
}

static SCM g_snd_groups(void) {return(gh_int2scm(active_groups(state)));}


static SCM g_snd_transform_sample(SCM bin, SCM slice, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  fft_info *fp;
  sono_info *si;
  int fbin,fslice;
  cp = get_cp(snd_n,chn_n);
  if ((cp) && (cp->ffting) && (!(chan_fft_in_progress(cp))))
    {
      fbin = int_or_zero(bin);
      fp = cp->fft;
      if ((fp) && (fbin < fp->current_size))
	{
	  if (fft_style(state) == NORMAL_FFT)
	    return(gh_double2scm(fp->data[fbin]));
	  else 
	    {
	      fslice = int_or_zero(slice);
	      si = (sono_info *)(cp->sonogram_data);
	      if ((si) && (fbin < si->target_bins) && (fslice < si->active_slices))
		return(gh_double2scm(si->data[fslice][fbin]));
	    }
	}
    }
  return(SCM_BOOL_F);
}  

static SCM g_snd_transform_samples(SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  fft_info *fp;
  sono_info *si;
  int bins,slices,i,j,len;
  SCM new_vect,tmp_vect;
  cp = get_cp(snd_n,chn_n);
  if ((cp) && (cp->ffting) && (!(chan_fft_in_progress(cp))))
    {
      fp = cp->fft;
      if (fp)
	{
	  bins = fp->current_size;
	  if (fft_style(state) == NORMAL_FFT)
	    {
	      len = fp->current_size;
	      new_vect = gh_vector(gh_int2scm(len),gh_double2scm(0.0));
	      for (i=0;i<len;i++) gh_vset(new_vect,gh_int2scm(i),gh_double2scm(fp->data[i]));
	      return(new_vect);
	    }

	  else 
	    {
	      si = (sono_info *)(cp->sonogram_data);
	      if (si)
		{
		  slices = si->active_slices;
		  bins = si->target_bins;
		  new_vect = gh_vector(gh_int2scm(slices),gh_double2scm(0.0));
		  for (i=0;i<slices;i++)
		    {
		      tmp_vect = gh_vector(gh_int2scm(bins),gh_double2scm(0.0));
		      gh_vset(new_vect,gh_int2scm(i),tmp_vect);
		      for (j=0;j<bins;j++)
			gh_vset(tmp_vect,gh_int2scm(j),gh_double2scm(si->data[i][j]));
		    }
		  return(new_vect);
		}
	    }
	}
    }
  return(SCM_BOOL_F);
}  


static int prefix_fix(SCM count)
{
  if (gh_number_p(count))
    return(gh_scm2int(count));
  else
    if (gh_number_p(gh_lookup("prefix-arg")))
      return(gh_scm2int(gh_lookup("prefix-arg")));
    else return(1);
}

static SCM g_snd_forward_graph(SCM count) {goto_next_graph(current_channel(state),prefix_fix(count)); return(count);}
static SCM g_snd_backward_graph(SCM count) {goto_previous_graph(current_channel(state),-(prefix_fix(count))); return(count);}
static SCM g_snd_forward_mark(SCM count) {handle_cursor(current_channel(state),goto_mark(current_channel(state),prefix_fix(count))); return(count);}
static SCM g_snd_backward_mark(SCM count) {handle_cursor(current_channel(state),goto_mark(current_channel(state),-(prefix_fix(count)))); return(count);}
static SCM g_snd_forward_mix(SCM count) {handle_cursor(current_channel(state),goto_mix(current_channel(state),prefix_fix(count))); return(count);}
static SCM g_snd_backward_mix(SCM count) {handle_cursor(current_channel(state),goto_mix(current_channel(state),-(prefix_fix(count)))); return(count);}

static SCM g_snd_forward_sample(SCM count) 
{
  chan_info *cp;
  cp = current_channel(state);
  if (cp) {handle_cursor(cp,cursor_move(cp,prefix_fix(count))); return(count);}
  return(SCM_BOOL_F);
}

static SCM g_snd_backward_sample(SCM count) 
{
  chan_info *cp;
  cp = current_channel(state);
  if (cp) {handle_cursor(cp,cursor_move(cp,-(prefix_fix(count)))); return(count);}
  return(SCM_BOOL_F);
}

static float *load_floats(SCM scalers, int *result_len)
{
  int len,i;
  float *scls;
  if (gh_vector_p(scalers))
    len = gh_vector_length(scalers);
  else
    if (gh_list_p(scalers))
      len = gh_list_length(scalers);
    else len = 1;
  if (len<=0) len=1;
  scls = (float *)calloc(len,sizeof(float));
  if (gh_vector_p(scalers))
    {
      for (i=0;i<len;i++) scls[i] = (float)gh_scm2double(gh_vref(scalers,gh_int2scm(i)));
    }
  else
    if (gh_list_p(scalers))
      {
	for (i=0;i<len;i++) scls[i] = (float)gh_scm2double(scm_list_ref(scalers,gh_int2scm(i)));
      }
    else
      if (gh_number_p(scalers))
	scls[0] = (float)gh_scm2double(scalers);
      else scls[0] = 1.0;
  result_len[0] = len;
  return(scls);
}

static SCM g_snd_scale_to(SCM scalers, SCM snd_n, SCM chn_n)
{
  /* chn_n irrelevant if syncing */
  snd_info *sp;
  chan_info *cp;
  int len[1];
  float *scls;
  sp = get_sp(snd_n);
  if (sp)
    {
      cp = get_cp(snd_n,chn_n);
      scls = load_floats(scalers,len);
      scale_to(state,sp,cp,scls,len[0],FALSE); /* last arg for selection */
      free(scls);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_scale_by(SCM scalers, SCM snd_n, SCM chn_n)
{
  /* chn_n irrelevant if syncing */
  snd_info *sp;
  chan_info *cp;
  int len[1];
  float *scls;
  sp = get_sp(snd_n);
  if (sp)
    {
      cp = get_cp(snd_n,chn_n);
      scls = load_floats(scalers,len);
      scale_by(state,sp,cp,scls,len[0],FALSE);
      free(scls);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_scale_selection_to(SCM scalers)
{
  int len[1];
  float *scls;
  if (region_ok(0))
    {
      scls = load_floats(scalers,len);
      scale_to(state,NULL,NULL,scls,len[0],TRUE);
      free(scls);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_scale_selection_by(SCM scalers)
{
  int len[1];
  float *scls;
  if (region_ok(0))
    {
      scls = load_floats(scalers,len);
      scale_by(state,NULL,NULL,scls,len[0],TRUE);
      free(scls);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_preload_directory(SCM directory) 
{
  char *str;
  str = gh_scm2newstr(directory,NULL);
  add_directory_to_prevlist(state,str);
  free(str);
  return(SCM_BOOL_F);
}

static SCM g_snd_preload_file(SCM file) 
{
  char *name;
  name = complete_filename(gh_scm2newstr(file,NULL));
  remember_me(state,filename_without_home_directory(name),name);
  return(SCM_BOOL_F);
}

static SCM g_snd_mix_position(SCM n) {return(gh_int2scm(mix_position(state,gh_scm2int(n))));}
static SCM g_snd_mix_length(SCM n) {return(gh_int2scm(mix_length(state,gh_scm2int(n))));}
static SCM g_snd_mix_anchor(SCM n) {return(gh_int2scm(mix_anchor(state,gh_scm2int(n))));}
static SCM g_snd_mix_groups(SCM n) {return(gh_int2scm(mix_groups(state,gh_scm2int(n))));}
static SCM g_snd_mix_state(SCM n) {return(gh_int2scm(in_mix_state(state,gh_scm2int(n))));}
static SCM g_snd_mix_speed(SCM n) {return(gh_double2scm(in_mix_speed(state,gh_scm2int(n))));}
static SCM g_snd_mix_amp(SCM n, SCM chan) {return(gh_double2scm(in_mix_amp(state,gh_scm2int(n),gh_scm2int(chan))));}

static SCM g_snd_set_mix_position(SCM n, SCM val) {return(gh_int2scm(set_mix_position(state,gh_scm2int(n),gh_scm2int(val))));}
static SCM g_snd_set_mix_length(SCM n, SCM val) {return(gh_int2scm(set_mix_length(state,gh_scm2int(n),gh_scm2int(val))));}
static SCM g_snd_set_mix_anchor(SCM n, SCM val) {return(gh_int2scm(set_mix_anchor(state,gh_scm2int(n),gh_scm2int(val))));}
static SCM g_snd_set_mix_groups(SCM n, SCM val) {return(gh_int2scm(set_mix_groups(state,gh_scm2int(n),gh_scm2int(val))));}
static SCM g_snd_set_mix_state(SCM n, SCM val) {return(gh_int2scm(in_set_mix_state(state,gh_scm2int(n),gh_scm2int(val))));}
static SCM g_snd_set_mix_speed(SCM n, SCM val) {return(gh_double2scm(in_set_mix_speed(state,gh_scm2int(n),gh_scm2double(val))));}
static SCM g_snd_set_mix_amp(SCM n, SCM chan, SCM val) {return(gh_double2scm(in_set_mix_amp(state,gh_scm2int(n),gh_scm2int(chan),gh_scm2double(val))));}

static SCM g_snd_group_tempo(SCM n) {return(gh_double2scm(mx_get_group_tempo(gh_scm2int(n))));}
static SCM g_snd_group_speed(SCM n) {return(gh_double2scm(mx_get_group_speed(gh_scm2int(n))));}
static SCM g_snd_group_beg(SCM n) {return(gh_double2scm(mx_get_group_beg(gh_scm2int(n))));}
static SCM g_snd_group_end(SCM n) {return(gh_double2scm(mx_get_group_end(gh_scm2int(n))));}
static SCM g_snd_group_amp(SCM n, SCM row) {return(gh_double2scm(mx_get_group_amp(gh_scm2int(n),gh_scm2int(row))));}

static SCM g_snd_set_group_tempo(SCM n, SCM val) {mx_set_group_tempo(state,gh_scm2int(n),gh_scm2double(val)); return(val);}
static SCM g_snd_set_group_speed(SCM n, SCM val) {mx_set_group_speed(state,gh_scm2int(n),gh_scm2double(val)); return(val);}
static SCM g_snd_set_group_beg(SCM n, SCM val) {mx_set_group_beg(state,gh_scm2int(n),gh_scm2double(val)); return(val);}
static SCM g_snd_set_group_end(SCM n, SCM val) {mx_set_group_end(state,gh_scm2int(n),gh_scm2double(val)); return(val);}
static SCM g_snd_set_group_amp(SCM n, SCM row, SCM val) {mx_set_group_amp(state,gh_scm2int(n),gh_scm2int(row),gh_scm2double(val)); return(val);}

static SCM g_snd_help_dialog(SCM subject, SCM msg)
{
  char *nmsg,*nsubj;
  nsubj = gh_scm2newstr(subject,NULL);
  nmsg = gh_scm2newstr(msg,NULL);
  snd_help(state,nsubj,nmsg);
  free(nsubj);
  free(nmsg);
  return(SCM_BOOL_F);
}

static SCM g_snd_enved_dialog(void) {create_envelope_editor(state); return(SCM_BOOL_F);}
static SCM g_snd_color_dialog(void) {start_color_dialog(state,0,0); return(SCM_BOOL_F);}
static SCM g_snd_orientation_dialog(void) {start_orientation_dialog(state,0,0); return(SCM_BOOL_F);}
static SCM g_snd_transform_dialog(void) {fire_up_transform_dialog(state); return(SCM_BOOL_F);}
static SCM g_snd_file_dialog(void) {start_file_dialog(state,0,0); return(SCM_BOOL_F);}
static SCM g_snd_region_dialog(void) {if (snd_regions() > 0) View_Region_Callback(main_PANE(state),(XtPointer)state,NULL); return(SCM_BOOL_F);}
static SCM g_snd_edit_header_dialog(SCM snd_n) {edit_header(get_sp(snd_n)); return(SCM_BOOL_F);}
static SCM g_snd_record_dialog(void) {snd_record_file(state); return(SCM_BOOL_F);}
static SCM g_snd_group_dialog(void) {fire_up_group_browser(state); return(SCM_BOOL_F);}
static SCM g_snd_clm_dialog(SCM msg) {start_clm_dialog(state,gh_scm2newstr(msg,NULL),NULL); return(SCM_BOOL_F);}
static SCM g_snd_yes_or_no_p(SCM msg) {if (snd_yes_or_no_p(state,gh_scm2newstr(msg,NULL))) return(SCM_BOOL_T); return(SCM_BOOL_F);}

static SCM g_show_edit_history(void) {return(gh_int2scm(show_edit_history(state)));}
static SCM g_set_show_edit_history(SCM on) {edit_history(state,bool_int_or_one(on)); return(on);}

#if HAVE_OSS
  static SCM g_clear_audio_inputs (void) {clear_soundcard_inputs(); return(SCM_BOOL_F);}
#endif

static env *get_env(SCM e, SCM base) /* list or vector in e */
{
  float *buf;
  int i,len;
  env *newenv;
  if (gh_vector_p(e))
    {
      len = gh_vector_length(e);
      buf = (float *)calloc(len,sizeof(float));
      for (i=0;i<len;i++) buf[i] = gh_scm2double(gh_vref(e,gh_int2scm(i)));
    }
  else
    if (gh_list_p(e))
      {
	len = gh_list_length(e);
	buf = (float *)calloc(len,sizeof(float));
        for (i=0;i<len;i++) buf[i] = gh_scm2double(scm_list_ref(e,gh_int2scm(i)));
      }
    else return(NULL);
  newenv = make_envelope(buf,len);
  if (gh_number_p(base)) newenv->base = gh_scm2double(base); else newenv->base = 1.0;
  return(newenv);
}

static SCM array_to_list(float *arr, int i, int len)
{
  if (i < (len-1))
    return(gh_cons(gh_double2scm(arr[i]),array_to_list(arr,i+1,len)));
  else return(gh_cons(gh_double2scm(arr[i]),SCM_EOL));
}

static SCM env2scm (env *e)
{
  if (e) return(array_to_list(e->data,0,e->pts*2));
  return(SCM_BOOL_F);
}

static SCM g_snd_set_filter_env(SCM edata, SCM base, SCM snd_n)
{
  snd_info *sp;
  sp = get_sp(snd_n);
  if (sp->filter_env) free_env(sp->filter_env);
  sp->filter_env = get_env(edata,base);
  filter_env_changed(sp,sp->filter_env);
  return(gh_cons(edata,base));
}

static SCM g_snd_filter_env(SCM snd_n)
{
  snd_info *sp;
  sp = get_sp(snd_n);
  if (sp) return(env2scm(sp->filter_env));
  return(SCM_BOOL_F);
}

static SCM g_snd_env_selection(SCM edata, SCM base, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  env *e;
  cp = get_cp(snd_n,chn_n);
  if ((cp) && (active_selection(cp)))
    {
      e = get_env(edata,base);
      if (e)
	{
	  apply_env(cp,e,0,0,1.0,TRUE,FALSE,"(env-selection)");
	  free_env(e);
	  return(SCM_BOOL_T);
	}
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_env(SCM edata, SCM samp_n, SCM samps, SCM base, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  env *e;
  int dur;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      e = get_env(edata,base);
      if (e)
	{
	  dur = int_or_zero(samps);
	  if (dur == 0) dur = current_ed_samples(cp);
	  apply_env(cp,e,int_or_zero(samp_n),dur,1.0,FALSE,FALSE,"(env)");
	  free_env(e);
	  return(SCM_BOOL_T);
	}
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_mix_file(SCM file, SCM chn_samp_n, SCM file_chn, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  char *name;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      name = complete_filename(gh_scm2newstr(file,NULL));
      file_mix_samples(int_or_zero(chn_samp_n),sound_samples(name)/sound_chans(name),name,cp,int_or_zero(file_chn),DONT_DELETE_ME,FALSE,1,"(mix)");
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_key(SCM kbd, SCM buckybits)
{
  return(gh_int2scm(keyboard_command(current_channel(state),gh_scm2int(kbd),gh_scm2int(buckybits))));
}

static SCM g_snd_add_to_main_menu(SCM label)
{
  return(gh_int2scm(add_to_main_menu(state,gh_scm2newstr(label,NULL))));
}

static char **callbacks = NULL;
static int callbacks_size = 0;
static int callb = 0;
#define CALLBACK_INCR 16

static SCM g_snd_add_to_menu(SCM menu, SCM label, SCM callstr)
{
  if (callbacks_size == callb)
    {
      callbacks_size += CALLBACK_INCR;
      if (callb == 0) 
	callbacks = (char **)calloc(callbacks_size,sizeof(char *));
      else callbacks = (char **)realloc(callbacks,callbacks_size * sizeof(char *));
    }
  add_to_menu(state,gh_scm2int(menu),gh_scm2newstr(label,NULL),callb);
  callbacks[callb] = gh_scm2newstr(callstr,NULL);
  callb++;
  return(label);
}

void g_snd_callback(snd_state *ss, int callb)
{
  char *buf;
  buf = callbacks[callb];
  scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,buf,clm_handler,buf);
}

static SCM g_snd_remove_from_menu(SCM menu, SCM label)
{
  return(gh_int2scm(remove_from_menu(state,gh_scm2int(menu),gh_scm2newstr(label,NULL))));
}

static SCM g_snd_change_menu_label(SCM menu, SCM old_label, SCM new_label)
{
  return(gh_int2scm(change_menu_label(gh_scm2int(menu),gh_scm2newstr(old_label,NULL),gh_scm2newstr(new_label,NULL))));
}

static SCM g_snd_set_menu_sensitive(SCM menu, SCM label, SCM on)
{
  return(gh_int2scm(set_menu_sensitive(gh_scm2int(menu),gh_scm2newstr(label,NULL),gh_scm2int(on))));
}


/* the standard fft... */

#define one_pi 3.141592653589793
static void shuffle (float* rl, float* im, int n)
{
  int i,m,j;
  float tempr,tempi;
  j=0;
  for (i=0;i<n;i++)
    {
      if (j>i) {tempr = rl[j]; tempi = im[j]; rl[j] = rl[i]; im[j] = im[i]; rl[i] = tempr; im[i] = tempi;}
      m = n>>1; 
      while ((m>=2) && (j>=m)) {j -= m; m = m>>1;}
      j += m;}}

static void g_fft (float* rl, float* im, int n, int isign, int ipow)
{
  int mmax,j,pow,prev,lg,i,ii,jj;
  float wrs,wis,tempr,tempi;
  double wr,wi,theta,wtemp,wpr,wpi;
  shuffle(rl,im,n);
  mmax = 2; prev = 1; pow = n*0.5; theta = (one_pi*isign);
  for (lg=0;lg<ipow;lg++)
    {
      wpr = cos(theta); wpi = sin(theta); wr = 1.0; wi = 0.0;
      for (ii=0;ii<prev;ii++)
	{
	  wrs = (float) wr;  wis = (float) wi; i = ii; j = ii + prev;
	  for (jj=0;jj<pow;jj++)
	    {
	      tempr = wrs*rl[j] - wis*im[j]; tempi = wrs*im[j] + wis*rl[j];
	      rl[j] = rl[i] - tempr; im[j] = im[i] - tempi; rl[i] += tempr; im[i] += tempi;
	      i += mmax; j += mmax;
	    }
	  wtemp = wr; wr = (wr*wpr) - (wi*wpi); wi = (wi*wpr) + (wtemp*wpi);
	}
      pow = pow*0.5; prev = mmax; theta = theta*0.5; mmax = mmax*2;
    }
}

static SCM g_snd_fft(SCM reals, SCM imag, SCM sign)
{
  int n,ipow,i,isign = 1;
  float *rl,*im;
  n = gh_vector_length(reals);
  ipow = log((float)n)/log(2.0);
  rl = (float *)calloc(n,sizeof(float));
  im = (float *)calloc(n,sizeof(float));
  if (gh_number_p(sign)) isign = gh_scm2int(sign);
  if (isign == 0) isign = 1;
  for (i=0;i<n;i++)
    {
      rl[i] = gh_scm2double(gh_vref(reals,gh_int2scm(i)));
      im[i] = gh_scm2double(gh_vref(imag,gh_int2scm(i)));
    }
  g_fft(rl,im,n,isign,ipow);
  for (i=0;i<n;i++)
    {
      gh_vset(reals,gh_int2scm(i),gh_double2scm(rl[i]));
      gh_vset(imag,gh_int2scm(i),gh_double2scm(im[i]));
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_src(SCM ratio_or_env, SCM base)
{
  /* follows sync and applies to current chan -- not the way everything else works */
  if (gh_number_p(ratio_or_env))
    src_env_or_num(state,NULL,gh_scm2double(ratio_or_env),TRUE,FALSE,"(src)");
  else src_env_or_num(state,get_env(ratio_or_env,base),1.0,FALSE,FALSE,"(src)");
  return(SCM_BOOL_F);
}

static SCM g_snd_filter(SCM filter_env, SCM order, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  cp = get_cp(snd_n,chn_n);
  if (cp) {apply_filter(cp,gh_scm2int(order),get_env(filter_env,gh_double2scm(1.0)),FALSE,"(filter)"); return(SCM_BOOL_T);}
  return(SCM_BOOL_F);
}


static SCM g_snd_graph(SCM data, SCM xlabel, SCM x0, SCM x1, SCM y0, SCM y1, SCM snd_n, SCM chn_n)
{
  chan_info *cp;
  lisp_grf *lg;
  char *label = NULL;
  int i;
  float ymin,ymax,val,nominal_x0,nominal_x1;
  cp = get_cp(snd_n,chn_n);
  if (cp)
    {
      if (!(cp->lisp_info))
	cp->lisp_info = (lisp_grf *)calloc(1,sizeof(lisp_grf));
      lg = cp->lisp_info;
      lg->length = gh_vector_length(data);
      if (lg->data_size < lg->length)
	{
	  if (lg->data_size > 0) free(lg->data);
	  lg->data_size = lg->length;
	  lg->data = (float *)calloc(lg->length,sizeof(float));
	}
      if ((gh_number_p(y0)) && (gh_number_p(y1)))
	{
	  ymin = gh_scm2double(y0);
	  ymax = gh_scm2double(y1);
	  for (i=0;i<lg->length;i++) lg->data[i] = gh_scm2double(gh_vref(data,gh_int2scm(i)));
	}
      else
	{
	  lg->data[0] = gh_scm2double(gh_vref(data,gh_int2scm(0)));
	  ymin = lg->data[0]; 
	  ymax = lg->data[0]; 
	  for (i=1;i<lg->length;i++)
	    {
	      val = gh_scm2double(gh_vref(data,gh_int2scm(i)));
	      lg->data[i] = val; 
	      if (ymin > val) ymin = val;
	      if (ymax < val) ymax = val;
	    }
	}
      if (gh_string_p(xlabel)) label = gh_scm2newstr(xlabel,NULL); 
      if (gh_number_p(x0)) nominal_x0 = gh_scm2double(x0); else nominal_x0 = 0.0;
      if (gh_number_p(x1)) nominal_x1 = gh_scm2double(x1); else nominal_x1 = 1.0;
      lg->axis = make_axis_info(cp,nominal_x0,nominal_x1,ymin,ymax,label,nominal_x0,nominal_x1,ymin,ymax,lg->axis);
      if (label) free(label);
      lg->peaks_ok = 1;
      lg->scaler = 1.0;
      cp->lisp_graphing = 1;
      display_channel_data(cp,cp->sound,cp->state);
    }
  return(SCM_BOOL_F);
}

static SCM g_snd_setkey(SCM key, SCM state, SCM code)
{
  char *cstr;
  cstr = gh_scm2newstr(code,NULL);
  set_keymap_entry(gh_scm2int(key),gh_scm2int(state),cstr);
  free(cstr);
  return(SCM_BOOL_T);
}

/* sndlib imported */
static SCM g_sound_samples(SCM filename) {return(gh_int2scm(sound_samples(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_datum_size(SCM filename) {return(gh_int2scm(sound_datum_size(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_data_location(SCM filename) {return(gh_int2scm(sound_data_location(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_chans(SCM filename) {return(gh_int2scm(sound_chans(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_srate(SCM filename) {return(gh_int2scm(sound_srate(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_header_type(SCM filename) {return(gh_int2scm(sound_header_type(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_data_format(SCM filename) {return(gh_int2scm(sound_data_format(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_length(SCM filename) {return(gh_int2scm(sound_length(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_type_specifier(SCM filename) {return(gh_int2scm(sound_type_specifier(gh_scm2newstr(filename,NULL))));}
static SCM g_sound_type_name(SCM type) {return(gh_str02scm(sound_type_name(gh_scm2int(type))));}
static SCM g_sound_format_name(SCM format) {return(gh_str02scm(sound_format_name(gh_scm2int(format))));}
static SCM g_sound_comment(SCM filename) {return(gh_str02scm(sound_comment(gh_scm2newstr(filename,NULL))));}
static SCM g_bytes_per_sample(SCM format) {return(gh_int2scm(bytes_per_sample(gh_scm2int(format))));}
static SCM g_audio_error(void) {return(gh_int2scm(audio_error()));}
static SCM g_audio_error_name(SCM err) {return(gh_str02scm(audio_error_name(gh_scm2int(err))));}

#ifdef _DEBUG_MALLOC_INC
static SCM g_dump_memory(void)
{
  /* gawk '$2 != "unknown"' snd.mem | sort -n +4 > ho */
  int fd;
  unsigned long cur;
  malloc_size(&cur);
  fd = creat("snd.mem",0666);
  malloc_list(fd,state->orig_size,cur);
  close(fd);
  return(SCM_BOOL_F);
}
#endif

static SCM g_snd_save_edit_history(SCM filename, SCM snd, SCM chn)
{
  char *fstr;
  FILE *fd;
  int i,j;
  snd_info *sp;
  fstr = gh_scm2newstr(filename,NULL);
  fd = fopen(fstr,"w");
  if (fd)
    {
      if ((gh_number_p(chn)) && (gh_number_p(snd)))
	edit_history_to_file(fd,get_cp(snd,chn));
      else
	{
	  if (gh_number_p(snd))
	    {
	      sp = get_sp(snd);
	      for (i=0;i<sp->nchans;i++)
		edit_history_to_file(fd,sp->chans[i]);
	    }
	  else
	    {
	      for (i=0;i<state->max_sounds;i++)
		{
		  if ((sp=((snd_info *)(state->sounds[i]))))
		    {
		      if (sp->inuse)
			{
			  for (j=0;j<sp->nchans;j++)
			    edit_history_to_file(fd,sp->chans[j]);
			}
		    }
		}
	    }
	}
      fclose(fd);
      return(SCM_BOOL_T);
    }
  return(SCM_BOOL_F);
}

static SCM g_set_oss_buffers(SCM num, SCM size)
{
#if HAVE_OSS
  set_oss_buffers(gh_scm2int(num),gh_scm2int(size));
#endif
  return(SCM_BOOL_F);
}

void g_initialize_gh(snd_state *ss)
{
  state = ss;
  /* 
   * most of the set-[boolean]s take #t as the default value, so we need to wrap them up in an extra lambda.
   * according to my rudimentary understanding of Scheme, this form of lambda sets arg to '() if there's
   * no explicit argument, and in Guile that is the same as #f; so the (or arg #t) form returns #t if
   * there are no args, but if an explicit #f is passed in, arg is '(#f) which itself is not #f, so
   * the function gets the argument #f (which is what we want).
   */
  /* these are the state variables handled as functions in Guile */
  gh_eval_str("(define guile (lambda nil 1))");

#ifdef _DEBUG_MALLOC_INC
  gh_new_procedure0_0("dump-memory",g_dump_memory);
#endif
  gh_new_procedure2_0("set-oss-buffers",g_set_oss_buffers);
  gh_new_procedure0_0("ask-before-overwrite",g_ask_before_overwrite);
  gh_new_procedure0_1("set-ask-before-overwrite",g_set_ask_before_overwrite);
  gh_new_procedure0_0("auto-resize",g_auto_resize);
  gh_new_procedure0_1("set-auto-resize",g_set_auto_resize);
  gh_new_procedure0_0("channel-style",g_channel_style);
  gh_new_procedure1_0("set-channel-style",g_set_channel_style);
  gh_new_procedure0_0("color-cutoff",g_color_cutoff);
  gh_new_procedure1_0("set-color-cutoff",g_set_color_cutoff);
  gh_new_procedure0_0("color-inverted",g_color_inverted);
  gh_new_procedure0_1("set-color-inverted",g_set_color_inverted);
  gh_new_procedure0_0("color-scale",g_color_scale);
  gh_new_procedure1_0("set-color-scale",g_set_color_scale);
  gh_new_procedure0_0("default-amp",g_default_amp);
  gh_new_procedure1_0("set-default-amp",g_set_default_amp);
  gh_new_procedure0_0("default-contrast",g_default_contrast);
  gh_new_procedure1_0("set-default-contrast",g_set_default_contrast);
  gh_new_procedure0_0("default-contrast-amp",g_default_contrast_amp);
  gh_new_procedure1_0("set-default-contrast-amp",g_set_default_contrast_amp);
  gh_new_procedure0_0("default-contrasting",g_default_contrasting);
  gh_new_procedure0_1("set-default-contrasting",g_set_default_contrasting);
  gh_new_procedure0_0("default-expand",g_default_expand);
  gh_new_procedure1_0("set-default-expand",g_set_default_expand);
  gh_new_procedure0_0("default-expand-hop",g_default_expand_hop);
  gh_new_procedure1_0("set-default-expand-hop",g_set_default_expand_hop);
  gh_new_procedure0_0("default-expand-length",g_default_expand_length);
  gh_new_procedure1_0("set-default-expand-length",g_set_default_expand_length);
  gh_new_procedure0_0("default-expand-ramp",g_default_expand_ramp);
  gh_new_procedure1_0("set-default-expand-ramp",g_set_default_expand_ramp);
  gh_new_procedure0_0("default-expanding",g_default_expanding);
  gh_new_procedure0_1("set-default-expanding",g_set_default_expanding);
  gh_new_procedure0_0("default-filter-order",g_default_filter_order);
  gh_new_procedure1_0("set-default-filter-order",g_set_default_filter_order);
  gh_new_procedure0_0("default-filtering",g_default_filtering);
  gh_new_procedure0_1("set-default-filtering",g_set_default_filtering);
  gh_new_procedure0_0("default-output-type",g_default_output_type);
  gh_new_procedure1_0("set-default-output-type",g_set_default_output_type);
  gh_new_procedure0_0("default-reverb-feedback",g_default_reverb_feedback);
  gh_new_procedure1_0("set-default-reverb-feedback",g_set_default_reverb_feedback);
  gh_new_procedure0_0("default-reverb-length",g_default_reverb_length);
  gh_new_procedure1_0("set-default-reverb-length",g_set_default_reverb_length);
  gh_new_procedure0_0("default-reverb-lowpass",g_default_reverb_lowpass);
  gh_new_procedure1_0("set-default-reverb-lowpass",g_set_default_reverb_lowpass);
  gh_new_procedure0_0("default-reverb-scale",g_default_reverb_scale);
  gh_new_procedure1_0("set-default-reverb-scale",g_set_default_reverb_scale);
  gh_new_procedure0_0("default-reverbing",g_default_reverbing);
  gh_new_procedure0_1("set-default-reverbing",g_set_default_reverbing);
  gh_new_procedure0_0("default-speed",g_default_speed);
  gh_new_procedure1_0("set-default-speed",g_set_default_speed);
  gh_new_procedure0_0("dot-size",g_dot_size);
  gh_new_procedure1_0("set-dot-size",g_set_dot_size);
  gh_new_procedure0_0("enved-base",g_enved_base);
  gh_new_procedure1_0("set-enved-base",g_set_enved_base);
  gh_new_procedure0_0("enved-clipping",g_enved_clipping);
  gh_new_procedure0_1("set-enved-clipping-1",g_set_enved_clipping);
  gh_eval_str("(define set-enved-clipping (lambda arg (apply set-enved-clipping-1 (or arg #t))))");
  gh_new_procedure0_0("enved-exping",g_enved_exping);
  gh_new_procedure0_1("set-enved-exping-1",g_set_enved_exping);
  gh_eval_str("(define set-enved-exping (lambda arg (apply set-enved-exping-1 (or arg #t))))");
  gh_new_procedure0_0("enved-target",g_enved_target);
  gh_new_procedure1_0("set-enved-target",g_set_enved_target);
  gh_new_procedure0_0("enved-waving",g_enved_waving);
  gh_new_procedure0_1("set-enved-waving-1",g_set_enved_waving);
  gh_eval_str("(define set-enved-waving (lambda arg (apply set-enved-waving-1 (or arg #t))))");
  gh_new_procedure0_0("eps-file",g_eps_file);
  gh_new_procedure1_0("set-eps-file",g_set_eps_file);
  gh_new_procedure0_0("fft-beta",g_fft_beta);
  gh_new_procedure1_0("set-fft-beta",g_set_fft_beta);
  gh_new_procedure0_0("fft-log-frequency",g_fft_log_frequency);
  gh_new_procedure0_1("set-fft-log-frequency-1",g_set_fft_log_frequency);
  gh_eval_str("(define set-fft-log-frequency (lambda arg (apply set-fft-log-frequency-1 (or arg #t))))");
  gh_new_procedure0_0("fft-log-magnitude",g_fft_log_magnitude);
  gh_new_procedure0_1("set-fft-log-magnitude-1",g_set_fft_log_magnitude);
  gh_eval_str("(define set-fft-log-magnitude (lambda arg (apply set-fft-log-magnitude-1 (or arg #t))))");
  gh_new_procedure0_0("fft-size",g_fft_size);
  gh_new_procedure1_0("set-fft-size",g_set_fft_size);
  gh_new_procedure0_0("fft-style",g_fft_style);
  gh_new_procedure1_0("set-fft-style",g_set_fft_style);
  gh_new_procedure0_0("fft-window",g_fft_window);
  gh_new_procedure1_0("set-fft-window",g_set_fft_window);
  gh_new_procedure0_0("filter-env-order",g_filter_env_order);
  gh_new_procedure1_0("set-filter-env-order",g_set_filter_env_order);
  gh_new_procedure0_0("fit-data-on-open",g_fit_data_on_open);
  gh_new_procedure0_1("set-fit-data-on-open",g_set_fit_data_on_open);
  gh_new_procedure0_0("graph-style",g_graph_style);
  gh_new_procedure1_0("set-graph-style",g_set_graph_style);
  gh_new_procedure0_0("initial-x0",g_initial_x0);
  gh_new_procedure1_0("set-initial-x0",g_set_initial_x0);
  gh_new_procedure0_0("initial-x1",g_initial_x1);
  gh_new_procedure1_0("set-initial-x1",g_set_initial_x1);
  gh_new_procedure0_0("initial-y0",g_initial_y0);
  gh_new_procedure1_0("set-initial-y0",g_set_initial_y0);
  gh_new_procedure0_0("initial-y1",g_initial_y1);
  gh_new_procedure1_0("set-initial-y1",g_set_initial_y1);
  gh_new_procedure0_0("line-size",g_line_size);
  gh_new_procedure1_0("set-line-size",g_set_line_size);
  gh_new_procedure0_0("mix-amp-scaler",g_mix_amp_scaler);
  gh_new_procedure1_0("set-mix-amp-scaler",g_set_mix_amp_scaler);
  gh_new_procedure0_0("mix-duration-brackets",g_mix_duration_brackets);
  gh_new_procedure1_0("set-mix-duration-brackets",g_set_mix_duration_brackets);
  gh_new_procedure0_0("mix-speed-scaler",g_mix_speed_scaler);
  gh_new_procedure1_0("set-mix-speed-scaler",g_set_mix_speed_scaler);
  gh_new_procedure0_0("mix-tempo-scaler",g_mix_tempo_scaler);
  gh_new_procedure1_0("set-mix-tempo-scaler",g_set_mix_tempo_scaler);
  gh_new_procedure0_0("mixer-group-max-out-chans",g_mixer_group_max_out_chans);
  gh_new_procedure1_0("set-mixer-group-max-out-chans",g_set_mixer_group_max_out_chans);
  gh_new_procedure0_0("mixer-groups",g_mixer_groups);
  gh_new_procedure1_0("set-mixer-groups",g_set_mixer_groups);
  gh_new_procedure0_0("movies",g_movies);
  gh_new_procedure0_1("set-movies",g_set_movies);
  gh_new_procedure0_0("normalize-fft",g_normalize_fft);
  gh_new_procedure0_1("set-normalize-fft",g_set_normalize_fft);
  gh_new_procedure0_0("normalize-on-open",g_normalize_on_open);
  gh_new_procedure0_1("set-normalize-on-open",g_set_normalize_on_open);
  gh_new_procedure0_0("prefix-arg",g_prefix_arg);
  gh_new_procedure1_0("set-prefix-arg",g_set_prefix_arg);
  gh_new_procedure0_0("print-length",g_print_length);
  gh_new_procedure1_0("set-print-length",g_set_print_length);
  gh_new_procedure0_0("raw-chans",g_raw_chans);
  gh_new_procedure1_0("set-raw-chans",g_set_raw_chans);
  gh_new_procedure0_0("raw-format",g_raw_format);
  gh_new_procedure1_0("set-raw-format",g_set_raw_format);
  gh_new_procedure0_0("raw-srate",g_raw_srate);
  gh_new_procedure1_0("set-raw-srate",g_set_raw_srate);
  gh_new_procedure0_0("raw-type",g_raw_type);
  gh_new_procedure1_0("set-raw-type",g_set_raw_type);
  gh_new_procedure0_0("recorder-autoload",g_recorder_autoload);
  gh_new_procedure0_1("set-recorder-autoload",g_set_recorder_autoload);
  gh_new_procedure0_0("recorder-buffer-size",g_recorder_buffer_size);
  gh_new_procedure1_0("set-recorder-buffer-size",g_set_recorder_buffer_size);
  gh_new_procedure0_0("recorder-file",g_recorder_file);
  gh_new_procedure1_0("set-recorder-file",g_set_recorder_file);
  gh_new_procedure0_0("recorder-in-format",g_recorder_in_format);
  gh_new_procedure1_0("set-recorder-in-format",g_set_recorder_in_format);
  gh_new_procedure0_0("recorder-out-chans",g_recorder_out_chans);
  gh_new_procedure1_0("set-recorder-out-chans",g_set_recorder_out_chans);
  gh_new_procedure0_0("recorder-out-format",g_recorder_out_format);
  gh_new_procedure1_0("set-recorder-out-format",g_set_recorder_out_format);
  gh_new_procedure0_0("recorder-srate",g_recorder_srate);
  gh_new_procedure1_0("set-recorder-srate",g_set_recorder_srate);
  gh_new_procedure0_0("reverb-decay",g_reverb_decay);
  gh_new_procedure1_0("set-reverb-decay",g_set_reverb_decay);
  gh_new_procedure0_0("save-state-on-exit",g_save_state_on_exit);
  gh_new_procedure0_1("set-save-state-on-exit",g_set_save_state_on_exit);
  gh_new_procedure0_0("session-file",g_session_file);
  gh_new_procedure1_0("set-session-file",g_set_session_file);
  gh_new_procedure0_0("show-fft-peaks",g_show_fft_peaks);
  gh_new_procedure0_1("set-show-fft-peaks",g_set_show_fft_peaks);
  gh_new_procedure0_0("show-marks",g_show_marks);
  gh_new_procedure0_1("set-show-marks-1",g_set_show_marks);
  gh_eval_str("(define set-show-marks (lambda arg (apply set-show-marks-1 (or arg #t))))");
  gh_new_procedure0_0("show-mix-consoles",g_show_mix_consoles);
  gh_new_procedure0_1("set-show-mix-consoles-1",g_set_show_mix_consoles);
  gh_eval_str("(define set-show-mix-consoles (lambda arg (apply set-show-mix-consoles-1 (or arg #t))))");
  gh_new_procedure0_0("show-y-zero",g_show_y_zero);
  gh_new_procedure0_1("set-show-y-zero-1",g_set_show_y_zero);
  gh_eval_str("(define set-show-y-zero (lambda arg (apply set-show-y-zero-1 (or arg #t))))");
  gh_new_procedure0_0("sinc-width",g_sinc_width);
  gh_new_procedure1_0("set-sinc-width",g_set_sinc_width);
  gh_new_procedure0_0("spectro-color",g_spectro_color);
  gh_new_procedure1_0("set-spectro-color",g_set_spectro_color);
  gh_new_procedure0_0("spectro-cutoff",g_spectro_cutoff);
  gh_new_procedure1_0("set-spectro-cutoff",g_set_spectro_cutoff);
  gh_new_procedure0_0("spectro-hop",g_spectro_hop);
  gh_new_procedure1_0("set-spectro-hop",g_set_spectro_hop);
  gh_new_procedure0_0("spectro-x-angle",g_spectro_x_angle);
  gh_new_procedure1_0("set-spectro-x-angle",g_set_spectro_x_angle);
  gh_new_procedure0_0("spectro-x-scale",g_spectro_x_scale);
  gh_new_procedure1_0("set-spectro-x-scale",g_set_spectro_x_scale);
  gh_new_procedure0_0("spectro-y-angle",g_spectro_y_angle);
  gh_new_procedure1_0("set-spectro-y-angle",g_set_spectro_y_angle);
  gh_new_procedure0_0("spectro-y-scale",g_spectro_y_scale);
  gh_new_procedure1_0("set-spectro-y-scale",g_set_spectro_y_scale);
  gh_new_procedure0_0("spectro-z-angle",g_spectro_z_angle);
  gh_new_procedure1_0("set-spectro-z-angle",g_set_spectro_z_angle);
  gh_new_procedure0_0("spectro-z-scale",g_spectro_z_scale);
  gh_new_procedure1_0("set-spectro-z-scale",g_set_spectro_z_scale);
  gh_new_procedure0_0("speed-style",g_speed_style);
  gh_new_procedure1_0("set-speed-style",g_set_speed_style);
  gh_new_procedure0_0("speed-tones",g_speed_tones);
  gh_new_procedure1_0("set-speed-tones",g_set_speed_tones);
  gh_new_procedure0_0("subsampling",g_subsampling);
  gh_new_procedure0_1("set-subsampling-1",g_set_subsampling);
  gh_eval_str("(define set-subsampling (lambda arg (apply set-subsampling-1 (or arg #t))))");
  gh_new_procedure0_0("temp-dir",g_temp_dir);
  gh_new_procedure1_0("set-temp-dir",g_set_temp_dir);
#if HAVE_XmHTML
  gh_new_procedure0_0("html-dir",g_html_dir);
  gh_new_procedure1_0("set-html-dir",g_set_html_dir);
#endif
  gh_new_procedure0_0("transform-type",g_transform_type);
  gh_new_procedure1_0("set-transform-type",g_set_transform_type);
  gh_new_procedure0_0("use-raw-defaults",g_use_raw_defaults);
  gh_new_procedure1_0("set-use-raw-defaults",g_set_use_raw_defaults);
  gh_new_procedure0_0("verbose-cursor",g_verbose_cursor);
  gh_new_procedure0_1("set-verbose-cursor-1",g_set_verbose_cursor);
  gh_eval_str("(define set-verbose-cursor (lambda arg (apply set-verbose-cursor-1 (or arg #t))))");
  gh_new_procedure0_0("vu-font",g_vu_font);
  gh_new_procedure1_0("set-vu-font",g_set_vu_font);
  gh_new_procedure0_0("vu-font-size",g_vu_font_size);
  gh_new_procedure1_0("set-vu-font-size",g_set_vu_font_size);
  gh_new_procedure0_0("vu-size",g_vu_size);
  gh_new_procedure1_0("set-vu-size",g_set_vu_size);
  gh_new_procedure0_0("wavelet-type",g_wavelet_type);
  gh_new_procedure1_0("set-wavelet-type",g_set_wavelet_type);
  gh_new_procedure0_0("wavo",g_wavo);
  gh_new_procedure1_0("set-wavo",g_set_wavo);
  gh_new_procedure0_0("wavo-hop",g_wavo_hop);
  gh_new_procedure1_0("set-wavo-hop",g_set_wavo_hop);
  gh_new_procedure0_0("wavo-trace",g_wavo_trace);
  gh_new_procedure1_0("set-wavo-trace",g_set_wavo_trace);
  gh_new_procedure0_0("window-x",g_window_x);
  gh_new_procedure1_0("set-window-x",g_set_window_x);
  gh_new_procedure0_0("window-y",g_window_y);
  gh_new_procedure1_0("set-window-y",g_set_window_y);
  gh_new_procedure0_0("x-axis-style",g_x_axis_style);
  gh_new_procedure1_0("set-x-axis-style",g_set_x_axis_style);
  gh_new_procedure0_0("xmax",g_xmax);
  gh_new_procedure1_0("set-xmax",g_set_xmax);
  gh_new_procedure0_0("xmin",g_xmin);
  gh_new_procedure1_0("set-xmin",g_set_xmin);
  gh_new_procedure0_0("ymax",g_ymax);
  gh_new_procedure1_0("set-ymax",g_set_ymax);
  gh_new_procedure0_0("ymin",g_ymin);
  gh_new_procedure1_0("set-ymin",g_set_ymin);
  gh_new_procedure0_0("zero-pad",g_zero_pad);
  gh_new_procedure1_0("set-zero-pad",g_set_zero_pad);
  gh_new_procedure0_0("zoom-focus-style",g_zoom_focus_style);
  gh_new_procedure1_0("set-zoom-focus-style",g_set_zoom_focus_style);
  gh_new_procedure0_0("edit-history-width",g_edit_history_width);
  gh_new_procedure1_0("set-edit-history-width",g_set_edit_history_width);
  
  /* end simple state vars */

  gh_new_procedure1_0("recorder-gain",g_recorder_gain);
  gh_new_procedure2_0("recorder-in-amp",g_recorder_in_amp);
  gh_new_procedure1_0("recorder-out-amp",g_recorder_out_amp);
  gh_new_procedure2_0("set-recorder-gain",g_set_recorder_gain);
  gh_new_procedure3_0("set-recorder-in-amp",g_set_recorder_in_amp);
  gh_new_procedure2_0("set-recorder-out-amp",g_set_recorder_out_amp);

#if HAVE_OSS
  gh_new_procedure0_0("clear-audio-inputs",g_clear_audio_inputs);
#endif

  gh_new_procedure0_1("set-just-sounds-1",g_set_just_sounds);
  gh_eval_str("(define set-just-sounds (lambda arg (apply set-just-sounds-1 (or arg #t))))");

  gh_new_procedure1_0("mix-position",g_snd_mix_position);
  gh_new_procedure1_0("mix-length",g_snd_mix_length);
  gh_new_procedure1_0("mix-anchor",g_snd_mix_anchor);
  gh_new_procedure1_0("mix-groups",g_snd_mix_groups);
  gh_new_procedure1_0("mix-state",g_snd_mix_state);
  gh_new_procedure1_0("mix-speed",g_snd_mix_speed);
  gh_new_procedure2_0("mix-amp",g_snd_mix_amp);

  gh_new_procedure2_0("set-mix-position",g_snd_set_mix_position);
  gh_new_procedure2_0("set-mix-length",g_snd_set_mix_length);
  gh_new_procedure2_0("set-mix-anchor",g_snd_set_mix_anchor);
  gh_new_procedure2_0("set-mix-groups",g_snd_set_mix_groups);
  gh_new_procedure2_0("set-mix-state",g_snd_set_mix_state);
  gh_new_procedure2_0("set-mix-speed",g_snd_set_mix_speed);
  gh_new_procedure3_0("set-mix-amp",g_snd_set_mix_amp);

  gh_new_procedure1_0("group-tempo",g_snd_group_tempo);
  gh_new_procedure1_0("group-speed",g_snd_group_speed);
  gh_new_procedure1_0("group-beg",g_snd_group_beg);
  gh_new_procedure1_0("group-end",g_snd_group_end);
  gh_new_procedure2_0("group-amp",g_snd_group_amp);

  gh_new_procedure2_0("set-group-tempo",g_snd_set_group_tempo);
  gh_new_procedure2_0("set-group-speed",g_snd_set_group_speed);
  gh_new_procedure2_0("set-group-beg",g_snd_set_group_beg);
  gh_new_procedure2_0("set-group-end",g_snd_set_group_end);
  gh_new_procedure3_0("set-group-amp",g_snd_set_group_amp);

  gh_new_procedure0_0("enved-dialog",g_snd_enved_dialog);
  gh_new_procedure0_0("color-dialog",g_snd_color_dialog);
  gh_new_procedure0_0("orientation-dialog",g_snd_orientation_dialog);
  gh_new_procedure0_0("transform-dialog",g_snd_transform_dialog);
  gh_new_procedure0_0("file-dialog",g_snd_file_dialog);
  gh_new_procedure0_0("region-dialog",g_snd_region_dialog);
  gh_new_procedure0_1("edit-header-dialog",g_snd_edit_header_dialog);
  gh_new_procedure0_0("record-dialog",g_snd_record_dialog);
  gh_new_procedure0_0("group-dialog",g_snd_group_dialog);
  gh_new_procedure1_0("clm-dialog",g_snd_clm_dialog);
  gh_new_procedure2_0("help-dialog",g_snd_help_dialog);

  gh_new_procedure0_0("show-edit-history",g_show_edit_history);
  gh_new_procedure0_1("set-show-edit-history-1",g_set_show_edit_history);
  gh_eval_str("(define set-show-edit-history (lambda arg (apply set-show-edit-history-1 (or arg #t))))");

  gh_new_procedure1_2("sample",g_snd_sample);
  gh_new_procedure2_2("set-sample",g_snd_set_sample);
  gh_new_procedure2_2("samples",g_snd_samples);
  gh_new_procedure3_2("set-samples",g_snd_set_samples);
  gh_new_procedure4_2("set-int-samples",g_snd_set_int_samples);
  gh_new_procedure2_0("clm-snd-samples",g_clm_snd_samples);
  gh_new_procedure1_0("clm-snd-set-samples",g_clm_snd_set_samples);
  gh_new_procedure1_1("clm-snd-replace-samples",g_clm_snd_replace_samples);
  gh_new_procedure1_0("clm-snd-update",g_clm_snd_update);
  gh_new_procedure1_0("clm-snd-close",g_clm_snd_close);
  gh_new_procedure0_1("snd-clm-samples",g_snd_clm_samples);
  gh_new_procedure1_2("delete-sample",g_snd_delete_sample);
  gh_new_procedure2_2("delete-samples",g_snd_delete_samples);
  gh_new_procedure3_2("delete-int-samples",g_snd_delete_int_samples);
  gh_new_procedure2_2("insert-sample",g_snd_insert_sample);
  gh_new_procedure3_2("insert-samples",g_snd_insert_samples);
  gh_new_procedure4_2("insert-int-samples",g_snd_insert_int_samples);
  gh_new_procedure0_2("cursor",g_snd_cursor);
  gh_new_procedure1_2("set-cursor",g_snd_set_cursor);
  gh_new_procedure0_2("left-sample",g_snd_left_sample);
  gh_new_procedure1_2("set-left-sample",g_snd_set_left_sample);
  gh_new_procedure0_2("right-sample",g_snd_right_sample);
  gh_new_procedure1_2("set-right-sample",g_snd_set_right_sample);
  gh_new_procedure0_1("channels",g_snd_channels);
  gh_new_procedure0_1("chans",g_snd_channels);
  gh_new_procedure0_1("srate",g_snd_srate);
  gh_new_procedure0_1("data-location",g_snd_data_location);
  gh_new_procedure0_1("data-format",g_snd_data_format);
  gh_new_procedure0_1("header-type",g_snd_header_type);
  gh_new_procedure0_1("comment",g_snd_comment);
  gh_new_procedure0_2("snd-length",g_snd_length);
  gh_new_procedure0_0("active-sounds",g_snd_active_sounds);
  gh_new_procedure0_0("max-sounds",g_snd_max_sounds);
  gh_new_procedure0_2("ffting?",g_snd_ffting);
  gh_new_procedure0_3("set-ffting-1",g_snd_set_ffting);
  gh_eval_str("(define set-ffting (lambda arg (apply set-ffting-1 (or arg #t))))");
  gh_new_procedure0_2("waving?",g_snd_waving);
  gh_new_procedure0_3("set-waving-1",g_snd_set_waving);
  gh_eval_str("(define set-waving (lambda arg (apply set-waving-1 (or arg #t))))");
  gh_new_procedure0_2("graphing?",g_snd_graphing);
  gh_new_procedure0_3("set-graphing-1",g_snd_set_graphing);
  gh_eval_str("(define set-graphing (lambda arg (apply set-graphing-1 (or arg #t))))");
  gh_new_procedure0_2("edits",g_snd_edits);
  gh_new_procedure0_2("maxamp",g_snd_maxamp);
  gh_new_procedure0_2("peaks",g_snd_peaks);
  gh_new_procedure0_2("marks",g_snd_marks);
  gh_new_procedure0_3("mark-sample",g_snd_mark_sample);
  gh_new_procedure1_3("set-mark-sample",g_snd_set_mark_sample);
  gh_new_procedure0_3("mark-name",g_snd_mark_name);
  gh_new_procedure1_3("set-mark-name",g_snd_set_mark_name);
  gh_new_procedure0_3("add-mark",g_snd_add_mark);
  gh_new_procedure0_3("delete-mark",g_snd_delete_mark);
  gh_new_procedure1_2("find-mark",g_snd_find_mark);
  gh_new_procedure0_3("undo",g_snd_undo);
  gh_new_procedure0_3("redo",g_snd_redo);
  gh_new_procedure0_3("insert-region",g_snd_insert_region);
  gh_new_procedure0_0("cut",g_snd_cut);
  gh_new_procedure0_0("selected-sound",g_snd_selected_sound);
  gh_new_procedure0_1("selected-channel",g_snd_selected_channel);
  gh_new_procedure0_1("select-sound",g_snd_select_sound);
  gh_new_procedure0_2("select-channel",g_snd_select_channel);
  gh_new_procedure0_1("control-panel-save",g_snd_control_panel_save);
  gh_new_procedure0_1("control-panel-restore",g_snd_control_panel_restore);
  gh_new_procedure0_2("x-bounds",g_snd_x_bounds);
  gh_new_procedure0_2("y-bounds",g_snd_y_bounds);
  gh_new_procedure2_2("set-x-bounds",g_snd_set_x_bounds);
  gh_new_procedure2_2("set-y-bounds",g_snd_set_y_bounds);
  gh_new_procedure3_2("set-y-limits",g_snd_set_y_limits);

  gh_new_procedure1_3("insert-sound",g_snd_insert_file);
  gh_new_procedure1_0("open-sound",g_snd_open);
  gh_new_procedure1_0("open-alternate-sound",g_snd_open_alternate);
  gh_new_procedure1_0("view-sound",g_snd_view);
  gh_new_procedure1_0("new-sound",g_snd_new_file);
  gh_new_procedure0_1("close-sound",g_snd_close);
  gh_new_procedure0_1("update-sound",g_snd_update);
  gh_new_procedure0_1("revert-sound",g_snd_revert);
  gh_new_procedure0_1("save-sound",g_snd_save);
  gh_new_procedure1_1("save-sound-as",g_snd_save_as);
  gh_new_procedure1_0("preload-directory",g_snd_preload_directory);
  gh_new_procedure1_0("preload-file",g_snd_preload_file);
  gh_new_procedure1_0("yes-or-no-p",g_snd_yes_or_no_p);

  gh_new_procedure0_1("forward-sample",g_snd_forward_sample);
  gh_new_procedure0_1("backward-sample",g_snd_backward_sample);
  gh_new_procedure0_1("forward-graph",g_snd_forward_graph);
  gh_new_procedure0_1("backward-graph",g_snd_backward_graph);
  gh_new_procedure0_1("forward-mark",g_snd_forward_mark);
  gh_new_procedure0_1("backward-mark",g_snd_backward_mark);
  gh_new_procedure0_1("forward-mix",g_snd_forward_mix);
  gh_new_procedure0_1("backward-mix",g_snd_backward_mix);

  gh_new_procedure0_0("regions",g_snd_regions);
  gh_new_procedure0_1("region-length",g_snd_region_length);
  gh_new_procedure0_1("region-srate",g_snd_region_srate);
  gh_new_procedure0_1("region-chans",g_snd_region_chans);
  gh_new_procedure0_1("region-maxamp",g_snd_region_maxamp);
  gh_new_procedure2_0("save-region",g_snd_save_region);
  gh_new_procedure0_1("select-region",g_snd_select_region);
  gh_new_procedure0_1("delete-region",g_snd_delete_region);
  gh_new_procedure2_0("protect-region",g_snd_protect_region);
  gh_new_procedure0_1("play-region",g_snd_play_region);
  gh_new_procedure2_2("make-region",g_snd_make_region);
  gh_new_procedure9_0("restore-region",g_restore_region);
  gh_new_procedure0_1("scale-selection-to",g_snd_scale_selection_to);
  gh_new_procedure0_1("scale-selection-by",g_snd_scale_selection_by);
  gh_new_procedure0_5("mix-region",g_snd_mix_region);
  gh_new_procedure0_3("region-sample",g_snd_region_sample);
  gh_new_procedure0_4("region-samples",g_snd_region_samples);

  gh_new_procedure0_0("update-graphs",g_snd_update_graphs);
  gh_new_procedure0_0("update-ffts",g_snd_update_ffts);
  gh_new_procedure0_3("play",g_snd_play);
  gh_new_procedure0_1("stop",g_snd_stop);
  gh_new_procedure0_0("groups",g_snd_groups);
  gh_new_procedure1_0("group-ok?",g_snd_group_ok);

  gh_new_procedure0_0("exit",g_snd_exit);
  gh_new_procedure0_0("version",g_snd_version);
  gh_new_procedure0_0("show-listener",g_snd_show_listener);
  gh_new_procedure0_0("hide-listener",g_snd_hide_listener);
  gh_new_procedure0_0("print",g_snd_print);
  gh_new_procedure1_0("save-state",g_snd_save_state);
  gh_new_procedure0_0("save-macros",g_snd_save_macros);
  gh_new_procedure0_1("save-marks",g_snd_save_marks);
  gh_new_procedure1_0("save-options",g_snd_save_options);
  gh_new_procedure0_1("save-envelopes",g_snd_save_envelopes);
  gh_new_procedure0_3("scale-to",g_snd_scale_to);
  gh_new_procedure0_3("scale-by",g_snd_scale_by);

  gh_new_procedure0_0("window-width",g_snd_window_width);
  gh_new_procedure0_0("window-height",g_snd_window_height);
  gh_new_procedure1_0("set-window-width",g_set_window_width);
  gh_new_procedure1_0("set-window-height",g_set_window_height);
  gh_new_procedure0_0("normalize-view",g_snd_normalize_view);

  gh_new_procedure0_1("syncing?",g_snd_syncing);
  gh_new_procedure0_2("set-syncing-1",g_snd_set_syncing);
  gh_eval_str("(define set-syncing (lambda arg (apply set-syncing-1 (or arg #t))))");
  gh_new_procedure0_1("uniting?",g_snd_uniting);
  gh_new_procedure0_2("set-uniting-1",g_snd_set_uniting);
  gh_eval_str("(define set-uniting (lambda arg (apply set-uniting-1 (or arg #t))))");
  gh_new_procedure0_1("read-only?",g_snd_read_only);
  gh_new_procedure0_2("set-read-only-1",g_snd_set_read_only);
  gh_eval_str("(define set-read-only (lambda arg (apply set-read-only-1 (or arg #t))))");
  gh_new_procedure0_1("expanding?",g_snd_expanding);
  gh_new_procedure0_2("set-expanding-1",g_snd_set_expanding);
  gh_eval_str("(define set-expanding (lambda arg (apply set-expanding-1 (or arg #t))))");
  gh_new_procedure0_1("contrasting?",g_snd_contrasting);
  gh_new_procedure0_2("set-contrasting-1",g_snd_set_contrasting);
  gh_eval_str("(define set-contrasting (lambda arg (apply set-contrasting-1 (or arg #t))))");
  gh_new_procedure0_1("reverbing?",g_snd_reverbing);
  gh_new_procedure0_2("set-reverbing-1",g_snd_set_reverbing);
  gh_eval_str("(define set-reverbing (lambda arg (apply set-reverbing-1 (or arg #t))))");
  gh_new_procedure0_1("filtering?",g_snd_filtering);
  gh_new_procedure0_2("set-filtering-1",g_snd_set_filtering);
  gh_eval_str("(define set-filtering (lambda arg (apply set-filtering-1 (or arg #t))))");
  gh_new_procedure0_1("filter-order",g_snd_filter_order);
  gh_new_procedure1_1("set-filter-order",g_snd_set_filter_order);
  gh_new_procedure0_1("file-name",g_snd_file_name);
  gh_new_procedure0_1("short-file-name",g_snd_short_file_name);
  gh_new_procedure0_1("contrast",g_snd_contrast);
  gh_new_procedure1_1("set-contrast",g_snd_set_contrast);
  gh_new_procedure0_1("contrast-amp",g_snd_contrast_amp);
  gh_new_procedure1_1("set-contrast-amp",g_snd_set_contrast_amp);
  gh_new_procedure0_1("expand",g_snd_expand);
  gh_new_procedure1_1("set-expand",g_snd_set_expand);
  gh_new_procedure0_1("expand-length",g_snd_expand_length);
  gh_new_procedure1_1("set-expand-length",g_snd_set_expand_length);
  gh_new_procedure0_1("expand-ramp",g_snd_expand_ramp);
  gh_new_procedure1_1("set-expand-ramp",g_snd_set_expand_ramp);
  gh_new_procedure0_1("expand-hop",g_snd_expand_hop);
  gh_new_procedure1_1("set-expand-hop",g_snd_set_expand_hop);
  gh_new_procedure0_1("speed",g_snd_speed);
  gh_new_procedure1_1("set-speed",g_snd_set_speed);
  gh_new_procedure0_1("reverb-length",g_snd_reverb_length);
  gh_new_procedure1_1("set-reverb-length",g_snd_set_reverb_length);
  gh_new_procedure0_1("reverb-scale",g_snd_reverb_scale);
  gh_new_procedure1_1("set-reverb-scale",g_snd_set_reverb_scale);
  gh_new_procedure0_1("reverb-feedback",g_snd_reverb_feedback);
  gh_new_procedure1_1("set-reverb-feedback",g_snd_set_reverb_feedback);
  gh_new_procedure0_1("reverb-lowpass",g_snd_reverb_lowpass);
  gh_new_procedure1_1("set-reverb-lowpass",g_snd_set_reverb_lowpass);
  gh_new_procedure0_1("cursor-follows-play",g_snd_cursor_follows_play);
  gh_new_procedure0_2("set-cursor-follows-play-1",g_snd_set_cursor_follows_play);
  gh_eval_str("(define set-cursor-follows-play (lambda arg (apply set-cursor-follows-play-1 (or arg #t))))");
  gh_new_procedure0_1("amp",g_snd_amp);
  gh_new_procedure1_1("set-amp",g_snd_set_amp);
  gh_new_procedure0_1("ok?",g_snd_ok);
  gh_new_procedure1_1("report-in-minibuffer",g_snd_report_in_minibuffer);
  gh_new_procedure1_1("append-to-minibuffer",g_snd_append_to_minibuffer);
  gh_new_procedure0_1("showing-controls?",g_snd_showing_controls);
  gh_new_procedure0_2("set-showing-controls-1",g_snd_set_show_controls);
  gh_eval_str("(define set-showing-controls (lambda arg (apply set-showing-controls-1 (or arg #t))))");
  gh_new_procedure0_1("filter-env",g_snd_filter_env);
  gh_new_procedure1_1("set-filter-env",g_snd_set_filter_env);
  gh_new_procedure2_0("set-env-base",g_snd_set_env_base);

  gh_new_procedure1_0("override-data-location",g_override_data_location);
  gh_new_procedure1_0("override-data-format",g_override_data_format);
  gh_new_procedure1_0("override-data-size",g_override_data_size);

  gh_new_procedure1_0("find-sound",g_snd_find_sound);
  gh_new_procedure0_2("transform-samples",g_snd_transform_samples);
  gh_new_procedure0_4("transform-sample",g_snd_transform_sample);

  gh_new_procedure1_3("env-selection",g_snd_env_selection);
  gh_new_procedure1_5("env",g_snd_env);
  gh_new_procedure1_4("mix",g_snd_mix_file);
  gh_new_procedure2_1("fft",g_snd_fft);
  gh_new_procedure1_1("src",g_snd_src);
  gh_new_procedure2_2("filter",g_snd_filter);

  gh_new_procedure2_0("key",g_snd_key);
  gh_new_procedure1_0("add-to-main-menu",g_snd_add_to_main_menu);
  gh_new_procedure3_0("add-to-menu",g_snd_add_to_menu);
  gh_new_procedure2_0("remove-from-menu",g_snd_remove_from_menu);
  gh_new_procedure3_0("change-menu-label",g_snd_change_menu_label);
  gh_new_procedure3_0("set-menu-sensitive",g_snd_set_menu_sensitive);

  gh_new_procedure1_0("save-defvar",g_snd_save_defvar);
  gh_new_procedure1_2("save-edit-history",g_snd_save_edit_history);
  gh_new_procedure4_0("restore-marks",g_restore_marks);
  gh_new_procedure1_7("graph",g_snd_graph);
  gh_new_procedure3_0("global-set-key",g_snd_setkey);
  gh_eval_str("(define global-unset-key (lambda (key state) (global-set-key key state \"cursor-no-action\")))");

  gh_define("open-hook",gh_str02scm(""));
  gh_define("close-hook",gh_str02scm(""));
  gh_define("fft-hook",gh_str02scm(""));
  gh_define("graph-hook",gh_str02scm(""));
  gh_define("exit-hook",gh_str02scm(""));
  gh_define("start-hook",gh_str02scm(""));
  gh_define("mouse-press-hook",gh_str02scm(""));
  gh_define("mouse-release-hook",gh_str02scm(""));
  gh_define("mouse-drag-hook",gh_str02scm(""));
  gh_define("key-press-hook",gh_str02scm(""));
  gh_define("open-hook-filename",gh_str02scm(""));
  gh_define("close-hook-sound",gh_int2scm(0));
  gh_define("fft-hook-sound",gh_int2scm(0));
  gh_define("graph-hook-sound",gh_int2scm(0));
  gh_define("key-hook-sound",gh_int2scm(0));
  gh_define("fft-hook-channel",gh_int2scm(0));
  gh_define("graph-hook-channel",gh_int2scm(0));
  gh_define("key-hook-channel",gh_int2scm(0));
  gh_define("fft-hook-scaler",gh_double2scm(0.0));  
  gh_define("graph-hook-y0",gh_double2scm(0.0));
  gh_define("graph-hook-y1",gh_double2scm(0.0));
  gh_define("graph-hook-x",gh_double2scm(0.0));
  gh_define("graph-hook-y",gh_double2scm(0.0));
  gh_define("graph-hook-button",gh_int2scm(0));
  gh_define("graph-hook-state",gh_int2scm(0));
  gh_define("graph-hook-key",gh_int2scm(0));

  gh_eval_str("(defmacro defvar (a b) `(begin (define ,a ,b) (save-defvar (symbol->string ',a))))");
  /* this is trying to keep track of envelopes for the envelope editor */

  gh_define("next-sound-file",gh_int2scm(NeXT_sound_file));
  gh_define("aiff-sound-file",gh_int2scm(AIFF_sound_file));
  gh_define("riff-sound-file",gh_int2scm(RIFF_sound_file));

  gh_define("snd-16-linear",gh_int2scm(snd_16_linear));
  gh_define("snd-8-mulaw",gh_int2scm(snd_8_mulaw));
  gh_define("snd-8-linear",gh_int2scm(snd_8_linear));
  gh_define("snd-32-float",gh_int2scm(snd_32_float));
  gh_define("snd-32-linear",gh_int2scm(snd_32_linear));
  gh_define("snd-8-alaw",gh_int2scm(snd_8_alaw));
  gh_define("snd-8-unsigned",gh_int2scm(snd_8_unsigned));
  gh_define("snd-24-linear",gh_int2scm(snd_24_linear));
  gh_define("snd-64-double",gh_int2scm(snd_64_double));
  gh_define("snd-16-linear-little-endian",gh_int2scm(snd_16_linear_little_endian));
  gh_define("snd-32-linear-little-endian",gh_int2scm(snd_32_linear_little_endian));
  gh_define("snd-32-float-little-endian",gh_int2scm(snd_32_float_little_endian));

  gh_define("amplitude-env",gh_int2scm(AMPLITUDE_ENV));
  gh_define("spectrum-env",gh_int2scm(SPECTRUM_ENV));
  gh_define("srate-env",gh_int2scm(SRATE_ENV));
  gh_define("graph-lines",gh_int2scm(GRAPH_LINES));
  gh_define("graph-dots",gh_int2scm(GRAPH_DOTS));
  gh_define("graph-filled",gh_int2scm(GRAPH_FILLED));
  gh_define("normal-fft",gh_int2scm(NORMAL_FFT));
  gh_define("sonogram",gh_int2scm(SONOGRAM));
  gh_define("spectrogram",gh_int2scm(SPECTROGRAM));
  gh_define("focus-left",gh_int2scm(FOCUS_LEFT));
  gh_define("focus-right",gh_int2scm(FOCUS_RIGHT));
  gh_define("focus-active",gh_int2scm(FOCUS_ACTIVE));
  gh_define("focus-middle",gh_int2scm(FOCUS_MIDDLE));
  gh_define("x-in-seconds",gh_int2scm(X_IN_SECONDS));
  gh_define("x-in-samples",gh_int2scm(X_IN_SAMPLES));
  gh_define("x-to-one",gh_int2scm(X_TO_ONE));
  gh_define("speed-as-float",gh_int2scm(SPEED_AS_FLOAT));
  gh_define("speed-as-ratio",gh_int2scm(SPEED_AS_RATIO));
  gh_define("speed-as-semitone",gh_int2scm(SPEED_AS_SEMITONE));
  gh_define("channels-separate",gh_int2scm(CHANNELS_SEPARATE));
  gh_define("channels-combined",gh_int2scm(CHANNELS_COMBINED));
  gh_define("channels-superimposed",gh_int2scm(CHANNELS_SUPERIMPOSED));
  gh_define("fourier-transform",gh_int2scm(FOURIER));
  gh_define("wavelet-transform",gh_int2scm(WAVELET));
  gh_define("hankel-transform",gh_int2scm(HANKEL));
  gh_define("chebyshev-transform",gh_int2scm(CHEBYSHEV));
  gh_define("legendre-transform",gh_int2scm(LEGENDRE));
  gh_define("rectangular-window",gh_int2scm(rectangular));
  gh_define("hanning-window",gh_int2scm(hanning));
  gh_define("welch-window",gh_int2scm(welch));
  gh_define("parzen-window",gh_int2scm(parzen));
  gh_define("bartlett-window",gh_int2scm(bartlett));
  gh_define("hamming-window",gh_int2scm(hamming));
  gh_define("blackman2-window",gh_int2scm(blackman2));
  gh_define("blackman3-window",gh_int2scm(blackman3));
  gh_define("blackman4-window",gh_int2scm(blackman4));
  gh_define("exponential-window",gh_int2scm(exponential));
  gh_define("riemann-window",gh_int2scm(riemann));
  gh_define("kaiser-window",gh_int2scm(kaiser));
  gh_define("cauchy-window",gh_int2scm(cauchy));
  gh_define("poisson-window",gh_int2scm(poisson));
  gh_define("gaussian-window",gh_int2scm(gaussian));
  gh_define("tukey-window",gh_int2scm(tukey));

  gh_define("cursor-in-view",gh_int2scm(CURSOR_IN_VIEW));
  gh_define("cursor-on-left",gh_int2scm(CURSOR_ON_LEFT));
  gh_define("cursor-on-right",gh_int2scm(CURSOR_ON_RIGHT));
  gh_define("cursor-in-middle",gh_int2scm(CURSOR_IN_MIDDLE));
  gh_define("cursor-update-display",gh_int2scm(CURSOR_UPDATE_DISPLAY));
  gh_define("cursor-no-action",gh_int2scm(CURSOR_NO_ACTION));
  gh_define("cursor-claim-selection",gh_int2scm(CURSOR_CLAIM_SELECTION));
  gh_define("keyboard-no-action",gh_int2scm(KEYBOARD_NO_ACTION));

  gh_new_procedure1_0("sound-samples",g_sound_samples);
  gh_new_procedure1_0("sound-datum-size",g_sound_datum_size);
  gh_new_procedure1_0("sound-data-location",g_sound_data_location);
  gh_new_procedure1_0("sound-chans",g_sound_chans);
  gh_new_procedure1_0("sound-srate",g_sound_srate);
  gh_new_procedure1_0("sound-header-type",g_sound_header_type);
  gh_new_procedure1_0("sound-data-format",g_sound_data_format);
  gh_new_procedure1_0("sound-length",g_sound_length);
  gh_new_procedure1_0("sound-type-specifier",g_sound_type_specifier);
  gh_new_procedure1_0("sound-type-name",g_sound_type_name);
  gh_new_procedure1_0("sound-format-name",g_sound_format_name);
  gh_new_procedure1_0("sound-comment",g_sound_comment);
  gh_new_procedure1_0("bytes-per-sample",g_bytes_per_sample);
  gh_new_procedure0_0("audio-error",g_audio_error);
  gh_new_procedure1_0("audio-error-name",g_audio_error_name);

}

static char *hook_string(char *hook_name)
{
  SCM hook;
  char *hook_str = NULL;
  hook = gh_lookup(hook_name);
  if (gh_string_p(hook))
    hook_str = gh_scm2newstr(hook,NULL);
  if ((hook_str) && (*hook_str))
    return(hook_str);
  return(NULL);
}

static int handle_hook(snd_state *ss, char *hook_str)
{
  SCM result;
  result = scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,hook_str,clm_handler,hook_str);
  free(hook_str);
  return(result == SCM_BOOL_T);
}

int dont_open(snd_state *ss, char *file)
{
  int result = FALSE;
  char *hook_str;
  gs_set("open-hook-filename",complete_filename(file));
  /* needs to be setup for start hook */
  if (!(ss->open_hook_active))
    {
      hook_str = hook_string("open-hook");
      if (hook_str)
	{
	  ss->open_hook_active = 1;
	  result = handle_hook(ss,hook_str);
	  ss->open_hook_active = 0;
	}
    }
  return(result);
}

int dont_close(snd_state *ss, snd_info *sp)
{
  int result = FALSE;
  char *hook_str;
  if (!(ss->close_hook_active))
    {
      hook_str = hook_string("close-hook");
      if (hook_str)
	{
	  gi_set("close-hook-sound",sp->index);
	  ss->close_hook_active = 1;
	  result = handle_hook(ss,hook_str);
	  ss->close_hook_active = 0;
	}
    }
  return(result);
}

int after_fft(snd_state *ss, chan_info *cp, float scaler)
{
  int result = FALSE;
  char *hook_str;
  if (!(ss->fft_hook_active))
    {
      hook_str = hook_string("fft-hook");
      if (hook_str)
	{
	  gi_set("fft-hook-sound",(cp->sound)->index);
	  gi_set("fft-hook-channel",cp->chan);
	  gd_set("fft-hook-scaler",scaler);
	  ss->fft_hook_active = 1;
	  result = handle_hook(ss,hook_str);
	  ss->fft_hook_active = 0;
	}
    }
  return(result);
}

int dont_graph(snd_state *ss, chan_info *cp)
{
  int result = FALSE;
  char *hook_str;
  if (!(ss->graph_hook_active))
    {
      hook_str = hook_string("graph-hook");
      if (hook_str)
	{
	  gi_set("graph-hook-sound",(cp->sound)->index);
	  gi_set("graph-hook-channel",cp->chan);
	  gd_set("graph-hook-y0",(cp->axis)->y0);
	  gd_set("graph-hook-y1",(cp->axis)->y1);
	  ss->graph_hook_active = 1;
	  result = handle_hook(ss,hook_str);
	  ss->graph_hook_active = 0;
	}
    }
  return(result);
}

int dont_exit(snd_state *ss)
{
  int result = FALSE;
  char *hook_str;
  if (!(ss->exit_hook_active))
    {
      hook_str = hook_string("exit-hook");
      if (hook_str)
	{
	  ss->exit_hook_active = 1;
	  result = handle_hook(ss,hook_str);
	  ss->exit_hook_active = 0;
	}
    }
  return(result);
}
  
int dont_start(snd_state *ss)
{
  int result = FALSE;
  char *hook_str;
  if (!(ss->start_hook_active))
    {
      hook_str = hook_string("start-hook");
      if (hook_str)
	{
	  ss->start_hook_active = 1;
	  result = handle_hook(ss,hook_str);
	  ss->start_hook_active = 0;
	}
    }
  return(result);
}
  
int handle_keymap(chan_info *cp, char *code)
{
  SCM result;
  gi_set("key-hook-sound",(cp->sound)->index);
  gi_set("key-hook-channel",cp->chan);
  result = scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,code,clm_handler,code);
  if ((gh_number_p(result)) && (gh_exact_p(result))) return(gh_scm2int(result));
  return(KEYBOARD_NO_ACTION);
}

/* mouse/key events within lisp graph */

static void handle_mouse_event(char *hook, snd_state *ss, snd_info *sp, chan_info *cp, float x, float y, int button, int state)
{
  char *hook_str;
  hook_str = hook_string(hook);
  if (hook_str)
    {
      gi_set("graph-hook-sound",sp->index);
      gi_set("graph-hook-channel",cp->chan);
      if (button != -1) gi_set("graph-hook-button",button);
      if (state != -1) gi_set("graph-hook-state",state);
      gd_set("graph-hook-x",x);
      gd_set("graph-hook-y",y);
      scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,hook_str,clm_handler,hook_str);
      free(hook_str);
    }
}

void handle_mouse_release(snd_state *ss, snd_info *sp, chan_info *cp, float x, float y, int button, int state)
{
  handle_mouse_event("mouse-release-hook",ss,sp,cp,x,y,button,state);
}

void handle_mouse_press(snd_state *ss, snd_info *sp, chan_info *cp, float x, float y, int button, int state)
{
  /* (set! mouse-press-hook "(report-in-minibuffer (number->string graph-hook-x))") */
  handle_mouse_event("mouse-press-hook",ss,sp,cp,x,y,button,state);
}

void handle_mouse_drag(snd_state *ss, snd_info *sp, chan_info *cp, float x, float y)
{
  handle_mouse_event("mouse-drag-hook",ss,sp,cp,x,y,-1,-1);
}

int handle_key_press(snd_state *ss, snd_info *sp, chan_info *cp, int key, int state)
{
  /* return TRUE to keep this key press from being passed to keyboard_command */
  char *hook_str;
  SCM result;
  hook_str = hook_string("key-press-hook");
  if (hook_str)
    {
      gi_set("graph-hook-sound",sp->index);
      gi_set("graph-hook-channel",cp->chan);
      gi_set("graph-hook-key",key);
      gi_set("graph-hook-state",state);
      result = scm_internal_catch(SCM_BOOL_T,eval_str_wrapper,hook_str,clm_handler,hook_str);
      free(hook_str);
      return(result == SCM_BOOL_T);
    }
  return(FALSE);
}

#endif

