diff -r 3a35024cb149 src/Makefile.am
--- a/src/Makefile.am	Sun Apr 22 15:32:13 2007 +0400
+++ b/src/Makefile.am	Sun Apr 22 16:56:31 2007 +0400
@@ -6,13 +6,15 @@ EXTRA_DIST = \
 EXTRA_DIST = \
 	jack_rack_1.0.dtd \
 	jack_rack_1.1.dtd \
-	jack_rack_1.2.dtd
+	jack_rack_1.2.dtd \
+	jack_rack_1.3.dtd
 
 dtddir = $(datadir)/dtds
 dtd_DATA = \
 	jack_rack_1.0.dtd \
 	jack_rack_1.1.dtd \
-	jack_rack_1.2.dtd
+	jack_rack_1.2.dtd \
+	jack_rack_1.3.dtd
 
 bin_PROGRAMS = jack-rack
 
diff -r 3a35024cb149 src/file.c
--- a/src/file.c	Sun Apr 22 15:32:13 2007 +0400
+++ b/src/file.c	Sun Apr 22 16:57:49 2007 +0400
@@ -26,6 +26,7 @@
 
 #include <gtk/gtk.h>
 #include <libxml/tree.h>
+#include <math.h>
 
 #include "file.h"
 #include "jack_rack.h"
@@ -53,7 +54,7 @@ jack_rack_create_doc (jack_rack_t * jack
   doc = xmlNewDoc(XML_DEFAULT_VERSION);
 
   /* dtd */
-  dtd = xmlNewDtd (doc, "jackrack", NULL, "http://jack-rack.sf.net/DTD/jack_rack_1.2.dtd");
+  dtd = xmlNewDtd (doc, "jackrack", NULL, "http://jack-rack.sf.net/DTD/jack_rack_1.3.dtd");
   doc->intSubset = dtd;
   xmlAddChild ((xmlNodePtr)doc, (xmlNodePtr)dtd);
   
@@ -130,6 +131,14 @@ jack_rack_create_doc (jack_rack_t * jack
           /* param */
           sprintf (num, "%d", midi_control_get_midi_param (midi_ctrl));
           xmlNewChild (midi_control, NULL, "midi_param", num);
+          
+          /* minvalue */
+          sprintf (num, "%f", midi_control_get_min_value (midi_ctrl));
+          xmlNewChild (midi_control, NULL, "min_value", num);
+          
+          /* maxvalue */
+          sprintf (num, "%f", midi_control_get_max_value (midi_ctrl));
+          xmlNewChild (midi_control, NULL, "max_value", num);
           
           if (midi_ctrl->ladspa_control)
             {
@@ -285,6 +294,8 @@ saved_rack_parse_plugin (saved_rack_t * 
           xmlNodePtr control_node;
           
           midi_ctrl = g_malloc (sizeof (midi_control_t));
+          midi_ctrl->min = -HUGE_VAL;
+          midi_ctrl->max = HUGE_VAL;
           
           for (sub_node = node->children; sub_node; sub_node = sub_node->next)
             {
@@ -298,6 +309,18 @@ saved_rack_parse_plugin (saved_rack_t * 
                 {
                   content = xmlNodeGetContent (sub_node);
                   midi_ctrl->midi_param = atoi (content);
+                  xmlFree (content);
+                }
+              else if (strcmp (sub_node->name, "min_value") == 0)
+                {
+                  content = xmlNodeGetContent (sub_node);
+                  midi_ctrl->min = atof (content);
+                  xmlFree (content);
+                }
+              else if (strcmp (sub_node->name, "max_value") == 0)
+                {
+                  content = xmlNodeGetContent (sub_node);
+                  midi_ctrl->max = atof (content);
                   xmlFree (content);
                 }
               else if (strcmp (sub_node->name, "ladspa") == 0)
diff -r 3a35024cb149 src/jack_rack_1.3.dtd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jack_rack_1.3.dtd	Sun Apr 22 16:55:38 2007 +0400
@@ -0,0 +1,30 @@
+<!ELEMENT jackrack        (channels, samplerate, plugin*)>
+<!ELEMENT channels        (#PCDATA)>
+<!ELEMENT samplerate      (#PCDATA)>
+
+<!ELEMENT plugin          (id, enabled, wet_dry_enabled, wet_dry_locked?,
+                           wet_dry_values, lockall?, controlrow*, midi_control*)>
+<!ELEMENT id              (#PCDATA)>
+<!ELEMENT enabled         (#PCDATA)>
+<!ELEMENT wet_dry_enabled (#PCDATA)>
+<!ELEMENT wet_dry_locked  (#PCDATA)>
+<!ELEMENT lockall         (#PCDATA)>
+
+<!ELEMENT wet_dry_values  (value+)>
+
+<!ELEMENT midi_control    (midi_channel, midi_param, min_value, max_value, (ladspa | wet_dry))>
+<!ELEMENT midi_channel    (#PCDATA)>
+<!ELEMENT midi_param      (#PCDATA)>
+<!ELEMENT min_value       (#PCDATA)>
+<!ELEMENT max_value       (#PCDATA)>
+
+<!ELEMENT ladspa          (copy, control)>
+<!ELEMENT copy            (#PCDATA)>
+<!ELEMENT control         (#PCDATA)>
+
+<!ELEMENT wet_dry         (channel)>
+<!ELEMENT channel         (#PCDATA)>
+
+<!ELEMENT controlrow      (lock?, value*)>
+<!ELEMENT lock            (#PCDATA)>
+<!ELEMENT value           (#PCDATA)>
diff -r 3a35024cb149 src/midi_control.c
--- a/src/midi_control.c	Sun Apr 22 15:32:13 2007 +0400
+++ b/src/midi_control.c	Sun Apr 22 16:31:24 2007 +0400
@@ -86,6 +86,8 @@ ladspa_midi_control_new (plugin_slot_t *
           midi_ctrl->max = exp (midi_ctrl->max);
         }
     }
+  midi_ctrl->real_min = midi_ctrl->min;
+  midi_ctrl->real_max = midi_ctrl->max;
   
   
   return midi_ctrl;
@@ -236,6 +238,60 @@ midi_control_get_control_name    (midi_c
   return str->str;
 }
 
+static LADSPA_Data
+midi_control_clip_value	(midi_control_t *midi_ctrl, LADSPA_Data value)
+{
+  if (value < midi_ctrl->real_min)
+  	value = midi_ctrl->real_min;
+  else if (value > midi_ctrl->real_max)
+  	value = midi_ctrl->real_max;
+  return value;
+}
+
+LADSPA_Data
+midi_control_set_min_value	(midi_control_t *midi_ctrl, LADSPA_Data value)
+{
+  value = midi_control_clip_value (midi_ctrl, value);
+  pthread_mutex_lock (&midi_ctrl->midi_param_lock);
+  midi_ctrl->min = value;
+  pthread_mutex_unlock (&midi_ctrl->midi_param_lock);
+  return value;
+}
+
+LADSPA_Data
+midi_control_set_max_value	(midi_control_t *midi_ctrl, LADSPA_Data value)
+{
+  value = midi_control_clip_value (midi_ctrl, value);
+  pthread_mutex_lock (&midi_ctrl->midi_param_lock);
+  midi_ctrl->max = value;
+  pthread_mutex_unlock (&midi_ctrl->midi_param_lock);
+  return value;
+}
+
+LADSPA_Data
+midi_control_get_min_value       (midi_control_t * midi_ctrl)
+{
+  LADSPA_Data value;
+  
+  pthread_mutex_lock (&midi_ctrl->midi_param_lock);
+  value = midi_ctrl->min;
+  pthread_mutex_unlock (&midi_ctrl->midi_param_lock);
+  
+  return value;
+}
+
+LADSPA_Data
+midi_control_get_max_value       (midi_control_t * midi_ctrl)
+{
+  LADSPA_Data value;
+  
+  pthread_mutex_lock (&midi_ctrl->midi_param_lock);
+  value = midi_ctrl->max;
+  pthread_mutex_unlock (&midi_ctrl->midi_param_lock);
+  
+  return value;
+}
+
 #endif /* HAVE_ALSA */
 
 
diff -r 3a35024cb149 src/midi_control.h
--- a/src/midi_control.h	Sun Apr 22 15:32:13 2007 +0400
+++ b/src/midi_control.h	Sun Apr 22 16:29:12 2007 +0400
@@ -48,6 +48,9 @@ struct _midi_control
   LADSPA_Data         min;
   LADSPA_Data         max;
   
+  LADSPA_Data         real_min;
+  LADSPA_Data         real_max;
+  
   lff_t               *fifo;
   lff_t               *fifos;
 
@@ -88,6 +91,12 @@ gboolean      midi_control_get_locked   
 
 const char *  midi_control_get_control_name    (midi_control_t * midi_ctrl);
 
+LADSPA_Data   midi_control_set_min_value       (midi_control_t * midi_ctrl, LADSPA_Data value);
+LADSPA_Data   midi_control_set_max_value       (midi_control_t * midi_ctrl, LADSPA_Data value);
+
+LADSPA_Data   midi_control_get_min_value       (midi_control_t * midi_ctrl);
+LADSPA_Data   midi_control_get_max_value       (midi_control_t * midi_ctrl);
+
 #endif /* __JR_MIDI_CONTROL_H__ */
 
 #endif /* HAVE_ALSA */
diff -r 3a35024cb149 src/midi_window.c
--- a/src/midi_window.c	Sun Apr 22 15:32:13 2007 +0400
+++ b/src/midi_window.c	Sun Apr 22 16:23:16 2007 +0400
@@ -32,6 +32,8 @@ static void remove_cb  (GtkButton *butto
 static void remove_cb  (GtkButton *button, gpointer user_data);
 static void channel_cb (GtkCellRendererText *channel_renderer, gchar *arg1, gchar *arg2, gpointer user_data);
 static void param_cb   (GtkCellRendererText *param_renderer, gchar *arg1, gchar *arg2, gpointer user_data);
+static void minvalue_cb(GtkCellRendererText *param_renderer, gchar *arg1, gchar *arg2, gpointer user_data);
+static void maxvalue_cb(GtkCellRendererText *param_renderer, gchar *arg1, gchar *arg2, gpointer user_data);
 
 
 /**
@@ -44,6 +46,8 @@ midi_window_create_control_view (midi_wi
   GtkCellRenderer *renderer;
   GtkCellRenderer *channel_renderer;
   GtkCellRenderer *param_renderer;
+  GtkCellRenderer *minvalue_renderer;
+  GtkCellRenderer *maxvalue_renderer;
   GtkTreeViewColumn *column;
 
   /* scroll window for the list */
@@ -60,6 +64,8 @@ midi_window_create_control_view (midi_wi
                                        G_TYPE_INT,
                                        G_TYPE_INT,
                                        G_TYPE_INT,
+				       G_TYPE_FLOAT,
+				       G_TYPE_FLOAT,
                                        G_TYPE_POINTER);
   /* the view */
   mwin->controls_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (mwin->controls));
@@ -102,6 +108,26 @@ midi_window_create_control_view (midi_wi
   
   column = gtk_tree_view_column_new_with_attributes (
              _("MIDI Controller"), param_renderer, "text", PARAM_COLUMN, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (mwin->controls_view), column);
+
+  /* minvalue column */
+  minvalue_renderer = gtk_cell_renderer_text_new ();
+  g_object_set (minvalue_renderer, "editable", TRUE, NULL);
+  g_signal_connect (G_OBJECT (minvalue_renderer), "edited",
+                    G_CALLBACK (minvalue_cb), mwin);
+  
+  column = gtk_tree_view_column_new_with_attributes (
+             _("Min Value"), minvalue_renderer, "text", MINVALUE_COLUMN, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (mwin->controls_view), column);
+
+  /* maxvalue column */
+  maxvalue_renderer = gtk_cell_renderer_text_new ();
+  g_object_set (maxvalue_renderer, "editable", TRUE, NULL);
+  g_signal_connect (G_OBJECT (maxvalue_renderer), "edited",
+                    G_CALLBACK (maxvalue_cb), mwin);
+  
+  column = gtk_tree_view_column_new_with_attributes (
+             _("Max Value"), maxvalue_renderer, "text", MAXVALUE_COLUMN, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (mwin->controls_view), column);
 
 }
@@ -223,6 +249,8 @@ midi_window_add_control (midi_window_t *
                     : midi_ctrl->control.wet_dry.channel) + 1,
     CHANNEL_COLUMN, midi_control_get_midi_channel (midi_ctrl),
     PARAM_COLUMN, midi_control_get_midi_param (midi_ctrl),
+    MINVALUE_COLUMN, midi_ctrl->min,
+    MAXVALUE_COLUMN, midi_ctrl->max,
     MIDI_CONTROL_POINTER, midi_ctrl,
     -1);
   
@@ -330,6 +358,57 @@ param_cb (GtkCellRendererText *cell,
                       -1);
 }
 
+static void
+minvalue_cb(GtkCellRendererText *cell,
+            gchar *path_string,
+            gchar *new_text,
+            gpointer user_data)
+{
+  midi_window_t *mwin = user_data;
+  midi_control_t *midi_ctrl;
+  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+  GtkTreeIter iter;
+  LADSPA_Data value;
+
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (mwin->controls), &iter, path);
+  
+  gtk_tree_model_get (GTK_TREE_MODEL (mwin->controls), &iter,
+                      MIDI_CONTROL_POINTER, &midi_ctrl,
+                      -1);
+
+  value = atof(new_text);
+  value = midi_control_set_min_value(midi_ctrl, value);
+  
+  gtk_list_store_set (mwin->controls, &iter,
+                      MINVALUE_COLUMN, value,
+                      -1);
+}
+
+static void
+maxvalue_cb(GtkCellRendererText *cell,
+            gchar *path_string,
+            gchar *new_text,
+            gpointer user_data)
+{
+  midi_window_t *mwin = user_data;
+  midi_control_t *midi_ctrl;
+  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+  GtkTreeIter iter;
+  LADSPA_Data value;
+
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (mwin->controls), &iter, path);
+  
+  gtk_tree_model_get (GTK_TREE_MODEL (mwin->controls), &iter,
+                      MIDI_CONTROL_POINTER, &midi_ctrl,
+                      -1);
+
+  value = atof(new_text);
+  value = midi_control_set_max_value(midi_ctrl, value);
+  
+  gtk_list_store_set (mwin->controls, &iter,
+                      MAXVALUE_COLUMN, value,
+                      -1);
+}
 
 
 #endif /* HAVE_ALSA */
diff -r 3a35024cb149 src/midi_window.h
--- a/src/midi_window.h	Sun Apr 22 15:32:13 2007 +0400
+++ b/src/midi_window.h	Sun Apr 22 15:33:50 2007 +0400
@@ -39,6 +39,8 @@ enum _midi_window_columns
   INDEX_COLUMN,
   CHANNEL_COLUMN,
   PARAM_COLUMN,
+  MINVALUE_COLUMN,
+  MAXVALUE_COLUMN,
   MIDI_CONTROL_POINTER,
   N_COLUMNS
 };
diff -r 3a35024cb149 src/plugin_slot.c
--- a/src/plugin_slot.c	Sun Apr 22 15:32:13 2007 +0400
+++ b/src/plugin_slot.c	Sun Apr 22 16:44:44 2007 +0400
@@ -471,6 +471,8 @@ plugin_slot_new     (jack_rack_t * jack_
         
         midi_control_set_midi_channel (new_midi_ctrl, midi_ctrl->midi_channel);
         midi_control_set_midi_param   (new_midi_ctrl, midi_ctrl->midi_param);
+        midi_control_set_min_value    (new_midi_ctrl, midi_ctrl->min);
+        midi_control_set_max_value    (new_midi_ctrl, midi_ctrl->max);
         
         plugin_slot_add_midi_control (plugin_slot, new_midi_ctrl);
         
