Initial commit
[fillmore] / src / fillmore / ProjectProperties.vala
1 /* Copyright 2009-2010 Yorba Foundation
2  *
3  * This software is licensed under the GNU Lesser General Public License
4  * (version 2.1 or later).  See the COPYING file in this distribution. 
5  */
6
7 public class ProjectProperties : Gtk.Dialog {
8     const int NUMBER_OF_SAMPLES = 4;
9     const long G_USEC_PER_SEC = 1000000;
10
11     TimeVal[] tap_time = new TimeVal[NUMBER_OF_SAMPLES];
12     int tap_index = 0;
13     bool sample_full = false;
14     Gtk.Adjustment tempo_adjustment;
15     Gtk.Adjustment volume_adjustment;
16     Gtk.ComboBox timesignature_combo;
17     Gtk.ToggleButton click_during_play;
18     Gtk.ToggleButton click_during_record;
19
20     public void setup(Model.Project project, Gtk.Builder builder) {
21         tempo_adjustment = (Gtk.Adjustment) builder.get_object("tempo_adjustment");
22         volume_adjustment = (Gtk.Adjustment) builder.get_object("volume_adjustment");
23         timesignature_combo = (Gtk.ComboBox) builder.get_object("timesignature_combo");
24         click_during_play = (Gtk.ToggleButton) builder.get_object("playback");
25         click_during_record = (Gtk.ToggleButton) builder.get_object("record");
26         set_tempo(project.get_bpm());
27         set_volume(project.click_volume);
28         set_during_play(project.click_during_play);
29         set_during_record(project.click_during_record);
30         set_time_signature(project.get_time_signature());
31     }
32
33     public void set_tempo(int tempo) {
34         tempo_adjustment.set_value(tempo);
35     }
36
37     public int get_tempo() {
38         return (int) tempo_adjustment.get_value();
39     }
40
41     public void set_volume(double volume) {
42         volume_adjustment.set_value(volume);
43     }
44
45     public double get_click_volume() {
46         return volume_adjustment.get_value();
47     }
48
49     public Fraction get_time_signature() {
50         return Fraction.from_string(timesignature_combo.get_active_text());
51     }
52
53     void set_time_signature(Fraction time_signature) {
54         string sig = time_signature.to_string();
55
56         Gtk.TreeIter iter;
57         if (timesignature_combo.model.get_iter_first(out iter)) {
58             do {
59                 string s;
60                 timesignature_combo.model.get(iter, 0, out s, -1);
61                 if (s == sig) {
62                     timesignature_combo.set_active_iter(iter);
63                     return;
64                 }
65             } while (timesignature_combo.model.iter_next(ref iter));
66         }
67     }
68
69     void set_during_play(bool active) {
70         click_during_play.active = active;
71     }
72
73     public bool during_play() {
74         return click_during_play.active;
75     }
76
77     void set_during_record(bool active) {
78         click_during_record.active = active;
79     }
80
81     public bool during_record() {
82         return click_during_record.active;
83     }
84
85     public void on_tap() {
86         TimeVal time_val = TimeVal();
87         time_val.get_current_time();
88         tap_time[tap_index] = time_val;
89         ++tap_index;
90         if (tap_index == NUMBER_OF_SAMPLES) {
91             sample_full = true;
92             tap_index = 0;
93         }
94         calculate_bpm();
95     }
96
97     void calculate_bpm() {
98         int number_of_samples = sample_full ? NUMBER_OF_SAMPLES : tap_index;
99         if (number_of_samples < 2) {
100             return;
101         }
102
103         int start_index = sample_full ? tap_index : 0;
104
105         double delta_sum = 0;
106         for (int i = 0; i < number_of_samples - 1; ++i) {
107             int current_index = (i + start_index) % NUMBER_OF_SAMPLES;
108             int next_index = (current_index + 1) % NUMBER_OF_SAMPLES;
109             long difference = 
110                 (tap_time[next_index].tv_sec - tap_time[current_index].tv_sec) * G_USEC_PER_SEC +
111                 tap_time[next_index].tv_usec - tap_time[current_index].tv_usec;
112
113             if (difference > 5 * G_USEC_PER_SEC) {
114                 // User waited too long.  Save the time and start over
115                 tap_time[0] = tap_time[tap_index - 1];
116                 sample_full = false;
117                 tap_index = 1;
118                 return;
119             }
120             delta_sum += difference;
121         }
122         double average = delta_sum/(number_of_samples - 1)/G_USEC_PER_SEC;
123         tempo_adjustment.set_value((int)(60.0/average));
124     }
125 }