[gegl] gcut: rewrite to use seconds instead of frames as native unit



commit 11579be49da1abd91261a86a5208a82707b355e7
Author: Øyvind Kolås <pippin gimp org>
Date:   Tue Jul 25 00:47:45 2017 +0200

    gcut: rewrite to use seconds instead of frames as native unit

 gcut/clip.c     |   40 +++---
 gcut/gcut-ui.c  |  401 ++++++++++++++++++++++++++++++-------------------------
 gcut/gcut.c     |  265 ++++++++++++++++++++----------------
 gcut/gcut.h     |   71 +++++-----
 gcut/renderer.c |   27 ++--
 5 files changed, 435 insertions(+), 369 deletions(-)
---
diff --git a/gcut/clip.c b/gcut/clip.c
index 4d78bd2..a876880 100644
--- a/gcut/clip.c
+++ b/gcut/clip.c
@@ -179,47 +179,47 @@ void clip_set_path (Clip *clip, const char *in_path)
   }
 }
 
-int clip_get_start (Clip *clip)
+double clip_get_start (Clip *clip)
 {
   return clip->start;
 }
 
-int clip_get_end (Clip *clip)
+double clip_get_end (Clip *clip)
 {
   return clip->end;
 }
 
-int clip_get_frames (Clip *clip)
+double clip_get_duration (Clip *clip)
 {
-  int frames = clip_get_end (clip) - clip_get_start (clip) + 1;
-  if (frames < 0) frames = 0;
+  double duration = clip_get_end (clip) - clip_get_start (clip) + 1;
+  if (duration < 0) duration = 0;
   if (clip->is_meta)
     return 0;
-  return frames;
+  return duration;
 }
 
-void clip_set_start (Clip *clip, int start)
+void clip_set_start (Clip *clip, double start)
 {
   clip->start = start;
 }
-void clip_set_end (Clip *clip, int end)
+void clip_set_end (Clip *clip, double end)
 {
   clip->end = end;
 }
 
-void clip_set_range (Clip *clip, int start, int end)
+void clip_set_range (Clip *clip, double start, double end)
 {
   clip_set_start (clip, start);
   clip_set_end (clip, end);
 }
 
-void clip_set_full (Clip *clip, const char *path, int start, int end)
+void clip_set_full (Clip *clip, const char *path, double start, double end)
 {
   clip_set_path (clip, path);
   clip_set_range (clip, start, end);
 }
 
-Clip *clip_new_full (GeglEDL *edl, const char *path, int start, int end)
+Clip *clip_new_full (GeglEDL *edl, const char *path, double start, double end)
 {
   Clip *clip = clip_new (edl);
   clip_set_full (clip, path, start, end);
@@ -397,18 +397,18 @@ static void clip_rig_chain (Clip *clip, int clip_frame_no)
   g_mutex_unlock (&clip->mutex);
 }
 
-void clip_render_frame (Clip *clip, int clip_frame_no)
+void clip_render_pos (Clip *clip, double clip_frame_pos)
 {
-      clip_rig_chain (clip, clip_frame_no);
-      g_mutex_lock (&clip->mutex);
-      gegl_node_process (clip->loader); // for the audio fetch
-      clip_fetch_audio (clip);
+  clip_rig_chain (clip, clip_frame_pos);
+  g_mutex_lock (&clip->mutex);
+  gegl_node_process (clip->loader); // for the audio fetch
+  clip_fetch_audio (clip);
 
-      g_mutex_unlock (&clip->mutex);
+  g_mutex_unlock (&clip->mutex);
 }
 
 
-gchar *clip_get_frame_hash (Clip *clip, int clip_frame_no)
+gchar *clip_get_pos_hash (Clip *clip, double clip_frame_pos)
 {
   GeglEDL *edl = clip->edl;
   gchar *frame_recipe;
@@ -416,10 +416,10 @@ gchar *clip_get_frame_hash (Clip *clip, int clip_frame_no)
   GChecksum *hash;
   int is_static_source = clip_is_static_source (clip);
 
-  frame_recipe = g_strdup_printf ("%s: %s %i %s %ix%i",
+  frame_recipe = g_strdup_printf ("%s: %s %.3f %s %ix%i",
       "gcut-pre-4",
       clip_get_path (clip),
-      clip->filter_graph || (!is_static_source) ? clip_frame_no : 0,
+      clip->filter_graph || (!is_static_source) ? clip_frame_pos : 0.0,
       clip->filter_graph,
       edl->video_width,
       edl->video_height);
diff --git a/gcut/gcut-ui.c b/gcut/gcut-ui.c
index 40e4670..7001921 100644
--- a/gcut/gcut-ui.c
+++ b/gcut/gcut-ui.c
@@ -6,6 +6,7 @@
 #include <string.h>
 #include <signal.h>
 #include <stdio.h>
+#include <math.h>
 #include <mrg.h>
 #include <gegl.h>
 #include "gcut.h"
@@ -165,17 +166,17 @@ static void insert_string (GeglEDL *edl, const char *string)
 #endif
 
 static void insert_clip (GeglEDL *edl, const char *path,
-                         int in, int out)
+                         double in, double out)
 {
   GList *iter;
   Clip *clip, *cur_clip;
-  int end_frame = edl->frame_no;
-  int clip_frame_no;
+  double end_pos = edl->frame_pos_ui;
+  double clip_frame_pos;
   if (in < 0)
     in = 0;
   if (out < 0)
   {
-    int duration = 0;
+    double duration = 0;
     if (!empty_selection (edl))
     {
       out = edl->selection_end - edl->selection_start;
@@ -183,7 +184,7 @@ static void insert_clip (GeglEDL *edl, const char *path,
     }
     else
     {
-      gcut_get_video_info (path, &duration, NULL);
+      gcut_get_video_info (path, NULL, &duration, NULL);
       out = duration;
     }
     if (out < in)
@@ -191,24 +192,24 @@ static void insert_clip (GeglEDL *edl, const char *path,
   }
   clip = clip_new_full (edl, path, in, out);
   clip->title = g_strdup (basename (path));
-  cur_clip = gcut_get_clip (edl, edl->frame_no, &clip_frame_no);
+  cur_clip = gcut_get_clip (edl, edl->frame_pos_ui, &clip_frame_pos);
 
   if (empty_selection (edl))
   {
     gcut_get_duration (edl);
-    if (edl->frame_no != cur_clip->abs_start)
+    if (fabs (edl->frame_pos_ui - cur_clip->abs_start) < 0.001)
     {
       gcut_get_duration (edl);
-      clip_split (cur_clip, clip_frame_no);
-      cur_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+      clip_split (cur_clip, clip_frame_pos);
+      cur_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
     }
   }
   else
   {
     Clip *last_clip;
-    int sin, sout;
-    int cur_clip_frame_no;
-    int last_clip_frame_no;
+    double sin, sout;
+    double cur_clip_frame_pos;
+    double last_clip_frame_pos;
 
     sin = edl->selection_start;
     sout = edl->selection_end + 1;
@@ -217,33 +218,33 @@ static void insert_clip (GeglEDL *edl, const char *path,
       sout = edl->selection_start + 1;
       sin = edl->selection_end;
     }
-    cur_clip = gcut_get_clip (edl, sin, &cur_clip_frame_no);
-    clip_split (cur_clip, cur_clip_frame_no);
+    cur_clip = gcut_get_clip (edl, sin, &cur_clip_frame_pos);
+    clip_split (cur_clip, cur_clip_frame_pos);
     gcut_get_duration (edl);
-    cur_clip = gcut_get_clip (edl, sin, &cur_clip_frame_no);
-    last_clip = gcut_get_clip (edl, sout, &last_clip_frame_no);
+    cur_clip = gcut_get_clip (edl, sin, &cur_clip_frame_pos);
+    last_clip = gcut_get_clip (edl, sout, &last_clip_frame_pos);
     if (cur_clip == last_clip)
     {
-      clip_split (last_clip, last_clip_frame_no);
+      clip_split (last_clip, last_clip_frame_pos);
     }
-    last_clip = edl_get_clip_for_frame (edl, sout);
+    last_clip = edl_get_clip_for_pos (edl, sout);
 
-    cur_clip = edl_get_clip_for_frame (edl, sin);
+    cur_clip = edl_get_clip_for_pos (edl, sin);
     while (cur_clip != last_clip)
     {
       clip_remove (cur_clip);
-      cur_clip = edl_get_clip_for_frame (edl, sin);
+      cur_clip = edl_get_clip_for_pos (edl, sin);
     }
-    edl->frame_no = sin;
+    edl->frame_pos_ui = sin;
   }
 
-  cur_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+  cur_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
   iter = g_list_find (edl->clips, cur_clip);
   edl->clips = g_list_insert_before (edl->clips, iter, clip);
-  end_frame += out - in + 1;
-  edl->frame_no = end_frame;
+  end_pos += out - in + 1;
+  edl->frame_pos_ui = end_pos;
 
-  edl->active_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+  edl->active_clip = edl_get_clip_for_pos (edl, end_pos);
 
   gcut_make_proxies (edl);
 }
@@ -276,9 +277,9 @@ static void clicked_clip (MrgEvent *e, void *data1, void *data2)
   Clip *clip = data1;
   GeglEDL *edl = data2;
 
-  edl->frame_no = e->x;
-  edl->selection_start = edl->frame_no;
-  edl->selection_end = edl->frame_no;
+  edl->frame_pos_ui = e->x;
+  edl->selection_start = edl->frame_pos_ui;
+  edl->selection_end = edl->frame_pos_ui;
   edl->active_clip = clip;
   edl->playing = 0;
   scroll_to_fit (edl, e->mrg);
@@ -291,7 +292,7 @@ static void clicked_clip (MrgEvent *e, void *data1, void *data2)
 static void drag_clip (MrgEvent *e, void *data1, void *data2)
 {
   GeglEDL *edl = data2;
-  edl->frame_no = e->x;
+  edl->frame_pos_ui = e->x;
   if (e->x >= edl->selection_start)
   {
     edl->selection_end = e->x;
@@ -329,7 +330,7 @@ static void released_clip (MrgEvent *e, void *data1, void *data2)
 {
   Clip *clip = data1;
   GeglEDL *edl = data2;
-  edl->frame_no = e->x;
+  edl->frame_pos_ui = e->x;
   edl->active_clip = clip;
   if (edl->selection_end < edl->selection_start)
   {
@@ -379,14 +380,14 @@ static void prev_cut (MrgEvent *event, void *data1, void *data2)
 
     if (iter)
     {
-       if (edl->frame_no == edl->active_clip->abs_start)
+       if (fabs (edl->frame_pos_ui - edl->active_clip->abs_start) < 0.001)
        {
          iter = iter->prev;
          if (iter) edl->active_clip = iter->data;
        }
     }
-    edl->frame_no = edl->active_clip->abs_start;
-    edl->selection_start = edl->selection_end = edl->frame_no;
+    edl->frame_pos_ui = edl->active_clip->abs_start;
+    edl->selection_start = edl->selection_end = edl->frame_pos_ui;
   }
   mrg_event_stop_propagate (event);
   scroll_to_fit (edl, event->mrg);
@@ -405,16 +406,16 @@ static void next_cut (MrgEvent *event, void *data1, void *data2)
     if (iter)
     {
       edl->active_clip = iter->data;
-      edl->frame_no = edl->active_clip->abs_start;
+      edl->frame_pos_ui = edl->active_clip->abs_start;
     }
     else
     {
-      edl->frame_no = edl->active_clip->abs_start + clip_get_frames (edl->active_clip);
+      edl->frame_pos_ui = edl->active_clip->abs_start + clip_get_duration (edl->active_clip);
     }
   }
   mrg_event_stop_propagate (event);
   mrg_queue_draw (event->mrg, NULL);
-  edl->selection_start = edl->selection_end = edl->frame_no;
+  edl->selection_start = edl->selection_end = edl->frame_pos_ui;
   scroll_to_fit (edl, event->mrg);
   changed++;
 }
@@ -422,12 +423,12 @@ static void next_cut (MrgEvent *event, void *data1, void *data2)
 static void extend_selection_to_previous_cut (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
-  int sel_start, sel_end;
-  edl->active_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+  double sel_start, sel_end;
+  edl->active_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
 
   gcut_get_selection (edl, &sel_start, &sel_end);
   prev_cut (event, data1, data2);
-  sel_start = edl->frame_no;
+  sel_start = edl->frame_pos_ui;
   gcut_set_selection (edl, sel_start, sel_end);
 
   mrg_event_stop_propagate (event);
@@ -439,11 +440,11 @@ static void extend_selection_to_previous_cut (MrgEvent *event, void *data1, void
 static void extend_selection_to_next_cut (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
-  int sel_start, sel_end;
+  double sel_start, sel_end;
 
   gcut_get_selection (edl, &sel_start, &sel_end);
   next_cut (event, data1, data2);
-  sel_start = edl->frame_no;
+  sel_start = edl->frame_pos_ui;
   gcut_set_selection (edl, sel_start, sel_end);
 
   mrg_event_stop_propagate (event);
@@ -451,27 +452,35 @@ static void extend_selection_to_next_cut (MrgEvent *event, void *data1, void *da
   changed++;
 }
 
+static inline int float_eq(double a, double b)
+{
+  if (fabs(a-b) < 0.0001)
+    return 1;
+  return 0;
+}
+
 static void extend_selection_to_the_left (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
-  int sel_start, sel_end;
+  double sel_start, sel_end;
+  double fragment = 1.0 / edl->fps;
 
   gcut_get_selection (edl, &sel_start, &sel_end);
-  if (edl->frame_no == sel_end)
+  if (float_eq (edl->frame_pos_ui, sel_end))
   {
-    sel_end --;
-    edl->frame_no --;
+    sel_end -= fragment;
+    edl->frame_pos_ui -= fragment;
   }
-  else if (edl->frame_no == sel_start)
+  else if (float_eq (edl->frame_pos_ui, sel_start))
   {
-    sel_start --;
-    edl->frame_no --;
+    sel_start -= fragment;
+    edl->frame_pos_ui -= fragment;
   }
   else
   {
-    sel_start = sel_end = edl->frame_no;
-    sel_end --;
-    edl->frame_no --;
+    sel_start = sel_end = edl->frame_pos_ui;
+    sel_end -= fragment;
+    edl->frame_pos_ui -= fragment;
   }
   gcut_set_selection (edl, sel_start, sel_end);
 
@@ -484,24 +493,26 @@ static void extend_selection_to_the_left (MrgEvent *event, void *data1, void *da
 static void extend_selection_to_the_right (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
-  int sel_start, sel_end;
+  gdouble sel_start, sel_end;
+
+  double fragment = 1.0 / edl->fps;
 
   gcut_get_selection (edl, &sel_start, &sel_end);
-  if (edl->frame_no == sel_end)
+  if (float_eq (edl->frame_pos_ui, sel_end))
   {
-    sel_end ++;
-    edl->frame_no ++;
+    sel_end += fragment;
+    edl->frame_pos_ui += fragment;
   }
-  else if (edl->frame_no == sel_start)
+  else if (float_eq (edl->frame_pos_ui, sel_start))
   {
-    sel_start ++;
-    edl->frame_no ++;
+    sel_start += fragment;
+    edl->frame_pos_ui += fragment;
   }
   else
   {
-    sel_start = sel_end = edl->frame_no;
-    sel_end ++;
-    edl->frame_no ++;
+    sel_start = sel_end = edl->frame_pos_ui;
+    sel_end += fragment;
+    edl->frame_pos_ui += fragment;
   }
   gcut_set_selection (edl, sel_start, sel_end);
 
@@ -511,17 +522,22 @@ static void extend_selection_to_the_right (MrgEvent *event, void *data1, void *d
 }
 
 static int ui_tweaks = 0;
-static int are_mergable (Clip *clip1, Clip *clip2, int delta)
+static int are_mergable (Clip *clip1, Clip *clip2, double delta)
 {
+  GeglEDL *edl;
+  double fragment;
   if (!clip1 || !clip2)
     return 0;
+  edl = clip1->edl;
+  fragment = 1.0 / edl->fps;
+
   if (!clip1->path)
     return 0;
   if (!clip2->path)
     return 0;
   if (strcmp (clip1->path, clip2->path))
     return 0;
-  if (clip2->start != (clip1->end + 1 + delta))
+  if (!float_eq (clip2->start, (clip1->end + fragment + delta)))
     return 0;
   if (clip1->filter_graph==NULL && clip2->filter_graph != NULL)
     return 0;
@@ -545,7 +561,7 @@ static void clip_remove (Clip *clip)
     return;
 
   edl->clips = g_list_remove (edl->clips, clip);
-  edl->active_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+  edl->active_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
 }
 
 static GeglNode *selected_node = NULL;
@@ -753,8 +769,8 @@ static void clip_split (Clip *oldclip, int shift)
 static void split_clip (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
-  int clip_frame_no = 0;
-  Clip *clip = gcut_get_clip (edl, edl->frame_no, &clip_frame_no);
+  double clip_frame_pos = 0;
+  Clip *clip = gcut_get_clip (edl, edl->frame_pos_ui, &clip_frame_pos);
   if (!edl->active_clip)
     return;
 
@@ -764,7 +780,7 @@ static void split_clip (MrgEvent *event, void *data1, void *data2)
     return;
   }
 
-  clip_split (edl->active_clip, clip_frame_no);
+  clip_split (edl->active_clip, clip_frame_pos);
   {
     //edl->active_clip = clip;
   }
@@ -853,7 +869,7 @@ static gboolean save_idle (Mrg *mrg, gpointer edl)
 static void set_range (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
-  int start, end;
+  double start, end;
 
   gcut_get_selection (edl, &start, &end);
   gcut_set_range (edl, start, end);
@@ -968,13 +984,14 @@ static void down (MrgEvent *event, void *data1, void *data2)
 static void step_frame_back (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
+  double fragment = 1.0 / edl->fps;
   stop_playing (event, data1, data2);
   {
     edl->selection_start = edl->selection_end;
-    edl->frame_no --;
-    if (edl->frame_no < 0)
-      edl->frame_no = 0;
-    edl->active_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+    edl->frame_pos_ui -= fragment;
+    if (edl->frame_pos_ui < 0)
+      edl->frame_pos_ui = 0;
+    edl->active_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
   }
   mrg_event_stop_propagate (event);
   mrg_queue_draw (event->mrg, NULL);
@@ -984,11 +1001,12 @@ static void step_frame_back (MrgEvent *event, void *data1, void *data2)
 static void step_frame (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
+  double fragment = 1.0 / edl->fps;
   stop_playing (event, data1, data2);
   {
     edl->selection_start = edl->selection_end;
-    edl->frame_no ++;
-    edl->active_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+    edl->frame_pos_ui += fragment;
+    edl->active_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
   }
   mrg_event_stop_propagate (event);
   mrg_queue_draw (event->mrg, NULL);
@@ -999,21 +1017,23 @@ static void clip_end_start_dec (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
   Clip *clip1, *clip2;
+  double fragment = 1.0 / edl->fps;
   if (edl->selection_start < edl->selection_end)
   {
-    clip1 = edl_get_clip_for_frame (edl, edl->selection_start);
-    clip2 = edl_get_clip_for_frame (edl, edl->selection_end);
+    clip1 = edl_get_clip_for_pos (edl, edl->selection_start);
+    clip2 = edl_get_clip_for_pos (edl, edl->selection_end);
   }
   else
   {
-    clip1 = edl_get_clip_for_frame (edl, edl->selection_end);
-    clip2 = edl_get_clip_for_frame (edl, edl->selection_start);
+    clip1 = edl_get_clip_for_pos (edl, edl->selection_end);
+    clip2 = edl_get_clip_for_pos (edl, edl->selection_start);
   }
-  edl->selection_start--;
-  edl->selection_end--;
-  clip1->end--;
-  clip2->start--;
-  edl->frame_no--;
+  edl->selection_start-= fragment;
+  edl->selection_end-= fragment;
+  clip1->end-= fragment;
+  clip2->start-= fragment;
+  edl->frame_pos_ui -= fragment;
+
   gcut_cache_invalid (edl);
   mrg_event_stop_propagate (event);
   mrg_queue_draw (event->mrg, NULL);
@@ -1023,21 +1043,23 @@ static void clip_end_start_inc (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
   Clip *clip1, *clip2;
+  double fragment = 1.0 / edl->fps;
+
   if (edl->selection_start < edl->selection_end)
   {
-    clip1 = edl_get_clip_for_frame (edl, edl->selection_start);
-    clip2 = edl_get_clip_for_frame (edl, edl->selection_end);
+    clip1 = edl_get_clip_for_pos (edl, edl->selection_start);
+    clip2 = edl_get_clip_for_pos (edl, edl->selection_end);
   }
   else
   {
-    clip1 = edl_get_clip_for_frame (edl, edl->selection_end);
-    clip2 = edl_get_clip_for_frame (edl, edl->selection_start);
+    clip1 = edl_get_clip_for_pos (edl, edl->selection_end);
+    clip2 = edl_get_clip_for_pos (edl, edl->selection_start);
   }
-  edl->selection_start++;
-  edl->selection_end++;
-  clip1->end++;
-  clip2->start++;
-  edl->frame_no++;
+  edl->selection_start+=fragment;
+  edl->selection_end+=fragment;
+  clip1->end+=fragment;
+  clip2->start+=fragment;
+  edl->frame_pos_ui +=fragment;
 
   gcut_cache_invalid (edl);
   mrg_event_stop_propagate (event);
@@ -1073,10 +1095,12 @@ static void clip_start_end_dec (MrgEvent *event, void *data1, void *data2)
 static void clip_end_inc (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
+  double fragment = 1.0 / edl->fps;
+
   if (edl->active_clip)
     {
-      edl->active_clip->end++;
-      edl->frame_no++;
+      edl->active_clip->end+=fragment;
+      edl->frame_pos_ui +=fragment;
     }
   gcut_cache_invalid (edl);
   mrg_event_stop_propagate (event);
@@ -1086,10 +1110,12 @@ static void clip_end_inc (MrgEvent *event, void *data1, void *data2)
 static void clip_end_dec (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
+  double fragment = 1.0 / edl->fps;
+
   if (edl->active_clip)
     {
-      edl->active_clip->end--;
-      edl->frame_no--;
+      edl->active_clip->end-=fragment;
+      edl->frame_pos_ui -=fragment;
       gcut_cache_invalid (edl);
     }
   mrg_event_stop_propagate (event);
@@ -1100,9 +1126,10 @@ static void clip_end_dec (MrgEvent *event, void *data1, void *data2)
 static void clip_start_inc (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
+  double fragment = 1.0 / edl->fps;
   if (edl->active_clip)
     {
-      edl->active_clip->start++;
+      edl->active_clip->start+= fragment;
       gcut_cache_invalid (edl);
     }
   mrg_event_stop_propagate (event);
@@ -1112,9 +1139,10 @@ static void clip_start_inc (MrgEvent *event, void *data1, void *data2)
 static void clip_start_dec (MrgEvent *event, void *data1, void *data2)
 {
   GeglEDL *edl = data1;
+  double fragment = 1.0 / edl->fps;
   if (edl->active_clip)
     {
-      edl->active_clip->start--;
+      edl->active_clip->start-=fragment;
       gcut_cache_invalid (edl);
     }
   mrg_event_stop_propagate (event);
@@ -1234,10 +1262,10 @@ static void render_clip (Mrg *mrg, GeglEDL *edl, const char *clip_path, int clip
 static void scroll_to_fit (GeglEDL *edl, Mrg *mrg)
 {
   /* scroll to fit playhead */
-  if ( (edl->frame_no - edl->t0) / edl->scale > mrg_width (mrg) * 0.9)
-    edl->t0 = edl->frame_no - (mrg_width (mrg) * 0.8) * edl->scale;
-  else if ( (edl->frame_no - edl->t0) / edl->scale < mrg_width (mrg) * 0.1)
-    edl->t0 = edl->frame_no - (mrg_width (mrg) * 0.2) * edl->scale;
+  if ( (edl->frame_pos_ui - edl->t0) / edl->scale > mrg_width (mrg) * 0.9)
+    edl->t0 = edl->frame_pos_ui - (mrg_width (mrg) * 0.8) * edl->scale;
+  else if ( (edl->frame_pos_ui - edl->t0) / edl->scale < mrg_width (mrg) * 0.1)
+    edl->t0 = edl->frame_pos_ui - (mrg_width (mrg) * 0.2) * edl->scale;
 }
 
 static void shuffle_forward (MrgEvent *event, void *data1, void *data2)
@@ -1266,7 +1294,7 @@ static void shuffle_forward (MrgEvent *event, void *data1, void *data2)
       self->next = nextnext;
       if (self->next)
         self->next->prev = self;
-      edl->frame_no += clip_get_frames (next->data);
+      edl->frame_pos_ui += clip_get_duration (next->data);
     }
   }
 
@@ -1304,7 +1332,7 @@ static void shuffle_back (MrgEvent *event, void *data1, void *data2)
       if (next)
         next->prev = prev;
 
-      edl->frame_no -= clip_get_frames (prev->data);
+      edl->frame_pos_ui -= clip_get_duration (prev->data);
     }
   }
 
@@ -1320,7 +1348,7 @@ static void slide_forward (MrgEvent *event, void *data1, void *data2)
   GList *prev = NULL,
         *next = NULL, *self;
   
-  edl->active_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+  edl->active_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
   self = g_list_find (edl->clips, edl->active_clip);
 
   gcut_cache_invalid (edl);
@@ -1335,6 +1363,7 @@ static void slide_forward (MrgEvent *event, void *data1, void *data2)
 
   if (self)
   {
+    double fragment = 1.0 / edl->fps;
     next = self->next;
     prev = self->prev;
 
@@ -1346,44 +1375,44 @@ static void slide_forward (MrgEvent *event, void *data1, void *data2)
 
       if (are_mergable (prev_clip, next_clip, 0))
       {
-        if (clip_get_frames (next_clip) == 1)
+        if (float_eq (clip_get_duration (next_clip), fragment))
         {
-          prev_clip->end++;
+          prev_clip->end+=fragment;
           edl->clips = g_list_remove (edl->clips, next_clip);
-          edl->frame_no ++;
+          edl->frame_pos_ui += fragment;
         }
         else
         {
-          prev_clip->end ++;
-          next_clip->start ++;
-          edl->frame_no ++;
+          prev_clip->end += fragment;
+          next_clip->start += fragment;
+          edl->frame_pos_ui += fragment;
         }
-      } else if (are_mergable (prev_clip, next_clip, clip_get_frames (self_clip)))
+      } else if (are_mergable (prev_clip, next_clip, clip_get_duration (self_clip)))
       {
-        if (clip_get_frames (next_clip) == 1)
+        if (float_eq (clip_get_duration (next_clip), fragment))
         {
-          prev_clip->end++;
+          prev_clip->end += fragment;
           edl->clips = g_list_remove (edl->clips, next_clip);
-          edl->frame_no ++;
+          edl->frame_pos_ui += fragment;
         }
         else
         {
-          prev_clip->end ++;
-          next_clip->start ++;
-          edl->frame_no ++;
+          prev_clip->end += fragment;
+          next_clip->start += fragment;
+          edl->frame_pos_ui += fragment;
         }
       }
       else {
-        if (clip_get_frames (next_clip) == 1)
+        if (float_eq (clip_get_duration (next_clip), fragment))
         {
-          int frame_no = edl->frame_no + 1;
+          double frame_pos = edl->frame_pos_ui + fragment;
           shuffle_forward (event, data1, data2);
-          edl->frame_no = frame_no;
+          edl->frame_pos_ui = frame_pos;
         } else {
-          int frame_no = edl->frame_no + 1;
-          clip_split (next_clip, next_clip->start + 1);
+          double frame_pos = edl->frame_pos_ui + fragment;
+          clip_split (next_clip, next_clip->start + fragment);
           shuffle_forward (event, data1, data2);
-          edl->frame_no = frame_no;
+          edl->frame_pos_ui = frame_pos;
         }
       }
     }
@@ -1402,7 +1431,7 @@ static void slide_back (MrgEvent *event, void *data1, void *data2)
         *next = NULL,
         *self;
 
-  edl->active_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+  edl->active_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
   self = g_list_find (edl->clips, edl->active_clip);
 
   gcut_cache_invalid (edl);
@@ -1417,6 +1446,7 @@ static void slide_back (MrgEvent *event, void *data1, void *data2)
 
   if (self)
   {
+    double fragment = 1.0 / edl->fps;
     next = self->next;
     prev = self->prev;
 
@@ -1428,45 +1458,45 @@ static void slide_back (MrgEvent *event, void *data1, void *data2)
 
       if (are_mergable (prev_clip, next_clip, 0))
       {
-        if (clip_get_frames (prev_clip) == 1)
+        if (float_eq (clip_get_duration (prev_clip), fragment))
         {
-          next_clip->start --;
+          next_clip->start -= fragment;
           edl->clips = g_list_remove (edl->clips, prev_clip);
-          edl->frame_no --;
+          edl->frame_pos_ui -= fragment;
         }
         else
         {
-          prev_clip->end --;
-          next_clip->start --;
-          edl->frame_no --;
+          prev_clip->end -= fragment;
+          next_clip->start -= fragment;
+          edl->frame_pos_ui -= fragment;
         }
-      } else if (are_mergable (prev_clip, next_clip, clip_get_frames (self_clip)))
+      } else if (are_mergable (prev_clip, next_clip, clip_get_duration (self_clip)))
       {
-        if (clip_get_frames (prev_clip) == 1)
+        if (float_eq (clip_get_duration (prev_clip), fragment))
         {
-          prev_clip->end--;
+          prev_clip->end-= fragment;
           edl->clips = g_list_remove (edl->clips, prev_clip);
-          edl->frame_no --;
+          edl->frame_pos_ui -= fragment;
         }
         else
         {
-          prev_clip->end --;
-          next_clip->start --;
-          edl->frame_no --;
+          prev_clip->end -= fragment;
+          next_clip->start -= fragment;
+          edl->frame_pos_ui -= fragment;
         }
       }
       else
       {
-        if (clip_get_frames (prev_clip) == 1)
+        if (float_eq (clip_get_duration (prev_clip), fragment))
         {
-        int frame_no = edl->frame_no - 1;
+        double frame_pos = edl->frame_pos_ui - fragment;
         shuffle_back (event, data1, data2);
-        edl->frame_no = frame_no;
+        edl->frame_pos_ui = frame_pos;
         } else {
-        int frame_no = edl->frame_no - 1;
+        double frame_pos = edl->frame_pos_ui - fragment;
         clip_split (prev_clip, prev_clip->end );
         shuffle_back (event, data1, data2);
-        edl->frame_no = frame_no;
+        edl->frame_pos_ui = frame_pos;
         }
       }
     }
@@ -1589,7 +1619,7 @@ static void jump_to_pos (MrgEvent *e, void *data1, void *data2)
   gint pos = GPOINTER_TO_INT(data2);
 
   fprintf (stderr, "set frame %i\n", pos);
-  edl->frame_no = pos;
+  edl->frame_pos_ui = pos;
   mrg_event_stop_propagate (e);
   mrg_queue_draw (e->mrg, NULL);
 }
@@ -1700,9 +1730,9 @@ static void remove_key (MrgEvent *e, void *data1, void *data2)
     GeglPath *path = g_object_get_qdata (G_OBJECT (node), anim_quark);
     int nodes = gegl_path_get_n_nodes (path);
     int i;
-    int clip_frame_no=0;
+    double clip_frame_pos=0;
     GeglPathItem path_item;
-    gcut_get_clip (edl, edl->frame_no, &clip_frame_no);
+    gcut_get_clip (edl, edl->frame_pos_ui, &clip_frame_pos);
 
     for (i = 0; i < nodes; i ++)
     {
@@ -1775,30 +1805,31 @@ static void update_double_string (const char *new_string, void *user_data)
     GeglPath *path = g_object_get_qdata (G_OBJECT (snode), anim_quark);
     int nodes = gegl_path_get_n_nodes (path);
     int i;
-    int clip_frame_no=0;
+    double clip_frame_pos=0;
+    double fragment = 1.0 / edl->fps;
     GeglPathItem path_item;
-    gcut_get_clip (edl, edl->frame_no, &clip_frame_no);
+    gcut_get_clip (edl, edl->frame_pos_ui, &clip_frame_pos);
 
     for (i = 0; i < nodes; i ++)
     {
       gegl_path_get_node (path, i, &path_item);
-      if (fabs (path_item.point[0].x - clip_frame_no) < 0.5)
+      if (fabs (path_item.point[0].x - clip_frame_pos) < 0.5 * fragment)
       {
-        path_item.point[0].x = clip_frame_no;
+        path_item.point[0].x = clip_frame_pos;
         path_item.point[0].y = val;
         gegl_path_replace_node (path, i, &path_item);
         goto done;
       }
-      else if (path_item.point[0].x > clip_frame_no)
+      else if (path_item.point[0].x > clip_frame_pos)
       {
-        path_item.point[0].x = clip_frame_no;
+        path_item.point[0].x = clip_frame_pos;
         path_item.point[0].y = val;
         gegl_path_insert_node (path, i - 1, &path_item);
         goto done;
       }
     }
     path_item.type = 'L';
-    path_item.point[0].x = clip_frame_no;
+    path_item.point[0].x = clip_frame_pos;
     path_item.point[0].y = val;
     gegl_path_insert_node (path, -1, &path_item);
 done:
@@ -2056,8 +2087,8 @@ static float print_props (Mrg *mrg, GeglEDL *edl, GeglNode *node, float x, float
     {
        cairo_t *cr = mrg_cr (mrg);
        GeglPath *path = g_object_get_qdata (G_OBJECT (node), anim_quark);
-       int clip_frame_no;
-       gcut_get_clip (edl, edl->frame_no, &clip_frame_no);
+       double clip_frame_pos;
+       gcut_get_clip (edl, edl->frame_pos_ui, &clip_frame_pos);
        mrg_printf (mrg, "{anim}");
        {
          GeglPathItem path_item;
@@ -2066,13 +2097,13 @@ static float print_props (Mrg *mrg, GeglEDL *edl, GeglNode *node, float x, float
          for (j = 0 ; j < nodes; j ++)
          {
            gegl_path_get_node (path, j, &path_item);
-           if (fabs (path_item.point[0].x - clip_frame_no) < 0.5)
+           if (fabs (path_item.point[0].x - clip_frame_pos) < 0.5)
            {
       gpointer *data = g_new0 (gpointer, 4);
       data[0]=edl;
       data[1]=node;
       data[2]=(void*)g_intern_string(props[i]->name);
-      data[3]=GINT_TO_POINTER(clip_frame_no);
+      data[3]=GINT_TO_POINTER(clip_frame_pos);
              mrg_text_listen_full (mrg, MRG_CLICK, remove_key, data, node, (void*)g_free, NULL);
              mrg_printf (mrg, "(key)");
              mrg_text_listen_done (mrg);
@@ -2090,7 +2121,8 @@ static float print_props (Mrg *mrg, GeglEDL *edl, GeglNode *node, float x, float
                         mrg_height (mrg) * SPLIT_VER);
 
        {
-         int j;
+         double j;
+         double fragment =1.0 / edl->fps;
          gdouble y = 0.0;
          gdouble miny = 100000.0;
          gdouble maxy = -100000.0;
@@ -2098,7 +2130,7 @@ static float print_props (Mrg *mrg, GeglEDL *edl, GeglNode *node, float x, float
          // todo: draw markers for zero, min and max, with labels
          //       do all curves in one scaled space? - will break for 2 or more magnitudes diffs
 
-         for (j = -10; j < clip_get_frames (edl->active_clip) + 10; j ++)
+         for (j = -1.0; j < clip_get_duration (edl->active_clip) + 1.0; j += fragment)
          {
            gegl_path_calc_y_for_x (path, j, &y);
            if (y < miny) miny = y;
@@ -2109,7 +2141,7 @@ static float print_props (Mrg *mrg, GeglEDL *edl, GeglNode *node, float x, float
          gegl_path_calc_y_for_x (path, 0, &y);
          y = VID_HEIGHT * 0.9 - ((y - miny) / (maxy - miny)) * VID_HEIGHT * 0.8;
          cairo_move_to (cr, 0, y);
-         for (j = -10; j < clip_get_frames (edl->active_clip) + 10; j ++)
+         for (j = -1.0; j < clip_get_duration (edl->active_clip) + 1.0; j += fragment)
          {
            gegl_path_calc_y_for_x (path, j, &y);
            y = VID_HEIGHT * 0.9 - ((y - miny) / (maxy - miny)) * VID_HEIGHT * 0.8;
@@ -2653,7 +2685,7 @@ static void update_ui_clip (Clip *clip, int clip_frame_no)
 
     if (clip->is_chain)
       gegl_create_chain (clip->path, source_start, source_end,
-                         clip->edl->frame_no - clip->abs_start,
+                         clip->edl->frame_pos_ui - clip->abs_start,
                          1.0, NULL, &error);
 
     filter_start = gegl_node_new ();
@@ -2666,7 +2698,7 @@ static void update_ui_clip (Clip *clip, int clip_frame_no)
     if (clip->filter_graph)
     {
       gegl_create_chain (clip->filter_graph, filter_start, filter_end,
-                         clip->edl->frame_no - clip->abs_start,
+                         clip->edl->frame_pos_ui - clip->abs_start,
                          1.0, NULL, &error);
     }
     ui_clip = clip;
@@ -2751,7 +2783,7 @@ static void gcut_draw (Mrg     *mrg,
   GList *l;
   cairo_t *cr = mrg_cr (mrg);
   double t;
-  int clip_frame_no;
+  double clip_frame_pos;
   int scroll_height = mrg_height (mrg) * (1.0 - SPLIT_VER) * 0.2;
   int duration = gcut_get_duration (edl); // causes update of abs_start
   float y2 = y - mrg_em (mrg) * 1.5;
@@ -2763,13 +2795,13 @@ static void gcut_draw (Mrg     *mrg,
     return;
 
 
-  edl->active_clip = gcut_get_clip (edl, edl->frame_no, &clip_frame_no);
+  edl->active_clip = gcut_get_clip (edl, edl->frame_pos_ui, &clip_frame_pos);
 
   if (edl->active_clip) // && edl->active_clip->filter_graph)
   {
     Clip *clip = edl->active_clip;
 
-    update_ui_clip (clip, clip_frame_no);
+    update_ui_clip (clip, clip_frame_pos);
 
     mrg_set_style (mrg, "font-size: 2.5%; background-color: #0000; color: #ffff");
 
@@ -2823,14 +2855,14 @@ static void gcut_draw (Mrg     *mrg,
   for (l = edl->clips; l; l = l->next)
   {
     Clip *clip = l->data;
-    int frames = clip_get_frames (clip);
-    cairo_rectangle (cr, t, y, frames, scroll_height);
+    double duration = clip_get_duration (clip);
+    cairo_rectangle (cr, t, y, duration, scroll_height);
     cairo_stroke (cr);
-    t += frames;
+    t += duration;
   }
 
   {
-  int start = 0, end = 0;
+  double start = 0, end = 0;
   gcut_get_range (edl, &start, &end);
   cairo_rectangle (cr, start, y, end - start, scroll_height);
   cairo_set_source_rgba (cr, 0, 0.11, 0.0, 0.5);
@@ -2839,11 +2871,12 @@ static void gcut_draw (Mrg     *mrg,
   cairo_stroke (cr);
 
   {
-    double frame = edl->frame_no;
+    double pos = edl->frame_pos_ui;
+    double fragment = 1.0 / edl->fps;
     if (fpx < 1.0)
-      cairo_rectangle (cr, frame, y-5, 1.0, 5 + scroll_height);
+      cairo_rectangle (cr, pos, y-5, fragment, 5 + scroll_height);
     else
-      cairo_rectangle (cr, frame, y-5, fpx, 5 + scroll_height);
+      cairo_rectangle (cr, pos, y-5, fpx, 5 + scroll_height);
     cairo_set_source_rgba (cr,1,0,0,0.85);
     cairo_fill (cr);
   }
@@ -2872,7 +2905,7 @@ static void gcut_draw (Mrg     *mrg,
   for (l = edl->clips; l; l = l->next)
   {
     Clip *clip = l->data;
-    int frames = clip_get_frames (clip);
+    double duration = clip_get_duration (clip);
     if (clip->is_meta)
     {
       double tx = t, ty = y;
@@ -2886,7 +2919,7 @@ static void gcut_draw (Mrg     *mrg,
     else
     {
       Clip *next = clip_get_next (clip);
-      render_clip (mrg, edl, clip->path, clip->start, frames, t, y, clip->fade, next?next->fade:0);
+      render_clip (mrg, edl, clip->path, clip->start, duration, t, y, clip->fade, next?next->fade:0);
       /* .. check if we are having anim things going on.. if so - print it here  */
     }
 
@@ -2900,7 +2933,7 @@ static void gcut_draw (Mrg     *mrg,
     mrg_listen (mrg, MRG_RELEASE, released_clip, clip, edl);
     cairo_stroke (cr);
 
-    t += frames;
+    t += duration;
   }
 
   if (!edl->playing){
@@ -2957,11 +2990,12 @@ static void gcut_draw (Mrg     *mrg,
   }
 
   {
-  double frame = edl->frame_no;
+  double pos = edl->frame_pos_ui;
+  double fragment = 1.0 / edl->fps;
   if (fpx < 1.0)
-    cairo_rectangle (cr, frame, y-PAD_DIM, 1.0, VID_HEIGHT + PAD_DIM * 2);
+    cairo_rectangle (cr, pos, y-PAD_DIM, fragment, VID_HEIGHT + PAD_DIM * 2);
   else
-    cairo_rectangle (cr, frame, y-PAD_DIM, fpx, VID_HEIGHT + PAD_DIM * 2);
+    cairo_rectangle (cr, pos, y-PAD_DIM, fpx, VID_HEIGHT + PAD_DIM * 2);
   cairo_set_source_rgba (cr,1,0,0,1);
   cairo_fill (cr);
   cairo_restore (cr);
@@ -3051,6 +3085,7 @@ void gcut_ui (Mrg *mrg, void *data)
 {
   State *o = data;
   GeglEDL *edl = o->edl;
+  gdouble fragment = 1.0 / edl->fps;
 
   int long start_time = babl_ticks ();
 
@@ -3139,7 +3174,7 @@ void gcut_ui (Mrg *mrg, void *data)
     mrg_printf (mrg, "frame %i (%i shown)",edl->frame_no, done_frame);
   else
 #endif
-  mrg_printf (mrg, " %i  ", edl->frame_no);
+  mrg_printf (mrg, " %f  ", edl->frame_pos_ui);
 
 #if 0
   if (edl->active_source)
@@ -3173,7 +3208,7 @@ void gcut_ui (Mrg *mrg, void *data)
     if (edl->playing)
     {
       mrg_add_binding (mrg, "space", NULL, "pause", renderer_toggle_playing, edl);
-      if (edl->active_clip && edl->frame_no != edl->active_clip->abs_start)
+      if (edl->active_clip && !float_eq (edl->frame_pos_ui, edl->active_clip->abs_start))
         mrg_add_binding (mrg, "v", NULL, "split clip", split_clip, edl);
     }
     else
@@ -3220,7 +3255,7 @@ void gcut_ui (Mrg *mrg, void *data)
 
         if (edl->active_clip)
         {
-          if (edl->frame_no == edl->active_clip->abs_start)
+          if (float_eq (edl->frame_pos_ui, edl->active_clip->abs_start))
           {
             GList *iter = g_list_find (edl->clips, edl->active_clip);
             Clip *clip2 = NULL;
@@ -3250,7 +3285,7 @@ void gcut_ui (Mrg *mrg, void *data)
       {
         mrg_add_binding (mrg, "i", NULL, "insert filter", insert_filter, edl);
 
-        if (edl->frame_no == edl->active_clip->abs_start)
+        if (float_eq (edl->frame_pos_ui, edl->active_clip->abs_start))
         {
 
           if (empty_selection (edl))
@@ -3271,7 +3306,7 @@ void gcut_ui (Mrg *mrg, void *data)
         {
           if (empty_selection (edl))
           {
-            if (edl->frame_no == edl->active_clip->abs_start + clip_get_frames (edl->active_clip)-1)
+            if (float_eq (edl->frame_pos_ui, edl->active_clip->abs_start + clip_get_duration 
(edl->active_clip)-fragment))
             {
               mrg_add_binding (mrg, "control-left/right", NULL, "adjust out", clip_end_inc, edl);
               mrg_add_binding (mrg, "control-right", NULL, NULL, clip_end_inc, edl);
diff --git a/gcut/gcut.c b/gcut/gcut.c
index ca8a5f1..eea0ac7 100644
--- a/gcut/gcut.c
+++ b/gcut/gcut.c
@@ -1,6 +1,7 @@
 #include "config.h"
 #include <string.h>
 #include <signal.h>
+#include <math.h>
 #include <unistd.h>
 #include <ctype.h>
 #include <stdio.h>
@@ -129,8 +130,9 @@ GeglEDL *gcut_new           (void)
   edl->audio_bitrate    = DEFAULT_audio_bitrate;
   edl->audio_samplerate = DEFAULT_audio_samplerate;
   edl->framedrop        = DEFAULT_framedrop;
-  edl->frame_no         = 0;  /* frame-no in ui shell */
-  edl->frame = -1;            /* frame-no in renderer thread */
+  edl->frame_pos_ui     = 0.0;  /* frame-no in ui shell */
+  edl->frame = -1;              /* frame-no in renderer thread */
+  edl->pos  = -1.0;             /* frame-no in renderer thread */
   edl->scale = 1.0;
 
   edl->buffer = gegl_buffer_new (&roi, babl_format ("R'G'B'A u8"));
@@ -176,26 +178,26 @@ void     gcut_free          (GeglEDL *edl)
 }
 
 
-Clip *gcut_get_clip (GeglEDL *edl, int frame, int *clip_frame_no)
+Clip *gcut_get_clip (GeglEDL *edl, double frame_pos, double *clip_frame_pos)
 {
   GList *l;
-  int clip_start = 0;
+  double clip_start = 0;
 
   for (l = edl->clips; l; l = l->next)
   {
     Clip *clip = l->data;
-    int clip_frames = clip_get_frames (clip);
+    double clip_duration = clip_get_duration (clip);
     if (clip->is_meta)
       continue;
 
-    if (frame - clip_start < clip_frames)
+    if (frame_pos - clip_start < clip_duration)
     {
       /* found right clip */
-      if (clip_frame_no)
-       *clip_frame_no = (frame - clip_start) + clip_get_start (clip);
+      if (clip_frame_pos)
+       *clip_frame_pos = (frame_pos - clip_start) + clip_get_start (clip);
       return clip;
     }
-    clip_start += clip_frames;
+    clip_start += clip_duration;
   }
   return NULL;
 }
@@ -205,7 +207,7 @@ int cache_misses = 0;
 
 void gcut_set_use_proxies (GeglEDL *edl, int use_proxies)
 {
-  int frame;
+  double frame_pos;
   edl->use_proxies = use_proxies;
 
   if (edl->use_proxies)
@@ -213,11 +215,12 @@ void gcut_set_use_proxies (GeglEDL *edl, int use_proxies)
   else
     gcut_set_size (edl, edl->video_width, edl->video_height);
 
-  frame = edl->frame;
-  if (frame > 0)
+  frame_pos = edl->pos;
+
+  if (frame_pos > 0)
   {
     edl->frame--;
-    gcut_set_frame (edl, frame);
+    gcut_set_pos (edl, frame_pos);
   }
 
 }
@@ -225,35 +228,33 @@ void gcut_set_use_proxies (GeglEDL *edl, int use_proxies)
 /* computes the hash of a given rendered frame - without altering
  * any state
  */
-gchar *gcut_get_frame_hash_full (GeglEDL *edl, int frame,
-                                 Clip **clip0, int *clip0_frame,
-                                 Clip **clip1, int *clip1_frame,
-                                 double *mix)
+gchar *gcut_get_pos_hash_full (GeglEDL *edl, double pos,
+                               Clip **clip0, double *clip0_pos,
+                               Clip **clip1, double *clip1_pos,
+                               double *mix)
 {
   GList *l;
-  int clip_start = 0;
-  int prev_clip_start = 0;
-
-
+  double clip_start = 0;
+  double prev_clip_start = 0;
 
   for (l = edl->clips; l; l = l->next)
   {
     Clip *clip = l->data;
-    int clip_frames = clip_get_frames (clip);
+    double clip_duration = clip_get_duration (clip);
 
     if (clip->is_meta)
       continue;
 
-    if (frame - clip_start < clip_frames)
+    if (pos - clip_start < clip_duration)
     {
-      int clip_frame_no = (frame - clip_start) + clip_get_start (clip);
+      double clip_frame_pos = (pos - clip_start) + clip_get_start (clip);
 
       GList *lp = l->prev;
       GList *ln = l->next;
       Clip *prev = lp?lp->data:NULL;
       Clip *next = ln?ln->data:NULL;
-      int prev_fade_len;
-      int next_fade_len;
+      double prev_fade_len;
+      double next_fade_len;
 
       while (prev && prev->is_meta)
       {
@@ -269,11 +270,11 @@ gchar *gcut_get_frame_hash_full (GeglEDL *edl, int frame,
 
       /* XXX: fade in from black if there is no previous clip */
 
-      prev_fade_len = prev ? clip_get_frames (prev) : clip_frames;
-      next_fade_len = next ? clip_get_frames (next) : clip_frames;
+      prev_fade_len = prev ? clip_get_duration (prev) : clip_duration;
+      next_fade_len = next ? clip_get_duration (next) : clip_duration;
 
-      if (prev_fade_len > clip_frames) prev_fade_len = clip_frames;
-      if (next_fade_len > clip_frames) next_fade_len = clip_frames;
+      if (prev_fade_len > clip_duration) prev_fade_len = clip_duration;
+      if (next_fade_len > clip_duration) next_fade_len = clip_duration;
 
       prev_fade_len /= 2;
       next_fade_len /= 2;  /* 1/4 the length of the smallest of this or other
@@ -290,11 +291,11 @@ gchar *gcut_get_frame_hash_full (GeglEDL *edl, int frame,
           next_fade_len = next->fade/2;
       }
 
-      if (prev && frame - clip_start < prev_fade_len)                   /* in */
+      if (prev && pos - clip_start < prev_fade_len)                   /* in */
       {
-        char *clip0_hash = clip_get_frame_hash (clip, clip_frame_no);
-        char *clip1_hash = clip_get_frame_hash (prev, frame - prev_clip_start + clip_get_start (prev));
-        double ratio = 0.5 + ((frame-clip_start) * 1.0 / prev_fade_len)/2;
+        char *clip0_hash = clip_get_pos_hash (clip, clip_frame_pos);
+        char *clip1_hash = clip_get_pos_hash (prev, pos - prev_clip_start + clip_get_start (prev));
+        double ratio = 0.5 + ((pos -clip_start) * 1.0 / prev_fade_len)/2;
         char *str = g_strdup_printf ("%s %s %f", clip1_hash, clip0_hash, ratio);
         GChecksum *hash = g_checksum_new (G_CHECKSUM_MD5);
         char *ret;
@@ -306,19 +307,19 @@ gchar *gcut_get_frame_hash_full (GeglEDL *edl, int frame,
         ret = g_strdup (g_checksum_get_string(hash));
         g_checksum_free (hash);
         if (clip0) *clip0 = prev;
-        if (clip0_frame) *clip0_frame = frame - prev_clip_start + clip_get_start (prev);
+        if (clip0_pos) *clip0_pos = pos - prev_clip_start + clip_get_start (prev);
         if (clip1) *clip1 = clip;
-        if (clip1_frame) *clip1_frame = clip_frame_no;
+        if (clip1_pos) *clip1_pos = clip_frame_pos;
         if (mix) *mix = ratio;
 
         return ret;
       }
 
-      if (next && frame - clip_start > clip_frames - next_fade_len)/* out*/
+      if (next && pos - clip_start > clip_duration - next_fade_len)/* out*/
       {
-        char *clip0_hash = clip_get_frame_hash (clip, clip_frame_no);
-        char *clip1_hash = clip_get_frame_hash (next, frame - (clip_start + clip_frames) + clip_get_start 
(next));
-        double ratio = (1.0-(clip_frames-(frame-clip_start)) * 1.0 / next_fade_len)/2;
+        char *clip0_hash = clip_get_pos_hash (clip, clip_frame_pos);
+        char *clip1_hash = clip_get_pos_hash (next, pos - (clip_start + clip_duration) + clip_get_start 
(next));
+        double ratio = (1.0-(clip_duration -(pos -clip_start)) * 1.0 / next_fade_len)/2;
         GChecksum *hash = g_checksum_new (G_CHECKSUM_MD5);
         char *str = g_strdup_printf ("%s %s %f", clip0_hash, clip1_hash, ratio);
         char *ret;
@@ -329,8 +330,8 @@ gchar *gcut_get_frame_hash_full (GeglEDL *edl, int frame,
         ret = g_strdup (g_checksum_get_string(hash));
         g_checksum_free (hash);
         if (clip0) *clip0 = clip;
-        if (clip0_frame) *clip0_frame = clip_frame_no;
-        if (clip1_frame) *clip1_frame = frame - (clip_start +clip_frames) + clip_get_start (next);
+        if (clip0_pos) *clip0_pos = clip_frame_pos;
+        if (clip1_pos) *clip1_pos = pos - (clip_start +clip_duration) + clip_get_start (next);
         if (clip1) *clip1 = next;
         if (mix)   *mix = ratio;
         return ret;
@@ -338,27 +339,27 @@ gchar *gcut_get_frame_hash_full (GeglEDL *edl, int frame,
       else
       {
         if (clip0) *clip0 = clip;
-        if (clip0_frame) *clip0_frame = clip_frame_no;
+        if (clip0_pos) *clip0_pos = clip_frame_pos;
         if (clip1) *clip1 = NULL;
         if (mix)   *mix = 0.0;
-        return clip_get_frame_hash (clip, clip_frame_no);
+        return clip_get_pos_hash (clip, clip_frame_pos);
       }
     }
     prev_clip_start = clip_start;
-    clip_start += clip_frames;
+    clip_start += clip_duration;
   }
 
-  if (clip0) *clip0 = NULL;
-  if (clip0_frame) *clip0_frame = 0;
-  if (clip1_frame) *clip1_frame = 0;
-  if (clip1) *clip1 = NULL;
-  if (mix)   *mix = 0.0;
+  if (clip0)     *clip0 = NULL;
+  if (clip0_pos) *clip0_pos = 0;
+  if (clip1_pos) *clip1_pos = 0;
+  if (clip1)     *clip1 = NULL;
+  if (mix)       *mix = 0.0;
   return NULL;
 }
 
-gchar *gcut_get_frame_hash (GeglEDL *edl, int frame)
+gchar *gcut_get_pos_hash (GeglEDL *edl, double pos)
 {
-  return gcut_get_frame_hash_full (edl, frame, NULL, NULL, NULL, NULL, NULL);
+  return gcut_get_pos_hash_full (edl, pos, NULL, NULL, NULL, NULL, NULL);
 }
 
 void gcut_update_buffer (GeglEDL *edl)
@@ -374,10 +375,11 @@ void gcut_update_buffer (GeglEDL *edl)
 }
 /*  calling this causes gcut to rig up its graphs for providing/rendering this frame
  */
-void gcut_set_frame (GeglEDL *edl, int frame)
+void gcut_set_pos (GeglEDL *edl, double pos)
 {
-  Clip *clip0; int clip0_frame;
-  Clip *clip1; int clip1_frame;
+  int frame = pos * edl->fps;
+  Clip *clip0; double clip0_pos;
+  Clip *clip1; double clip1_pos;
 
   if ((edl->frame) == frame && (frame != 0))
   {
@@ -388,8 +390,9 @@ void gcut_set_frame (GeglEDL *edl, int frame)
 
   double mix;
 
-  char *frame_hash = gcut_get_frame_hash_full (edl, frame, &clip0, &clip0_frame, &clip1, &clip1_frame, &mix);
+  char *frame_hash = gcut_get_pos_hash_full (edl, pos, &clip0, &clip0_pos, &clip1, &clip1_pos, &mix);
   char *cache_path = g_strdup_printf ("%s.gcut/cache/%s", edl->parent_path, frame_hash);
+  edl->pos = pos;
   edl->frame = frame;
   g_free (frame_hash);
   if (g_file_test (cache_path, G_FILE_TEST_IS_REGULAR) &&
@@ -398,7 +401,7 @@ void gcut_set_frame (GeglEDL *edl, int frame)
     Clip *clip = NULL;
     gegl_node_set (edl->cache_loader, "path", cache_path, NULL);
     gegl_node_link_many (edl->cache_loader, edl->result, NULL);
-    clip = edl_get_clip_for_frame (edl, edl->frame);
+    clip = edl_get_clip_for_pos (edl, pos);
     if (clip)
     {
     if (clip->audio)
@@ -428,14 +431,14 @@ void gcut_set_frame (GeglEDL *edl, int frame)
 
   if (clip1 == NULL)
   {
-    clip_render_frame (clip0, clip0_frame);
+    clip_render_pos (clip0, clip0_pos);
     gegl_node_link_many (clip0->nop_crop, edl->result, NULL);
   }
   else
   {
     gegl_node_set (edl->mix, "ratio", mix, NULL);
-    clip_render_frame (clip0, clip0_frame);
-    clip_render_frame (clip1, clip1_frame);
+    clip_render_pos (clip0, clip0_pos);
+    clip_render_pos (clip1, clip1_pos);
     gegl_node_link_many (clip0->nop_crop, edl->mix, edl->result, NULL);
     gegl_node_connect_to (clip1->nop_crop, "output", edl->mix, "aux");
   }
@@ -485,39 +488,46 @@ double gcut_get_fps (GeglEDL *edl)
 {
   return edl->fps;
 }
-int    gcut_get_frame (GeglEDL *edl)
+double gcut_get_pos (GeglEDL *edl)
 {
-  return edl->frame;
+  return edl->pos;
 }
 
 GeglAudioFragment *gcut_get_audio (GeglEDL *edl)
 {
-  Clip * clip = edl_get_clip_for_frame (edl, edl->frame);
+  Clip * clip = edl_get_clip_for_pos (edl, edl->pos);
   return clip?clip->audio:NULL;
 }
 
-void gcut_get_video_info (const char *path, int *duration, double *fps)
+void gcut_get_video_info (const char *path, int *frames, double *duration, double *fps)
 {
   GeglNode *gegl = gegl_node_new ();
   GeglNode *probe = gegl_node_new_child (gegl, "operation",
                           "gegl:ff-load", "path", path, NULL);
+  double r_fps;
+  int    r_frames;
   gegl_node_process (probe);
 
-  if (duration)
-  gegl_node_get (probe, "frames", duration, NULL);
+  gegl_node_get (probe, "frames", &r_frames, NULL);
+  gegl_node_get (probe, "frame-rate", &r_fps, NULL);
+
+  if (frames)
+    *frames = r_frames;
   if (fps)
-  gegl_node_get (probe, "frame-rate", fps, NULL);
+    *fps = r_fps;
+  if (duration)
+    *duration = r_frames / r_fps;
   g_object_unref (gegl);
 }
 
-int gcut_get_duration (GeglEDL *edl)
+double gcut_get_duration (GeglEDL *edl)
 {
-  int count = 0;
+  double count = 0;
   GList *l;
   for (l = edl->clips; l; l = l->next)
   {
     ((Clip*)(l->data))->abs_start = count;
-    count += clip_get_frames (l->data);
+    count += clip_get_duration (l->data);
   }
   return count;
 }
@@ -526,7 +536,7 @@ int gcut_get_duration (GeglEDL *edl)
 
 void gcut_parse_line (GeglEDL *edl, const char *line)
 {
-  int start = 0; int end = 0;
+  double start = 0; double end = 0;
   const char *rest = NULL;
   char path[1024];
   if (line[0] == '#' ||
@@ -562,7 +572,7 @@ void gcut_parse_line (GeglEDL *edl, const char *line)
      if (!strcmp (key, "selection-end"))     edl->selection_end = g_strtod (value, NULL);
      //if (!strcmp (key, "range-start"))       edl->range_start = g_strtod (value, NULL);
      //if (!strcmp (key, "range-end"))         edl->range_end = g_strtod (value, NULL);
-     if (!strcmp (key, "frame-no"))          edl->frame_no = g_strtod (value, NULL);
+     if (!strcmp (key, "frame-pos"))         edl->frame_pos_ui = g_strtod (value, NULL);
      if (!strcmp (key, "frame-scale"))       edl->scale = g_strtod (value, NULL);
      if (!strcmp (key, "t0"))                edl->t0 = g_strtod (value, NULL);
 
@@ -578,17 +588,28 @@ void gcut_parse_line (GeglEDL *edl, const char *line)
     if (!p)
       p = line + strlen(line)-1;
     {
+      int is_seconds = 0;
       if (p>line) p --;
       while (p>line && *p == ' ') p --;
 
-      while (p>line && isdigit (*p)) p --;
-      end = atoi (p+1);
+      while (p>line && (isdigit (*p) || (*p=='s'))){
+        if (*p == 's') is_seconds = 1;
+        p --;
+      }
+      end = g_strtod (p+1, NULL);
+      if (!is_seconds)
+        end /= edl->fps;
 
       if (p>line) p --;
       while (p>line && *p == ' ') p --;
-
-      while (p>line && isdigit (*p)) p --;
-      start = atoi (p+1);
+      is_seconds = 0;
+      while (p>line && (isdigit (*p) || (*p=='s'))){
+        if (*p == 's') is_seconds = 1;
+        p --;
+      }
+      start = g_strtod (p+1, NULL);
+      if (!is_seconds)
+        start /= edl->fps;
 
       if (p>line) p --;
       while (p>line && *p == ' ') p --;
@@ -611,10 +632,15 @@ void gcut_parse_line (GeglEDL *edl, const char *line)
      edl->clips = g_list_append (edl->clips, clip);
      if (strstr (line, "[fade="))
        {
+         int was_seconds = 0;
          ff_probe = 1;
          rest = strstr (line, "[fade=") + strlen ("[fade=");
-         clip->fade = atoi (rest);
-         while (*rest && *rest != ']') rest++;
+         clip->fade = g_strtod (rest, NULL);
+         while (*rest && *rest != ']'){ if (*rest == 's') was_seconds =1; rest++;}
+         if (!was_seconds)
+         {
+           clip->fade = clip->fade / edl->fps;
+         }
          if (*rest == ']') rest++;
        }
 
@@ -628,7 +654,8 @@ void gcut_parse_line (GeglEDL *edl, const char *line)
 
      if (ff_probe && !clip_is_static_source (clip))
        {
-         gcut_get_video_info (clip->path, &clip->duration, &clip->fps);
+         int clip_frames;
+         gcut_get_video_info (clip->path, &clip_frames, &clip->duration, &clip->fps);
 
          if (edl->fps == 0.0)
          {
@@ -975,10 +1002,10 @@ static void init (int argc, char **argv)
 static void encode_frames (GeglEDL *edl)
 {
   int frame_no;
-  for (frame_no = edl->range_start; frame_no <= edl->range_end; frame_no++)
+  for (frame_no = edl->range_start * edl->fps; frame_no <= edl->range_end * edl->fps; frame_no++)
   {
-    edl->frame_no = frame_no;
-    gcut_set_frame (edl, edl->frame_no);
+    int frame_no_ui = frame_no;
+    gcut_set_pos (edl, frame_no_ui / edl->fps);
 
     fprintf (stdout, "\r%1.2f%% %04d / %04d   ",
      100.0 * (frame_no-edl->range_start) * 1.0 / (edl->range_end - edl->range_start),
@@ -1013,51 +1040,52 @@ static inline int this_cacher (int frame_no)
 
 static void process_frames_cache (GeglEDL *edl)
 {
-  int frame_no = edl->frame_no;
-  int frame_start = edl->frame_no;
+  int frame_no = edl->frame_pos_ui * edl->fps;
+  int frame_start = frame_no;
   int duration;
 
   GList *l;
-  int clip_start = 0;
+  double clip_start = 0;
 
   signal(SIGUSR2, handler1);
   duration = gcut_get_duration (edl);
   // TODO: use bitmap from ui to speed up check
 
-  edl->frame_no = frame_start;
-  if (this_cacher (edl->frame_no))
-    gcut_set_frame (edl, edl->frame_no);
+  edl->frame_pos_ui = frame_start;
+  if (this_cacher (floor (edl->frame_pos_ui * edl->fps)))
+    gcut_set_pos (edl, edl->frame_pos_ui);
    if (stop_cacher)
     return;
 
   for (l = edl->clips; l; l = l->next)
   {
     Clip *clip = l->data;
-    int clip_frames = clip_get_frames (clip);
-    edl->frame_no = clip_start;
-    if (this_cacher (edl->frame_no))
+    double clip_duration = clip_get_duration (clip);
+    int frame_pos_ui = floor (clip_start * edl->fps);
+    if (this_cacher (frame_pos_ui))
     {
-      gcut_set_frame (edl, edl->frame_no);
+      gcut_set_pos (edl, frame_pos_ui / edl->fps);
     }
 
-    clip_start += clip_frames;
+    clip_start += clip_duration;
     if (stop_cacher)
       return;
   }
 
   for (frame_no = frame_start - 3; frame_no < duration; frame_no++)
   {
-    edl->frame_no = frame_no;
-    if (this_cacher (edl->frame_no))
-      gcut_set_frame (edl, edl->frame_no);
+    int frame_pos_ui = floor (frame_no / edl->fps);
+
+    if (this_cacher (frame_no))
+      gcut_set_pos (edl, frame_pos_ui);
     if (stop_cacher)
       return;
   }
   for (frame_no = 0; frame_no < frame_start; frame_no++)
   {
-    edl->frame_no = frame_no;
-    if (this_cacher (edl->frame_no))
-      gcut_set_frame (edl, edl->frame_no);
+    int frame_pos_ui = floor (frame_no / edl->fps);
+    if (this_cacher (frame_no))
+      gcut_set_pos (edl, frame_pos_ui);
     if (stop_cacher)
       return;
   }
@@ -1080,7 +1108,7 @@ guchar *gcut_get_cache_bitmap (GeglEDL *edl, int *length_ret)
 
   for (frame_no = 0; frame_no < duration; frame_no++)
   {
-    const gchar *hash = gcut_get_frame_hash (edl, frame_no);
+    const gchar *hash = gcut_get_pos_hash (edl, frame_no / edl->fps);
     gchar *path = g_strdup_printf ("%s.gcut/cache/%s", edl->parent_path, hash);
     if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
       set_bit (ret, frame_no);
@@ -1092,8 +1120,8 @@ guchar *gcut_get_cache_bitmap (GeglEDL *edl, int *length_ret)
 
 static void process_frames_cache_stat (GeglEDL *edl)
 {
-  int frame_no = edl->frame_no;
-  int duration;
+  int frame_no = edl->frame_pos_ui / edl->fps;
+  double duration;
   signal(SIGUSR2, handler1);
   duration = gcut_get_duration (edl);
 
@@ -1102,9 +1130,9 @@ static void process_frames_cache_stat (GeglEDL *edl)
           project
    */
 
-  for (frame_no = 0; frame_no < duration; frame_no++)
+  for (frame_no = 0; frame_no < duration * edl->fps; frame_no++)
   {
-    const gchar *hash = gcut_get_frame_hash (edl, frame_no);
+    const gchar *hash = gcut_get_pos_hash (edl, frame_no / edl->fps);
     gchar *path = g_strdup_printf ("%s.gcut/cache/%s", edl->parent_path, hash);
     if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
       fprintf (stdout, "%i ", frame_no);
@@ -1418,7 +1446,7 @@ char *gcut_serialize (GeglEDL *edl)
   if (edl->t0 != 1.0)
     g_string_append_printf (ser, "t0=%f\n", edl->t0);
 
-  g_string_append_printf (ser, "frame-no=%i\n", edl->frame_no);
+  g_string_append_printf (ser, "frame-pos=%.3f\n", edl->frame_pos_ui);
   g_string_append_printf (ser, "\n");
 
   for (l = edl->clips; l; l = l->next)
@@ -1439,11 +1467,11 @@ char *gcut_serialize (GeglEDL *edl)
     }
     else
     {
-    g_string_append_printf (ser, "%s %d %d ", path, clip->start, clip->end);
+    g_string_append_printf (ser, "%s %.3fs %.3fs ", path, clip->start, clip->end);
     if (clip->filter_graph||clip->fade)
       g_string_append_printf (ser, "-- ");
     if (clip->fade)
-      g_string_append_printf (ser, "[fade=%i] ", clip->fade);
+      g_string_append_printf (ser, "[fade=%.3fs] ", clip->fade);
     if (clip->filter_graph)
       g_string_append_printf (ser, "%s", clip->filter_graph);
     g_string_append_printf (ser, "\n");
@@ -1563,15 +1591,15 @@ gegl_meta_get_audio (const char        *path,
 #endif
 }
 
-void gcut_set_selection (GeglEDL *edl, int start_frame, int end_frame)
+void gcut_set_selection (GeglEDL *edl, double start_frame, double end_frame)
 {
   edl->selection_start = start_frame;
   edl->selection_end   = end_frame;
 }
 
 void gcut_get_selection (GeglEDL *edl,
-                         int     *start_frame,
-                         int     *end_frame)
+                         double  *start_frame,
+                         double  *end_frame)
 {
   if (start_frame)
     *start_frame = edl->selection_start;
@@ -1579,15 +1607,15 @@ void gcut_get_selection (GeglEDL *edl,
     *end_frame = edl->selection_end;
 }
 
-void gcut_set_range (GeglEDL *edl, int start_frame, int end_frame)
+void gcut_set_range (GeglEDL *edl, double start_frame, double end_frame)
 {
   edl->range_start = start_frame;
   edl->range_end   = end_frame;
 }
 
 void gcut_get_range (GeglEDL *edl,
-                     int     *start_frame,
-                     int     *end_frame)
+                     double  *start_frame,
+                     double  *end_frame)
 {
   if (start_frame)
     *start_frame = edl->range_start;
@@ -1595,18 +1623,19 @@ void gcut_get_range (GeglEDL *edl,
     *end_frame = edl->range_end;
 }
 
-Clip * edl_get_clip_for_frame (GeglEDL *edl, int frame)
+Clip * edl_get_clip_for_pos (GeglEDL *edl, double pos)
 {
   GList *l;
-  int t = 0;
+  double t = 0;
   for (l = edl->clips; l; l = l->next)
   {
     Clip *clip = l->data;
-    if (frame >= t && frame < t + clip_get_frames (clip))
+    double duration = clip_get_duration (clip);
+    if (pos >= t && pos < t + duration)
     {
       return clip;
     }
-    t += clip_get_frames (clip);
+    t += duration;
   }
   return NULL;
 }
diff --git a/gcut/gcut.h b/gcut/gcut.h
index fbd3ce9..0858c3f 100644
--- a/gcut/gcut.h
+++ b/gcut/gcut.h
@@ -83,27 +83,27 @@ void        gcut_free               (GeglEDL    *edl);
 void        gcut_set_fps            (GeglEDL    *edl,
                                      double      fps);
 double      gcut_get_fps            (GeglEDL    *edl);
-int         gcut_get_duration       (GeglEDL    *edl);
+double      gcut_get_duration       (GeglEDL    *edl);
 void        gcut_parse_line         (GeglEDL    *edl, const char *line);
 GeglEDL    *gcut_new_from_path      (const char *path);
 void        gcut_load_path          (GeglEDL    *edl, const char *path);
 void        gcut_save_path          (GeglEDL    *edl, const char *path);
 GeglAudioFragment  *gcut_get_audio  (GeglEDL    *edl);
-Clip       *gcut_get_clip           (GeglEDL *edl, int frame, int *clip_frame_no);
+Clip       *gcut_get_clip           (GeglEDL *edl, double pos, double *clip_frame_pos);
 
-void        gcut_set_frame          (GeglEDL    *edl, int frame);
-int         gcut_get_frame          (GeglEDL    *edl);
+void        gcut_set_pos            (GeglEDL    *edl, double pos);
+double      gcut_get_pos            (GeglEDL    *edl);
 char       *gcut_serialize          (GeglEDL    *edl);
 
-void        gcut_set_range          (GeglEDL    *edl, int start_frame, int end_frame);
+void        gcut_set_range          (GeglEDL    *edl, double start, double end);
 void        gcut_get_range          (GeglEDL    *edl,
-                                     int        *start_frame,
-                                     int        *end_frame);
+                                     double     *start,
+                                     double     *end);
 
-void        gcut_set_selection      (GeglEDL    *edl, int start_frame, int end_frame);
+void        gcut_set_selection      (GeglEDL    *edl, double start, double end);
 void        gcut_get_selection      (GeglEDL    *edl,
-                                     int        *start_frame,
-                                     int        *end_frame);
+                                     double     *start,
+                                     double     *end);
 char       *gcut_make_thumb_path    (GeglEDL    *edl, const char *clip_path);
 guchar     *gcut_get_cache_bitmap   (GeglEDL *edl, int *length_ret);
 
@@ -112,26 +112,26 @@ Clip       *clip_new               (GeglEDL *edl);
 void        clip_free              (Clip *clip);
 const char *clip_get_path          (Clip *clip);
 void        clip_set_path          (Clip *clip, const char *path);
-int         clip_get_start         (Clip *clip);
-int         clip_get_end           (Clip *clip);
-int         clip_get_frames        (Clip *clip);
-void        clip_set_start         (Clip *clip, int start);
-void        clip_set_end           (Clip *clip, int end);
-void        clip_set_range         (Clip *clip, int start, int end);
+double      clip_get_start         (Clip *clip);
+double      clip_get_end           (Clip *clip);
+double      clip_get_duration      (Clip *clip);
+void        clip_set_start         (Clip *clip, double start);
+void        clip_set_end           (Clip *clip, double end);
+void        clip_set_range         (Clip *clip, double start, double end);
 int         clip_is_static_source  (Clip *clip);
-gchar *     clip_get_frame_hash    (Clip *clip, int clip_frame_no);
+gchar *     clip_get_pos_hash      (Clip *clip, double clip_frame_pos);
 Clip  *     clip_get_next          (Clip *self);
 Clip  *     clip_get_prev          (Clip *self);
 void        clip_fetch_audio       (Clip *clip);
-void        clip_set_full          (Clip *clip, const char *path, int start, int end);
-Clip  *     clip_new_full          (GeglEDL *edl, const char *path, int start, int end);
+void        clip_set_full          (Clip *clip, const char *path, double start, double end);
+Clip  *     clip_new_full          (GeglEDL *edl, const char *path, double start, double end);
 
 //void   clip_set_frame_no      (Clip *clip, int frame_no);
-void        clip_render_frame       (Clip *clip, int clip_frame_no);
+void        clip_render_pos     (Clip *clip, double clip_frame_pos);
 
-Clip *      edl_get_clip_for_frame (GeglEDL           *edl, int frame);
+Clip *      edl_get_clip_for_pos   (GeglEDL           *edl, double pos);
 void        gcut_make_proxies      (GeglEDL           *edl);
-void        gcut_get_video_info    (const char        *path, int *duration, double *fps);
+void        gcut_get_video_info    (const char        *path, int *frames, double *duration, double *fps);
 void        gegl_meta_set_audio    (const char        *path,
                                     GeglAudioFragment *audio);
 void        gegl_meta_get_audio    (const char        *path,
@@ -147,21 +147,21 @@ struct _Clip
 {
   char  *path;  /*path to media file */
   char  *title;
-  int    start; /*frame number starting with 0 */
-  int    end;   /*last frame, inclusive fro single frame, make equal to start */
-  int    duration;
+  double start; /*frame number starting with 0 */
+  double end;   /*last frame, inclusive fro single frame, make equal to start */
+  double duration;
   int    editing;
   char  *filter_graph; /* chain of gegl filters */
   
   GeglEDL *edl;
 
   double fps;
-  int    fade; /* the main control for fading in.. */
+  double fade; /* the main control for fading in.. */
   int    static_source;
   int    is_chain;
   int    is_meta;
 
-  int    abs_start;
+  double    abs_start;
 
   const char        *clip_path;
   GeglNode          *gegl;
@@ -185,7 +185,8 @@ struct _GeglEDL
   char         *parent_path;
   GList        *clip_db;
   GList        *clips;
-  int           frame; /* render thread, frame_no is ui side */
+  int           frame; /* render thread, frame_no_ui is ui side */
+  double        pos;   /* render thread, frame_pos_ui is ui side */
   double        fps;
   GeglBuffer   *buffer;
   GeglBuffer   *buffer_copy_temp;
@@ -215,8 +216,8 @@ struct _GeglEDL
   int           video_tolerance;
   int           audio_bitrate;
   int           audio_samplerate;
-  int           frame_no;
-  int           source_frame_no;
+  double        frame_pos_ui;
+  int           source_frame_pos;
   int           use_proxies;
   int           framedrop;
   int           ui_mode;
@@ -244,12 +245,12 @@ void gcut_update_buffer (GeglEDL *edl);
 void gcut_cache_invalid (GeglEDL *edl);
 
 
-gchar *gcut_get_frame_hash (GeglEDL *edl, int frame);
+gchar *gcut_get_pos_hash (GeglEDL *edl, double pos);
 
-gchar *gcut_get_frame_hash_full (GeglEDL *edl, int frame,
-                                 Clip **clip0, int *clip0_frame,
-                                 Clip **clip1, int *clip1_frame,
-                                 double *mix);
+gchar *gcut_get_pos_hash_full (GeglEDL *edl, double pos,
+                               Clip **clip0, double *clip0_pos,
+                               Clip **clip1, double *clip1_pos,
+                               double *mix);
 int gegl_make_thumb_image (GeglEDL *edl, const char *path, const char *icon_path);
 
 #ifdef MICRO_RAPTOR_GUI
diff --git a/gcut/renderer.c b/gcut/renderer.c
index f0d54fa..56910fd 100644
--- a/gcut/renderer.c
+++ b/gcut/renderer.c
@@ -111,16 +111,16 @@ static gpointer renderer_thread (gpointer data)
   {
     playing_iteration (edl->mrg, edl);
     {
-      if (edl->frame_no != done_frame)
+      if ((int)(edl->frame_pos_ui * edl->fps) != done_frame)
       {
-        rendering_frame = edl->frame_no;
+        rendering_frame = edl->frame_pos_ui * edl->fps;
 
         {
           GeglRectangle ext = {0,0,edl->width, edl->height};
           //GeglRectangle ext = gegl_node_get_bounding_box (edl->result);
           gegl_buffer_set_extent (edl->buffer, &ext);
         }
-        gcut_set_frame (edl, edl->frame_no); /* this does the frame-set, which causes render  */
+        gcut_set_pos (edl, edl->frame_pos_ui); /* this does the frame-set, which causes render  */
 #if 0
         {
           GeglRectangle ext = gegl_node_get_bounding_box (edl->result);
@@ -187,11 +187,11 @@ void renderer_toggle_playing (MrgEvent *event, void *data1, void *data2)
   prev_ticks = babl_ticks ();
 }
 
-static int max_frame (GeglEDL *edl)
+static double max_pos (GeglEDL *edl)
 {
   GList *l;
   int t = 0;
-  int start, end;
+  double start, end;
 
   gcut_get_range (edl, &start, &end);
   if (end)
@@ -200,7 +200,7 @@ static int max_frame (GeglEDL *edl)
   for (l = edl->clips; l; l = l->next)
   {
     Clip *clip = l->data;
-    t += clip_get_frames (clip);
+    t += clip_get_duration (clip);
   }
 
   return t;
@@ -211,6 +211,7 @@ void playing_iteration (Mrg *mrg, GeglEDL *edl)
 {
   long ticks = 0;
   double delta = 1;
+  double fragment = 1.0 / edl->fps;
   ticks = babl_ticks ();
   if (prev_ticks == 0) prev_ticks = ticks;
 
@@ -264,16 +265,16 @@ void playing_iteration (Mrg *mrg, GeglEDL *edl)
 
       if (edl->active_clip)
       {
-        int start, end;
-        edl->frame_no += delta;
+        double start, end;
+        edl->frame_pos_ui += delta * fragment;
         gcut_get_range (edl, &start, &end);
-        if (edl->frame_no > max_frame (edl))
+        if (edl->frame_pos_ui > max_pos (edl))
         {
-           edl->frame_no = 0;
+           edl->frame_pos_ui = 0;
            if (end)
-             edl->frame_no = start;
+             edl->frame_pos_ui = start;
         }
-        edl->active_clip = edl_get_clip_for_frame (edl, edl->frame_no);
+        edl->active_clip = edl_get_clip_for_pos (edl, edl->frame_pos_ui);
         prev_ticks = ticks;
       }
       }
@@ -282,5 +283,5 @@ void playing_iteration (Mrg *mrg, GeglEDL *edl)
 
 int renderer_done (GeglEDL *edl)
 {
-  return done_frame == edl->frame_no; //rendering_frame;
+  return done_frame == (gint)(edl->frame_pos_ui * edl->fps); //rendering_frame;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]