Two in one:
[blender.git] / source / blender / src / editseq.c
index 1fc3e948f3746a8c67563267073ce8a5f9bc8ac1..050c0999d015a5e639581c52ac4f7ef52d297001 100644 (file)
@@ -55,6 +55,7 @@
 #include "IMB_imbuf.h"
 
 #include "DNA_ipo_types.h"
+#include "DNA_curve_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
@@ -85,6 +86,7 @@
 
 #include "BSE_edit.h"
 #include "BSE_sequence.h"
+#include "BSE_seqeffects.h"
 #include "BSE_filesel.h"
 #include "BSE_drawipo.h"
 #include "BSE_seqaudio.h"
 #include "blendef.h"
 #include "mydevice.h"
 
-Sequence *last_seq=0;
+static Sequence *_last_seq=0;
+static int _last_seq_init=0;
+
+#ifdef WIN32
+char last_imagename[FILE_MAXDIR+FILE_MAXFILE]= "c:\\";
+#else
 char last_imagename[FILE_MAXDIR+FILE_MAXFILE]= "/";
+#endif
+
 char last_sounddir[FILE_MAXDIR+FILE_MAXFILE]= "";
 
 #define SEQ_DESEL      ~(SELECT+SEQ_LEFTSEL+SEQ_RIGHTSEL)
@@ -103,17 +112,52 @@ char last_sounddir[FILE_MAXDIR+FILE_MAXFILE]= "";
 static int test_overlap_seq(Sequence *);
 static void shuffle_seq(Sequence *);
 
+Sequence *get_last_seq()
+{
+       if(!_last_seq_init) {
+               Editing *ed;
+               Sequence *seq;
+
+               ed= G.scene->ed;
+               if(!ed) return NULL;
+
+               for(seq= ed->seqbasep->first; seq; seq=seq->next)
+                       if(seq->flag & SELECT)
+                               _last_seq= seq;
+
+               _last_seq_init = 1;
+       }
+
+       return _last_seq;
+}
+
+void set_last_seq(Sequence *seq)
+{
+       _last_seq = seq;
+       _last_seq_init = 1;
+}
+
+void clear_last_seq()
+{
+       _last_seq = NULL;
+       _last_seq_init = 0;
+}
+
 static void change_plugin_seq(char *str)       /* called from fileselect */
 {
-/*     extern Sequence *last_seq; already done few lines before !!!*/
+       struct SeqEffectHandle sh;
+       Sequence *last_seq= get_last_seq();
 
-       if(last_seq && last_seq->type!=SEQ_PLUGIN) return;
+       if(last_seq && last_seq->type != SEQ_PLUGIN) return;
 
-       free_plugin_seq(last_seq->plugin);
+       sh = get_sequence_effect(last_seq);
+       sh.free(last_seq);
+       sh.init_plugin(last_seq, str);
 
-       last_seq->plugin= (PluginSeq *)add_plugin_seq(str, last_seq->name+2);
+       last_seq->machine = MAX3(last_seq->seq1->machine, 
+                                last_seq->seq2->machine, 
+                                last_seq->seq3->machine);
 
-       last_seq->machine= MAX3(last_seq->seq1->machine, last_seq->seq2->machine, last_seq->seq3->machine);
        if( test_overlap_seq(last_seq) ) shuffle_seq(last_seq);
        
        BIF_undo_push("Load/change Sequencer plugin");
@@ -151,54 +195,52 @@ void boundbox_seq(void)
 
 }
 
+int sequence_is_free_transformable(Sequence * seq)
+{
+       return seq->type < SEQ_EFFECT
+               || (get_sequence_effect_num_inputs(seq->type) == 0);
+}
+
 Sequence *find_nearest_seq(int *hand)
 {
        Sequence *seq;
        Editing *ed;
-       float x, y, facx, facy;
+       float x, y;
        short mval[2];
-
+       float pixelx;
+       float handsize;
+       float minhandle, maxhandle;
+       View2D *v2d = G.v2d;
        *hand= 0;
 
        ed= G.scene->ed;
        if(ed==0) return 0;
+       
+       pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin);
 
        getmouseco_areawin(mval);
        areamouseco_to_ipoco(G.v2d, mval, &x, &y);
-
+       
        seq= ed->seqbasep->first;
+       
        while(seq) {
+               /* clamp handles to defined size in pixel space */
+               handsize = seq->handsize;
+               minhandle = 7;
+               maxhandle = 28;
+               CLAMP(handsize, minhandle*pixelx, maxhandle*pixelx);
+               
                if(seq->machine == (int)y) {
-                       if(seq->startdisp<=x && seq->enddisp>=x) {
-
-                               if(seq->type < SEQ_EFFECT) {
-                                       if( seq->handsize+seq->startdisp >=x ) {
-                                               /* within triangle? */
-                                               facx= (x-seq->startdisp)/seq->handsize;
-                                               if( (y - (int)y) <0.5) {
-                                                       facy= (y - 0.2 - (int)y)/0.3;
-                                                       if( facx < facy ) *hand= 1;
-                                               }
-                                               else {
-                                                       facy= (y - 0.5 - (int)y)/0.3;
-                                                       if( facx+facy < 1.0 ) *hand= 1;
-                                               }
-
-                                       }
-                                       else if( -seq->handsize+seq->enddisp <=x ) {
-                                               /* within triangle? */
-                                               facx= 1.0 - (seq->enddisp-x)/seq->handsize;
-                                               if( (y - (int)y) <0.5) {
-                                                       facy= (y - 0.2 - (int)y)/0.3;
-                                                       if( facx+facy > 1.0 ) *hand= 2;
-                                               }
-                                               else {
-                                                       facy= (y - 0.5 - (int)y)/0.3;
-                                                       if( facx > facy ) *hand= 2;
-                                               }
-                                       }
+                       /* check for both normal strips, and strips that have been flipped horizontally */
+                       if( ((seq->startdisp < seq->enddisp) && (seq->startdisp<=x && seq->enddisp>=x)) ||
+                               ((seq->startdisp > seq->enddisp) && (seq->startdisp>=x && seq->enddisp<=x)) )
+                       {
+                               if(sequence_is_free_transformable(seq)) {
+                                       if( handsize+seq->startdisp >=x )
+                                               *hand= 1;
+                                       else if( -handsize+seq->enddisp <=x )
+                                               *hand= 2;
                                }
-
                                return seq;
                        }
                }
@@ -207,34 +249,51 @@ Sequence *find_nearest_seq(int *hand)
        return 0;
 }
 
-void clear_last_seq(void)
+void update_seq_ipo_rect(Sequence * seq)
 {
-       /* from (example) ipo: when it is changed, also do effects with same ipo */
-       Sequence *seq;
-       Editing *ed;
-       StripElem *se;
-       int a;
+       float start;
+       float end;
 
-       if(last_seq) {
+       if (!seq || !seq->ipo) {
+               return;
+       }
+       start =  -5.0;
+       end   =  105.0;
+
+       /* Adjust IPO window to sequence and 
+          avoid annoying snap-back to startframe 
+          when Lock Time is on */
+       if (G.v2d->flag & V2D_VIEWLOCK) {
+               if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
+                       start = -5.0 + seq->startdisp;
+                       end = 5.0 + seq->enddisp;
+               } else {
+                       start = (float)G.scene->r.sfra - 0.1;
+                       end = G.scene->r.efra;
+               }
+       }
 
-               ed= G.scene->ed;
-               if(ed==0) return;
+       seq->ipo->cur.xmin= start;
+       seq->ipo->cur.xmax= end;
+}
 
-               WHILE_SEQ(&ed->seqbase) {
-                       if(seq==last_seq || (last_seq->ipo && seq->ipo==last_seq->ipo)) {
-                               a= seq->len;
-                               se= seq->strip->stripdata;
-                               if(se) {
-                                       while(a--) {
-                                               if(se->ibuf) IMB_freeImBuf(se->ibuf);
-                                               se->ibuf= 0;
-                                               se->ok= 1;
-                                               se++;
-                                       }
-                               }
-                       }
-               }
-               END_SEQ
+void update_seq_icu_rects(Sequence * seq)
+{
+       IpoCurve *icu= NULL;
+       struct SeqEffectHandle sh;
+
+       if (!seq || !seq->ipo) {
+               return;
+       }
+
+       if(!(seq->type & SEQ_EFFECT)) {
+               return;
+       }
+
+       sh = get_sequence_effect(seq);
+
+       for(icu= seq->ipo->curve.first; icu; icu= icu->next) {
+               sh.store_icu_yrange(seq, icu->adrcode, &icu->ymin, &icu->ymax);
        }
 }
 
@@ -307,6 +366,22 @@ static void shuffle_seq(Sequence *test)
        }
 }
 
+static int seq_is_parent(Sequence *par, Sequence *seq)
+{
+       return ((par->seq1 == seq) || (par->seq2 == seq) || (par->seq3 == seq));
+}
+
+static int seq_is_predecessor(Sequence *pred, Sequence *seq)
+{
+       if(pred == seq) return 0;
+       else if(seq_is_parent(pred, seq)) return 1;
+       else if(pred->seq1 && seq_is_predecessor(pred->seq1, seq)) return 1;
+       else if(pred->seq2 && seq_is_predecessor(pred->seq2, seq)) return 1;
+       else if(pred->seq3 && seq_is_predecessor(pred->seq3, seq)) return 1;
+
+       return 0;
+}
+
 static void deselect_all_seq(void)
 {
        Sequence *seq;
@@ -373,51 +448,46 @@ void mouse_select_seq(void)
 
        seq= find_nearest_seq(&hand);
 
-       if(G.qual==0) deselect_all_seq();
+       if(!(G.qual & LR_SHIFTKEY)) deselect_all_seq();
 
        if(seq) {
-               last_seq= seq;
+               set_last_seq(seq);
 
                if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) {
                        if(seq->strip) {
                                strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1);
                        }
                } else
-               if (seq->type == SEQ_SOUND) {
+               if (seq->type == SEQ_HD_SOUND || seq->type == SEQ_RAM_SOUND) {
                        if(seq->strip) {
                                strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1);
                        }
                }
 
-               if(G.qual==0) {
+               if((G.qual & LR_SHIFTKEY) && (seq->flag & SELECT)) {
+                       if(hand==0) seq->flag &= SEQ_DESEL;
+                       else if(hand==1) {
+                               if(seq->flag & SEQ_LEFTSEL) 
+                                       seq->flag &= ~SEQ_LEFTSEL;
+                               else seq->flag |= SEQ_LEFTSEL;
+                       }
+                       else if(hand==2) {
+                               if(seq->flag & SEQ_RIGHTSEL) 
+                                       seq->flag &= ~SEQ_RIGHTSEL;
+                               else seq->flag |= SEQ_RIGHTSEL;
+                       }
+               }
+               else {
                        seq->flag |= SELECT;
                        if(hand==1) seq->flag |= SEQ_LEFTSEL;
                        if(hand==2) seq->flag |= SEQ_RIGHTSEL;
                }
-               else {
-                       if(seq->flag & SELECT) {
-                               if(hand==0) seq->flag &= SEQ_DESEL;
-                               else if(hand==1) {
-                                       if(seq->flag & SEQ_LEFTSEL) seq->flag &= ~SEQ_LEFTSEL;
-                                       else seq->flag |= SEQ_LEFTSEL;
-                               }
-                               else if(hand==2) {
-                                       if(seq->flag & SEQ_RIGHTSEL) seq->flag &= ~SEQ_RIGHTSEL;
-                                       else seq->flag |= SEQ_RIGHTSEL;
-                               }
-                       }
-                       else {
-                               seq->flag |= SELECT;
-                               if(hand==1) seq->flag |= SEQ_LEFTSEL;
-                               if(hand==2) seq->flag |= SEQ_RIGHTSEL;
-                       }
-               }
                recurs_sel_seq(seq);
        }
 
        force_draw(0);
 
-       if(last_seq) allqueue(REDRAWIPO, 0);
+       if(get_last_seq()) allqueue(REDRAWIPO, 0);
        BIF_undo_push("Select Sequencer");
 
        std_rmouse_transform(transform_seq);
@@ -433,7 +503,7 @@ static Sequence *alloc_sequence(int cfra, int machine)
        seq= MEM_callocN( sizeof(Sequence), "addseq");
        BLI_addtail(ed->seqbasep, seq);
 
-       last_seq= seq;
+       set_last_seq(seq);
 
        *( (short *)seq->name )= ID_SEQ;
        seq->name[2]= 0;
@@ -441,7 +511,8 @@ static Sequence *alloc_sequence(int cfra, int machine)
        seq->flag= SELECT;
        seq->start= cfra;
        seq->machine= machine;
-
+       seq->mul= 1.0;
+       
        return seq;
 }
 
@@ -451,6 +522,7 @@ static Sequence *sfile_to_sequence(SpaceFile *sfile, int cfra, int machine, int
        Strip *strip;
        StripElem *se;
        int totsel, a;
+       char name[160], rel[160];
 
        /* are there selected files? */
        totsel= 0;
@@ -479,12 +551,20 @@ static Sequence *sfile_to_sequence(SpaceFile *sfile, int cfra, int machine, int
        }
 
        calc_sequence(seq);
+       
+       if(sfile->flag & FILE_STRINGCODE) {
+               strcpy(name, sfile->dir);
+               strcpy(rel, G.sce);
+               BLI_makestringcode(rel, name);
+       } else {
+               strcpy(name, sfile->dir);
+       }
 
        /* strip and stripdata */
        seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
        strip->len= totsel;
        strip->us= 1;
-       strncpy(strip->dir, sfile->dir, FILE_MAXDIR-1);
+       strncpy(strip->dir, name, FILE_MAXDIR-1);
        strip->stripdata= se= MEM_callocN(totsel*sizeof(StripElem), "stripelem");
 
        for(a=0; a<sfile->totfile; a++) {
@@ -515,6 +595,7 @@ static void sfile_to_mv_sequence(SpaceFile *sfile, int cfra, int machine)
        Strip *strip;
        StripElem *se;
        int totframe, a;
+       char name[160], rel[160];
        char str[FILE_MAXDIR+FILE_MAXFILE];
 
        totframe= 0;
@@ -525,7 +606,8 @@ static void sfile_to_mv_sequence(SpaceFile *sfile, int cfra, int machine)
        /* is it a movie? */
        anim = openanim(str, IB_rect);
        if(anim==0) {
-               error("The selected file is not a movie");
+               error("The selected file is not a movie or "
+                     "FFMPEG-support not compiled in!");
                return;
        }
 
@@ -536,14 +618,23 @@ static void sfile_to_mv_sequence(SpaceFile *sfile, int cfra, int machine)
        seq->len= totframe;
        seq->type= SEQ_MOVIE;
        seq->anim= anim;
+       seq->anim_preseek = IMB_anim_get_preseek(anim);
 
        calc_sequence(seq);
+       
+       if(sfile->flag & FILE_STRINGCODE) {
+               strcpy(name, sfile->dir);
+               strcpy(rel, G.sce);
+               BLI_makestringcode(rel, name);
+       } else {
+               strcpy(name, sfile->dir);
+       }
 
        /* strip and stripdata */
        seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
        strip->len= totframe;
        strip->us= 1;
-       strncpy(strip->dir, sfile->dir, FILE_MAXDIR-1);
+       strncpy(strip->dir, name, FILE_MAXDIR-1);
        strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem");
 
        /* name movie in first strip */
@@ -558,7 +649,8 @@ static void sfile_to_mv_sequence(SpaceFile *sfile, int cfra, int machine)
        strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1);
 }
 
-static Sequence *sfile_to_snd_sequence(SpaceFile *sfile, int cfra, int machine)
+static Sequence *sfile_to_ramsnd_sequence(SpaceFile *sfile, 
+                                         int cfra, int machine)
 {
        Sequence *seq;
        bSound *sound;
@@ -566,6 +658,7 @@ static Sequence *sfile_to_snd_sequence(SpaceFile *sfile, int cfra, int machine)
        StripElem *se;
        double totframe;
        int a;
+       char name[160], rel[160];
        char str[256];
 
        totframe= 0.0;
@@ -591,16 +684,24 @@ static Sequence *sfile_to_snd_sequence(SpaceFile *sfile, int cfra, int machine)
        /* make seq */
        seq= alloc_sequence(cfra, machine);
        seq->len= totframe;
-       seq->type= SEQ_SOUND;
+       seq->type= SEQ_RAM_SOUND;
        seq->sound = sound;
 
        calc_sequence(seq);
+       
+       if(sfile->flag & FILE_STRINGCODE) {
+               strcpy(name, sfile->dir);
+               strcpy(rel, G.sce);
+               BLI_makestringcode(rel, name);
+       } else {
+               strcpy(name, sfile->dir);
+       }
 
        /* strip and stripdata */
        seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
        strip->len= totframe;
        strip->us= 1;
-       strncpy(strip->dir, sfile->dir, FILE_MAXDIR-1);
+       strncpy(strip->dir, name, FILE_MAXDIR-1);
        strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem");
 
        /* name sound in first strip */
@@ -618,6 +719,68 @@ static Sequence *sfile_to_snd_sequence(SpaceFile *sfile, int cfra, int machine)
        return seq;
 }
 
+static void sfile_to_hdsnd_sequence(SpaceFile *sfile, int cfra, int machine)
+{
+       Sequence *seq;
+       struct hdaudio *hdaudio;
+       Strip *strip;
+       StripElem *se;
+       int totframe, a;
+       char name[160], rel[160];
+       char str[FILE_MAXDIR+FILE_MAXFILE];
+
+       totframe= 0;
+
+       strncpy(str, sfile->dir, FILE_MAXDIR-1);
+       strncat(str, sfile->file, FILE_MAXDIR-1);
+
+       /* is it a sound file? */
+       hdaudio = sound_open_hdaudio(str);
+       if(hdaudio==0) {
+               error("The selected file is not a sound file or "
+                     "FFMPEG-support not compiled in!");
+               return;
+       }
+
+       totframe= sound_hdaudio_get_duration(hdaudio, G.scene->r.frs_sec);
+
+       /* make seq */
+       seq= alloc_sequence(cfra, machine);
+       seq->len= totframe;
+       seq->type= SEQ_HD_SOUND;
+       seq->hdaudio= hdaudio;
+
+       calc_sequence(seq);
+       
+       if(sfile->flag & FILE_STRINGCODE) {
+               strcpy(name, sfile->dir);
+               strcpy(rel, G.sce);
+               BLI_makestringcode(rel, name);
+       } else {
+               strcpy(name, sfile->dir);
+       }
+
+       /* strip and stripdata */
+       seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+       strip->len= totframe;
+       strip->us= 1;
+       strncpy(strip->dir, name, FILE_MAXDIR-1);
+       strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem");
+
+       /* name movie in first strip */
+       strncpy(se->name, sfile->file, FILE_MAXFILE-1);
+
+       for(a=1; a<=totframe; a++, se++) {
+               se->ok= 2;
+               se->ibuf = 0;
+               se->nr= a;
+       }
+
+       /* last active name */
+       strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1);
+}
+
+
 static void add_image_strips(char *name)
 {
        SpaceFile *sfile;
@@ -715,7 +878,71 @@ static void add_movie_strip(char *name)
 
 }
 
-static void add_sound_strip(char *name)
+static void add_movie_and_hdaudio_strip(char *name)
+{
+       SpaceFile *sfile;
+       float x, y;
+       int cfra, machine;
+       short mval[2];
+
+       deselect_all_seq();
+
+       /* restore windowmatrices */
+       areawinset(curarea->win);
+       drawseqspace(curarea, curarea->spacedata.first);
+
+       /* search sfile */
+       sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+       if(sfile==0) return;
+
+       /* where will it be */
+       getmouseco_areawin(mval);
+       areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+       cfra= (int)(x+0.5);
+       machine= (int)(y+0.5);
+
+       waitcursor(1);
+
+       /* read directory itself */
+       sfile_to_hdsnd_sequence(sfile, cfra, machine);
+       sfile_to_mv_sequence(sfile, cfra, machine);
+
+       waitcursor(0);
+
+       BIF_undo_push("Add movie and HD-audio strip Sequencer");
+       transform_seq('g', 0);
+
+}
+
+static void add_sound_strip_ram(char *name)
+{
+       SpaceFile *sfile;
+       float x, y;
+       int cfra, machine;
+       short mval[2];
+
+       deselect_all_seq();
+
+       sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+       if (sfile==0) return;
+
+       /* where will it be */
+       getmouseco_areawin(mval);
+       areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+       cfra= (int)(x+0.5);
+       machine= (int)(y+0.5);
+
+       waitcursor(1);
+
+       sfile_to_ramsnd_sequence(sfile, cfra, machine);
+
+       waitcursor(0);
+
+       BIF_undo_push("Add ram sound strip Sequencer");
+       transform_seq('g', 0);
+}
+
+static void add_sound_strip_hd(char *name)
 {
        SpaceFile *sfile;
        float x, y;
@@ -735,11 +962,11 @@ static void add_sound_strip(char *name)
 
        waitcursor(1);
 
-       sfile_to_snd_sequence(sfile, cfra, machine);
+       sfile_to_hdsnd_sequence(sfile, cfra, machine);
 
        waitcursor(0);
 
-       BIF_undo_push("Add sound strip Sequencer");
+       BIF_undo_push("Add hd sound strip Sequencer");
        transform_seq('g', 0);
 }
 
@@ -749,6 +976,7 @@ static void reload_sound_strip(char *name)
        Editing *ed;
        Sequence *seq, *seqact;
        SpaceFile *sfile;
+       Sequence *last_seq= get_last_seq();
 
        ed= G.scene->ed;
 
@@ -791,6 +1019,7 @@ static void reload_image_strip(char *name)
        Editing *ed;
        Sequence *seq, *seqact;
        SpaceFile *sfile;
+       Sequence *last_seq= get_last_seq();
 
        ed= G.scene->ed;
 
@@ -816,17 +1045,7 @@ static void reload_image_strip(char *name)
                free_sequence(seq);
                BLI_remlink(ed->seqbasep, seq);
 
-               seq= ed->seqbasep->first;
-               while(seq) {
-                       if(seq->type & SEQ_EFFECT) {
-                               /* new_stripdata is clear */
-                               if(seq->seq1==seqact || seq->seq2==seqact || seq->seq3==seqact) {
-                                       calc_sequence(seq);
-                                       new_stripdata(seq);
-                               }
-                       }
-                       seq= seq->next;
-               }
+               update_changed_seq_and_deps(seqact, 1, 1);
        }
        waitcursor(0);
 
@@ -846,49 +1065,60 @@ static int event_to_efftype(int event)
        if(event==10) return SEQ_PLUGIN;
        if(event==13) return SEQ_WIPE;
        if(event==14) return SEQ_GLOW;
+       if(event==15) return SEQ_TRANSFORM;
+       if(event==16) return SEQ_COLOR;
+       if(event==17) return SEQ_SPEED;
        return 0;
 }
 
-static int add_seq_effect(int type)
+static int seq_effect_find_selected(Editing *ed, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3)
 {
-       Editing *ed;
-       Sequence *seq, *seq1, *seq2, *seq3;
-       Strip *strip;
-       float x, y;
-       int cfra, machine;
-       short mval[2];
-
-       if(G.scene->ed==0) return 0;
-       ed= G.scene->ed;
+       Sequence *seq1= 0, *seq2= 0, *seq3= 0, *seq;
+       
+       if (!activeseq)
+               seq2= get_last_seq();
 
-       /* apart from last_seq there have to be 2 selected sequences */
-       seq1= seq3= 0;
-       seq2= last_seq;         /* last_seq changes with alloc_seq! */
-       seq= ed->seqbasep->first;
-       while(seq) {
+       for(seq=ed->seqbasep->first; seq; seq=seq->next) {
                if(seq->flag & SELECT) {
-                       if (seq->type == SEQ_SOUND) { error("Can't apply effects to audio sequence strips"); return 0; }
-                       if(seq != seq2) {
-                               if(seq1==0) seq1= seq;
-                               else if(seq3==0) seq3= seq;
-                               else {
-                                       seq1= 0;
-                                       break;
-                               }
+                       if (seq->type == SEQ_RAM_SOUND
+                           || seq->type == SEQ_HD_SOUND) { 
+                               error("Can't apply effects to "
+                                     "audio sequence strips");
+                               return 0;
+                       }
+                       if((seq != activeseq) && (seq != seq2)) {
+                                if(seq2==0) seq2= seq;
+                                else if(seq1==0) seq1= seq;
+                                else if(seq3==0) seq3= seq;
+                                else {
+                                       error("Can't apply effect to more than 3 sequence strips");
+                                       return 0;
+                                }
                        }
                }
-               seq= seq->next;
        }
+       
+       /* make sequence selection a little bit more intuitive
+          for 3 strips: the last-strip should be sequence3 */
+       if (seq3 != 0 && seq2 != 0) {
+               Sequence *tmp = seq2;
+               seq2 = seq3;
+               seq3 = tmp;
+       }
+       
 
-       if(type==10 || type==13 || type==14) {  /* plugin: minimal 1 select */
+       switch(get_sequence_effect_num_inputs(type)) {
+       case 0:
+               seq1 = seq2 = seq3 = 0;
+               break;
+       case 1:
                if(seq2==0)  {
                        error("Need at least one selected sequence strip");
                        return 0;
                }
                if(seq1==0) seq1= seq2;
                if(seq3==0) seq3= seq2;
-       }
-       else {
+       case 2:
                if(seq1==0 || seq2==0) {
                        error("Need 2 selected sequence strips");
                        return 0;
@@ -896,6 +1126,29 @@ static int add_seq_effect(int type)
                if(seq3==0) seq3= seq2;
        }
 
+       *selseq1= seq1;
+       *selseq2= seq2;
+       *selseq3= seq3;
+
+       return 1;
+}
+
+static int add_seq_effect(int type, char *str)
+{
+       Editing *ed;
+       Sequence *newseq, *seq1, *seq2, *seq3;
+       Strip *strip;
+       float x, y;
+       int cfra, machine;
+       short mval[2];
+       struct SeqEffectHandle sh;
+
+       if(G.scene->ed==0) return 0;
+       ed= G.scene->ed;
+
+       if(!seq_effect_find_selected(ed, NULL, event_to_efftype(type), &seq1, &seq2, &seq3))
+               return 0;
+
        deselect_all_seq();
 
        /* where will it be (cfra is not realy needed) */
@@ -904,62 +1157,69 @@ static int add_seq_effect(int type)
        cfra= (int)(x+0.5);
        machine= (int)(y+0.5);
 
-       seq= alloc_sequence(cfra, machine);
+       /* allocate and initialize */
+       newseq= alloc_sequence(cfra, machine);
+       newseq->type= event_to_efftype(type);
 
-       seq->type= event_to_efftype(type);
+       sh = get_sequence_effect(newseq);
 
-       /* Allocate variable structs for effects with settings */
-       if(seq->type==SEQ_WIPE){
-               init_wipe_effect(seq);
-       }
-       else if(seq->type==SEQ_GLOW){
-               init_glow_effect(seq);
-       }
+       newseq->seq1= seq1;
+       newseq->seq2= seq2;
+       newseq->seq3= seq3;
 
-       if(seq->type==SEQ_ALPHAUNDER || seq->type==SEQ_ALPHAOVER) {
-               seq->seq2= seq1;
-               seq->seq1= seq2;
-       }
-       else {
-               seq->seq1= seq1;
-               seq->seq2= seq2;
+       sh.init(newseq);
+
+       if (!seq1) {
+               newseq->len= 1;
+               newseq->startstill= 25;
+               newseq->endstill= 24;
        }
-       seq->seq3= seq3;
-       calc_sequence(seq);
 
-       seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
-       strip->len= seq->len;
+       calc_sequence(newseq);
+
+       newseq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+       strip->len= newseq->len;
        strip->us= 1;
-       if(seq->len>0) strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+       if(newseq->len>0)
+               strip->stripdata= MEM_callocN(newseq->len*sizeof(StripElem), "stripelem");
 
-       BIF_undo_push("Add effect strip Sequencer");
+       /* initialize plugin */
+       if(newseq->type == SEQ_PLUGIN) {
+               sh.init_plugin(newseq, str);
 
-       return 1;
-}
+               if(newseq->plugin==0) {
+                       BLI_remlink(ed->seqbasep, newseq);
+                       free_sequence(newseq);
+                       set_last_seq(NULL);
+                       return 0;
+               }
+       }
 
-static void load_plugin_seq(char *str)         /* called from fileselect */
-{
-       Editing *ed;
+       /* set find a free spot to but the strip */
+       if (newseq->seq1) {
+               newseq->machine= MAX3(newseq->seq1->machine, 
+                                     newseq->seq2->machine,
+                                     newseq->seq3->machine);
+       }
+       if(test_overlap_seq(newseq)) shuffle_seq(newseq);
 
-       add_seq_effect(10);             /* this sets last_seq */
+       update_changed_seq_and_deps(newseq, 1, 1);
 
-       free_plugin_seq(last_seq->plugin);
+       /* push undo and go into grab mode */
+       if(newseq->type == SEQ_PLUGIN) {
+               BIF_undo_push("Add plugin strip Sequencer");
+       } else {
+               BIF_undo_push("Add effect strip Sequencer");
+       }
 
-       last_seq->plugin= (PluginSeq *)add_plugin_seq(str, last_seq->name+2);
+       transform_seq('g', 0);
 
-       if(last_seq->plugin==0) {
-               ed= G.scene->ed;
-               BLI_remlink(ed->seqbasep, last_seq);
-               free_sequence(last_seq);
-               last_seq= 0;
-       }
-       else {
-               last_seq->machine= MAX3(last_seq->seq1->machine, last_seq->seq2->machine, last_seq->seq3->machine);
-               if( test_overlap_seq(last_seq) ) shuffle_seq(last_seq);
+       return 1;
+}
 
-               BIF_undo_push("Add plugin strip Sequencer");
-               transform_seq('g', 0);
-       }
+static void load_plugin_seq(char *str)         /* called from fileselect */
+{
+       add_seq_effect(10, str);
 }
 
 void add_sequence(int type)
@@ -985,9 +1245,15 @@ void add_sequence(int type)
                case SEQ_MOVIE:
                        event = 102;
                        break;
-               case SEQ_SOUND:
+               case SEQ_RAM_SOUND:
                        event = 103;
                        break;
+               case SEQ_HD_SOUND:
+                       event = 104;
+                       break;
+               case SEQ_MOVIE_AND_HD_SOUND:
+                       event = 105;
+                       break;
                case SEQ_PLUGIN:
                        event = 10;
                        break;
@@ -1021,13 +1287,46 @@ void add_sequence(int type)
                case SEQ_GLOW:
                        event = 14;
                        break;
+               case SEQ_TRANSFORM:
+                       event = 15;
+                       break;
+               case SEQ_COLOR:
+                       event = 16;
+                       break;
+               case SEQ_SPEED:
+                       event = 17;
+                       break;
                default:
                        event = 0;
                        break;
                }
        }
        else {
-               event= pupmenu("Add Sequence Strip%t|Images%x1|Movie%x102|Audio%x103|Scene%x101|Plugin%x10|Cross%x2|Gamma Cross%x3|Add%x4|Sub%x5|Mul%x6|Alpha Over%x7|Alpha Under%x8|Alpha Over Drop%x9|Wipe%x13|Glow%x14");
+               event= pupmenu("Add Sequence Strip%t"
+                              "|Images%x1"
+                              "|Movie%x102"
+#ifdef WITH_FFMPEG
+                                  "|Movie + Audio (HD)%x105"
+                              "|Audio (RAM)%x103"
+                              "|Audio (HD)%x104"
+#else
+                                  "|Audio (Wav)%x103"
+#endif
+                              "|Scene%x101"
+                              "|Plugin%x10"
+                              "|Cross%x2"
+                              "|Gamma Cross%x3"
+                              "|Add%x4"
+                              "|Sub%x5"
+                              "|Mul%x6"
+                              "|Alpha Over%x7"
+                              "|Alpha Under%x8"
+                              "|Alpha Over Drop%x9"
+                              "|Wipe%x13"
+                              "|Glow%x14"
+                              "|Transforms%x15"
+                              "|Color Generator%x16"
+                              "|Speed Control%x17");
        }
 
        if(event<1) return;
@@ -1043,6 +1342,9 @@ void add_sequence(int type)
 
                activate_fileselect(FILE_SPECIAL, "Select Images", last_imagename, add_image_strips);
                break;
+       case 105:
+               activate_fileselect(FILE_SPECIAL, "Select Movie+Audio", last_imagename, add_movie_and_hdaudio_strip);
+               break;
        case 102:
 
                activate_fileselect(FILE_SPECIAL, "Select Movie", last_imagename, add_movie_strip);
@@ -1078,6 +1380,8 @@ void add_sequence(int type)
                                seq->len= sce->r.efra - sce->r.sfra + 1;
 
                                seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+                               strncpy(seq->name + 2, sce->id.name + 2, 
+                                       sizeof(seq->name) - 2);
                                strip->len= seq->len;
                                strip->us= 1;
                                if(seq->len>0) strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
@@ -1100,67 +1404,103 @@ void add_sequence(int type)
        case 10:
        case 13:
        case 14:
-
-               if(last_seq==0) error("Need at least one active sequence strip");
-               else if(event==10) {
+       case 15:
+       case 16:
+       case 17:
+               if(get_last_seq()==0 && 
+                  get_sequence_effect_num_inputs( event_to_efftype(event))> 0)
+                       error("Need at least one active sequence strip");
+               else if(event==10)
                        activate_fileselect(FILE_SPECIAL, "Select Plugin", U.plugseqdir, load_plugin_seq);
-               }
-               else {
-                       if( add_seq_effect(event) ) transform_seq('g', 0);
-               }
+               else
+                       add_seq_effect(event, NULL);
 
                break;
        case 103:
                if (!last_sounddir[0]) strncpy(last_sounddir, U.sounddir, FILE_MAXDIR-1);
-               activate_fileselect(FILE_SPECIAL, "Select Wav", last_sounddir, add_sound_strip);
+               activate_fileselect(FILE_SPECIAL, "Select Audio (RAM)", last_sounddir, add_sound_strip_ram);
+               break;
+       case 104:
+               if (!last_sounddir[0]) strncpy(last_sounddir, U.sounddir, FILE_MAXDIR-1);
+               activate_fileselect(FILE_SPECIAL, "Select Audio (HD)", last_sounddir, add_sound_strip_hd);
                break;
        }
 }
 
 void change_sequence(void)
 {
+       Sequence *last_seq= get_last_seq();
        Scene *sce;
        short event;
 
        if(last_seq==0) return;
 
        if(last_seq->type & SEQ_EFFECT) {
-               event= pupmenu("Change Effect%t|Switch A <-> B %x1|Switch B <-> C %x10|Plugin%x11|Recalculate%x12|Cross%x2|Gamma Cross%x3|Add%x4|Sub%x5|Mul%x6|Alpha Over%x7|Alpha Under%x8|Alpha Over Drop%x9|Wipe%x13|Glow%x14");
-               if(event>0) {
+               event = pupmenu("Change Effect%t"
+                               "|Switch A <-> B %x1"
+                               "|Switch B <-> C %x10"
+                               "|Plugin%x11"
+                               "|Recalculate%x12"
+                               "|Cross%x2"
+                               "|Gamma Cross%x3"
+                               "|Add%x4"
+                               "|Sub%x5"
+                               "|Mul%x6"
+                               "|Alpha Over%x7"
+                               "|Alpha Under%x8"
+                               "|Alpha Over Drop%x9"
+                               "|Wipe%x13"
+                               "|Glow%x14"
+                               "|Transform%x15"
+                               "|Color Generator%x16"
+                               "|Speed Control%x17");
+               if(event > 0) {
                        if(event==1) {
-                               SWAP(Sequence *, last_seq->seq1, last_seq->seq2);
+                               SWAP(Sequence *,last_seq->seq1,last_seq->seq2);
                        }
                        else if(event==10) {
-                               SWAP(Sequence *, last_seq->seq2, last_seq->seq3);
+                               SWAP(Sequence *,last_seq->seq2,last_seq->seq3);
                        }
                        else if(event==11) {
-                               activate_fileselect(FILE_SPECIAL, "Select Plugin", U.plugseqdir, change_plugin_seq);
+                               activate_fileselect(
+                                       FILE_SPECIAL, "Select Plugin", 
+                                       U.plugseqdir, change_plugin_seq);
                        }
-                       else if(event==12);     /* recalculate: only new_stripdata */
+                       else if(event==12);     
+                                /* recalculate: only new_stripdata */
                        else {
-                               /* to be sure, free plugin */
-                               free_plugin_seq(last_seq->plugin);
-                               last_seq->plugin= 0;
-                               last_seq->type= event_to_efftype(event);
-
-                               switch(last_seq->type){
-                                       case SEQ_WIPE:
-                                               init_wipe_effect(last_seq);
-                                               break;
-                                       case SEQ_GLOW:
-                                               init_glow_effect(last_seq);
-                                               break;
+                               /* free previous effect and init new effect */
+                               struct SeqEffectHandle sh;
+
+                               if (get_sequence_effect_num_inputs(
+                                           last_seq->type)
+                                   < get_sequence_effect_num_inputs(
+                                           event_to_efftype(event))) {
+                                       error("New effect needs more "
+                                             "input strips!");
+                               } else {
+                                       sh = get_sequence_effect(last_seq);
+                                       sh.free(last_seq);
+                                       
+                                       last_seq->type 
+                                               = event_to_efftype(event);
+                                       
+                                       sh = get_sequence_effect(last_seq);
+                                       sh.init(last_seq);
                                }
-
                        }
-                       new_stripdata(last_seq);
+
+                       update_changed_seq_and_deps(last_seq, 0, 1);
                        allqueue(REDRAWSEQ, 0);
                        BIF_undo_push("Change effect Sequencer");
                }
        }
        else if(last_seq->type == SEQ_IMAGE) {
                if(okee("Change images")) {
-                       activate_fileselect(FILE_SPECIAL, "Select Images", last_imagename, reload_image_strip);
+                       activate_fileselect(FILE_SPECIAL, 
+                                           "Select Images", 
+                                           last_imagename, 
+                                           reload_image_strip);
                }
        }
        else if(last_seq->type == SEQ_MOVIE) {
@@ -1174,8 +1514,7 @@ void change_sequence(void)
 
                        last_seq->len= sce->r.efra - sce->r.sfra + 1;
                        last_seq->sfra= sce->r.sfra;
-                       new_stripdata(last_seq);
-                       calc_sequence(last_seq);
+                       update_changed_seq_and_deps(last_seq, 1, 1);
 
                        allqueue(REDRAWSEQ, 0);
                }
@@ -1183,35 +1522,87 @@ void change_sequence(void)
 
 }
 
-static int is_a_sequence(Sequence *test)
+void reassign_inputs_seq_effect()
 {
-       Sequence *seq;
-       Editing *ed;
+       Editing *ed= G.scene->ed;
+       Sequence *seq1, *seq2, *seq3, *last_seq = get_last_seq();
 
-       ed= G.scene->ed;
-       if(ed==0 || test==0) return 0;
+       if(last_seq==0 || !(last_seq->type & SEQ_EFFECT)) return;
+       if(ed==0) return;
 
-       seq= ed->seqbasep->first;
-       while(seq) {
-               if(seq==test) return 1;
-               seq= seq->next;
+       if(!seq_effect_find_selected(ed, last_seq, last_seq->type, &seq1, &seq2, &seq3))
+               return;
+
+       /* see reassigning would create a cycle */
+       if(seq_is_predecessor(seq1, last_seq) || seq_is_predecessor(seq2, last_seq) ||
+          seq_is_predecessor(seq3, last_seq)) {
+               error("Can't reassign inputs: no cycles allowed");
+               return;
        }
+       
+       last_seq->seq1 = seq1;
+       last_seq->seq2 = seq2;
+       last_seq->seq3 = seq3;
 
-       return 0;
+       update_changed_seq_and_deps(last_seq, 1, 1);
+
+       allqueue(REDRAWSEQ, 0);
 }
 
-static void recurs_del_seq(ListBase *lb)
+static Sequence *del_seq_find_replace_recurs(Sequence *seq)
+{
+       Sequence *seq1, *seq2, *seq3;
+
+       /* try to find a replacement input sequence, and flag for later deletion if
+          no replacement can be found */
+
+       if(!seq)
+               return NULL;
+       else if(!(seq->type & SEQ_EFFECT))
+               return ((seq->flag & SELECT)? NULL: seq);
+       else if(!(seq->flag & SELECT)) {
+               /* try to find replacement for effect inputs */
+               seq1= del_seq_find_replace_recurs(seq->seq1);
+               seq2= del_seq_find_replace_recurs(seq->seq2);
+               seq3= del_seq_find_replace_recurs(seq->seq3);
+
+               if(seq1==seq->seq1 && seq2==seq->seq2 && seq3==seq->seq3);
+               else if(seq1 || seq2 || seq3) {
+                       seq->seq1= (seq1)? seq1: (seq2)? seq2: seq3;
+                       seq->seq2= (seq2)? seq2: (seq1)? seq1: seq3;
+                       seq->seq3= (seq3)? seq3: (seq1)? seq1: seq2;
+
+                       update_changed_seq_and_deps(seq, 1, 1);
+               }
+               else
+                       seq->flag |= SELECT; /* mark for delete */
+       }
+
+       if (seq->flag & SELECT) {
+               if((seq1 = del_seq_find_replace_recurs(seq->seq1))) return seq1;
+               if((seq2 = del_seq_find_replace_recurs(seq->seq2))) return seq2;
+               if((seq3 = del_seq_find_replace_recurs(seq->seq3))) return seq3;
+               else return NULL;
+       }
+       else
+               return seq;
+}
+
+static void recurs_del_seq_flag(ListBase *lb, short flag, short deleteall)
 {
        Sequence *seq, *seqn;
+       Sequence *last_seq = get_last_seq();
 
        seq= lb->first;
        while(seq) {
                seqn= seq->next;
-               if(seq->flag & SELECT) {
-                       if(seq->type==SEQ_SOUND && seq->sound) seq->sound->id.us--;
+               if((seq->flag & flag) || deleteall) {
+                       if(seq->type==SEQ_RAM_SOUND && seq->sound) 
+                               seq->sound->id.us--;
+
                        BLI_remlink(lb, seq);
-                       if(seq==last_seq) last_seq= 0;
-                       if(seq->type==SEQ_META) recurs_del_seq(&seq->seqbase);
+                       if(seq==last_seq) set_last_seq(0);
+                       if(seq->type==SEQ_META) recurs_del_seq_flag(&seq->seqbase, flag, 1);
                        if(seq->ipo) seq->ipo->id.us--;
                        free_sequence(seq);
                }
@@ -1221,36 +1612,27 @@ static void recurs_del_seq(ListBase *lb)
 
 void del_seq(void)
 {
-       Sequence *seq, *seqn;
+       Sequence *seq;
        MetaStack *ms;
        Editing *ed;
-       int doit;
 
        if(okee("Erase selected")==0) return;
 
        ed= G.scene->ed;
        if(ed==0) return;
 
-       recurs_del_seq(ed->seqbasep);
+       /* free imbufs of all dependent strips */
+       for(seq=ed->seqbasep->first; seq; seq=seq->next)
+               if(seq->flag & SELECT)
+                       update_changed_seq_and_deps(seq, 1, 0);
 
-       /* test effects */
-       doit= 1;
-       while(doit) {
-               doit= 0;
-               seq= ed->seqbasep->first;
-               while(seq) {
-                       seqn= seq->next;
-                       if(seq->type & SEQ_EFFECT) {
-                               if( is_a_sequence(seq->seq1)==0 || is_a_sequence(seq->seq2)==0 || is_a_sequence(seq->seq3)==0 ) {
-                                       BLI_remlink(ed->seqbasep, seq);
-                                       if(seq==last_seq) last_seq= 0;
-                                       free_sequence(seq);
-                                       doit= 1;
-                               }
-                       }
-                       seq= seqn;
-               }
-       }
+       /* for effects, try to find a replacement input */
+       for(seq=ed->seqbasep->first; seq; seq=seq->next)
+               if((seq->type & SEQ_EFFECT) && !(seq->flag & SELECT))
+                       del_seq_find_replace_recurs(seq);
+
+       /* delete all selected strips */
+       recurs_del_seq_flag(ed->seqbasep, SELECT, 0);
 
        /* updates lengths etc */
        seq= ed->seqbasep->first;
@@ -1271,8 +1653,6 @@ void del_seq(void)
        allqueue(REDRAWSEQ, 0);
 }
 
-
-
 static void recurs_dupli_seq(ListBase *old, ListBase *new)
 {
        Sequence *seq, *seqn;
@@ -1298,7 +1678,7 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new)
                                seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
 
                                seqn->seqbase.first= seqn->seqbase.last= 0;
-                               recurs_dupli_seq(&seq->seqbase, &seqn->seqbase);
+                               recurs_dupli_seq(&seq->seqbase,&seqn->seqbase);
 
                        }
                        else if(seq->type == SEQ_SCENE) {
@@ -1308,7 +1688,7 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new)
 
                                seqn->strip= MEM_dupallocN(seq->strip);
 
-                               if(seq->len>0) seqn->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+                               if(seq->len>0) seqn->strip->stripdata = MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
 
                                seq->flag &= SEQ_DESEL;
                                seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
@@ -1336,7 +1716,7 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new)
                                seq->flag &= SEQ_DESEL;
                                seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
                        }
-                       else if(seq->type == SEQ_SOUND) {
+                       else if(seq->type == SEQ_RAM_SOUND) {
                                seqn= MEM_dupallocN(seq);
                                seq->newseq= seqn;
                                BLI_addtail(new, seqn);
@@ -1361,6 +1741,32 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new)
                                seq->flag &= SEQ_DESEL;
                                seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
                        }
+                       else if(seq->type == SEQ_HD_SOUND) {
+                               seqn= MEM_dupallocN(seq);
+                               seq->newseq= seqn;
+                               BLI_addtail(new, seqn);
+
+                               seqn->strip= MEM_dupallocN(seq->strip);
+                               seqn->anim= 0;
+                               seqn->hdaudio
+                                       = sound_copy_hdaudio(seq->hdaudio);
+                               if(seqn->ipo) seqn->ipo->id.us++;
+
+                               if(seqn->len>0) {
+                                       seqn->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+                                       /* copy first elem */
+                                       *seqn->strip->stripdata= *seq->strip->stripdata;
+                                       se= seqn->strip->stripdata;
+                                       a= seq->len;
+                                       while(a--) {
+                                               se->ok= 1;
+                                               se++;
+                                       }
+                               }
+
+                               seq->flag &= SEQ_DESEL;
+                               seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
+                       }
                        else if(seq->type < SEQ_EFFECT) {
                                seqn= MEM_dupallocN(seq);
                                seq->newseq= seqn;
@@ -1372,30 +1778,30 @@ static void recurs_dupli_seq(ListBase *old, ListBase *new)
                                seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
                        }
                        else {
-                               if(seq->seq1->newseq) {
-
-                                       seqn= MEM_dupallocN(seq);
-                                       seq->newseq= seqn;
-                                       BLI_addtail(new, seqn);
+                               seqn= MEM_dupallocN(seq);
+                               seq->newseq= seqn;
+                               BLI_addtail(new, seqn);
 
-                                       seqn->seq1= seq->seq1->newseq;
-                                       if(seq->seq2 && seq->seq2->newseq) seqn->seq2= seq->seq2->newseq;
-                                       if(seq->seq3 && seq->seq3->newseq) seqn->seq3= seq->seq3->newseq;
+                               if(seq->seq1 && seq->seq1->newseq) seqn->seq1= seq->seq1->newseq;
+                               if(seq->seq2 && seq->seq2->newseq) seqn->seq2= seq->seq2->newseq;
+                               if(seq->seq3 && seq->seq3->newseq) seqn->seq3= seq->seq3->newseq;
 
-                                       if(seqn->ipo) seqn->ipo->id.us++;
+                               if(seqn->ipo) seqn->ipo->id.us++;
 
-                                       if(seq->plugin) {
-                                               seqn->plugin= MEM_dupallocN(seq->plugin);
-                                               open_plugin_seq(seqn->plugin, seqn->name+2);
-                                       }
-                                       seqn->strip= MEM_dupallocN(seq->strip);
+                               if (seq->type & SEQ_EFFECT) {
+                                       struct SeqEffectHandle sh;
+                                       sh = get_sequence_effect(seq);
+                                       if(sh.copy)
+                                               sh.copy(seq, seqn);
+                               }
 
-                                       if(seq->len>0) seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+                               seqn->strip= MEM_dupallocN(seq->strip);
 
-                                       seq->flag &= SEQ_DESEL;
+                               if(seq->len>0) seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
 
-                                       seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
-                               }
+                               seq->flag &= SEQ_DESEL;
+                               
+                               seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
                        }
 
                }
@@ -1530,7 +1936,7 @@ void make_meta(void)
        Sequence *seq, *seqm, *next;
        Editing *ed;
        int tot;
-
+       
        ed= G.scene->ed;
        if(ed==0) return;
 
@@ -1540,7 +1946,10 @@ void make_meta(void)
        while(seq) {
                if(seq->flag & SELECT) {
                        tot++;
-                       if (seq->type == SEQ_SOUND) { error("Can't make Meta Strip from audio"); return; }
+                       if (seq->type == SEQ_RAM_SOUND) { 
+                               error("Can't make Meta Strip from audio"); 
+                               return; 
+                       }
                }
                seq= seq->next;
        }
@@ -1553,15 +1962,21 @@ void make_meta(void)
        while(seq) {
                if(seq->flag & SELECT) {
                        if(seq->type & SEQ_EFFECT) {
-                               if((seq->seq1->flag & SELECT)==0) tot= 0;
-                               if((seq->seq2->flag & SELECT)==0) tot= 0;
-                               if((seq->seq3->flag & SELECT)==0) tot= 0;
+                               if(seq->seq1 && 
+                                  (seq->seq1->flag & SELECT)==0) tot= 0;
+                               if(seq->seq2 &&
+                                  (seq->seq2->flag & SELECT)==0) tot= 0;
+                               if(seq->seq3 &&
+                                  (seq->seq3->flag & SELECT)==0) tot= 0;
                        }
                }
                else if(seq->type & SEQ_EFFECT) {
-                       if(seq->seq1->flag & SELECT) tot= 0;
-                       if(seq->seq2->flag & SELECT) tot= 0;
-                       if(seq->seq3->flag & SELECT) tot= 0;
+                       if(seq->seq1 &&
+                          (seq->seq1->flag & SELECT)) tot= 0;
+                       if(seq->seq2 &&
+                          (seq->seq2->flag & SELECT)) tot= 0;
+                       if(seq->seq3 &&
+                          (seq->seq3->flag & SELECT)) tot= 0;
                }
                if(tot==0) break;
                seq= seq->next;
@@ -1592,18 +2007,25 @@ void make_meta(void)
        seqm->strip->len= seqm->len;
        seqm->strip->us= 1;
        if(seqm->len) seqm->strip->stripdata= MEM_callocN(seqm->len*sizeof(StripElem), "metastripdata");
-
        set_meta_stripdata(seqm);
 
        BIF_undo_push("Make Meta Sequencer");
        allqueue(REDRAWSEQ, 0);
 }
 
+static int seq_depends_on_meta(Sequence *seq, Sequence *seqm)
+{
+       if (seq == seqm) return 1;
+       else if (seq->seq1 && seq_depends_on_meta(seq->seq1, seqm)) return 1;
+       else if (seq->seq2 && seq_depends_on_meta(seq->seq2, seqm)) return 1;
+       else if (seq->seq3 && seq_depends_on_meta(seq->seq3, seqm)) return 1;
+       else return 0;
+}
+
 void un_meta(void)
 {
        Editing *ed;
-       Sequence *seq, *seqn;
-       int doit;
+       Sequence *seq, *last_seq = get_last_seq();
 
        ed= G.scene->ed;
        if(ed==0) return;
@@ -1620,25 +2042,12 @@ void un_meta(void)
        BLI_remlink(ed->seqbasep, last_seq);
        free_sequence(last_seq);
 
-       /* test effects */
-       doit= 1;
-       while(doit) {
-               doit= 0;
-               seq= ed->seqbasep->first;
-               while(seq) {
-                       seqn= seq->next;
-                       if(seq->type & SEQ_EFFECT) {
-                               if( is_a_sequence(seq->seq1)==0 || is_a_sequence(seq->seq2)==0 || is_a_sequence(seq->seq3)==0 ) {
-                                       BLI_remlink(ed->seqbasep, seq);
-                                       if(seq==last_seq) last_seq= 0;
-                                       free_sequence(seq);
-                                       doit= 1;
-                               }
-                       }
-                       seq= seqn;
-               }
-       }
+       /* emtpy meta strip, delete all effects depending on it */
+       for(seq=ed->seqbasep->first; seq; seq=seq->next)
+               if((seq->type & SEQ_EFFECT) && seq_depends_on_meta(seq, last_seq))
+                       seq->flag |= SEQ_FLAG_DELETE;
 
+       recurs_del_seq_flag(ed->seqbasep, SEQ_FLAG_DELETE, 0);
 
        /* test for effects and overlap */
        WHILE_SEQ(ed->seqbasep) {
@@ -1651,6 +2060,8 @@ void un_meta(void)
        }
        END_SEQ;
 
+       sort_seq();
+
        BIF_undo_push("Un-make Meta Sequencer");
        allqueue(REDRAWSEQ, 0);
 
@@ -1682,10 +2093,10 @@ void exit_meta(void)
                seq= seq->next;
        }
 
-       last_seq= ms->parseq;
+       set_last_seq(ms->parseq);
 
-       last_seq->flag= SELECT;
-       recurs_sel_seq(last_seq);
+       ms->parseq->flag= SELECT;
+       recurs_sel_seq(ms->parseq);
 
        MEM_freeN(ms);
        allqueue(REDRAWSEQ, 0);
@@ -1698,6 +2109,7 @@ void enter_meta(void)
 {
        MetaStack *ms;
        Editing *ed;
+       Sequence *last_seq= get_last_seq();
 
        ed= G.scene->ed;
        if(ed==0) return;
@@ -1714,7 +2126,7 @@ void enter_meta(void)
 
        ed->seqbasep= &last_seq->seqbase;
 
-       last_seq= 0;
+       set_last_seq(NULL);
        allqueue(REDRAWSEQ, 0);
        BIF_undo_push("Enter meta strip Sequence");
 }
@@ -1726,7 +2138,9 @@ void enter_meta(void)
 typedef struct TransSeq {
        int start, machine;
        int startstill, endstill;
+       int startdisp, enddisp;
        int startofs, endofs;
+       int len;
 } TransSeq;
 
 void transform_seq(int mode, int context)
@@ -1824,7 +2238,7 @@ void transform_seq(int mode, int context)
                                                                        seq->startofs= ix;
                                                                        seq->startstill= 0;
                                                                }
-                                                               else if (seq->type != SEQ_SOUND) {
+                                                               else if (seq->type != SEQ_RAM_SOUND && seq->type != SEQ_HD_SOUND) {
                                                                        seq->startstill= -ix;
                                                                        seq->startofs= 0;
                                                                }
@@ -1847,7 +2261,7 @@ void transform_seq(int mode, int context)
                                                                        seq->endofs= -ix;
                                                                        seq->endstill= 0;
                                                                }
-                                                               else if (seq->type != SEQ_SOUND) {
+                                                               else if (seq->type != SEQ_RAM_SOUND && seq->type != SEQ_HD_SOUND) {
                                                                        seq->endstill= ix;
                                                                        seq->endofs= 0;
                                                                }
@@ -1857,7 +2271,7 @@ void transform_seq(int mode, int context)
                                                        }
                                                }
                                                if( (seq->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL))==0 ) {
-                                                       if(seq->type<SEQ_EFFECT) seq->start= ts->start+ ix;
+                                                       if(sequence_is_free_transformable(seq)) seq->start= ts->start+ ix;
 
                                                        if(seq->depth==0) seq->machine= ts->machine+ iy;
 
@@ -1889,9 +2303,9 @@ void transform_seq(int mode, int context)
                                        }
                                }
                                else if(seq->type & SEQ_EFFECT) {
-                                       if(seq->seq1->flag & SELECT) calc_sequence(seq);
-                                       else if(seq->seq2->flag & SELECT) calc_sequence(seq);
-                                       else if(seq->seq3->flag & SELECT) calc_sequence(seq);
+                                       if(seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(seq);
+                                       else if(seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(seq);
+                                       else if(seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(seq);
                                }
                        }
                        END_SEQ;
@@ -1906,7 +2320,9 @@ void transform_seq(int mode, int context)
                                switch(event) {
                                case ESCKEY:
                                case LEFTMOUSE:
+                               case RIGHTMOUSE:
                                case SPACEKEY:
+                               case RETKEY:
                                        afbreek= 1;
                                        break;
                                case MIDDLEMOUSE:
@@ -1925,7 +2341,7 @@ void transform_seq(int mode, int context)
                }
        }
 
-       if(event==ESCKEY) {
+       if((event==ESCKEY) || (event==RIGHTMOUSE)) {
 
                ts= transmain;
                WHILE_SEQ(ed->seqbasep) {
@@ -1942,9 +2358,9 @@ void transform_seq(int mode, int context)
 
                                ts++;
                        } else if(seq->type & SEQ_EFFECT) {
-                               if(seq->seq1->flag & SELECT) calc_sequence(seq);
-                               else if(seq->seq2->flag & SELECT) calc_sequence(seq);
-                               else if(seq->seq3->flag & SELECT) calc_sequence(seq);
+                               if(seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(seq);
+                               else if(seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(seq);
+                               else if(seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(seq);
                        }
 
                }
@@ -1979,71 +2395,134 @@ void transform_seq(int mode, int context)
        allqueue(REDRAWSEQ, 0);
 }
 
-
-void clever_numbuts_seq(void)
+void seq_cut(int cutframe)
 {
-       PluginSeq *pis;
-       StripElem *se;
-       VarStruct *varstr;
-       int a;
-
-       if(last_seq==0) return;
-       if(last_seq->type==SEQ_PLUGIN) {
-               pis= last_seq->plugin;
-               if(pis->vars==0) return;
-
-               varstr= pis->varstr;
-               if(varstr) {
-                       for(a=0; a<pis->vars; a++, varstr++) {
-                               add_numbut(a, varstr->type, varstr->name, varstr->min, varstr->max, &(pis->data[a]), varstr->tip);
-                       }
-
-                       if( do_clever_numbuts(pis->pname, pis->vars, REDRAW) ) {
-                               new_stripdata(last_seq);
-                               free_imbuf_effect_spec(CFRA);
-                               allqueue(REDRAWSEQ, 0);
-                       }
+       Editing *ed;
+       Sequence *seq;
+       TransSeq *ts, *transmain;
+       int tot=0;
+       ListBase newlist;
+       
+       ed= G.scene->ed;
+       if(ed==0) return;
+       
+       /* test for validity */
+       for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+               if(seq->flag & SELECT) {
+                       if(cutframe > seq->startdisp && cutframe < seq->enddisp)
+                               if(seq->type==SEQ_META) break;
                }
        }
-       else if(last_seq->type==SEQ_MOVIE) {
-
-               if(last_seq->mul==0.0) last_seq->mul= 1.0;
-
-               add_numbut(0, TEX, "Name:", 0.0, 21.0, last_seq->name+2, 0);
-               add_numbut(1, TOG|SHO|BIT|4, "FilterY", 0.0, 1.0, &last_seq->flag, 0);
-               /* warning: only a single bit-button possible: we work at copied data! */
-               add_numbut(2, NUM|FLO, "Mul", 0.01, 5.0, &last_seq->mul, 0);
-
-               if( do_clever_numbuts("Movie", 3, REDRAW) ) {
-                       se= last_seq->curelem;
-
-                       if(se && se->ibuf ) {
-                               IMB_freeImBuf(se->ibuf);
-                               se->ibuf= 0;
-                       }
-                       allqueue(REDRAWSEQ, 0);
+       if(seq) {
+               error("Cannot cut Meta strips");
+               return;
+       }
+       
+       /* we build an array of TransSeq, to denote which strips take part in cutting */
+       for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+               if(seq->flag & SELECT) {
+                       if(cutframe > seq->startdisp && cutframe < seq->enddisp)
+                               tot++;
+                       else
+                               seq->flag &= ~SELECT;   // bad code, but we need it for recurs_dupli_seq... note that this ~SELECT assumption is used in loops below too (ton)
                }
        }
-       else if(last_seq->type==SEQ_SOUND) {
-
-               add_numbut(0, TEX, "Name:", 0.0, 21.0, last_seq->name+2, 0);
-               add_numbut(1, NUM|FLO, "Gain (dB):", -96.0, 6.0, &last_seq->level, 0);
-               add_numbut(2, NUM|FLO, "Pan:", -1.0, 1.0, &last_seq->pan, 0);
-               add_numbut(3, TOG|SHO|BIT|5, "Mute", 0.0, 1.0, &last_seq->flag, 0);
-
-               if( do_clever_numbuts("Audio", 4, REDRAW) ) {
-                       se= last_seq->curelem;
-                       allqueue(REDRAWSEQ, 0);
+       
+       if(tot==0) {
+               error("No strips to cut");
+               return;
+       }
+       
+       ts=transmain= MEM_callocN(tot*sizeof(TransSeq), "transseq");
+       
+       for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+               if(seq->flag & SELECT) {
+                       
+                       ts->start= seq->start;
+                       ts->machine= seq->machine;
+                       ts->startstill= seq->startstill;
+                       ts->endstill= seq->endstill;
+                       ts->startdisp= seq->startdisp;
+                       ts->enddisp= seq->enddisp;
+                       ts->startofs= seq->startofs;
+                       ts->endofs= seq->endofs;
+                       ts->len= seq->len;
+                       
+                       ts++;
                }
        }
-       else if(last_seq->type==SEQ_META) {
-
-               add_numbut(0, TEX, "Name:", 0.0, 21.0, last_seq->name+2, 0);
+               
+       for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+               if(seq->flag & SELECT) {
+                       
+                       /* strips with extended stillframes before */
+                       if ((seq->startstill) && (cutframe <seq->start)) {
+                               seq->start= cutframe -1;
+                               seq->startstill= cutframe -seq->startdisp -1;
+                               seq->len= 1;
+                               seq->endstill= 0;
+                       }
+                       
+                       /* normal strip */
+                       else if ((cutframe >=seq->start)&&(cutframe <=(seq->start+seq->len))) {
+                               seq->endofs = (seq->start+seq->len) - cutframe;
+                       }
+                       
+                       /* strips with extended stillframes after */
+                       else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) {
+                               seq->endstill -= seq->enddisp - cutframe;
+                       }
+                       
+                       calc_sequence(seq);
+               }
+       }
+               
+       newlist.first= newlist.last= NULL;
+       
+       /* now we duplicate the cut strip and move it into place afterwards */
+       recurs_dupli_seq(ed->seqbasep, &newlist);
+       addlisttolist(ed->seqbasep, &newlist);
+       
+       ts= transmain;
+       
+       /* go through all the strips and correct them based on their stored values */
+       for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+               if(seq->flag & SELECT) {
 
-               if( do_clever_numbuts("Meta", 1, REDRAW) ) {
-                       allqueue(REDRAWSEQ, 0);
+                       /* strips with extended stillframes before */
+                       if ((seq->startstill) && (cutframe == seq->start + 1)) {
+                               seq->start = ts->start;
+                               seq->startstill= ts->start- cutframe;
+                               seq->len = ts->len;
+                               seq->endstill = ts->endstill;
+                       }
+                       
+                       /* normal strip */
+                       else if ((cutframe>=seq->start)&&(cutframe<=(seq->start+seq->len))) {
+                               seq->startstill = 0;
+                               seq->startofs = cutframe - ts->start;
+                               seq->endofs = ts->endofs;
+                               seq->endstill = ts->endstill;
+                       }                               
+                       
+                       /* strips with extended stillframes after */
+                       else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) {
+                               seq->start = cutframe - ts->len +1;
+                               seq->startofs = ts->len-1;
+                               seq->endstill = ts->enddisp - cutframe -1;
+                               seq->startstill = 0;
+                       }
+                       calc_sequence(seq);
+                       
+                       ts++;
                }
        }
+               
+       /* as last: */  
+       sort_seq();
+       MEM_freeN(transmain);
+       
+       allqueue(REDRAWSEQ, 0);
 }
 
 void seq_snap_menu(void)
@@ -2069,7 +2548,7 @@ void seq_snap(short event)
        /* also check metas */
        WHILE_SEQ(ed->seqbasep) {
                if(seq->flag & SELECT) {
-                       if(seq->type<SEQ_EFFECT) seq->start= CFRA-seq->startofs+seq->startstill;
+                       if(sequence_is_free_transformable(seq)) seq->start= CFRA-seq->startofs+seq->startstill;
                        calc_sequence(seq);
                }
        }
@@ -2138,6 +2617,7 @@ void borderselect_seq(void)
                                else {
                                        seq->flag &= ~SELECT;
                                }
+                               recurs_sel_seq(seq);
                        }
 
                        seq= seq->next;