Initial commit
[fillmore] / src / fillmore / ProjectProperties.vala
diff --git a/src/fillmore/ProjectProperties.vala b/src/fillmore/ProjectProperties.vala
new file mode 100644 (file)
index 0000000..1caff22
--- /dev/null
@@ -0,0 +1,125 @@
+/* Copyright 2009-2010 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution. 
+ */
+
+public class ProjectProperties : Gtk.Dialog {
+    const int NUMBER_OF_SAMPLES = 4;
+    const long G_USEC_PER_SEC = 1000000;
+
+    TimeVal[] tap_time = new TimeVal[NUMBER_OF_SAMPLES];
+    int tap_index = 0;
+    bool sample_full = false;
+    Gtk.Adjustment tempo_adjustment;
+    Gtk.Adjustment volume_adjustment;
+    Gtk.ComboBox timesignature_combo;
+    Gtk.ToggleButton click_during_play;
+    Gtk.ToggleButton click_during_record;
+
+    public void setup(Model.Project project, Gtk.Builder builder) {
+        tempo_adjustment = (Gtk.Adjustment) builder.get_object("tempo_adjustment");
+        volume_adjustment = (Gtk.Adjustment) builder.get_object("volume_adjustment");
+        timesignature_combo = (Gtk.ComboBox) builder.get_object("timesignature_combo");
+        click_during_play = (Gtk.ToggleButton) builder.get_object("playback");
+        click_during_record = (Gtk.ToggleButton) builder.get_object("record");
+        set_tempo(project.get_bpm());
+        set_volume(project.click_volume);
+        set_during_play(project.click_during_play);
+        set_during_record(project.click_during_record);
+        set_time_signature(project.get_time_signature());
+    }
+
+    public void set_tempo(int tempo) {
+        tempo_adjustment.set_value(tempo);
+    }
+
+    public int get_tempo() {
+        return (int) tempo_adjustment.get_value();
+    }
+
+    public void set_volume(double volume) {
+        volume_adjustment.set_value(volume);
+    }
+
+    public double get_click_volume() {
+        return volume_adjustment.get_value();
+    }
+
+    public Fraction get_time_signature() {
+        return Fraction.from_string(timesignature_combo.get_active_text());
+    }
+
+    void set_time_signature(Fraction time_signature) {
+        string sig = time_signature.to_string();
+
+        Gtk.TreeIter iter;
+        if (timesignature_combo.model.get_iter_first(out iter)) {
+            do {
+                string s;
+                timesignature_combo.model.get(iter, 0, out s, -1);
+                if (s == sig) {
+                    timesignature_combo.set_active_iter(iter);
+                    return;
+                }
+            } while (timesignature_combo.model.iter_next(ref iter));
+        }
+    }
+
+    void set_during_play(bool active) {
+        click_during_play.active = active;
+    }
+
+    public bool during_play() {
+        return click_during_play.active;
+    }
+
+    void set_during_record(bool active) {
+        click_during_record.active = active;
+    }
+
+    public bool during_record() {
+        return click_during_record.active;
+    }
+
+    public void on_tap() {
+        TimeVal time_val = TimeVal();
+        time_val.get_current_time();
+        tap_time[tap_index] = time_val;
+        ++tap_index;
+        if (tap_index == NUMBER_OF_SAMPLES) {
+            sample_full = true;
+            tap_index = 0;
+        }
+        calculate_bpm();
+    }
+
+    void calculate_bpm() {
+        int number_of_samples = sample_full ? NUMBER_OF_SAMPLES : tap_index;
+        if (number_of_samples < 2) {
+            return;
+        }
+
+        int start_index = sample_full ? tap_index : 0;
+
+        double delta_sum = 0;
+        for (int i = 0; i < number_of_samples - 1; ++i) {
+            int current_index = (i + start_index) % NUMBER_OF_SAMPLES;
+            int next_index = (current_index + 1) % NUMBER_OF_SAMPLES;
+            long difference = 
+                (tap_time[next_index].tv_sec - tap_time[current_index].tv_sec) * G_USEC_PER_SEC +
+                tap_time[next_index].tv_usec - tap_time[current_index].tv_usec;
+
+            if (difference > 5 * G_USEC_PER_SEC) {
+                // User waited too long.  Save the time and start over
+                tap_time[0] = tap_time[tap_index - 1];
+                sample_full = false;
+                tap_index = 1;
+                return;
+            }
+            delta_sum += difference;
+        }
+        double average = delta_sum/(number_of_samples - 1)/G_USEC_PER_SEC;
+        tempo_adjustment.set_value((int)(60.0/average));
+    }
+}