[specimen] [dubphil at free.fr: here is my patch]

Eric Dantan Rzewnicki eric at zhevny.com
Fri Apr 2 13:20:20 CDT 2010


Forwarding to list, just to make sure it doesn't get lost in my INBOX
and so others can take a look. -edrz

----- Forwarded message from Dubphil <dubphil at free.fr> -----

Date: Fri, 02 Apr 2010 18:55:36 +0200
From: Dubphil <dubphil at free.fr>
Subject: here is my patch
To: Eric Dantan Rzewnicki <eric at zhevny.com>

Eric,

this is the patch from the SVN trunk (few hours old), Specimen can be  
compiled and run well but the functionnality I want to add is not working 
yet.

this is what is working :

- run specimen with the parameter -c <nb_stereo_channel> adds the relevant 
number of ports pair to jack client
- number of stereo channel can be setted in the audio settings  window
- the left and right outputs parameters can be set, saved and load from a 
bank, this stands in the SMP tab of a patch

this is what is not working :

- the drop down menus of the "Outputs" section of the SMP patch tab are  
not populated by the available jack ports. The code is here but it doesn't 
work (I spent almost all this day to find why without success)
- the routing of the sound of a patch to the assigned outputs (I'm very  
lost here)
- the -c param is not used to populate the spinbutton of the audioi  
settings window, and this parameter is not saved somewhere (I don't know  
where to save this).

Hope the design I choose is the good one.

Best.

Philippe


Index: src/beef.c
===================================================================
--- src/beef.c	(r??vision 89)
+++ src/beef.c	(copie de travail)
@@ -79,6 +79,14 @@
 	xmlNewTextChild (xmlpatch, NULL, (const xmlChar *) "play_mode",
 			 (const xmlChar *) tmp);
 
+	sprintf (tmp, "%d", patch_get_lout (id[i]));
+	xmlNewTextChild (xmlpatch, NULL, (const xmlChar *) "lout",
+			 (const xmlChar *) tmp);
+
+	sprintf (tmp, "%d", patch_get_rout (id[i]));
+	xmlNewTextChild (xmlpatch, NULL, (const xmlChar *) "rout",
+			 (const xmlChar *) tmp);
+
 	sprintf (tmp, "%d", patch_get_cut (id[i]));
 	xmlNewTextChild (xmlpatch, NULL, (const xmlChar *) "cut",
 			 (const xmlChar *) tmp);
@@ -442,6 +450,24 @@
 		    patch_set_play_mode (id, atoi ((const char *) key));
 
 		}
+		else if (!xmlStrcmp
+			 (cur->name, (const xmlChar *) "lout"))
+		{
+		    key =
+			xmlNodeListGetString (doc, cur->xmlChildrenNode,
+					      1);
+		    patch_set_lout (id, atoi ((const char *) key));
+
+		}
+		else if (!xmlStrcmp
+			 (cur->name, (const xmlChar *) "rout"))
+		{
+		    key =
+			xmlNodeListGetString (doc, cur->xmlChildrenNode,
+					      1);
+		    patch_set_rout (id, atoi ((const char *) key));
+
+		}
 		else if (!xmlStrcmp (cur->name, (const xmlChar *) "cut"))
 		{
 		    key =
Index: src/jackdriver.c
===================================================================
--- src/jackdriver.c	(r??vision 89)
+++ src/jackdriver.c	(copie de travail)
@@ -24,7 +24,7 @@
 #include "gui/gui.h"
 
 /* prototypes */
-static int start ( );
+static int start (int nb_schan);
 static int stop ( );
 
 /* file-global variables */
@@ -39,6 +39,7 @@
 #endif
 static jack_client_t*  client;
 static float*          buffer;
+static int             nb_schan = 1;
 static int             rate = 44100;
 static int             periodsize = 2048;
 static int             running = 0;
@@ -254,7 +255,7 @@
 static void restart ( )
 {
      stop ( );
-     start ( );
+     start (nb_schan);
 }
 
 static void cb_sync (GtkToggleButton* button, gpointer data)
@@ -265,11 +266,21 @@
 	  sync_set_method (SYNC_METHOD_MIDI);
 }
 
+static void nb_jack_schan (GtkSpinButton* spinner)
+{
+	 nb_schan = gtk_spin_button_get_value_as_int (spinner);
+     return;
+}
+
+
 static void init ( )
 {
      GtkWidget* hbox;
      GtkWidget* vbox;
+     GtkWidget* hbox2;
      GtkWidget* button;
+     GtkWidget* spinner;
+     GtkWidget* label;
 
      config_frame = gtk_frame_new ("JACK");
 
@@ -277,6 +288,20 @@
      gtk_container_set_border_width (GTK_CONTAINER (vbox), GUI_SPACING);
      gtk_container_add (GTK_CONTAINER (config_frame), vbox);
      gtk_widget_show (vbox);
+
+     hbox2 = gtk_hbox_new (FALSE, GUI_SPACING);
+     gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0);
+     gtk_widget_show (hbox2);
+ 
+     label = gtk_label_new ("Number of stereo channel :");
+     gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
+     gtk_widget_show (label);
+   
+     spinner = gtk_spin_button_new_with_range (nb_schan, 16.0, 1.0);
+     gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
+     gtk_box_pack_start (GTK_BOX (hbox2), spinner, FALSE, FALSE, 0);
+     gtk_widget_show (spinner);
+     g_signal_connect (G_OBJECT (spinner), "value_changed", G_CALLBACK (nb_jack_schan), NULL);
      
      hbox = gtk_hbox_new (FALSE, GUI_SPACING);
      gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
@@ -307,7 +332,7 @@
 			       (gpointer) button);
 }
 
-static int start (void)
+static int start (int nb_schan)
 {
      const char** ports;
      char* instancename = strdup (get_instance_name ( ));
@@ -334,12 +359,21 @@
 #endif
      jack_on_shutdown (client, shutdown, 0);
 
-     lport =
-	  jack_port_register (client, "out_left", JACK_DEFAULT_AUDIO_TYPE,
+     int j; 
+     char port_name[80] = "";  
+     for (j=1; j<=nb_schan; j++)
+     { 
+        sprintf(port_name, "out_%d_left",j);
+        lport =
+	    jack_port_register (client, port_name, JACK_DEFAULT_AUDIO_TYPE,
 			      JackPortIsOutput, 0);
-     rport =
-	  jack_port_register (client, "out_right", JACK_DEFAULT_AUDIO_TYPE,
+        
+        sprintf(port_name, "out_%d_right",j);
+        rport =
+	    jack_port_register (client, port_name, JACK_DEFAULT_AUDIO_TYPE,
 			      JackPortIsOutput, 0);
+     }
+
 #if defined HAVE_JACK_MIDI || defined HAVE_OLD_JACK_MIDI || defined HAVE_OLDEST_JACK_MIDI
      midiport =
 	  jack_port_register (client, "midi_input", JACK_DEFAULT_MIDI_TYPE,
@@ -373,7 +407,22 @@
      ports = jack_get_ports (client, NULL, NULL,
 			  JackPortIsInput | JackPortIsPhysical);
 
-     if (ports[0] != NULL)
+     int n;
+     for(n=0;ports[n] == NULL;n++)
+     {      
+        if (ports[n] != NULL)
+        {
+	        if (jack_connect (client, jack_port_name (lport), ports[n]) != 0)
+	        errmsg (strcat(strcat("Cannot connect", ports[n]), "\n"));
+	    }
+        else
+        {
+	        errmsg ("Output ports unavailable\n");
+        }
+	    free (ports);
+     }   
+
+/*     if (ports[0] != NULL)
      {
 	  if (jack_connect (client, jack_port_name (lport), ports[0]) != 0)
 	       errmsg ("Cannot connect left output port\n");
@@ -393,7 +442,7 @@
      {
 	  errmsg ("Cannot connect output ports\n");
      }
-
+*/
      debug ("Initialization complete\n");
      running = 1;
      pthread_mutex_unlock (&running_mutex);
@@ -437,6 +486,22 @@
      return "JACK";
 }
 
+static const char** getports ( )
+{
+     const char** ports;
+     if (running)
+     {   
+        ports = jack_get_ports (client, NULL, NULL,
+			  JackPortIsInput | JackPortIsPhysical);
+
+        return ports;
+     }
+     else
+     {
+        return NULL;
+     }   
+}
+
 static GtkWidget* getwidget ( )
 {
      return config_frame;
@@ -460,5 +525,6 @@
      getperiodsize,
      getwidget,
      getname,
+     getports,
      getid
 };
Index: src/driver.c
===================================================================
--- src/driver.c	(r??vision 89)
+++ src/driver.c	(copie de travail)
@@ -1,3 +1,4 @@
+#include <string.h>
 #include "specimen.h"
 #include "driver.h"
 #include "lfo.h"
@@ -27,7 +28,7 @@
 	  ndrivers = 0;
 }
 
-int driver_start (int id)
+int driver_start (int id, int nb_schan)
 {
      if (id < 0 || id >= ndrivers)
 	  return DRIVER_ERR_ID;
@@ -41,7 +42,7 @@
      curdriver = id;
 
      if(id==0){
-     	return drivers[id]->start ( );
+     	return drivers[id]->start (nb_schan);
      }
      return drivers[id]->start ( );
 }
@@ -67,6 +68,13 @@
      return drivers[id]->getname ( );
 }
 
+const char** driver_get_ports (int id)
+{
+
+     return drivers[id]->getports ( );
+}
+
+
 GtkWidget* driver_get_widget (int id)
 {
      if (id < 0 || id >= ndrivers)
Index: src/patch.c
===================================================================
--- src/patch.c	(r??vision 89)
+++ src/patch.c	(copie de travail)
@@ -130,7 +130,8 @@
     float    pitch_bend;	/* pitch bending factor */
     gboolean mono;		/* whether patch is monophonic or not */
     gboolean legato;		/* whether patch is played legato or not */
-
+    int      lout;	/* left output of the patch */
+    int      rout;	/* right output of the patch */
     PatchPlayMode play_mode;	/* how this patch is to be played */
     PatchParam    vol;		/* volume:                  [0.0, 1.0] */
     PatchParam    pan;		/* panning:                [-1.0, 1.0] */
@@ -2557,6 +2558,26 @@
     return 0;
 }
 
+/* sets the left output */
+int patch_set_lout (int id, int lout)
+{
+    if (!isok (id))
+	return PATCH_ID_INVALID;
+    
+    patches[id].lout = lout;
+    return 0;
+}
+
+/* sets the left output */
+int patch_set_rout (int id, int rout)
+{
+    if (!isok (id))
+	return PATCH_ID_INVALID;
+    
+    patches[id].rout = rout;
+    return 0;
+}
+
 /* sets the play mode */
 int patch_set_play_mode (int id, PatchPlayMode mode)
 {
@@ -2883,6 +2904,22 @@
     return patches[id].pitch_steps;
 }
 
+/* get the left output */
+int patch_get_lout (int id)
+{
+    if (!isok (id))
+	return PATCH_ID_INVALID;
+    return patches[id].lout;
+}
+
+/* get the right output */
+int patch_get_rout (int id)
+{
+    if (!isok (id))
+	return PATCH_ID_INVALID;
+    return patches[id].rout;
+}
+
 /* get the play mode */
 PatchPlayMode patch_get_play_mode (int id)
 {
Index: src/driver.h
===================================================================
--- src/driver.h	(r??vision 89)
+++ src/driver.h	(copie de travail)
@@ -26,15 +26,17 @@
      int         (*getperiodsize) ( );
      GtkWidget*  (*getwidget)     ( );
      const char* (*getname)       ( );
+     const char** (*getports)      ( );
      void*       (*getid)         ( );
 }
 Driver;
 
 void        driver_init          ( );
-int         driver_start         (int id);
+int         driver_start         (int id, int nb_schan);
 void        driver_stop          ( );
 int         driver_get_count     ( );
 const char* driver_get_name      (int id);
+const char** driver_get_ports    (int id);
 GtkWidget*  driver_get_widget    (int id);
 void*       driver_get_client_id (int id);
 
Index: src/gui/audio-settings.c
===================================================================
--- src/gui/audio-settings.c	(r??vision 89)
+++ src/gui/audio-settings.c	(copie de travail)
@@ -38,7 +38,8 @@
 
 	  /* start the new sound system */
 	  driver_stop ( );
-	  driver_start (id);
+      /*FIX ME huggly hack setting 1 instead of getting the configured number of stereo channel nb_schan */
+	  driver_start (id, 1);
      }
 }
 
Index: src/gui/sampletab.c
===================================================================
--- src/gui/sampletab.c	(r??vision 89)
+++ src/gui/sampletab.c	(copie de travail)
@@ -1,5 +1,9 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <gtk/gtk.h>
 #include "sampletab.h"
+#include "driver.h"
 #include "gui.h"
 #include "waveform.h"
 #include "patch.h"
@@ -86,6 +90,26 @@
 }
 
 
+static void set_lout (SampleTab* self)
+{
+    int lout;
+
+    lout = gtk_option_menu_get_history(GTK_OPTION_MENU(self->lout_opt));
+
+    patch_set_lout(self->patch, lout);
+}
+
+ 
+static void set_rout (SampleTab* self)
+{
+    int rout;
+
+    rout = gtk_option_menu_get_history(GTK_OPTION_MENU(self->rout_opt));
+
+    patch_set_rout(self->patch, rout);
+}
+
+
 static void set_mode(SampleTab* self)
 {
     int val;
@@ -117,8 +141,21 @@
 
     patch_set_play_mode(self->patch, mode);
 }
+ 
     
+static void lout_cb(GtkOptionMenu* opt, SampleTab* self)
+{
+    set_lout(self);
+}
 
+
+static void rout_cb(GtkOptionMenu* opt, SampleTab* self)
+{
+    set_rout(self);
+}
+
+   
+
 static void mode_cb(GtkOptionMenu* opt, SampleTab* self)
 {
     set_mode(self);
@@ -143,6 +180,10 @@
 {
     g_signal_connect(G_OBJECT(self->waveform), "button-press-event",
 		     G_CALLBACK(waveform_cb), (gpointer) self);
+    g_signal_connect(G_OBJECT(self->lout_opt), "changed",
+		     G_CALLBACK(lout_cb), (gpointer) self);
+    g_signal_connect(G_OBJECT(self->rout_opt), "changed",
+		     G_CALLBACK(rout_cb), (gpointer) self);
     g_signal_connect(G_OBJECT(self->mode_opt), "changed",
 		     G_CALLBACK(mode_cb), (gpointer) self);
     g_signal_connect(G_OBJECT(self->reverse_check), "toggled",
@@ -154,6 +195,8 @@
 
 static void block(SampleTab* self)
 {
+    g_signal_handlers_block_by_func(self->lout_opt, lout_cb, self);
+    g_signal_handlers_block_by_func(self->rout_opt, rout_cb, self);
     g_signal_handlers_block_by_func(self->mode_opt, mode_cb, self);
     g_signal_handlers_block_by_func(self->reverse_check, reverse_cb, self);
 }
@@ -161,6 +204,8 @@
 
 static void unblock(SampleTab* self)
 {
+    g_signal_handlers_unblock_by_func(self->lout_opt, lout_cb, self);
+    g_signal_handlers_unblock_by_func(self->rout_opt, rout_cb, self);
     g_signal_handlers_unblock_by_func(self->mode_opt, mode_cb, self);
     g_signal_handlers_unblock_by_func(self->reverse_check, reverse_cb, self);
 }
@@ -228,6 +273,80 @@
 }    
 
 
+inline static GtkWidget* lout_opt_new(SampleTab* self)
+{
+    GtkWidget* menu;
+    GtkWidget* item;
+    GtkWidget* opt;
+    
+    /* lout menu */
+    menu = gtk_menu_new();
+
+    const char** ports;
+    ports = driver_get_ports (0);
+
+    if(ports == NULL)
+    {
+        item = gtk_menu_item_new_with_label("No left port");
+        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+        gtk_widget_show(item);
+    }
+    else
+    {
+        int n;
+        for (n=0;ports[n]==NULL;n++)
+        {
+            item = gtk_menu_item_new_with_label(ports[n]);
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            gtk_widget_show(item);
+        }
+    }
+
+    /* lout option menu */
+    opt = gtk_option_menu_new();
+    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
+
+    return opt;
+}
+
+
+inline static GtkWidget* rout_opt_new(SampleTab* self)
+{
+    GtkWidget* menu;
+    GtkWidget* item;
+    GtkWidget* opt;
+    
+    /* rout menu */
+    menu = gtk_menu_new();
+
+    const char** ports;
+    ports = driver_get_ports (0);
+    
+    if(ports == NULL)
+    {
+        item = gtk_menu_item_new_with_label("No right port");
+        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+        gtk_widget_show(item);
+    }
+    else
+    {
+        int n;
+        for (n=0;ports[n]==NULL;n++)
+        {
+            item = gtk_menu_item_new_with_label(ports[n]);
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            gtk_widget_show(item);
+        }
+    }
+
+    /* rout option menu */
+    opt = gtk_option_menu_new();
+    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
+
+    return opt;
+}
+
+
 static void sample_tab_init(SampleTab* self)
 {
     GtkBox* box = GTK_BOX(self);
@@ -284,6 +403,31 @@
     gtk_box_pack_start(GTK_BOX(hbox), self->reverse_check, TRUE, TRUE, 0);
     gtk_widget_show(self->reverse_check);
 
+    /* section padding */
+    pad = gui_vpad_new(GUI_SECSPACE);
+    gtk_box_pack_start(box, pad, FALSE, FALSE, 0);
+    gtk_widget_show(pad);
+    
+    /* outputs section */
+    section = gui_section_new("Outputs", &hbox);
+    gtk_box_pack_start(box, section, FALSE, FALSE, 0);
+    gtk_widget_show(section);
+
+    /* lout option menu */
+    self->lout_opt = lout_opt_new(self);
+    gtk_box_pack_start(GTK_BOX(hbox), self->lout_opt, TRUE, TRUE, 0);
+    gtk_widget_show(self->lout_opt);
+
+    /* pad */
+    pad = gui_hpad_new(GUI_SPACING);
+    gtk_box_pack_start(GTK_BOX(hbox), pad, FALSE, FALSE, 0);
+    gtk_widget_show(pad);
+ 
+    /* rout option menu */
+    self->rout_opt = rout_opt_new(self);
+    gtk_box_pack_start(GTK_BOX(hbox), self->rout_opt, TRUE, TRUE, 0);
+    gtk_widget_show(self->rout_opt);
+
     connect(self);
 }
 
@@ -298,6 +442,9 @@
 {
     PatchPlayMode mode;
     
+    int lout;
+    int rout;
+ 
     self->patch = patch;
 
     waveform_set_patch(WAVEFORM(self->waveform), patch);
@@ -311,6 +458,12 @@
     {
 	update_file_button(self);
 
+	lout = patch_get_lout(patch);
+	gtk_option_menu_set_history(GTK_OPTION_MENU(self->lout_opt), lout);
+
+	rout = patch_get_rout(patch);
+	gtk_option_menu_set_history(GTK_OPTION_MENU(self->rout_opt), rout);
+ 
 	mode = patch_get_play_mode(patch);
 
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->reverse_check),
Index: src/gui/sampletab.h
===================================================================
--- src/gui/sampletab.h	(r??vision 89)
+++ src/gui/sampletab.h	(copie de travail)
@@ -22,6 +22,8 @@
     int patch;
     GtkWidget* waveform;
     GtkWidget* mode_opt;
+    GtkWidget* lout_opt;
+    GtkWidget* rout_opt;
     GtkWidget* file_label;
     GtkWidget* file_button;
     GtkWidget* reverse_check;
Index: src/specimen.c
===================================================================
--- src/specimen.c	(r??vision 89)
+++ src/specimen.c	(copie de travail)
@@ -24,6 +24,7 @@
 	printf ("Usage: specimen [options] [bankname]\n\n");
 	printf ("Options:\n");
 	printf ("  -n, --name <name>  Specify instance name, defaults to \"specimen\"\n");
+	printf ("  -c, --channel <nb_stereo_channel>  Specify number of jack stereo channel\n");
 	printf ("  -h, --help         Display this help message\n\n");
 	printf ("For more information, please see:\n");
 	printf ("http://zhevny.com/specimen/\n");
@@ -42,17 +43,19 @@
 #endif
 
 	int opt;
+    int nb_schan = 1;
 	int longopt_index;
 	static struct option long_options[] = 
 	{
 		{ "name", 1, 0, 'n'},
+        { "channel", 1, 0, 'c'},
 		{ "uuid", 1, 0, 'U'},
 		{ "help", 0, 0, 'h'},
 		{ 0, 0, 0, 0}
 	};
 
 	/* command line argument processing */
-	while((opt = getopt_long(argc, argv, "n:U:h", long_options,
+	while((opt = getopt_long(argc, argv, "n:c:U:h", long_options,
 	                         &longopt_index)) > 0)
 	{
 		switch (opt)
@@ -60,6 +63,9 @@
 			case 'n':
 				instance_name = strdup(optarg);
 				break;
+    	    case 'c':
+	            nb_schan = atoi(optarg);
+		        break;
 			case 'U':
 				jackdriver_set_uuid( strdup(optarg) );
 				break;
@@ -93,7 +99,7 @@
 
 	/* start */
 	midi_start();
-	driver_start(0);
+	driver_start(0, nb_schan);
 #ifdef HAVE_LASH
 	lashdriver_start();
 	lashdriver_set_jack_name((char*)driver_get_client_id(0));
Index: src/patch.h
===================================================================
--- src/patch.h	(r??vision 89)
+++ src/patch.h	(copie de travail)
@@ -151,6 +151,8 @@
 int patch_set_lower_note   (int id, int note);
 int patch_set_monophonic   (int id, gboolean val);
 int patch_set_name         (int id, const char* name);
+int patch_set_lout         (int id, const int lout);
+int patch_set_rout         (int id, const int rout);
 int patch_set_note         (int id, int note);
 int patch_set_panning      (int id, float pan);
 int patch_set_pitch        (int id, float pitch);
@@ -179,6 +181,8 @@
 int           patch_get_lower_note    (int id);
 gboolean      patch_get_monophonic    (int id);
 char*         patch_get_name          (int id);
+int           patch_get_lout          (int id);
+int           patch_get_rout          (int id);
 int           patch_get_note          (int id);
 float         patch_get_panning       (int id);
 float         patch_get_pitch         (int id);


----- End forwarded message -----


More information about the Specimen mailing list