Adding first code drop
[demorecorder] / src / SettingsStructures.vala
diff --git a/src/SettingsStructures.vala b/src/SettingsStructures.vala
new file mode 100644 (file)
index 0000000..1b67831
--- /dev/null
@@ -0,0 +1,1283 @@
+/*  Demo Recorder for MAEMO 5
+*   Copyright (C) 2010 Dru Moore <usr@dru-id.co.uk>
+*   This program is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License version 2,
+*   or (at your option) any later version, as published by the Free
+*   Software Foundation
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details
+*
+*   You should have received a copy of the GNU General Public
+*   License along with this program; if not, write to the
+*   Free Software Foundation, Inc.,
+*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+namespace IdWorks {
+  
+  namespace SettingsStructures {
+
+  public struct VolumeSettings {
+    public double volume;
+    public bool mute;
+    
+    public VolumeSettings() {
+      this.volume = 1.0;
+      this.mute = false;
+    }
+    public VolumeSettings.with_values(double volume, bool mute) {
+      this.volume = volume;
+      this.mute = mute;
+    }
+    public string to_xml_string() {
+      return ("<VolumeSettings>\n" +
+             "<volume type=\"double\">%02f</volume>\n" +
+             "<mute type=\"bool\">%s</mute>\n" +
+             "</VolumeSettings>\n").printf(
+                 volume
+               , mute.to_string()
+             );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // VolumeSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("VolumeSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // VolumeSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "bool":
+              switch(node_name) {
+                case "mute":
+                  this.mute = iter->get_content().to_bool();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "double":
+              switch(node_name) {
+                case "volume":
+                  this.volume = iter->get_content().to_double();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+
+  public struct PanoramaSettings {
+    public double panorama;
+    
+    public PanoramaSettings() {
+      this.panorama = 0.0;
+    }
+    public PanoramaSettings.with_values(double panorama) {
+      this.panorama = panorama;
+    }
+    public string to_xml_string() {
+      return ("<PanoramaSettings>\n" +
+              "<panorama type=\"double\">%02f</panorama>\n" +
+              "</PanoramaSettings>\n").printf(
+                panorama
+              );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // PanoramaSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("PanoramaSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // PanoramaSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "double":
+              switch(node_name) {
+                case "panorama":
+                  this.panorama = iter->get_content().to_double();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+
+  public struct DynamicsSettings {
+    public bool active;
+    public string mode;
+    public string characteristics;
+    public double ratio;
+    public double threshold;
+    
+    public DynamicsSettings() {
+      this.active = false;
+      this.mode = "compressor";
+      this.characteristics = "soft-knee";
+      this.ratio = 1.0;
+      this.threshold = 1.0;
+    }
+    public DynamicsSettings.with_values(bool active, string mode, string characteristics, double ratio, double threshold) {
+      this.active = false;
+      this.mode = mode;
+      this.characteristics = characteristics;
+      this.ratio = ratio;
+      this.threshold = threshold;
+    }
+    public string to_xml_string() {
+      return ("<DynamicsSettings>\n" +
+              "<active type=\"bool\">%s</active>\n" +
+              "<mode type=\"string\"><![CDATA[%s]]></mode>\n" +
+              "<characteristics type=\"string\"><![CDATA[%s]]></characteristics>\n" +
+              "<ratio type=\"double\">%02f</ratio>\n" +
+              "<threshold type=\"double\">%02f</threshold>\n" +
+              "</DynamicsSettings>\n").printf(
+                active.to_string(),
+                mode,
+                characteristics,
+                ratio,
+                threshold
+              );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // DynamicsSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("DynamicsSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "bool":
+              switch(node_name) {
+                case "active":
+                  this.active = iter->get_content().to_bool();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "double":
+              switch(node_name) {
+                case "ratio":
+                  this.ratio = iter->get_content().to_double();
+                  break;
+                case "threshold":
+                  this.threshold = iter->get_content().to_double();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "string":
+              switch(node_name) {
+                case "mode":
+                  this.mode = iter->get_content();
+                  break;
+                case "characteristics":
+                  this.characteristics = iter->get_content();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+
+  public struct EchoSettings {
+    public bool active;
+    public uint64 max_delay;
+    public uint64 delay;
+    public double feedback;
+    public double intensity;
+    
+    public EchoSettings() {
+      this.active = false;
+      this.max_delay = 1 * Time.Nanoseconds.SECOND;
+      this.delay = 0;
+      this.feedback = 0;
+      this.intensity = 0;
+    }
+    public EchoSettings.with_values(bool active, uint64 max_delay, uint64 delay, double feedback, double intensity) {
+      this.active = active;
+      this.max_delay = max_delay;
+      this.delay = delay;
+      this.feedback = feedback;
+      this.intensity = intensity;
+    }
+    public string to_xml_string() {
+      return ("<EchoSettings>\n" +
+              "<active type=\"bool\">%s</active>\n" +
+              "<max_delay type=\"uint64\">%llu</max_delay>\n" +
+              "<delay type=\"uint64\">%llu</delay>\n" +
+              "<feedback type=\"double\">%02f</feedback>\n" +
+              "<intensity type=\"double\">%02f</intensity>\n" +
+              "</EchoSettings>\n").printf(
+                active.to_string(),
+                max_delay,
+                delay,
+                feedback,
+                intensity
+                );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // EchoSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("EchoSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // EchoSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "bool":
+              switch(node_name) {
+                case "active":
+                  this.active = iter->get_content().to_bool();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "double":
+              switch(node_name) {
+                case "feedback":
+                  this.feedback = iter->get_content().to_double();
+                  break;
+                case "intensity":
+                  this.intensity = iter->get_content().to_double();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "uint64":
+              switch(node_name) {
+                case "max_delay":
+                  this.max_delay = iter->get_content().to_uint64();
+                  break;
+                case "delay":
+                  this.delay = iter->get_content().to_uint64();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+  
+  public struct EqualizerSettings {
+    public bool active;
+    public double[] bands;
+    public string name;
+    
+    public EqualizerSettings() {
+      this.active = true;
+      this.name = "";
+      this.bands = new double[] {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
+    }
+    public EqualizerSettings.with_name(string val) {
+      this.active = true;
+      this.name = val;
+      this.bands = new double[] {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
+    }
+    public EqualizerSettings.with_values(string name, double[] bands) {
+      this.active = true;
+      this.name = name;
+      this.bands = bands;
+    }
+    public string to_xml_string() {
+      return ("<EqualizerSettings>\n" +
+              "<active type=\"bool\">%s></active>\n" +
+              "<name type=\"string\"><![CDATA[%s]]></name>\n" +
+              "<band_0 type=\"double\">>%02f</band_0>\n" +
+              "<band_1 type=\"double\">>%02f</band_1>\n" +
+              "<band_2 type=\"double\">>%02f</band_2>\n" +
+              "<band_3 type=\"double\">>%02f</band_3>\n" +
+              "<band_4 type=\"double\">>%02f</band_4>\n" +
+              "<band_5 type=\"double\">>%02f</band_5>\n" +
+              "<band_6 type=\"double\">>%02f</band_6>\n" +
+              "<band_7 type=\"double\">>%02f</band_7>\n" +
+              "<band_8 type=\"double\">>%02f</band_8>\n" +
+              "<band_9 type=\"double\">>%02f</band_9>\n" +
+              "</EqualizerSettings>\n").printf(
+                active.to_string(),
+                name,
+                bands[0],
+                bands[1],
+                bands[2],
+                bands[3],
+                bands[4],
+                bands[5],
+                bands[6],
+                bands[7],
+                bands[8],
+                bands[9]
+              );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("EqualizerSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "bool":
+              switch(node_name) {
+                case "active":
+                  this.active = iter->get_content().to_bool();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "double":
+              switch(node_name) {
+                case "band_0":
+                  this.bands[0] = iter->get_content().to_double();
+                  break;
+                case "band_1":
+                  this.bands[1]= iter->get_content().to_double();
+                  break;
+                case "band_2":
+                  this.bands[2] = iter->get_content().to_double();
+                  break;
+                case "band_3":
+                  this.bands[3] = iter->get_content().to_double();
+                  break;
+                case "band_4":
+                  this.bands[4] = iter->get_content().to_double();
+                  break;
+                case "band_5":
+                  this.bands[5] = iter->get_content().to_double();
+                  break;
+                case "band_6":
+                  this.bands[6] = iter->get_content().to_double();
+                  break;
+                case "band_7":
+                  this.bands[7] = iter->get_content().to_double();
+                  break;
+                case "band_8":
+                  this.bands[8] = iter->get_content().to_double();
+                  break;
+                case "band_9":
+                  this.bands[9] = iter->get_content().to_double();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "string":
+              switch(node_name) {
+                case "name":
+                  this.name = iter->get_content();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+    
+    public string to_string() {
+      return "%s: bands:{%02f %02f %02f %02f %02f %02f %02f %02f %02f %02f}\n".printf(
+      name
+      , bands[0]
+      , bands[1]
+      , bands[2]
+      , bands[3]
+      , bands[4]
+      , bands[5]
+      , bands[6]
+      , bands[7]
+      , bands[8]
+      , bands[9]);
+    }
+    
+    public string serialize_to_string() {
+      return "EqualizerPreset:%s,%02f,%02f,%02f,%02f,%02f,%02f,%02f,%02f,%02f,%02f\n".printf(
+      name.replace(",", "\\,")
+      , bands[0]
+      , bands[1]
+      , bands[2]
+      , bands[3]
+      , bands[4]
+      , bands[5]
+      , bands[6]
+      , bands[7]
+      , bands[8]
+      , bands[9]);
+    }
+    
+    public bool deserialize_from_string(string data) {
+      bool good = false;
+      // call parser to build an array of string of parts
+      string[] values = CdlParser.ParseLine(data);
+      // check length of array
+      if (13 == values.length) {
+        // parse parts into this
+        name = values[0];
+        for (int i = 0; i < 10; ++i) {
+          bands[i] = values[i + 1].to_double();
+        }
+        good = true;
+      }
+      return good;
+    }
+  }
+
+  public struct RecordingSettings {
+    public string source;
+    public double pregain;
+    public double volume;
+    public DynamicsSettings dynamics;
+    
+    public RecordingSettings() {
+      this.source = "microphone";
+      this.pregain = 1.0;
+      this.volume = 1.0;
+      this.dynamics = DynamicsSettings();
+    }
+    public RecordingSettings.with_values(string source, double pregain, double volume, DynamicsSettings dynamics) {
+      this.source = source;
+      this.pregain = pregain;
+      this.volume = volume;
+      this.dynamics = dynamics;
+    }
+    public string to_xml_string() {
+      return ("<RecordingSettings>\n" +
+              "<source type=\"string\"><![CDATA[%s]]></source>\n" +
+              "<pregain type=\"double\">%02f</pregain>\n" +
+              "<volume type=\"double\">%02f</volume>\n" +
+              "<dynamics type=\"DynamicsSettings\">\n%s</dynamics>\n" +
+              "</RecordingSettings>\n").printf(
+                source,
+                pregain,
+                volume,
+                dynamics.to_xml_string()
+              );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // RecordingSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("RecordingSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // RecordingSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "string":
+              switch(node_name) {
+                case "source":
+                  this.source = iter->get_content();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "double":
+              switch(node_name) {
+                case "pregain":
+                  this.pregain = iter->get_content().to_double();
+                  break;
+                case "volume":
+                  this.volume = iter->get_content().to_double();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "DynamicsSettings":
+              switch(node_name) {
+                case "dynamics":
+                  this.dynamics.from_xml_node_helper(iter);
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+  
+  public struct MonitorSettings {
+    public bool output_audio;
+    public RecordingSettings input;
+    
+    public MonitorSettings() {
+      this.output_audio = false;
+      this.input = RecordingSettings();
+    }
+    public MonitorSettings.with_values(bool output_audio, RecordingSettings input) {
+      this.output_audio = output_audio;
+      this.input = input;
+    }
+    public string to_xml_string() {
+      return ("<MonitorSettings>\n" +
+              "<output_audio type=\"bool\">%s</output_audio>\n" +
+              "<input type=\"RecordingSettings\">\n%s</input>\n" +
+              "</MonitorSettings>\n").printf(
+                output_audio.to_string(),
+                input.to_xml_string()
+              );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // MonitorSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("MonitorSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // MonitorSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "bool":
+              switch(node_name) {
+                case "output_audio":
+                  this.output_audio = iter->get_content().to_bool();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "RecordingSettings":
+              switch(node_name) {
+                case "input":
+                  this.input.from_xml_node_helper(iter);
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+
+  public struct TrackSettings {
+    public bool active;
+    public string uri;
+    public string name;
+    public string notes;
+    public VolumeSettings volume;
+    public PanoramaSettings panorama;
+    public DynamicsSettings dynamics;
+    public EchoSettings echo;
+    public EqualizerSettings equalizer;
+    
+    public TrackSettings() {
+      this.active = false;
+      this.uri = "";
+      this.name = "Unnamed";
+      this.notes = "";
+      this.volume = VolumeSettings();
+      this.panorama = PanoramaSettings();
+      this.dynamics = DynamicsSettings();
+      this.echo = EchoSettings();
+      this.equalizer = EqualizerSettings();
+    }
+    public TrackSettings.with_values(string uri, string name, string notes, bool active, VolumeSettings volume, PanoramaSettings panorama, DynamicsSettings dynamics, EchoSettings echo, EqualizerSettings equalizer) {
+      this.active = active;
+      this.uri = uri;
+      this.name = name;
+      this.notes = notes;
+      this.volume = volume;
+      this.panorama = panorama;
+      this.dynamics = dynamics;
+      this.echo = echo;
+      this.equalizer = equalizer;
+    }
+    public string to_xml_string() {
+      return ("<TrackSettings>\n" +
+              "<active type=\"bool\">%s</active>\n" +
+              "<uri type=\"string\"><![CDATA[%s]]></uri>\n" +
+              "<name type=\"string\"><![CDATA[%s]]></name>\n" +
+              "<notes type=\"string\"><![CDATA[%s]]></notes>\n" +
+              "<volume type=\"VolumeSettings\">\n%s</volume>\n" +
+              "<panorama type=\"PanoramaSettings\">\n%s</panorama>\n" +
+              "<dynamics type=\"DynamicsSettings\">\n%s</dynamics>\n" +
+              "<echo type=\"EchoSettings\">\n%s</echo>\n" +
+              "<equalizer type=\"EqualizerSettings\">\n%s</equalizer>\n" +
+              "</TrackSettings>\n").printf(
+                active.to_string(),
+                uri,
+                name,
+                notes,
+                volume.to_xml_string(),
+                panorama.to_xml_string(),
+                dynamics.to_xml_string(),
+                echo.to_xml_string(),
+                equalizer.to_xml_string()
+              );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // TrackSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("TrackSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // TrackSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "string":
+              switch(node_name) {
+                case "name":
+                  this.name = iter->get_content();
+                  break;
+                case "uri":
+                  this.uri = iter->get_content();
+                  break;
+                case "notes":
+                  this.notes = iter->get_content();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "bool":
+              switch(node_name) {
+                case "active":
+                  this.active = iter->get_content().to_bool();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "VolumeSettings":
+              switch(node_name) {
+                case "volume":
+                  this.volume.from_xml_node_helper(iter);
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "PanoramaSettings":
+              switch(node_name) {
+                case "panorama":
+                  this.panorama.from_xml_node_helper(iter);
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "DynamicsSettings":
+              switch(node_name) {
+                case "dynamics":
+                  this.dynamics.from_xml_node_helper(iter);
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "EchoSettings":
+              switch(node_name) {
+                case "echo":
+                  this.echo.from_xml_node_helper(iter);
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "EqualizerSettings":
+              switch(node_name) {
+                case "equalizer":
+                  this.equalizer.from_xml_node_helper(iter);
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+
+  public struct MixerSettings {
+    public VolumeSettings volume;
+    public PanoramaSettings panorama;
+    public EqualizerSettings equalizer;
+    
+    public MixerSettings() {
+      this.volume = VolumeSettings();
+      this.panorama = PanoramaSettings();
+      this.equalizer = EqualizerSettings();
+    }
+    public MixerSettings.with_values(VolumeSettings volume, PanoramaSettings panorama, EqualizerSettings equalizer) {
+      this.volume = volume;
+      this.panorama = panorama;
+      this.equalizer = equalizer;
+    }
+    public string to_xml_string() {
+      return ("<MixerSettings>\n" +
+              "<volume type=\"VolumeSettings\">\n%s</volume>\n" +
+              "<panorama type=\"PanoramaSettings\">\n%s</panorama>\n" +
+              "<equalizer type=\"EqualizerSettings\">\n%s</equalizer>\n" +
+              "</MixerSettings>\n").printf(
+                volume.to_xml_string(),
+                panorama.to_xml_string(),
+                equalizer.to_xml_string()
+              );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // MixerSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("MixerSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // MixerSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+              case "VolumeSettings":
+                switch(node_name) {
+                  case "volume":
+                    this.volume.from_xml_node_helper(iter);
+                    break;
+                  default:
+                    break;
+                }
+                break;
+              case "PanoramaSettings":
+                switch(node_name) {
+                  case "panorama":
+                    this.panorama.from_xml_node_helper(iter);
+                    break;
+                  default:
+                    break;
+                }
+                break;
+              case "EqualizerSettings":
+                switch(node_name) {
+                  case "equalizer":
+                    this.equalizer.from_xml_node_helper(iter);
+                    break;
+                  default:
+                    break;
+                }
+                break;
+              default:
+                continue;
+          }
+        }
+        
+      }
+    }
+  }
+  
+  public struct MixdownSettings {
+    public string encoder;
+    public string quality;
+    public string location;
+    public string artist;
+    public string title;
+    public string album;
+    public unowned List<Tagging.Tag?> tags;
+    
+    public MixdownSettings() {
+      this.encoder = "vorbisenc";
+      this.quality = "high";
+      this.location = "";
+      this.artist = "Unknown Artist";
+      this.title = "Untitled";
+      this.album = "Untitled";
+      this.tags = null;
+    }
+    public MixdownSettings.with_values(string encoder, string quality, string location, string artist, string title, string album, List<Tagging.Tag?> tags) {
+      this.encoder = encoder;
+      this.quality = quality;
+      this.location = location;
+      this.artist = artist;
+      this.title = title;
+      this.album = album;
+      this.tags = tags;
+    }
+    public string to_xml_string() {
+      return ("<MixdownSettings>\n" +
+              "<encoder type=\"string\"><![CDATA[%s]]></encoder>\n" +
+              "<quality type=\"string\"><![CDATA[%s]]></quality>\n" +
+              "<location type=\"string\"><![CDATA[%s]]></location>\n" +
+              "<artist type=\"string\"><![CDATA[%s]]></artist>\n" +
+              "<title type=\"string\"><![CDATA[%s]]></title>\n" +
+              "<album type=\"string\"><![CDATA[%s]]></album>\n" +
+              "<tags type=\"TagList\">\n%s</tags>\n" +
+              "</MixdownSettings>\n").printf(
+                encoder,
+                quality,
+                location,
+                artist,
+                title,
+                album,
+                Tagging.Tag.taglist_to_xml_string(tags)
+              );
+    }
+    public void from_xml_node_helper(Xml.Node* node) {
+      // MixdownSettings is below root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        if ("MixdownSettings" == iter->name) {
+          from_xml_node(iter);
+          break;
+        }
+      }
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // MixdownSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "string":
+              switch(node_name) {
+                case "encoder":
+                  this.encoder = iter->get_content();
+                  break;
+                case "quality":
+                  this.quality = iter->get_content();
+                  break;
+                case "location":
+                  this.location = iter->get_content();
+                  break;
+                case "artist":
+                  this.artist = iter->get_content();
+                  break;
+                case "title":
+                  this.title = iter->get_content();
+                  break;
+                case "album":
+                  this.album = iter->get_content();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "TagList":
+              switch(node_name) {
+                case "tags":
+                  Tagging.Tag.taglist_from_xml_node_helper(iter, ref this.tags);
+                  break;
+                default:
+                  break;
+              }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+
+  public struct ProjectSettings {
+    public string location;
+    public string name;
+    public string working_directory;
+    public int last_track_number;
+    public MonitorSettings monitor;
+    public MixerSettings mixer;
+    public MixdownSettings mixdown;
+    public unowned List<Track?> tracks;
+    
+    public ProjectSettings() {
+      this.name = "New Project";
+      this.location = "";
+      this.working_directory = "";
+      this.last_track_number = 0;
+      this.monitor = MonitorSettings();
+      this.mixer = MixerSettings();
+      this.mixdown = MixdownSettings();
+      this.tracks = null;
+    }
+    public ProjectSettings.with_values(string name, string location, string working_directory, int last_track_number, MonitorSettings monitor, MixerSettings mixer, MixdownSettings mixdown, List<Track?> tracks) {
+      this.name = name;
+      this.location = location;
+      this.working_directory = working_directory;
+      this.last_track_number = last_track_number;
+      this.monitor = monitor;
+      this.mixer = mixer;
+      this.mixdown = mixdown;
+      this.tracks = tracks;
+    }
+    public string to_xml_string() {
+      return ("<ProjectSettings version=\"1.0\">\n" +
+              "<name type=\"string\"><![CDATA[%s]]></name>\n" +
+              "<location type=\"string\"><![CDATA[%s]]></location>\n" +
+              "<working_directory type=\"string\"><![CDATA[%s]]></working_directory>\n" +
+              "<last_track_number type=\"int\">%i</last_track_number>\n" +
+              "<monitor type=\"MonitorSettings\">\n%s</monitor>\n" +
+              "<mixer type=\"MixerSettings\">\n%s</mixer>\n" +
+              "<mixdown type=\"MixdownSettings\">\n%s</mixdown>\n" +
+              "<tracks type=\"TrackList\">\n%s</tracks>\n" +
+              "</ProjectSettings>\n").printf(
+                name,
+                location,
+                working_directory,
+                last_track_number,
+                monitor.to_xml_string(),
+                mixer.to_xml_string(),
+                mixdown.to_xml_string(),
+                Track.tracklist_to_xml_string(tracks)
+              );
+    }
+    public void from_xml_node(Xml.Node* node) {
+      // ProjectSettings is root
+      // Loop over the passed node's children
+      for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+        // Spaces between tags are also nodes, discard them
+        if (iter->type != Xml.ElementType.ELEMENT_NODE) {
+          continue;
+        }
+        // Get the node's name
+        string node_name = iter->name;
+        // Get the nodes type
+        string? type = XmlHelpers.get_node_attribute(iter, "type");
+        // Get the node's content with <tags> stripped
+        if (null != type) {
+          // check the type
+          switch(type) {
+            case "string":
+              switch(node_name) {
+                case "name":
+                  this.name = iter->get_content();
+                  break;
+                case "location":
+                  this.location = iter->get_content();
+                  break;
+                case "working_directory":
+                  this.working_directory = iter->get_content();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "int":
+              switch(node_name) {
+                case "last_track_number":
+                  this.last_track_number = iter->get_content().to_int();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case "bool":
+              switch(node_name) {
+                default:
+                  break;
+              }
+              break;
+            case "double":
+              switch(node_name) {
+                default:
+                  break;
+              }
+              break;
+            case "uint64":
+              switch(node_name) {
+                default:
+                  break;
+              }
+              break;
+            case "MonitorSettings":
+              switch(node_name) {
+                case "monitor":
+                    this.monitor.from_xml_node_helper(iter);
+                    break;
+                  default:
+                    break;
+                }
+              break;
+            case "MixerSettings":
+                switch(node_name) {
+                  case "mixer":
+                    this.mixer.from_xml_node_helper(iter);
+                    break;
+                  default:
+                    break;
+                }
+              break;
+            case "MixdownSettings":
+                switch(node_name) {
+                  case "mixdown":
+                    this.mixdown.from_xml_node_helper(iter);
+                    break;
+                  default:
+                    break;
+                }
+              break;
+            case "TrackList":
+                switch(node_name) {
+                  case "tracks":
+                    Track.tracklist_from_xml_node_helper(iter, ref this.tracks);
+                    break;
+                  default:
+                    break;
+                }
+              break;
+            default:
+              continue;
+          }
+        }
+        
+      }
+    }
+  }
+
+  }
+
+}
\ No newline at end of file