1 /* Copyright 2009-2010 Yorba Foundation
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.
10 public interface TimeSystem : Object {
11 public signal void geometry_changed();
12 public abstract void calculate_pixel_step(float inc, float pixel_min, float pixel_div);
13 public abstract int64 xpos_to_time(int x);
14 public abstract int64 xsize_to_time(int x);
15 public abstract int time_to_xpos(int64 time);
16 public abstract int64 get_pixel_snap_time();
17 public abstract int time_to_xsize(int64 time);
18 public abstract float get_pixel_percentage();
19 public abstract int get_start_token(int xsize);
20 public abstract int get_next_position(int token);
21 public abstract int get_pixel_height(int token);
22 public abstract string? get_display_string(int token);
23 public abstract int frame_to_xsize(int frame);
24 public abstract int xsize_to_frame(int xsize);
25 public abstract string get_time_string(int64 time);
26 public abstract string get_time_duration(int64 time);
29 public abstract class TimeSystemBase : Object {
30 public const int PIXEL_SNAP_INTERVAL = 10;
32 public float pixel_percentage = 0.0f;
33 public float pixels_per_second;
34 public int64 pixel_snap_time;
36 const int BORDER = 4; // TODO: should use same value as timeline. will happen when this gets
37 // refactored back into view code.
39 abstract int[] get_timeline_seconds();
40 abstract int correct_sub_second_value(float seconds, int div, int fps);
42 protected int correct_seconds_value (float seconds, int div, int fps) {
44 return correct_sub_second_value(seconds, div, fps);
48 int secs = (int) seconds;
49 int [] timeline_seconds = get_timeline_seconds();
50 for (i = timeline_seconds.length - 1; i > 0; i--) {
51 if (secs <= timeline_seconds[i] &&
52 secs >= timeline_seconds[i - 1]) {
53 if ((div % (timeline_seconds[i] * fps)) == 0) {
56 if ((div % (timeline_seconds[i - 1] * fps)) == 0) {
62 return timeline_seconds[i] * fps;
65 public int64 get_pixel_snap_time() {
66 return pixel_snap_time;
69 public float get_pixel_percentage() {
70 return pixel_percentage;
73 public int64 xpos_to_time(int x) {
74 return xsize_to_time(x - BORDER);
77 public int64 xsize_to_time(int size) {
78 return (int64) ((float)(size * Gst.SECOND) / pixels_per_second);
81 public int time_to_xsize(int64 time) {
82 return (int) (time * pixels_per_second / Gst.SECOND);
85 public int time_to_xpos(int64 time) {
86 int pos = time_to_xsize(time) + BORDER;
88 if (xpos_to_time(pos) != time)
94 public class TimecodeTimeSystem : TimeSystem, TimeSystemBase {
95 float pixels_per_frame;
97 int small_pixel_frames = 0;
98 int medium_pixel_frames = 0;
99 int large_pixel_frames = 0;
101 public Fraction frame_rate_fraction = Fraction(30000, 1001);
103 override int correct_sub_second_value(float seconds, int div, int fps) {
104 int frames = (int)(fps * seconds);
113 int mod = div % frames;
115 mod = div % (++frames);
120 public string get_time_string(int64 the_time) {
123 int frame = time_to_frame_with_rate(the_time, frame_rate_fraction);
124 time = frame_to_string(frame, frame_rate_fraction);
129 public string get_time_duration(int64 the_time) {
130 // Timecode is already zero-based
131 return get_time_string(the_time);
133 public void calculate_pixel_step(float inc, float pixel_min, float pixel_div) {
134 int pixels_per_large = 300;
135 int pixels_per_medium = 50;
136 int pixels_per_small = 20;
138 pixel_percentage += inc;
139 if (pixel_percentage < 0.0f)
140 pixel_percentage = 0.0f;
141 else if (pixel_percentage > 1.0f)
142 pixel_percentage = 1.0f;
144 pixels_per_second = pixel_min * GLib.Math.powf(pixel_div, pixel_percentage);
145 int fps = frame_rate_fraction.nearest_int();
146 large_pixel_frames = correct_seconds_value(pixels_per_large / pixels_per_second, 0, fps);
147 medium_pixel_frames = correct_seconds_value(pixels_per_medium / pixels_per_second,
148 large_pixel_frames, fps);
149 small_pixel_frames = correct_seconds_value(pixels_per_small / pixels_per_second,
150 medium_pixel_frames, fps);
152 if (small_pixel_frames == medium_pixel_frames) {
153 int i = medium_pixel_frames;
156 if ((medium_pixel_frames % i) == 0) {
157 small_pixel_frames = i;
163 pixels_per_frame = pixels_per_second / (float) fps;
164 pixel_snap_time = xsize_to_time(PIXEL_SNAP_INTERVAL);
167 public int frame_to_xsize(int frame) {
168 return ((int) (frame * pixels_per_frame));
171 public int xsize_to_frame(int xsize) {
172 return (int) (xsize / pixels_per_frame);
175 public int get_start_token(int xsize) {
176 int start_frame = xsize_to_frame(xsize);
177 return large_pixel_frames * (start_frame / large_pixel_frames);
180 public int get_next_position(int token) {
181 return token + small_pixel_frames;
184 public string? get_display_string(int frame) {
185 if ((frame % large_pixel_frames) == 0) {
186 return frame_to_time(frame, frame_rate_fraction).to_string();
191 public int get_pixel_height(int frame) {
192 if ((frame % medium_pixel_frames) == 0) {
193 if (medium_pixel_frames == small_pixel_frames &&
194 (medium_pixel_frames != large_pixel_frames &&
195 frame % large_pixel_frames != 0)) {
206 override int[] get_timeline_seconds() {
207 return { 1, 2, 5, 10, 15, 20, 30, 60, 120, 300, 600, 900, 1200, 1800, 3600 };
211 public interface TempoInformation {
212 public abstract Fraction get_time_signature();
213 public abstract int get_bpm();
214 public signal void time_signature_changed(Fraction time_signature);
215 public signal void bpm_changed(int bpm);
218 public class BarBeatTimeSystem : TimeSystem, TimeSystemBase {
219 float pixels_per_sixteenth;
221 int small_pixel_sixteenth = 0;
222 int medium_pixel_sixteenth = 0;
223 int large_pixel_sixteenth = 0;
224 int[] timeline_bars = {
225 1, 2, 4, 8, 16, 24, 32, 64, 128, 256, 512, 768, 1024, 2048, 3192
229 Fraction time_signature;
230 float bars_per_minute;
231 float bars_per_second;
232 int sixteenths_per_bar;
233 int sixteenths_per_beat;
235 public BarBeatTimeSystem(TempoInformation tempo_information) {
236 bpm = tempo_information.get_bpm();
237 time_signature = tempo_information.get_time_signature();
238 tempo_information.bpm_changed.connect(on_bpm_changed);
239 tempo_information.time_signature_changed.connect(on_time_signature_changed);
243 void on_time_signature_changed(Fraction time_signature) {
244 emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_time_signature_changed");
245 this.time_signature = time_signature;
249 void on_bpm_changed(int bpm) {
250 emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_bpm_changed");
255 void set_constants() {
256 bars_per_minute = bpm / (float)time_signature.numerator;
257 bars_per_second = bars_per_minute / 60.0f;
259 sixteenths_per_beat = 16 / time_signature.denominator;
260 sixteenths_per_bar = time_signature.numerator * sixteenths_per_beat;
264 override int correct_sub_second_value(float bars, int div, int unused) {
265 int sixteenths = (int)(sixteenths_per_bar * bars);
267 if (sixteenths == 0) {
271 if (sixteenths > sixteenths_per_beat) {
272 return sixteenths_per_beat;
275 if (sixteenths > 2) {
282 string beats_to_string(int total_sixteenths, bool maximum_resolution, bool zero_based) {
283 int number_of_measures =
284 (total_sixteenths / sixteenths_per_beat) / time_signature.numerator;
286 int number_of_beats =
287 (total_sixteenths / sixteenths_per_beat) % time_signature.numerator;
288 int number_of_sixteenths = total_sixteenths % sixteenths_per_beat;
290 ++number_of_measures;
292 ++number_of_sixteenths;
294 float pixels_per_bar = pixels_per_second / bars_per_second;
295 float pixels_per_large_gap = large_pixel_sixteenth * pixels_per_sixteenth;
296 if (maximum_resolution ||
297 ((pixels_per_large_gap < pixels_per_sixteenth * sixteenths_per_beat) &&
298 number_of_sixteenths > 1)) {
299 return "%d.%d.%d".printf(number_of_measures, number_of_beats, number_of_sixteenths);
300 } else if (pixels_per_large_gap < pixels_per_bar && number_of_beats > 1) {
301 return "%d.%d".printf(number_of_measures, number_of_beats);
303 return "%d".printf(number_of_measures);
307 public string get_time_string(int64 the_time) {
308 double beats_per_second = bpm / 60.0;
309 double sixteenths_per_second = sixteenths_per_beat * beats_per_second;
310 double sixteenths_per_nanosecond = sixteenths_per_second / Gst.SECOND;
311 int total_beats = (int)(the_time * sixteenths_per_nanosecond);
312 return beats_to_string(total_beats, true, false);
315 public string get_time_duration(int64 the_time) {
316 double beats_per_second = bpm / 60.0;
317 double sixteenths_per_second = sixteenths_per_beat * beats_per_second;
318 double sixteenths_per_nanosecond = sixteenths_per_second / Gst.SECOND;
319 int total_beats = (int)(the_time * sixteenths_per_nanosecond);
320 if (total_beats == 0 && the_time > 0) {
324 return beats_to_string(total_beats, true, true);
327 public void calculate_pixel_step(float inc, float pixel_min, float pixel_div) {
328 int pixels_per_large = 80;
329 int pixels_per_medium = 40;
330 int pixels_per_small = 20;
332 pixel_percentage += inc;
333 if (pixel_percentage < 0.0f) {
334 pixel_percentage = 0.0f;
335 } else if (pixel_percentage > 1.0f) {
336 pixel_percentage = 1.0f;
339 pixels_per_second = pixel_min * GLib.Math.powf(pixel_div, pixel_percentage);
340 float pixels_per_bar = pixels_per_second / bars_per_second;
341 large_pixel_sixteenth = correct_seconds_value(
342 pixels_per_large / pixels_per_bar, 0, sixteenths_per_bar);
344 medium_pixel_sixteenth = correct_seconds_value(pixels_per_medium / pixels_per_bar,
345 large_pixel_sixteenth, sixteenths_per_bar);
346 small_pixel_sixteenth = correct_seconds_value(pixels_per_small / pixels_per_bar,
347 medium_pixel_sixteenth, sixteenths_per_bar);
348 if (small_pixel_sixteenth == medium_pixel_sixteenth) {
349 int i = medium_pixel_sixteenth;
352 if ((medium_pixel_sixteenth % i) == 0) {
353 small_pixel_sixteenth = i;
359 pixels_per_sixteenth = pixels_per_bar / (float) sixteenths_per_bar;
360 pixel_snap_time = xsize_to_time(PIXEL_SNAP_INTERVAL);
363 public int frame_to_xsize(int frame) {
364 return ((int) (frame * pixels_per_sixteenth));
367 public int xsize_to_frame(int xsize) {
368 return (int) (xsize / pixels_per_sixteenth);
371 public int get_start_token(int xsize) {
372 int start_frame = xsize_to_frame(xsize);
373 return large_pixel_sixteenth * (start_frame / large_pixel_sixteenth);
376 public int get_next_position(int token) {
377 return token + small_pixel_sixteenth;
380 public string? get_display_string(int frame) {
381 if ((frame % large_pixel_sixteenth) == 0) {
382 return beats_to_string(frame, false, false);
387 public int get_pixel_height(int frame) {
388 if ((frame % medium_pixel_sixteenth) == 0) {
389 if (medium_pixel_sixteenth == small_pixel_sixteenth &&
390 (medium_pixel_sixteenth != large_pixel_sixteenth &&
391 frame % large_pixel_sixteenth != 0)) {
402 override int[] get_timeline_seconds() {
403 return timeline_bars;