int main()
{
    signal(SIGINT, ctrlc);

    mapper_device dev = mdev_new("pwm", 9000, 0);

    float min0 = 0;
    float max1 = 1;
    float max1000 = 1000;

    mdev_add_input(dev, "/freq", 1, 'f', "Hz", &min0, &max1000,
                   (mapper_signal_handler*)handler_freq, 0);
    mdev_add_input(dev, "/gain", 1, 'f', "Hz", &min0, &max1,
                   (mapper_signal_handler*)handler_gain, 0);
    mdev_add_input(dev, "/duty", 1, 'f', "Hz", &min0, &max1,
                   (mapper_signal_handler*)handler_duty, 0);

    run_synth();

    set_duty(0.1);
    set_freq(110.0);
    set_gain(0.1);

    printf("Press Ctrl-C to quit.\n");

    while (!done)
        mdev_poll(dev, 10);

    mdev_free(dev);

    set_freq(0);
    sleep(1);

    stop_synth();
}
void
ags_recall_dssi_run_run_pre(AgsRecall *recall)
{
  AgsRecallDssi *recall_dssi;
  AgsRecallChannelRun *recall_channel_run;
  AgsRecallRecycling *recall_recycling;
  AgsRecallDssiRun *recall_dssi_run;
  AgsAudioSignal *audio_signal;
  AgsPort *current_port;
  AgsRecallID *recall_id;
  AgsRecyclingContext *parent_recycling_context, *recycling_context;
  
  AgsCountBeatsAudioRun *count_beats_audio_run;
  AgsRouteDssiAudioRun *route_dssi_audio_run;
    
  GList *list_start, *list;
  GList *port;
  
  GList *note_start, *note;

  snd_seq_event_t **event_buffer;
  unsigned long *event_count;
    
  gchar *specifier, *current_specifier;
  
  LADSPA_Data port_data;

  guint bank, program;
  guint output_lines, input_lines;
  guint notation_counter;
  guint x0, x1;
  guint port_count;
  
  guint copy_mode_in, copy_mode_out;
  guint buffer_size;
  guint i, i_stop;

  void (*parent_class_run_pre)(AgsRecall *recall);

  void (*select_program)(LADSPA_Handle Instance,
			 unsigned long Bank,
			 unsigned long Program);
  void (*run_synth)(LADSPA_Handle Instance,
		    unsigned long SampleCount,
		    snd_seq_event_t *Events,
		    unsigned long EventCount);
  void (*run)(LADSPA_Handle Instance,
	      unsigned long SampleCount);
  void (*deactivate)(LADSPA_Handle Instance);
  void (*cleanup)(LADSPA_Handle Instance);
  
  pthread_mutex_t *recall_dssi_mutex;
  pthread_mutex_t *port_mutex;

  /* get parent class */
  pthread_mutex_lock(ags_recall_get_class_mutex());

  parent_class_run_pre = AGS_RECALL_CLASS(ags_recall_dssi_run_parent_class)->run_pre;
  
  pthread_mutex_unlock(ags_recall_get_class_mutex());

  /* call parent */
  parent_class_run_pre(recall);

  g_object_get(recall,
	       "recall-id", &recall_id,
	       "source", &audio_signal,
	       NULL);

  g_object_get(recall_id,
	       "recycling-context", &recycling_context,
	       NULL);

  g_object_get(recycling_context,
	       "parent", &parent_recycling_context,
	       NULL);

  g_object_get(audio_signal,
	       "note", &note_start,
	       NULL);

  if(ags_recall_global_get_rt_safe() &&
     parent_recycling_context != NULL &&
     note_start == NULL){
    g_object_unref(recall_id);

    g_object_unref(audio_signal);
    
    g_object_unref(recycling_context);

    g_object_unref(parent_recycling_context);
    
    return;
  }

  g_list_free_full(note_start,
		   g_object_unref);
  
  g_object_get(recall,
	       "parent", &recall_recycling,
	       NULL);

  g_object_get(recall_recycling,
	       "parent", &recall_channel_run,
	       NULL);

  g_object_get(recall_channel_run,
	       "recall-channel", &recall_dssi,
	       NULL);

  recall_dssi_run = AGS_RECALL_DSSI_RUN(recall);

  g_object_get(recall_dssi_run,
	       "route-dssi-audio-run", &route_dssi_audio_run,
	       NULL);
  
  if(route_dssi_audio_run == NULL){
    g_object_unref(recall_id);

    g_object_unref(audio_signal);

    g_object_unref(recycling_context);

    g_object_unref(parent_recycling_context);

    g_object_unref(recall_recycling);
    
    g_object_unref(recall_channel_run);

    g_object_unref(recall_dssi);

    return;
  }

  /* get recall dssi mutex */
  pthread_mutex_lock(ags_recall_get_class_mutex());
  
  recall_dssi_mutex = AGS_RECALL(recall_dssi)->obj_mutex;
  
  pthread_mutex_unlock(ags_recall_get_class_mutex());

  g_object_get(route_dssi_audio_run,
	       "count-beats-audio-run", &count_beats_audio_run,
	       NULL);

  g_object_get(audio_signal,
	       "buffer-size", &buffer_size,
	       NULL);

  /* get some fields */
  pthread_mutex_lock(recall_dssi_mutex);

  output_lines = recall_dssi->output_lines;
  input_lines = recall_dssi->input_lines;

  pthread_mutex_unlock(recall_dssi_mutex);

  if(input_lines < output_lines){
    i_stop = output_lines;
  }else{
    i_stop = input_lines;
  }

  g_object_get(count_beats_audio_run,
	       "notation-counter", &notation_counter,
	       NULL);
  
  if(ags_recall_global_get_rt_safe()){  
    g_object_get(recall_dssi_run,
		 "note", &note_start,
		 NULL);
    
    note = note_start;
    
    while(note != NULL){
      g_object_get(note->data,
		   "x0", &x0,
		   "x1", &x1,
		   NULL);
	
      if((x1 + 1 <= notation_counter &&
	  !ags_note_test_flags(note->data, AGS_NOTE_FEED)) ||
	 x0 > notation_counter){
	recall_dssi_run->note = g_list_remove(recall_dssi_run->note,
					      note->data);
	g_object_unref(note->data);
      }
    
      note = note->next;
    }
    
    if(note_start == NULL){
      memset(recall_dssi_run->event_buffer[0], 0, sizeof(snd_seq_event_t));
    }

    g_list_free_full(note_start,
		     g_object_unref);
  }else{  
    g_object_get(recall_dssi_run,
		 "note", &note_start,
		 NULL);
    
    g_object_get(note_start->data,
		 "x0", &x0,
		 "x1", &x1,
		 NULL);
    
    if(audio_signal->stream_current == NULL ||
       (x1 + 1 <= notation_counter &&
	!ags_note_test_flags(note_start->data, AGS_NOTE_FEED)) ||
       x0 > notation_counter){
      //    g_message("done");

      pthread_mutex_lock(recall_dssi_mutex);

      deactivate = recall_dssi->plugin_descriptor->LADSPA_Plugin->deactivate;
      cleanup = recall_dssi->plugin_descriptor->LADSPA_Plugin->cleanup;
      
      pthread_mutex_unlock(recall_dssi_mutex);
      
      for(i = 0; i < i_stop; i++){
	/* deactivate */
	//TODO:JK: fix-me
	if(deactivate != NULL){
	  deactivate(recall_dssi_run->ladspa_handle[i]);
	}
      
	cleanup(recall_dssi_run->ladspa_handle[i]);
      }
      
      ags_recall_done(recall);

      g_list_free_full(note_start,
		       g_object_unref);

      goto ags_recall_dssi_run_run_pre_END;
    }
  }
  
  /* get copy mode and clear buffer */
  copy_mode_in = ags_audio_buffer_util_get_copy_mode(AGS_AUDIO_BUFFER_UTIL_FLOAT,
						     ags_audio_buffer_util_format_from_soundcard(audio_signal->format));

  copy_mode_out = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(audio_signal->format),
						      AGS_AUDIO_BUFFER_UTIL_FLOAT);
  
  if(recall_dssi_run->output != NULL){
    ags_audio_buffer_util_clear_float(recall_dssi_run->output, output_lines,
				      buffer_size);
  }

  if(recall_dssi_run->input != NULL){
    ags_audio_buffer_util_clear_float(recall_dssi_run->input, input_lines,
				      buffer_size);
  }

  /* copy data  */
  if(recall_dssi_run->input != NULL){
    ags_audio_buffer_util_copy_buffer_to_buffer(recall_dssi_run->input, input_lines, 0,
						audio_signal->stream_current->data, 1, 0,
						buffer_size, copy_mode_in);
  }

  /* select program */
  pthread_mutex_lock(recall_dssi_mutex);

  port_count = recall_dssi->plugin_descriptor->LADSPA_Plugin->PortCount;

  select_program = recall_dssi->plugin_descriptor->select_program;
  
  pthread_mutex_unlock(recall_dssi_mutex);

  /* cache port data */
  g_object_get(recall_dssi,
	       "port", &list_start,
	       NULL);
  
  for(i = 0; i < port_count; i++){
    pthread_mutex_lock(recall_dssi_mutex);

    specifier = g_strdup(recall_dssi->plugin_descriptor->LADSPA_Plugin->PortNames[i]);

    pthread_mutex_unlock(recall_dssi_mutex);

    list = list_start;
    
    while(list != NULL){
      gboolean success;
      
      current_port = list->data;

      /* get port mutex */
      pthread_mutex_lock(ags_port_get_class_mutex());

      port_mutex = current_port->obj_mutex;
      
      pthread_mutex_unlock(ags_port_get_class_mutex());

      /* check specifier */
      pthread_mutex_lock(port_mutex);

      current_specifier = g_strdup(current_port->specifier);
      
      pthread_mutex_unlock(port_mutex);
      
      success = (!g_strcmp0(specifier,
			    current_specifier)) ? TRUE: FALSE;
      g_free(current_specifier);
	
      if(success){
	GValue value = {0,};
	  
	g_value_init(&value,
		     G_TYPE_FLOAT);
	ags_port_safe_read(current_port,
			   &value);
	
	recall_dssi_run->port_data[i] = g_value_get_float(&value);

	g_value_unset(&value);
	
	break;
      }

      list = list->next;
    }

    g_free(specifier);
  }

  g_object_get(recall_dssi,
	       "bank", &bank,
	       "program", &program,
	       NULL);
  
  if(select_program != NULL){    
    for(i = 0; i < i_stop; i++){
      select_program(recall_dssi_run->ladspa_handle[i],
		     (unsigned long) bank,
		     (unsigned long) program);

      //      g_message("b p %u %u", bank, program);
    }
  }

  /* reset port data */    
  for(i = 0; i < port_count; i++){
    pthread_mutex_lock(recall_dssi_mutex);

    specifier = g_strdup(recall_dssi->plugin_descriptor->LADSPA_Plugin->PortNames[i]);

    pthread_mutex_unlock(recall_dssi_mutex);

    list = list_start;
    current_port = NULL;
    
    while(list != NULL){
      gboolean success;
      
      current_port = list->data;

      /* get port mutex */
      pthread_mutex_lock(ags_port_get_class_mutex());

      port_mutex = current_port->obj_mutex;
      
      pthread_mutex_unlock(ags_port_get_class_mutex());

      /* check specifier */
      pthread_mutex_lock(port_mutex);

      current_specifier = g_strdup(current_port->specifier);
      
      pthread_mutex_unlock(port_mutex);
      
      success = (!g_strcmp0(specifier,
			    current_specifier)) ? TRUE: FALSE;
      g_free(current_specifier);

      if(success){
	break;
      }

      list = list->next;
    }

    g_free(specifier);

    if(list != NULL){
      GValue value = {0,};
      
      g_value_init(&value,
		   G_TYPE_FLOAT);
      port_data = recall_dssi_run->port_data[i];

      g_value_set_float(&value,
			port_data);
      ags_port_safe_write(current_port,
			  &value);

      g_value_unset(&value);
    }
  }

  g_list_free_full(list_start,
		   g_object_unref);
  
  /* process data */
  pthread_mutex_lock(recall_dssi_mutex);

  run_synth = recall_dssi->plugin_descriptor->run_synth;
  run = recall_dssi->plugin_descriptor->LADSPA_Plugin->run;
  
  pthread_mutex_unlock(recall_dssi_mutex);

  g_object_get(recall_dssi_run,
	       "note", &note_start,
	       NULL);
  
  note = note_start;

  while(note != NULL){    
    if(run_synth != NULL){
      if(recall_dssi_run->event_buffer != NULL){
	event_buffer = recall_dssi_run->event_buffer;
	event_count = recall_dssi_run->event_count;
      
	while(*event_buffer != NULL){
	  if(event_buffer[0]->type == SND_SEQ_EVENT_NOTEON){
	    run_synth(recall_dssi_run->ladspa_handle[0],
		      (unsigned long) (output_lines * buffer_size),
		      event_buffer[0],
		      event_count[0]);
	  }
	  
	  event_buffer++;
	  event_count++;
	}
      }
    }else if(run != NULL){
      run(recall_dssi_run->ladspa_handle[0],
	  (unsigned long) buffer_size);
    }

    note = note->next;
  }

  g_list_free_full(note_start,
		   g_object_unref);
  
  /* copy data */
  if(recall_dssi_run->output != NULL){
    ags_audio_buffer_util_clear_buffer(audio_signal->stream_current->data, 1,
				       buffer_size, ags_audio_buffer_util_format_from_soundcard(audio_signal->format));
    
    ags_audio_buffer_util_copy_buffer_to_buffer(audio_signal->stream_current->data, 1, 0,
						recall_dssi_run->output, output_lines, 0,
						buffer_size, copy_mode_out);
  }

ags_recall_dssi_run_run_pre_END:
  
  g_object_unref(recall_id);

  g_object_unref(recycling_context);

  g_object_unref(parent_recycling_context);

  g_object_unref(recall_recycling);
    
  g_object_unref(recall_channel_run);

  g_object_unref(recall_dssi);

  g_object_unref(count_beats_audio_run);
}