#include "snd.h"

static int remove_temp_files(chan_info *cp, void *ptr)
{
  free_sound_list(cp);
  free_mix_list(cp);
  return(0);
}

void snd_exit_cleanly(snd_state *ss)
{  
  if ((save_state_on_exit(ss)) && (session_file(ss)))
    save_state(ss,session_file(ss));

  CLM_disconnect(ss);
  cleanup_clm_dialog(ss);
  cleanup_dac();
  if (ss->to_clm)
    {
      close(ss->from_clm);
      ss->from_clm = 0;
    }
  if (ss->to_clm)
    {
      close(ss->to_clm);
      ss->to_clm = 0;
    }
  map_over_chans(ss,remove_temp_files,NULL);
  cleanup_region_temp_files();
  cleanup_group_temp_files(ss);
  cleanup_recording();
}

/* ---------------- save sound state (options, or entire state) ---------------- */

static int fneq(float a, float b)
{
  /* floating point != replacement */
  return(fabs(a - b) > .00001);
}

void save_snd_state_options (snd_state *ss, FILE *fd)
{ /* for save options menu choice (.snd) -- mostly saving snd_state info */
  time_t ts;
  char buf[64];
  time(&ts);
  strftime(buf,64,"%a %d-%b-%y %H:%M %Z",localtime(&ts));
  fprintf(fd,"\n;;; Snd %s (%s) options saved %s\n",SND_RPM_VERSION,SND_VERSION,buf);

  if (fft_size(ss) != 256) fprintf(fd,"(set-fft-size %d)\n",fft_size(ss));
  if (fft_window(ss) != default_fft_window(NULL)) fprintf(fd,"(set-fft-window %d)\n",fft_window(ss));
  if (fft_style(ss) != NORMAL_FFT) fprintf(fd,"(set-fft-style %d)\n",fft_style(ss));
  if (sinc_width(ss) != 10) fprintf(fd,"(set-sinc-width %d)\n",sinc_width(ss));
  if (speed_tones(ss) != 12) fprintf(fd,"(set-speed-tones %d)\n",speed_tones(ss));
  if (window_width(ss) != 0) fprintf(fd,"(set-window-width %d)\n",window_width(ss));
  if (window_height(ss) != 0) fprintf(fd,"(set-window-height %d)\n",window_height(ss));
  if (window_x(ss) != -1) fprintf(fd,"(set-window-x %d)\n",window_x(ss));
  if (window_y(ss) != -1) fprintf(fd,"(set-window-y %d)\n",window_y(ss));
  if (default_contrasting(ss) != 0) fprintf(fd,"(set-default-contrasting %d)\n",default_contrasting(ss));
  if (default_expanding(ss) != 0) fprintf(fd,"(set-default-expanding %d)\n",default_expanding(ss));
  if (default_reverbing(ss) != 0) fprintf(fd,"(set-default-reverbing %d)\n",default_reverbing(ss));
  if (default_filtering(ss) != 0) fprintf(fd,"(set-default-filtering %d)\n",default_filtering(ss));
  if (default_filter_order(ss) != 2) fprintf(fd,"(set-default-filter-order %d)\n",default_filter_order(ss));
  if (default_output_type(ss) != DEFAULT_OUTPUT_TYPE) fprintf(fd,"(set-default-output-type %d)\n",default_output_type(ss));
  if (normalize_on_open(ss) != 1) fprintf(fd,"(set-normalize-on-open %d)\n",normalize_on_open(ss));
  if (auto_resize(ss) != 1 ) fprintf(fd,"(set-auto-resize %d)\n",auto_resize(ss));
  if (color_inverted(ss) != 1) fprintf(fd,"(set-color-inverted %d)\n",color_inverted(ss));
  if (zero_pad(ss) != 0) fprintf(fd,"(set-zero-pad %d)\n",zero_pad(ss));
  if (line_size(ss) != 128) fprintf(fd,"(set-line-size %d)\n",line_size(ss));
  if (ask_before_overwrite(ss) != 0) fprintf(fd,"(set-ask-before-overwrite %d)\n",ask_before_overwrite(ss));
  if (x_axis_style(ss) != X_IN_SECONDS) fprintf(fd,"(set-x-axis-style %d)\n",x_axis_style(ss));
  if (wavo(ss) != 0) fprintf(fd,"(set-wavo %d)\n",wavo(ss));
  if (wavo_hop(ss) != 3) fprintf(fd,"(set-wavo-hop %d)\n",wavo_hop(ss));
  if (wavo_trace(ss) != 64) fprintf(fd,"(set-wavo-trace %d)\n",wavo_trace(ss));
  if (spectro_hop(ss) != 4) fprintf(fd,"(set-spectro-hop %d)\n",spectro_hop(ss));
  if (spectro_color(ss) != -1) fprintf(fd,"(set-spectro-color %d)\n",spectro_color(ss));
  if (wavelet_type(ss) != 0) fprintf(fd,"(set-wavelet-type %d)\n",wavelet_type(ss));
  if (transform_type(ss) != FOURIER) fprintf(fd,"(set-transform-type %d)\n",transform_type(ss));
  if (dot_size(ss) != 1) fprintf(fd,"(set-dot-size %d)\n",dot_size(ss));
  if (speed_style(ss) != SPEED_AS_FLOAT) fprintf(fd,"(set-speed-style %d)\n",speed_style(ss));
  if (movies(ss) != 1) fprintf(fd,"(set-movies %d)\n",movies(ss));
  if (normalize_fft(ss) != 1) fprintf(fd,"(set-normalize-fft %d)\n",normalize_fft(ss));
  if (mix_duration_brackets(ss) != 0) fprintf(fd,"(set-mix-duration-brackets %d)\n",mix_duration_brackets(ss));
  if (fit_data_on_open(ss) != -1) fprintf(fd,"(set-fit-data-on-open %d)\n",fit_data_on_open(ss));
  if (zoom_focus_style(ss) != FOCUS_ACTIVE) fprintf(fd,"(set-zoom-focus-style %d)\n",zoom_focus_style(ss));
  if (save_state_on_exit(ss) != 0) fprintf(fd,"(set-save-state-on-exit %d)\n",save_state_on_exit(ss));
  if (graph_style(ss) != GRAPH_LINES) fprintf(fd,"(set-graph-style %d)\n",graph_style(ss));
  if (filter_env_order(ss) != 40) fprintf(fd,"(set-filter-env-order %d)\n",filter_env_order(ss));
  if (mixer_groups(ss) != 6) fprintf(fd,"(set-mixer-groups %d)\n",mixer_groups(ss));
  if (mixer_group_max_out_chans(ss) != 4) fprintf(fd,"(set-mixer-group-max-out-chans %d)\n",mixer_group_max_out_chans(ss));
  if (verbose_cursor(ss) != 0) fprintf(fd,"(set-verbose-cursor %d)\n",verbose_cursor(ss));
  if (show_fft_peaks(ss) != 0) fprintf(fd,"(set-show-fft-peaks %d)\n",show_fft_peaks(ss));
  if (show_y_zero(ss) != 0) fprintf(fd,"(set-show-y-zero %d)\n",show_y_zero(ss));
  if (show_marks(ss) != 1) fprintf(fd,"(set-show-marks %d)\n",show_marks(ss));
  if (show_edit_history(ss) != 0) fprintf(fd,"(set-show-edit-history %d)\n",show_edit_history(ss));
  if (edit_history_width(ss) != 0) fprintf(fd,"(set-edit-history-width %d)\n",edit_history_width(ss));
  if (subsampling(ss) != 1) fprintf(fd,"(set-subsampling %d)\n",subsampling(ss));
  if (fft_log_magnitude(ss) != 0) fprintf(fd,"(set-fft-log-magnitude %d)\n",fft_log_magnitude(ss));
  if (fft_log_frequency(ss) != 0) fprintf(fd,"(set-fft-log-frequency %d)\n",fft_log_frequency(ss));
  if (channel_style(ss) != CHANNELS_SEPARATE) fprintf(fd,"(set-channel-style %d)\n",channel_style(ss));
  if (sound_style(ss) != SOUNDS_VERTICAL) fprintf(fd,"(set-sound-style %d)\n",sound_style(ss));
  if (raw_srate(ss) != 44100) fprintf(fd,"(set-raw-srate %d)\n",raw_srate(ss));
  if (raw_chans(ss) != 1) fprintf(fd,"(set-raw-chans %d)\n",raw_chans(ss));
  if (raw_format(ss) != snd_16_linear) fprintf(fd,"(set-raw-format %d)\n",raw_format(ss));
  if (raw_type(ss) != NeXT_sound_file) fprintf(fd,"(set-raw-type %d)\n",raw_type(ss));
  if (use_raw_defaults(ss) != 0) fprintf(fd,"(set-use_raw-defaults %d)\n",use_raw_defaults(ss));
  if (print_length(ss) != 12) fprintf(fd,"(set-print-length %d)\n",print_length(ss));
  if (show_mix_consoles(ss) != 1) fprintf(fd,"(set-show-mix-consoles %d)\n",show_mix_consoles(ss));
  if (recorder_autoload(ss) != 0) fprintf(fd,"(set-recorder-autoload %d)\n",recorder_autoload(ss));
  if (recorder_buffer_size(ss) != 4096) fprintf(fd,"(set-recorder-buffer-size %d)\n",recorder_buffer_size(ss));
  if (recorder_out_chans(ss) != 2) fprintf(fd,"(set-recorder-out-chans %d)\n",recorder_out_chans(ss));
  if (recorder_out_format(ss) != COMPATIBLE_FORMAT) fprintf(fd,"(set-recorder-out-format %d)\n",recorder_out_format(ss));
  if (recorder_in_format(ss) != COMPATIBLE_FORMAT) fprintf(fd,"(set-recorder-in-format %d)\n",recorder_in_format(ss));
  if (recorder_srate(ss) != 22050) fprintf(fd,"(set-recorder-srate %d)\n",recorder_srate(ss));
  if (enved_waving(ss) != 0) fprintf(fd,"(set-enved-waving %d)\n",enved_waving(ss));
  if (enved_clipping(ss) != 0) fprintf(fd,"(set-enved-clipping %d)\n",enved_clipping(ss));
  if (enved_exping(ss) != 0) fprintf(fd,"(set-enved-exping %d)\n",enved_exping(ss));
  if (enved_target(ss) != AMPLITUDE_ENV) fprintf(fd,"(set-enved-target %d)\n",enved_target(ss));
  if (prefix_arg(ss) != 0) fprintf(fd,"(set-prefix-arg %d)\n",prefix_arg(ss));

  if (vu_font(ss) != NULL) fprintf(fd,"(set-vu-font \"%s\")\n",vu_font(ss));
  if (recorder_file(ss) != NULL) fprintf(fd,"(set-recorder-file \"%s\")\n",recorder_file(ss));
  if (session_file(ss) != NULL) fprintf(fd,"(set-session-file \"%s\")\n",session_file(ss));
  if (temp_dir(ss) != NULL) fprintf(fd,"(set-temp-dir \"%s\")\n",temp_dir(ss));
  if (eps_file(ss) != NULL) fprintf(fd,"(set-eps-file \"%s\")\n",eps_file(ss));

  if (fneq(default_contrast_amp(ss),1.0)) fprintf(fd,"(set-default-contrast-amp %.4f)\n",default_contrast_amp(ss));
  if (fneq(fft_beta(ss),0.0)) fprintf(fd,"(set-fft-beta %.4f)\n",fft_beta(ss));
  if (fneq(default_amp(ss),1.0)) fprintf(fd,"(set-default-amp %.4f)\n",default_amp(ss));
  if (fneq(default_contrast(ss),0.0)) fprintf(fd,"(set-default-contrast %.4f)\n",default_contrast(ss));
  if (fneq(default_expand_length(ss),.15)) fprintf(fd,"(set-default-expand-length %.4f)\n",default_expand_length(ss));
  if (fneq(default_expand_ramp(ss),.4)) fprintf(fd,"(set-default-expand-ramp %.4f)\n",default_expand_ramp(ss));
  if (fneq(default_expand_hop(ss),.05)) fprintf(fd,"(set-default-expand-hop %.4f)\n",default_expand_hop(ss));
  if (fneq(default_reverb_feedback(ss),1.09)) fprintf(fd,"(set-default-reverb-feedback %.4f)\n",default_reverb_feedback(ss));
  if (fneq(default_reverb_lowpass(ss),0.7)) fprintf(fd,"(set-default-reverb-lowpass %.4f)\n",default_reverb_lowpass(ss));
  if (fneq(default_expand(ss),1.0)) fprintf(fd,"(set-default-expand %.4f)\n",default_expand(ss));
  if (fneq(default_speed(ss),1.0)) fprintf(fd,"(set-default-speed %.4f)\n",default_speed(ss));
  if (fneq(default_reverb_scale(ss),0.0)) fprintf(fd,"(set-default-reverb-scale %.4f)\n",default_reverb_scale(ss));
  if (fneq(default_reverb_length(ss),1.0)) fprintf(fd,"(set-default-reverb-length %.4f)\n",default_reverb_length(ss));
  if (fneq(reverb_decay(ss),1.0)) fprintf(fd,"(set-reverb-decay %.4f)\n",reverb_decay(ss));
  if (fneq(initial_x0(ss),0.0)) fprintf(fd,"(set-initial-x0 %.4f)\n",initial_x0(ss));
  if (fneq(initial_x1(ss),0.1)) fprintf(fd,"(set-initial-x1 %.4f)\n",initial_x1(ss));
  if (fneq(initial_y0(ss),-1.0)) fprintf(fd,"(set-initial-y0 %.4f)\n",initial_y0(ss));
  if (fneq(initial_y1(ss),1.0)) fprintf(fd,"(set-initial-y1 %.4f)\n",initial_y1(ss));
  if (fneq(xmax(ss),0.0)) fprintf(fd,"(set-xmax %.4f)\n",xmax(ss));
  if (fneq(xmin(ss),0.0)) fprintf(fd,"(set-xmin %.4f)\n",xmin(ss));
  if (fneq(ymax(ss),1.0)) fprintf(fd,"(set-ymax %.4f)\n",ymax(ss));
  if (fneq(ymin(ss),-1.0)) fprintf(fd,"(set-ymin %.4f)\n",ymin(ss));
  if (fneq(color_cutoff(ss),.003)) fprintf(fd,"(set-color-cutoff %.4f)\n",color_cutoff(ss));
  if (fneq(color_scale(ss),0.5)) fprintf(fd,"(set-color-scale %.4f)\n",color_scale(ss));
  if (fneq(spectro_x_scale(ss),1.0)) fprintf(fd,"(set-spectro-x-scale %.4f)\n",spectro_x_scale(ss));
  if (fneq(spectro_y_scale(ss),1.0)) fprintf(fd,"(set-spectro-y-scale %.4f)\n",spectro_y_scale(ss));
  if (fneq(spectro_z_scale(ss),0.1)) fprintf(fd,"(set-spectro-z-scale %.4f)\n",spectro_z_scale(ss));
  if (fneq(spectro_z_angle(ss),-2.0)) fprintf(fd,"(set-spectro-z-angle %.4f)\n",spectro_z_angle(ss));
  if (fneq(spectro_x_angle(ss),90.0)) fprintf(fd,"(set-spectro-x-angle %.4f)\n",spectro_x_angle(ss));
  if (fneq(spectro_y_angle(ss),0.0)) fprintf(fd,"(set-spectro-y-angle %.4f)\n",spectro_y_angle(ss));
  if (fneq(spectro_cutoff(ss),1.0)) fprintf(fd,"(set-spectro-cutoff %.4f)\n",spectro_cutoff(ss));
  if (fneq(vu_size(ss),1.0)) fprintf(fd,"(set-vu-size %.4f)\n",vu_size(ss));
  if (fneq(vu_font_size(ss),1.0)) fprintf(fd,"(set-vu-font-size %.4f)\n",vu_font_size(ss));
  if (fneq(enved_base(ss),1.0)) fprintf(fd,"(set-enved-base %.4f)\n",enved_base(ss));

  fprintf(fd,";;; end of snd options\n");
}

static FILE *open_restart_file(char *name, int append)
{
  FILE *fd;
  char *str;
  char buf[128];
  str = name;
  if ((*str) == '~')
    {
      strcpy(buf,getenv("HOME"));
      strcat(buf,++str);
      str=buf;
    }
  if (append)
    fd = fopen(str,"a");
  else fd = fopen(str,"w");
  return(fd);
}

FILE *open_snd_init_file (snd_state *ss)
{ /* needed also by keyboard macro saver */
  return(open_restart_file(ss->init_file,TRUE));
}

int save_options (snd_state *ss) /* snd-xmenu */
{
  FILE *fd;
  fd = open_snd_init_file(ss);
  if (fd)
    {
      save_snd_state_options(ss,fd);
      fclose(fd);
      return(0);
    }
  else return(-1);
}

#define white_space "      "

static int save_sound_state (snd_info *sp, void *ptr) 
{
  int chan;
  FILE *fd;
  chan_info *cp;
  axis_info *ap;
  fd = (FILE *)ptr;
  fprintf(fd,"(let ((sfile (or (find-sound \"%s\") (%s \"%s\"))))\n  (if sfile\n    (begin\n",
	  sp->shortname,
	  (sp->read_only) ? "view-sound" : "open-sound",
	  sp->fullname);
  fprintf(fd,"%s(set-syncing %d sfile)\n",white_space,sp->syncing);
  fprintf(fd,"%s(set-contrasting %d sfile)\n",white_space,sp->contrasting);
  fprintf(fd,"%s(set-contrast %.4f sfile)\n",white_space,sp->contrast);
  fprintf(fd,"%s(set-expanding %d sfile)\n",white_space,sp->expanding);
  fprintf(fd,"%s(set-expand %.4f sfile)\n",white_space,sp->expand);
  fprintf(fd,"%s(set-expand-ramp %.4f sfile)\n",white_space,sp->local_exprmp);
  fprintf(fd,"%s(set-expand-hop %.4f sfile)\n",white_space,sp->local_exphop);
  fprintf(fd,"%s(set-expand-length %.4f sfile)\n",white_space,sp->local_explen);
  fprintf(fd,"%s(set-speed %.4f sfile)\n",white_space,sp->srate);
  fprintf(fd,"%s(set-reverbing %d sfile)\n",white_space,sp->reverbing);
  fprintf(fd,"%s(set-reverb-scale %.4f sfile)\n",white_space,sp->revscl);
  fprintf(fd,"%s(set-reverb-length %.4f sfile)\n",white_space,sp->revlen);
  fprintf(fd,"%s(set-reverb-feedback %.4f sfile)\n",white_space,sp->local_revfb);
  fprintf(fd,"%s(set-reverb-lowpass %.4f sfile)\n",white_space,sp->local_revlp);
  fprintf(fd,"%s(set-amp %.4f sfile)\n",white_space,sp->amp);
  fprintf(fd,"%s(set-filtering %d sfile)\n",white_space,sp->filtering);
  fprintf(fd,"%s(set-filter-order %d sfile)\n",white_space,sp->filter_order);
  fprintf(fd,"%s(set-cursor-follows-play %d sfile)\n",white_space,sp->cursor_follows_play);
  for (chan=0;chan<sp->nchans;chan++)
    {
      cp = sp->chans[chan];
      ap = cp->axis;
      fprintf(fd,"%s(set-waving %d sfile %d)\n",white_space,cp->waving,chan);
      fprintf(fd,"%s(set-ffting %d sfile %d)\n",white_space,cp->ffting,chan);
      fprintf(fd,"%s(set-graphing %d sfile %d)\n",white_space,cp->lisp_graphing,chan);
      fprintf(fd,"%s(set-x-bounds %.4f %.4f sfile %d)\n",white_space,ap->x0,ap->x1,chan);
      fprintf(fd,"%s(set-y-bounds %.4f %.4f sfile %d)\n",white_space,ap->y0,ap->y1,chan);
      fprintf(fd,"%s(set-cursor %d sfile %d)\n",white_space,cp->cursor,chan);
      edit_history_to_file(fd,cp);
    }
  fprintf(fd,"      )))\n");
  return(0);
}

int save_state (snd_state *ss, char *session_name)
{
  FILE *save_fd;
  char buf[256];
  save_fd = open_restart_file(session_name,FALSE);
  if (save_fd == NULL) 
    {
      sprintf(buf,snd_string_cant_write_p,session_name,strerror(errno));
      snd_printf(ss,buf);
      return(-1);
    }
  else
    {
      save_prevlist(save_fd);                                /* list of previous files (View: Files option) */
      map_over_sounds(ss,save_sound_state,(void *)save_fd);  /* current sound state -- will traverse chans */
      save_macro_state(ss,save_fd);                          /* current unsaved keyboard macros (snd-chn.c) */
      save_envelope_editor_state(ss,save_fd);                /* current envelope editor window state */
      save_regions(save_fd);                                 /* regions */
      save_snd_state_options(ss,save_fd);                    /* options = user-settable global state variables */
      if (transform_dialog_is_active()) fprintf(save_fd,"(transform-dialog)\n");
      if (enved_dialog_is_active()) fprintf(save_fd,"(enved-dialog)\n");
      if (color_dialog_is_active()) fprintf(save_fd,"(color-dialog)\n");
      if (orientation_dialog_is_active()) fprintf(save_fd,"(orientation-dialog)\n");
      if (file_dialog_is_active()) fprintf(save_fd,"(file-dialog)\n"); /* View: Files dialog, not Open: File */
      if (region_dialog_is_active()) fprintf(save_fd,"(region-dialog)\n");
      if (record_dialog_is_active()) fprintf(save_fd,"(record-dialog)\n");
      if (group_dialog_is_active()) fprintf(save_fd,"(group-dialog)\n");
      fclose(save_fd);
      /* cp->mixes is mix_state struct -- has mix_pool->mixdata array */
      /* each mixdata struct has states -> arrays of console_state structs */
      /* each console_state has beg end etc */
      /* groups? */
    }
  return(0);
}

