mixer align audio, track dump tweak, zwdw refresh edl fix, sketcher tweak
authorGood Guy <good1.2guy@gmail.com>
Sat, 23 Mar 2019 18:32:19 +0000 (12:32 -0600)
committerGood Guy <good1.2guy@gmail.com>
Sat, 23 Mar 2019 18:32:19 +0000 (12:32 -0600)
12 files changed:
cinelerra-5.1/cinelerra/Makefile
cinelerra-5.1/cinelerra/mainmenu.C
cinelerra-5.1/cinelerra/mainmenu.h
cinelerra-5.1/cinelerra/mainmenu.inc
cinelerra-5.1/cinelerra/mixersalign.C [new file with mode: 0644]
cinelerra-5.1/cinelerra/mixersalign.h [new file with mode: 0644]
cinelerra-5.1/cinelerra/mixersalign.inc [new file with mode: 0644]
cinelerra-5.1/cinelerra/mwindow.C
cinelerra-5.1/cinelerra/mwindow.h
cinelerra-5.1/cinelerra/track.C
cinelerra-5.1/cinelerra/zwindow.C
cinelerra-5.1/plugins/sketcher/sketcherwindow.h

index ad888cf..e0d94a3 100644 (file)
@@ -212,6 +212,7 @@ OBJS := $(OVERLAYS) \
        $(OBJDIR)/menuveffects.o \
        $(OBJDIR)/meterhistory.o \
        $(OBJDIR)/meterpanel.o \
+       $(OBJDIR)/mixersalign.o \
        $(OBJDIR)/module.o \
        $(OBJDIR)/mtimebar.o \
        $(OBJDIR)/mwindowedit.o \
index 01bc15a..8718915 100644 (file)
@@ -55,6 +55,7 @@
 #include "menueditlength.h"
 #include "menutransitionlength.h"
 #include "menuveffects.h"
+#include "mixersalign.h"
 #include "mwindowgui.h"
 #include "mwindow.h"
 #include "new.h"
@@ -271,8 +272,8 @@ void MainMenu::create_objects()
        windowmenu->add_item(new BC_MenuItem("-"));
        windowmenu->add_item(split_x = new SplitX(mwindow));
        windowmenu->add_item(split_y = new SplitY(mwindow));
-       windowmenu->add_item(mixer_viewer = new MixerViewer(mwindow));
-       windowmenu->add_item(new TileMixers(mwindow));
+       windowmenu->add_item(mixer_items = new MixerItems(mwindow));
+       mixer_items->create_objects();
        windowmenu->add_item(new TileWindows(mwindow,_("Tile left"),0));
        windowmenu->add_item(new TileWindows(mwindow,_("Tile right"),1));
        windowmenu->add_item(new BC_MenuItem("-"));
@@ -1590,6 +1591,21 @@ int SplitY::handle_event()
 }
 
 
+MixerItems::MixerItems(MWindow *mwindow)
+ : BC_MenuItem(_("Mixers..."))
+{
+       this->mwindow = mwindow;
+}
+
+void MixerItems::create_objects()
+{
+       BC_SubMenu *mixer_submenu = new BC_SubMenu();
+       add_submenu(mixer_submenu);
+       mixer_submenu->add_submenuitem(new MixerViewer(mwindow));
+       mixer_submenu->add_submenuitem(new TileMixers(mwindow));
+       mixer_submenu->add_submenuitem(new AlignMixers(mwindow));
+}
+
 MixerViewer::MixerViewer(MWindow *mwindow)
  : BC_MenuItem(_("Mixer Viewer"), _("Shift-M"), 'M')
 {
@@ -1616,6 +1632,20 @@ int TileMixers::handle_event()
        return 1;
 }
 
+AlignMixers::AlignMixers(MWindow *mwindow)
+ : BC_MenuItem(_("Align mixers"))
+{
+       this->mwindow = mwindow;
+}
+
+int AlignMixers::handle_event()
+{
+       int wx, wy;
+       mwindow->gui->get_abs_cursor(wx, wy);
+       mwindow->mixers_align->start_dialog(wx, wy);
+       return 1;
+}
+
 
 LoadLayoutItem::LoadLayoutItem(LoadLayout *load_layout, const char *text, int idx, int hotkey)
  : BC_MenuItem(text, "", hotkey)
index 64c8659..674be02 100644 (file)
@@ -128,7 +128,7 @@ public:
        ShowLWindow *show_lwindow;
        SplitX *split_x;
        SplitY *split_y;
-       MixerViewer *mixer_viewer;
+       MixerItems *mixer_items;
        LoadLayout *load_layout;
        LoadLayout *save_layout;
 };
@@ -417,6 +417,22 @@ public:
        MWindow *mwindow;
 };
 
+class MixerItems : public BC_MenuItem
+{
+public:
+       MixerItems(MWindow *mwindow);
+       void create_objects();
+       MWindow *mwindow;
+};
+
+class MixerViewer : public BC_MenuItem
+{
+public:
+       MixerViewer(MWindow *mwindow);
+       int handle_event();
+       MWindow *mwindow;
+};
+
 class TileMixers : public BC_MenuItem
 {
 public:
@@ -425,6 +441,14 @@ public:
        MWindow *mwindow;
 };
 
+class AlignMixers : public BC_MenuItem
+{
+public:
+       AlignMixers(MWindow *mwindow);
+       int handle_event();
+       MWindow *mwindow;
+};
+
 // ======================================== audio
 
 class AddAudioTrack : public BC_MenuItem
@@ -706,14 +730,6 @@ public:
        MWindow *mwindow;
 };
 
-class MixerViewer : public BC_MenuItem
-{
-public:
-       MixerViewer(MWindow *mwindow);
-       int handle_event();
-       MWindow *mwindow;
-};
-
 
 class LoadLayoutItem : public BC_MenuItem
 {
index 81dd0c1..6cf7720 100644 (file)
@@ -58,6 +58,8 @@ class CutCommercials;
 class DetachTransitions;
 class MuteSelection;
 class TrimSelection;
+class MixerItems;
+class MixerViewer;
 class TileMixers;
 class AddAudioTrack;
 class DeleteAudioTrack;
@@ -92,7 +94,6 @@ class ShowLWindow;
 class TileWindows;
 class SplitX;
 class SplitY;
-class MixerViewer;
 class LoadLayoutItem;
 class LoadLayout;
 class LoadLayoutDialog;
diff --git a/cinelerra-5.1/cinelerra/mixersalign.C b/cinelerra-5.1/cinelerra/mixersalign.C
new file mode 100644 (file)
index 0000000..34f230e
--- /dev/null
@@ -0,0 +1,1073 @@
+/*
+ * CINELERRA
+ * Copyright (C) 2008-2015 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "mixersalign.h"
+#include "arender.h"
+#include "clip.h"
+#include "edit.h"
+#include "edits.h"
+#include "edl.h"
+#include "localsession.h"
+#include "mainerror.h"
+#include "mainprogress.h"
+#include "mwindow.h"
+#include "mwindowgui.h"
+#include "preferences.h"
+#include "track.h"
+#include "tracks.h"
+#include "renderengine.h"
+#include "samples.h"
+#include "track.h"
+#include "transportque.h"
+#include "zwindow.h"
+
+MixersAlignMixer::MixersAlignMixer(Mixer *mix)
+{
+       this->mixer = mix;
+       this->nudge = 0;
+       mx = 0;  mi = -1;
+       aidx = -1;
+}
+
+const char *MixersAlignMixerList::mix_titles[MIX_SZ] = {
+       N_("Mixer"), N_("Nudge"),
+};
+
+int MixersAlignMixerList::mix_widths[MIX_SZ] = {
+       130, 50,
+};
+
+MixersAlignMixerList::MixersAlignMixerList(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y, int w, int h)
+ : BC_ListBox(x, y, w, h, LISTBOX_TEXT)
+{
+       set_selection_mode(LISTBOX_MULTIPLE);
+       this->dialog = dialog;
+       this->gui = gui;
+       for( int i=MIX_SZ; --i>=0; ) {
+               col_widths[i] = mix_widths[i];
+               col_titles[i] = _(mix_titles[i]);
+       }
+}
+
+MixersAlignMixerList::~MixersAlignMixerList()
+{
+       clear();
+}
+
+void MixersAlignMixerList::clear()
+{
+       for( int i=MIX_SZ; --i>=0; )
+               cols[i].remove_all_objects();
+}
+
+void MixersAlignMixerList::add_mixer(MixersAlignMixer *mixer)
+{
+       char mixer_text[BCSTRLEN];
+       snprintf(mixer_text, sizeof(mixer_text), "%d: %s",
+               mixer->mixer->idx, mixer->mixer->title);
+       cols[MIX_MIXER].append(new BC_ListBoxItem(mixer_text));
+       char nudge_text[BCSTRLEN];
+       sprintf(nudge_text, _("%0.4f"), mixer->nudge);
+       cols[MIX_NUDGE].append(new BC_ListBoxItem(nudge_text));
+}
+
+void MixersAlignMixerList::load_list()
+{
+       clear();
+       for( int i=0,sz=dialog->mixers.size(); i<sz; ++i )
+               add_mixer(dialog->mixers[i]);
+}
+
+void MixersAlignMixerList::update()
+{
+       int xpos = get_xposition(), ypos = get_yposition();
+       BC_ListBox::update(&cols[0], &col_titles[0],&col_widths[0],MIX_SZ, xpos,ypos);
+}
+
+int MixersAlignMixerList::selection_changed()
+{
+       for( int m=0; m<dialog->mixers.size(); ++m ) {
+               MixersAlignMixer *mix = dialog->mixers[m];
+               if( !is_selected(m) ) {
+                       for( int i=0; i<dialog->atracks.size(); ++i ) {
+                               if( m != dialog->amixer_of(i) ) continue;
+                               gui->atrack_list->set_selected(i, 0);
+                       }
+                       mix->aidx = -1;
+                       mix->mx = 0;
+                       mix->mi = -1;
+                       mix->nudge = 0;
+               }
+               else if( mix->aidx < 0 ) {
+                       MixersAlignATrack *best = 0;  int idx = -1;
+                       for( int i=0; i<dialog->atracks.size(); ++i ) {
+                               if( m != dialog->amixer_of(i) ) continue;
+                               MixersAlignATrack *atrk = dialog->atracks[i];
+                               if( atrk->mi < 0 ) continue;
+                               gui->atrack_list->set_selected(i, 0);
+                               if( best && best->mx >= atrk->mx ) continue;
+                               best = atrk;  idx = i;
+                       }
+                       if( idx >= 0 && best ) {
+                               gui->atrack_list->set_selected(idx, 1);
+                               MixersAlignMixer *mix = dialog->mixers[m];
+                               mix->aidx = idx;
+                               mix->mx = best->mx;
+                               mix->mi = best->mi;
+                               mix->nudge = best->nudge;
+                       }
+                       else {
+                               for( int i=0; i<dialog->atracks.size(); ++i ) {
+                                       if( m != dialog->amixer_of(i) ) continue;
+                                       gui->atrack_list->set_selected(i, 1);
+                               }
+                       }
+               }
+       }
+       gui->atrack_list->update();
+
+       load_list();
+       for( int i=0; i<dialog->atracks.size(); ++i ) {
+               if( !gui->atrack_list->is_selected(i) ) continue;
+               int m = dialog->amixer_of(i);
+               if( m >= 0 ) set_selected(m, 1);
+       }
+       update();
+       return 0;
+}
+
+MixersAlignMTrack::MixersAlignMTrack(Track *trk, int no)
+{
+       this->track = trk;
+       this->no = no;
+}
+
+
+const char *MixersAlignMTrackList::mtk_titles[MTK_SZ] = {
+       N_("No"), N_("Mixer"), N_("Track"),
+};
+
+int MixersAlignMTrackList::mtk_widths[MTK_SZ] = {
+       32, 48, 110,
+};
+
+MixersAlignMTrackList::MixersAlignMTrackList(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y, int w, int h)
+ : BC_ListBox(x, y, w, h, LISTBOX_TEXT)
+{
+       set_selection_mode(LISTBOX_SINGLE);
+       this->dialog = dialog;
+       this->gui = gui;
+       for( int i=MTK_SZ; --i>=0; ) {
+               col_widths[i] = mtk_widths[i];
+               col_titles[i] = _(mtk_titles[i]);
+       }
+}
+
+MixersAlignMTrackList::~MixersAlignMTrackList()
+{
+       clear();
+}
+
+void MixersAlignMTrackList::clear()
+{
+       for( int i=MTK_SZ; --i>=0; )
+               cols[i].remove_all_objects();
+}
+
+void MixersAlignMTrackList::add_mtrack(MixersAlignMTrack *mtrk)
+{
+       char no_text[BCSTRLEN];
+       snprintf(no_text, sizeof(no_text),"%d", mtrk->no+1);
+       cols[MTK_NO].append(new BC_ListBoxItem(no_text));
+       char mixer_text[BCSTRLEN];
+       Track *track = mtrk->track;
+       int midx = -1, m = dialog->mixer_of(track, midx);
+       snprintf(mixer_text, sizeof(mixer_text),"%d:%d", m+1,midx);
+       cols[MTK_MIXER].append(new BC_ListBoxItem(mixer_text));
+       cols[MTK_TRACK].append(new BC_ListBoxItem(track->title));
+}
+
+void MixersAlignMTrackList::load_list()
+{
+       clear();
+       for( int i=0,sz=dialog->mtracks.size(); i<sz; ++i )
+               add_mtrack(dialog->mtracks[i]);
+}
+
+void MixersAlignMTrackList::update()
+{
+       int xpos = get_xposition(), ypos = get_yposition();
+       BC_ListBox::update(&cols[0], &col_titles[0],&col_widths[0],MTK_SZ, xpos,ypos);
+}
+
+
+MixersAlignATrack::MixersAlignATrack(Track *trk, int no)
+{
+       this->track = trk;
+       this->no = no;
+       this->nudge = 0;
+       mx = 0;  mi = -1;
+}
+
+
+const char *MixersAlignATrackList::atk_titles[ATK_SZ] = {
+       N_("Track"), N_("Audio"), N_("Nudge"), N_("R"), N_("pos"),
+};
+
+int MixersAlignATrackList::atk_widths[ATK_SZ] = {
+       40, 100, 60, 60, 60,
+};
+
+MixersAlignATrackList::MixersAlignATrackList(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y, int w, int h)
+ : BC_ListBox(x, y, w, h, LISTBOX_TEXT)
+{
+       set_selection_mode(LISTBOX_MULTIPLE);
+       this->dialog = dialog;
+       this->gui = gui;
+       for( int i=ATK_SZ; --i>=0; ) {
+               col_widths[i] = atk_widths[i];
+               col_titles[i] = _(atk_titles[i]);
+       }
+}
+
+MixersAlignATrackList::~MixersAlignATrackList()
+{
+       clear();
+}
+
+void MixersAlignATrackList::clear()
+{
+       for( int i=ATK_SZ; --i>=0; )
+               cols[i].remove_all_objects();
+}
+
+void MixersAlignATrackList::add_atrack(MixersAlignATrack *atrack)
+{
+       char atrack_text[BCSTRLEN];
+       Track *track = atrack->track;
+       int midx = -1, m = dialog->mixer_of(track, midx);
+       snprintf(atrack_text, sizeof(atrack_text), "%d/%d", atrack->no+1,m+1);
+       cols[ATK_TRACK].append(new BC_ListBoxItem(atrack_text));
+       cols[ATK_AUDIO].append(new BC_ListBoxItem(track->title));
+       char nudge_text[BCSTRLEN];
+       sprintf(nudge_text, "%0.4f", atrack->nudge);
+       cols[ATK_NUDGE].append(new BC_ListBoxItem(nudge_text));
+       char mx_text[BCSTRLEN];
+       sprintf(mx_text, "%0.4f", atrack->mx);
+       cols[ATK_MX].append(new BC_ListBoxItem(mx_text));
+       char mi_text[BCSTRLEN];
+       sprintf(mi_text, "%jd", atrack->mi);
+       cols[ATK_MI].append(new BC_ListBoxItem(mi_text));
+}
+
+
+void MixersAlignATrackList::load_list()
+{
+       clear();
+       for( int i=0,sz=dialog->atracks.size(); i<sz; ++i )
+               add_atrack(dialog->atracks[i]);
+}
+
+void MixersAlignATrackList::update()
+{
+       int xpos = get_xposition(), ypos = get_yposition();
+       BC_ListBox::update(&cols[0], &col_titles[0],&col_widths[0],ATK_SZ, xpos,ypos);
+}
+
+int MixersAlignATrackList::selection_changed()
+{
+       int idx = get_buttonpress() == LEFT_BUTTON ? get_highlighted_item() : -1;
+       int m = idx >= 0 ? dialog->amixer_of(idx) : -1;
+       if( m >= 0 ) {
+               int sel = 0;
+               MixersAlignMixer *mix = dialog->mixers[m];
+               for( int i=0; i<dialog->atracks.size(); ++i ) {
+                       int k = dialog->amixer_of(i);
+                       if( k < 0 ) { set_selected(i, 0);  continue; }
+                       if( m != k ) continue;
+                       MixersAlignATrack *atrk = dialog->atracks[i];
+                       if( atrk->mi < 0 ) continue;
+                       int is_sel = is_selected(i);
+                       set_selected(i, 0);
+                       if( i != idx ) continue;
+                       if( is_sel ) {
+                               mix->aidx = idx;
+                               mix->mx = atrk->mx;
+                               mix->mi = atrk->mi;
+                               mix->nudge = atrk->nudge;
+                               sel = 1;
+                       }
+                       else {
+                               mix->aidx = -1;
+                               mix->mx = 0;
+                               mix->mi = -1;
+                               mix->nudge = 0;
+                       }
+               }
+               if( sel )
+                       set_selected(idx, 1);
+       }
+       update();
+
+       gui->mixer_list->load_list();
+       for( int i=0; i<dialog->atracks.size(); ++i ) {
+               if( !is_selected(i) ) continue;
+               int m = dialog->amixer_of(i);
+               if( m < 0 ) continue;
+               gui->mixer_list->set_selected(m, 1);
+       }
+       gui->mixer_list->update();
+       return 0;
+}
+
+MixersAlignReset::MixersAlignReset(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y)
+ : BC_GenericButton(x, y, _("Reset"))
+{
+       this->gui = gui;
+       this->dialog = dialog;
+}
+
+int MixersAlignReset::calculate_width(BC_WindowBase *gui)
+{
+       return BC_GenericButton::calculate_w(gui, _("Reset"));
+}
+
+int MixersAlignReset::handle_event()
+{
+       dialog->load_mixers();
+       dialog->load_mtracks();
+       dialog->load_atracks();
+       gui->load_lists();
+       gui->default_selection();
+       return 1;
+}
+
+MixersAlignMatch::MixersAlignMatch(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y)
+ : BC_GenericButton(x, y, _("Match"))
+{
+       this->gui = gui;
+       this->dialog = dialog;
+}
+
+int MixersAlignMatch::handle_event()
+{
+       if( !dialog->thread->running() ) {
+               gui->reset->disable();
+               gui->match->disable();
+               gui->apply->disable();
+               gui->undo->disable();
+               dialog->thread->start();
+       }
+       return 1;
+}
+
+MixersAlignApply::MixersAlignApply(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y)
+ : BC_GenericButton(x, y, _("Apply"))
+{
+       this->gui = gui;
+       this->dialog = dialog;
+}
+
+int MixersAlignApply::calculate_width(BC_WindowBase *gui)
+{
+       return BC_GenericButton::calculate_w(gui, _("Apply"));
+}
+
+int MixersAlignApply::handle_event()
+{
+       dialog->apply();
+       return 1;
+}
+
+MixersAlignUndo::MixersAlignUndo(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y)
+ : BC_GenericButton(x, y, _("Undo"))
+{
+       this->gui = gui;
+       this->dialog = dialog;
+}
+
+int MixersAlignUndo::handle_event()
+{
+       MWindow *mwindow = dialog->mwindow;
+       mwindow->edl->copy_all(dialog->undo_edl);
+       mwindow->gui->lock_window("MixersAlignUndo::handle_event");
+       mwindow->update_gui(1);
+       mwindow->gui->unlock_window();
+       return gui->reset->handle_event();
+}
+
+
+MixersAlignWindow::MixersAlignWindow(MixersAlign *dialog, int x, int y)
+ : BC_Window(_("Align Mixers"), x, y, 880, 380, 880, 380, 1)
+{
+       this->dialog = dialog;
+}
+MixersAlignWindow::~MixersAlignWindow()
+{
+}
+
+void MixersAlignWindow::create_objects()
+{
+       int x = 10, y = 10, w4 = (get_w()-x-10)/4, lw = w4 + 20;
+       int x1 = x, x2 = x1 + lw , x3 = x2 + lw, x4 = get_w()-x;
+       mixer_title = new BC_Title(x1,y, _("Mixers:"), MEDIUMFONT, YELLOW);
+       add_subwindow(mixer_title);
+       mtrack_title = new BC_Title(x2,y, _("Master Track:"), MEDIUMFONT, YELLOW);
+       add_subwindow(mtrack_title);
+       atrack_title = new BC_Title(x3,y, _("Audio Tracks:"), MEDIUMFONT, YELLOW);
+       add_subwindow(atrack_title);
+       y += mixer_title->get_h() + 10;
+       int y1 = y, y2 = get_h() - BC_OKButton::calculate_h() - 15;
+       int lh = y2 - y1;
+       mixer_list = new MixersAlignMixerList(this, dialog, x1, y, x2-x1-20, lh);
+       add_subwindow(mixer_list);
+       mtrack_list = new MixersAlignMTrackList(this, dialog, x2, y, x3-x2-20, lh);
+       add_subwindow(mtrack_list);
+       atrack_list = new MixersAlignATrackList(this, dialog, x3, y, x4-x3-20, lh);
+       add_subwindow(atrack_list);
+       int xr = x2-10 - MixersAlignReset::calculate_width(this);
+       add_subwindow(reset = new MixersAlignReset(this, dialog, xr, y2+20));
+       add_subwindow(match = new MixersAlignMatch(this, dialog, x2+10, y2+20));
+       int xa = x3-10 - MixersAlignApply::calculate_width(this);
+       add_subwindow(apply = new MixersAlignApply(this, dialog, xa, y2+20));
+       add_subwindow(undo = new MixersAlignUndo(this, dialog, x3+10, y2+20));
+
+       add_subwindow(new BC_OKButton(this));
+       add_subwindow(new BC_CancelButton(this));
+}
+
+int MixersAlignWindow::resize_event(int w, int h)
+{
+       int x = 10, y = 10, w4 = (w-x-10)/4, lw = w4 + 20;
+       int x1 = x, x2 = x1 + lw , x3 = x2 + lw, x4 = w-x;
+       mixer_title->reposition_window(x1, y);
+       mtrack_title->reposition_window(x2, y);
+       atrack_title->reposition_window(x3, y);
+       y += mixer_title->get_h() + 10;
+       int y1 = y, y2 = h - BC_OKButton::calculate_h() - 15;
+       int lh = y2 - y1;
+       mixer_list->reposition_window(x1, y, x2-x1-20, lh);
+       mtrack_list->reposition_window(x2, y, x3-x2-20, lh);
+       atrack_list->reposition_window(x3, y, x4-x3-20, lh);
+       int xr = x2-10 - MixersAlignReset::calculate_width(this);
+       reset->reposition_window(xr, y2+20);
+       match->reposition_window(x2+10, y2+20);
+       int xa = x3-10 - MixersAlignApply::calculate_width(this);
+       apply->reposition_window(xa, y2+20);
+       undo->reposition_window(x3+10, y2+20);
+       return 0;
+}
+
+void MixersAlignWindow::load_lists()
+{
+       mixer_list->load_list();
+       mtrack_list->load_list();
+       atrack_list->load_list();
+}
+
+void MixersAlignWindow::default_selection()
+{
+// mixers selects all mixers
+       mixer_list->set_all_selected(1);
+// master selects first mixer audio track
+       for( int i=0; i<dialog->mtracks.size(); ++i ) {
+               if( dialog->mmixer_of(i) >= 0 ) {
+                       mtrack_list->set_selected(i, 1);
+                       break;
+               }
+       }
+// audio selects all mixer audio tracks
+       for( int i=0; i<dialog->atracks.size(); ++i ) {
+               if( dialog->amixer_of(i) >= 0 )
+                       atrack_list->set_selected(i, 1);
+       }
+       update_gui();
+}
+
+void MixersAlignWindow::update_gui()
+{
+       mixer_list->update();
+       mtrack_list->update();
+       atrack_list->update();
+}
+
+
+MixersAlign::MixersAlign(MWindow *mwindow)
+{
+       this->mwindow = mwindow;
+       this->ma_gui = 0;
+       farming = new Mutex("MixersAlign::farming");
+       total_lock = new Mutex("MixersAlign::total_lock");
+       thread = new MixersAlignThread(this);
+       total_rendered = 0;
+       master_r = 0;
+       master_i = 0;
+       master_len = 0;
+       progress = 0;
+       failed = 0;
+       undo_edl = 0;
+       master_start = master_end = 0;
+       audio_start = audio_end = 0;
+}
+
+MixersAlign::~MixersAlign()
+{
+       failed = -1;
+       farming->lock("MixersAlign::~MixersAlign");
+       close_window();
+       delete farming;
+       delete thread;
+       delete total_lock;
+       delete progress;
+       delete [] master_r;
+       delete [] master_i;
+}
+
+void MixersAlign::start_dialog(int wx, int wy)
+{
+       this->wx = wx;
+       this->wy = wy;
+       this->undo_edl = new EDL();
+       undo_edl->create_objects();
+       undo_edl->copy_all(mwindow->edl);
+       start();
+}
+
+BC_Window *MixersAlign::new_gui()
+{
+       load_mixers();
+       load_mtracks();
+       load_atracks();
+       ma_gui = new MixersAlignWindow(this, wx, wy);
+       ma_gui->lock_window("MixersAlign::new_gui");
+       ma_gui->create_objects();
+       ma_gui->load_lists();
+       ma_gui->default_selection();
+       ma_gui->show_window(1);
+       ma_gui->unlock_window();
+       return ma_gui;
+}
+
+void MixersAlign::apply()
+{
+       int idx = ma_gui->mtrack_list->get_selection_number(0, 0);
+       int midx = -1, mid = mixer_of(mtracks[idx]->track, midx);
+       
+       for( int m, i=0; (m=ma_gui->mixer_list->get_selection_number(0,i))>=0; ++i ) {
+               if( m == mid ) continue;  // master does not move
+               MixersAlignMixer *mix = mixers[m];
+               Mixer *mixer = mix->mixer;
+               for( int i=0; i<mixer->mixer_ids.size(); ++i ) {
+                       int id = mixer->mixer_ids[i];
+                       Track *track = mwindow->edl->tracks->first;
+                       while( track && track->mixer_id != id ) track = track->next;
+                       if( !track ) continue;
+                       int64_t dt = track->to_units(mix->nudge, 0);
+                       for( Edit *edit=track->edits->first; edit; edit=edit->next )
+                               edit->startproject += dt;
+                       track->optimize();
+               }
+       }
+
+       mwindow->gui->lock_window("MixersAlign::handle_done_event");
+       mwindow->update_gui(1);
+       mwindow->gui->unlock_window();
+}
+
+
+MixersAlignThread::MixersAlignThread(MixersAlign *dialog)
+ : Thread(1, 0, 0)
+{
+       this->dialog = dialog;
+}
+MixersAlignThread::~MixersAlignThread()
+{
+       join();
+}
+
+void MixersAlignThread::run()
+{
+       dialog->update_match();
+       MixersAlignWindow *ma_gui = dialog->ma_gui;
+       ma_gui->lock_window("MixersAlignThread::run");
+       ma_gui->reset->enable();
+       ma_gui->match->enable();
+       ma_gui->apply->enable();
+       ma_gui->undo->enable();
+       ma_gui->unlock_window();
+}
+
+
+void MixersAlign::handle_done_event(int result)
+{
+       if( !result ) {
+               EDL *edl = mwindow->edl;
+               mwindow->edl = undo_edl;
+               mwindow->undo_before();
+               mwindow->edl = edl;
+               mwindow->undo_after(_("align mixers"), LOAD_ALL);
+       }
+       else if( thread->running() ) {
+               failed = -1;
+               thread->join();
+       }
+}
+
+void MixersAlign::handle_close_event(int result)
+{
+       undo_edl->remove_user();
+       undo_edl = 0;
+       ma_gui = 0;
+}
+
+void MixersAlign::load_mixers()
+{
+       mixers.remove_all_objects();
+       Mixers &edl_mixers = mwindow->edl->mixers;
+       for( int i=0; i<edl_mixers.size(); ++i )
+               mixers.append(new MixersAlignMixer(edl_mixers[i]));
+}
+
+void MixersAlign::load_mtracks()
+{
+       mtracks.remove_all_objects();
+       Track *track=mwindow->edl->tracks->first;
+       for( int no=0; track; ++no, track=track->next ) {
+               if( track->data_type != TRACK_AUDIO ) continue;
+               mtracks.append(new MixersAlignMTrack(track, no));
+       }
+}
+
+void MixersAlign::load_atracks()
+{
+       atracks.remove_all_objects();
+       Track *track=mwindow->edl->tracks->first;
+       for( int no=0; track; ++no, track=track->next ) {
+               if( track->data_type != TRACK_AUDIO ) continue;
+               if( mixer_of(track) < 0 ) continue;
+               atracks.append(new MixersAlignATrack(track, no));
+       }
+}
+
+
+int MixersAlign::mixer_of(Track *track, int &midx)
+{
+       int id = track->mixer_id, k = mixers.size(), idx = -1;
+       while( idx < 0 && --k >= 0 )
+               idx = mixers[k]->mixer->mixer_ids.number_of(id);
+       midx = idx;
+       return k;
+}
+
+EDL *MixersAlign::mixer_audio_clip(Mixer *mixer)
+{
+       EDL *edl = new EDL(mwindow->edl);
+       edl->create_objects();
+       Track *track = mwindow->edl->tracks->first;
+       for( ; track; track=track->next ) {
+               int id = track->mixer_id;
+               if( track->data_type != TRACK_AUDIO ) continue;
+               if( mixer->mixer_ids.number_of(id) < 0 ) continue;
+               Track *mixer_audio = edl->tracks->add_audio_track(0, 0);
+               mixer_audio->copy_from(track);
+               mixer_audio->play = 1;
+       }
+       return edl;
+}
+
+EDL *MixersAlign::mixer_master_clip(Track *track)
+{
+       EDL *edl = new EDL(mwindow->edl);
+       edl->create_objects();
+       Track *master_audio = edl->tracks->add_audio_track(0, 0);
+       master_audio->copy_from(track);
+       master_audio->play = 1;
+       return edl;
+}
+
+int64_t MixersAlign::mixer_tracks_total()
+{
+       int64_t total_len = 0;
+       int64_t sample_rate = mwindow->edl->get_sample_rate();
+       int m = -1, idx = 0;
+       for( ; (m=ma_gui->mixer_list->get_selection_number(0, idx))>=0 ; ++idx ) {
+               Mixer *mixer = mixers[m]->mixer;
+               double render_end = 0;
+               Track *track = mwindow->edl->tracks->first;
+               for( ; track; track=track->next ) {
+                       int id = track->mixer_id;
+                       if( track->data_type != TRACK_AUDIO ) continue;
+                       if( mixer->mixer_ids.number_of(id) < 0 ) continue;
+                       double track_end = track->get_length();
+                       if( render_end < track_end ) render_end = track_end;
+               }
+               if( render_end > audio_end ) render_end = audio_end;
+               double len = render_end - audio_start;
+               if( len > 0 ) total_len += len * sample_rate;
+       }
+       return total_len;
+}
+
+MixersAlignARender::MixersAlignARender(MWindow *mwindow, EDL *edl)
+ : RenderEngine(0, mwindow->preferences, 0, 0)
+{
+       TransportCommand command;
+       command.command = NORMAL_FWD;
+       command.get_edl()->copy_all(edl);
+       command.change_type = CHANGE_ALL;
+       command.realtime = 0;
+       set_vcache(mwindow->video_cache);
+       set_acache(mwindow->audio_cache);
+       arm_command(&command);
+}
+
+MixersAlignARender::~MixersAlignARender()
+{
+}
+
+int MixersAlignARender::render(Samples **samples, int64_t len, int64_t pos)
+{
+       return arender ? arender->process_buffer(samples, len, pos) : -1;
+}
+
+MixersAlignPackage::MixersAlignPackage()
+{
+       mixer = 0;
+}
+
+MixersAlignPackage::~MixersAlignPackage()
+{
+}
+
+MixersAlignFarm::MixersAlignFarm(MixersAlign *dialog, int n)
+ : LoadServer(bmin(dialog->mwindow->preferences->processors, n), n)
+{
+       this->dialog = dialog;
+       dialog->farming->lock("MixersAlignFarm::MixersAlignFarm");
+}
+MixersAlignFarm::~MixersAlignFarm()
+{
+       dialog->farming->unlock();
+}
+
+LoadPackage* MixersAlignFarm::new_package()
+{
+       return new MixersAlignPackage();
+}
+
+void MixersAlignFarm::init_packages()
+{
+       for( int i = 0; i < get_total_packages(); ++i ) {
+               int m = dialog->ma_gui->mixer_list->get_selection_number(0, i);
+               MixersAlignPackage *package = (MixersAlignPackage *)get_package(i);
+               package->mixer = dialog->mixers[m];
+       }
+}
+
+LoadClient* MixersAlignFarm::new_client()
+{
+       return new MixersAlignClient(this);
+}
+
+MixersAlignClient::MixersAlignClient(MixersAlignFarm *farm)
+ : LoadClient(farm)
+{
+}
+
+MixersAlignClient::~MixersAlignClient()
+{
+}
+
+void MixersAlignClient::process_package(LoadPackage *pkg)
+{
+       MixersAlignFarm *farm = (MixersAlignFarm *)server;
+       MixersAlign *dialog = farm->dialog;
+       MixersAlignPackage *package = (MixersAlignPackage *)pkg;
+       dialog->process_package(farm, package);
+}
+
+static inline void conj_product(int n, double *rp, double *ip,
+               double *arp, double *aip, double *brp, double *bip)
+{
+       for( int i=0; i<n; ++i ) {
+               double ar = arp[i], ai = aip[i];
+               double br = brp[i], bi = -bip[i];
+               rp[i] = ar*br - ai*bi;
+               ip[i] = ar*bi + ai*br;
+       }
+}
+
+void MixersAlign::process_package(MixersAlignFarm *farm,
+                MixersAlignPackage *package)
+{
+       if( progress->is_cancelled() ) failed = -1;
+       if( failed ) return;
+       MixersAlignMixer *amix = package->mixer;
+       EDL *edl = mixer_audio_clip(amix->mixer);
+
+       MixersAlignARender audio(mwindow, edl);
+       int sample_rate = edl->get_sample_rate();
+       int channels = edl->get_audio_channels();
+       int64_t audio_samples = edl->get_audio_samples();
+       int64_t cur_pos = audio_start * sample_rate;
+       int64_t end_pos = audio_end * sample_rate;
+       if( end_pos > audio_samples ) end_pos = audio_samples;
+       int len = master_len, len2 = len/2;
+       double *audio_r = new double[len];
+       double *audio_i = new double[len];
+       Samples *samples[2][MAX_CHANNELS];
+       for( int k=0; k<2; ++k ) {
+               for( int i=0; i<MAX_CHANNELS; ++i )
+                       samples[k][i] = i<channels ? new Samples(len2) : 0;
+       }
+       int k = 0;
+       int64_t nxt_pos = cur_pos+len2;
+       if( nxt_pos > end_pos ) nxt_pos = end_pos;
+       int len1 = nxt_pos - cur_pos;
+       int ret = audio.render(samples[k], len1, cur_pos);
+       while( !ret && !failed && cur_pos < end_pos ) {
+               update_progress(len1);
+               int64_t pos = cur_pos;
+               cur_pos = nxt_pos;  nxt_pos += len2;
+               if( nxt_pos > end_pos ) nxt_pos = end_pos;
+               len1 = nxt_pos - cur_pos;
+               ret = audio.render(samples[1-k], len1, cur_pos);
+               if( ret ) break;
+               Track *track = edl->tracks->first;
+               for( int ch=0; ch<channels && track; ++ch, track=track->next ) {
+                       int id = track->mixer_id, atk = atracks.size();
+                       while( --atk >= 0 && id != atracks[atk]->track->mixer_id );
+                       if( atk < 0 ) continue;
+                       int i = 0;
+                       double *lp = samples[k][ch]->get_data();
+                       for( int j=0; j<len2; ++j ) audio_r[i++] = *lp++;
+                       double *np = samples[1-k][ch]->get_data();
+                       for( int j=0; j<len1; ++j ) audio_r[i++] = *np++;
+                       while( i < len ) audio_r[i++] = 0;
+                       do_fft(len, 0, audio_r, 0, audio_r, audio_i);
+                       conj_product(len, audio_r, audio_i,
+                               audio_r, audio_i, master_r, master_i);
+                       do_fft(len, 1, audio_r, audio_i, audio_r, audio_i);
+                       double mx = 0;  int64_t mi = -1;
+                       for( int i=0; i<len2; ++i ) {
+                               double v = fabs(audio_r[i]);
+                               if( mx < v ) { mx = v;  mi = i + pos; }
+                       }
+                       mx /= master_ss;
+                       MixersAlignATrack *atrack= atracks[atk];
+                       if( atrack->mx < mx ) {
+                               atrack->mx = mx;
+                               atrack->mi = mi;
+                       }
+               }
+               k = 1-k;
+               if( progress->is_cancelled() ) failed = -1;
+       }
+       if( ret && !failed ) {
+               eprintf("Audio render failed:\n%s", edl->path);
+               failed = 1;
+       }
+       delete [] audio_r;
+       delete [] audio_i;
+       for( int k=0; k<2; ++k ) {
+               for( int i=channels; --i>=0; )
+                       delete samples[k][i];
+       }
+       edl->remove_user();
+}
+
+
+void MixersAlign::update_progress(int64_t len)
+{
+       total_lock->lock();
+       total_rendered += len;
+       total_lock->unlock();
+       progress->update(total_rendered);
+}
+
+static inline uint64_t high_bit_mask(uint64_t n)
+{
+       n |= n >> 1;   n |= n >> 2;
+       n |= n >> 4;   n |= n >> 8;
+       n |= n >> 16;  n |= n >> 32;
+       return n;
+}
+
+void MixersAlign::load_master_audio(Track *track)
+{
+       EDL *edl = mixer_master_clip(track);
+       MixersAlignARender audio(mwindow, edl);
+       int sample_rate = edl->get_sample_rate();
+       int channels = edl->get_audio_channels();
+       int64_t audio_samples = edl->get_audio_samples();
+       int64_t cur_pos = master_start * sample_rate;
+       int64_t end_pos = master_end * sample_rate;
+       if( end_pos > audio_samples ) end_pos = audio_samples;
+       if( cur_pos >= end_pos ) {
+               eprintf(_("master audio track empty"));
+               failed = 1;
+               return;
+       }
+       int64_t audio_len = end_pos - cur_pos;
+       if( audio_len > sample_rate * 60 ) {
+               eprintf(_("master audio track length > 60 seconds"));
+               failed = 1;
+               return;
+       }
+       int64_t fft_len = (high_bit_mask(audio_len)+1) << 1;
+       if( master_len != fft_len ) {
+               master_len = fft_len;
+               delete [] master_r;  master_r = new double[master_len];
+               delete [] master_i;  master_i = new double[master_len];
+       }
+       {       Samples *samples[MAX_CHANNELS];
+               for( int i=0; i<MAX_CHANNELS; ++i )
+                       samples[i] = i<channels ? new Samples(audio_len) : 0;
+               int ret = audio.render(samples, audio_len, cur_pos);
+               if( ret ) failed = 1;
+               edl->remove_user();
+               double *dp = samples[0]->get_data();
+               int i = 0;  double ss = 0;
+               for( ; i<audio_len; ++i ) { ss += *dp * *dp;  master_r[i] = *dp++; }
+               master_ss = ss;
+               for( ; i<fft_len; ++i ) master_r[i] = 0;
+               for( int i=channels; --i>=0; )
+                       delete samples[i];
+       }
+       do_fft(fft_len, 0, master_r, 0, master_r, master_i);
+}
+
+void MixersAlign::scan_mixer_audio()
+{
+       for( int i=0; i<mixers.size(); ++i ) mixers[i]->aidx = -1;
+       int n = 0;
+       while( ma_gui->mixer_list->get_selection_number(0, n) >= 0 ) ++n;
+       if( !n ) {
+               eprintf(_("no mixers selected"));
+               return;
+       }
+
+       Timer timer;
+       total_rendered = 0;
+       MixersAlignFarm farm(this, n);
+       int64_t total_len = mixer_tracks_total();
+       mwindow->gui->lock_window("MixersAlign::scan_mixer_audio");
+       progress = mwindow->mainprogress->
+               start_progress(_("Render mixer audio"), total_len);
+       mwindow->gui->unlock_window();
+
+       farm.process_packages();
+       if( progress->is_cancelled() ) failed = -1;
+
+       char text[BCSTRLEN];
+       double secs = timer.get_difference()/1000.;
+       sprintf(text, _("Render mixer done: %0.3f secs"), secs);
+       mwindow->gui->lock_window("MixersAlign::scan_mixer_audio");
+       progress->update(0);
+       mwindow->mainprogress->end_progress(progress);
+       progress = 0;
+       mwindow->gui->show_message(text);
+       mwindow->gui->unlock_window();
+}
+
+void MixersAlign::update_match()
+{
+       int midx = ma_gui->mtrack_list->get_selection_number(0, 0);
+       if( midx < 0 ) {
+               eprintf(_("selection (master) not set"));
+               return;
+       }
+       master_start = mwindow->edl->local_session->get_inpoint();
+       if( master_start < 0 ) {
+               eprintf(_("in point selection (master start) must be set"));
+               return;
+       }
+       master_end = mwindow->edl->local_session->get_outpoint();
+       if( master_end < 0 ) {
+               eprintf(_("out point selection (master end) must be set"));
+               return;
+       }
+       if( master_start >= master_end ) {
+               eprintf(_("in/out point selection (master start/end) invalid"));
+               return;
+       }
+       audio_start = mwindow->edl->local_session->get_selectionstart();
+       audio_end = mwindow->edl->local_session->get_selectionend();
+       if( audio_start >= audio_end ) {
+               eprintf(_("selection (audio start/end) invalid"));
+               return;
+       }
+
+       failed = 0;
+       if( !failed ) load_master_audio(mtracks[midx]->track);
+        if( !failed ) scan_mixer_audio();
+       if( !failed ) update();
+       if( failed < 0 ) {
+               mwindow->gui->lock_window("MixersAlign::update_match");
+               mwindow->gui->show_message(_("mixer selection match canceled"));
+               mwindow->gui->unlock_window();
+       }
+       else if( failed > 0 )
+               eprintf(_("Error in match render."));
+}
+
+void MixersAlign::update()
+{
+// mixer best matches
+       for( int m=0; m<mixers.size(); ++m ) {
+               MixersAlignMixer *mix = mixers[m];
+               Mixer *mixer = mix->mixer;
+               mix->mx = 0;  mix->mi = -1;  mix->aidx = -1;
+               for( int i=0; i<mixer->mixer_ids.size(); ++i ) {
+                       int id = mixer->mixer_ids[i], k = atracks.size();
+                       while( --k >= 0 && atracks[k]->track->mixer_id != id );
+                       if( k < 0 ) continue;
+                       MixersAlignATrack *atrk = atracks[k];
+                       atrk->nudge = atrk->mi < 0 ? 0 :
+                               master_start - atrk->track->from_units(atrk->mi);
+                       if( mix->mx >= atrk->mx ) continue;
+                       mix->aidx = k;
+                       mix->mx = atrk->mx;
+                       mix->mi = atrk->mi;
+                       mix->nudge = atrk->nudge;
+               }
+       }
+
+       ma_gui->lock_window("MixersAlign::update");
+       ma_gui->mixer_list->load_list();
+       ma_gui->mixer_list->set_all_selected(1);
+       ma_gui->mixer_list->update();
+
+       ma_gui->atrack_list->load_list();
+       for( int m=0; m<mixers.size(); ++m ) {
+               int aidx = mixers[m]->aidx;
+               if( aidx >= 0 ) ma_gui->atrack_list->set_selected(aidx, 1);
+       }
+       ma_gui->atrack_list->update();
+       ma_gui->unlock_window();
+}
+
diff --git a/cinelerra-5.1/cinelerra/mixersalign.h b/cinelerra-5.1/cinelerra/mixersalign.h
new file mode 100644 (file)
index 0000000..86abbe6
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * CINELERRA
+ * Copyright (C) 2008-2015 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __MIXERSALIGN_H__
+#define __MIXERSALIGN_H__
+
+#include "edl.inc"
+#include "fourier.h"
+#include "guicast.h"
+#include "language.h"
+#include "loadbalance.h"
+#include "mainprogress.inc"
+#include "mixersalign.inc"
+#include "mwindow.inc"
+#include "renderengine.h"
+#include "samples.inc"
+#include "track.inc"
+#include "zwindow.inc"
+
+class MixersAlignMixer
+{
+public:
+       MixersAlignMixer(Mixer *mix);
+       Mixer *mixer;
+       double nudge;
+       double mx;
+       int64_t mi;
+       int aidx;
+};
+
+class MixersAlignMixers : public ArrayList<MixersAlignMixer*>
+{
+public:
+       MixersAlignMixers() {}
+       ~MixersAlignMixers() { remove_all_objects(); }
+};
+
+class MixersAlignMixerList : public BC_ListBox
+{
+       enum { MIX_MIXER, MIX_NUDGE, MIX_SZ };
+       static const char *mix_titles[MIX_SZ];
+       static int mix_widths[MIX_SZ];
+public:
+       MixersAlignMixerList(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y, int w, int h);
+       ~MixersAlignMixerList();
+
+       void clear();
+
+       void add_mixer(MixersAlignMixer *mixer);
+       void load_list();
+       void update();
+       int selection_changed();
+
+       MixersAlignWindow *gui;
+       MixersAlign *dialog;
+       MixersAlignMixers mixers;
+
+       const char *col_titles[MIX_SZ];
+       int col_widths[MIX_SZ];
+       ArrayList<BC_ListBoxItem*> cols[MIX_SZ];
+
+       void set_all_selected(int v) { BC_ListBox::set_all_selected(cols, v); }
+       void set_selected(int idx, int v) { BC_ListBox::set_selected(cols, idx, v); }
+       bool is_selected(int idx) { return cols[0][idx]->get_selected() != 0; }
+};
+
+
+class MixersAlignMTrack
+{
+public:
+       MixersAlignMTrack(Track *trk, int no);
+
+       Track *track;
+       int no;
+};
+
+class MixersAlignMTracks : public ArrayList<MixersAlignMTrack*>
+{
+public:
+       MixersAlignMTracks() {}
+       ~MixersAlignMTracks() { remove_all_objects(); }
+};
+
+
+class MixersAlignMTrackList : public BC_ListBox
+{
+       enum { MTK_NO, MTK_MIXER, MTK_TRACK, MTK_SZ };
+       static const char *mtk_titles[MTK_SZ];
+       static int mtk_widths[MTK_SZ];
+public:
+       MixersAlignMTrackList(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y, int w, int h);
+       ~MixersAlignMTrackList();
+
+       void clear();
+       void add_mtrack(MixersAlignMTrack *mtrk);
+       void load_list();
+       void update();
+
+       MixersAlignWindow *gui;
+       MixersAlign *dialog;
+
+       ArrayList<BC_ListBoxItem*> cols[MTK_SZ];
+       const char *col_titles[MTK_SZ];
+       int col_widths[MTK_SZ];
+
+       void set_all_selected(int v) { BC_ListBox::set_all_selected(cols, v); }
+       void set_selected(int idx, int v) { BC_ListBox::set_selected(cols, idx, v); }
+       bool is_selected(int idx) { return cols[0][idx]->get_selected() != 0; }
+};
+
+
+class MixersAlignATrack
+{
+public:
+       MixersAlignATrack(Track *trk, int no);
+       Track *track;
+       int no;
+       double nudge;
+       double mx;
+       int64_t mi;
+};
+
+class MixersAlignATracks : public ArrayList<MixersAlignATrack*>
+{
+public:
+       MixersAlignATracks() {}
+       ~MixersAlignATracks() { remove_all_objects(); }
+};
+
+class MixersAlignATrackList : public BC_ListBox
+{
+       enum { ATK_TRACK, ATK_AUDIO, ATK_NUDGE, ATK_MX, ATK_MI, ATK_SZ };
+       static const char *atk_titles[ATK_SZ];
+       static int atk_widths[ATK_SZ];
+public:
+       MixersAlignATrackList(MixersAlignWindow *gui,
+               MixersAlign *dialog, int x, int y, int w, int h);
+       ~MixersAlignATrackList();
+
+       void clear();
+       void add_atrack(MixersAlignATrack *track);
+       void load_list();
+       void update();
+       int selection_changed();
+
+       MixersAlignWindow *gui;
+       MixersAlign *dialog;
+
+       ArrayList<BC_ListBoxItem*> cols[ATK_SZ];
+       const char *col_titles[ATK_SZ];
+       int col_widths[ATK_SZ];
+
+       void set_all_selected(int v) { BC_ListBox::set_all_selected(cols, v); }
+       void set_selected(int idx, int v) { BC_ListBox::set_selected(cols, idx, v); }
+       bool is_selected(int idx) { return cols[0][idx]->get_selected() != 0; }
+};
+
+class MixersAlignReset : public BC_GenericButton
+{
+public:
+       MixersAlignReset(MixersAlignWindow *gui, MixersAlign *dialog, int x, int y);
+       int handle_event();
+       static int calculate_width(BC_WindowBase *gui);
+
+       MixersAlign *dialog;
+       MixersAlignWindow *gui;
+};
+
+class MixersAlignThread : public Thread
+{
+public:
+       MixersAlignThread(MixersAlign *dialog);
+       ~MixersAlignThread();
+       void run();
+
+       MixersAlign *dialog;
+};
+
+class MixersAlignMatch : public BC_GenericButton
+{
+public:
+       MixersAlignMatch(MixersAlignWindow *gui, MixersAlign *dialog, int x, int y);
+       int handle_event();
+
+       MixersAlign *dialog;
+       MixersAlignWindow *gui;
+};
+
+class MixersAlignApply : public BC_GenericButton
+{
+public:
+       MixersAlignApply(MixersAlignWindow *gui, MixersAlign *dialog, int x, int y);
+       int handle_event();
+       static int calculate_width(BC_WindowBase *gui);
+
+       MixersAlign *dialog;
+       MixersAlignWindow *gui;
+};
+
+class MixersAlignUndo : public BC_GenericButton
+{
+public:
+       MixersAlignUndo(MixersAlignWindow *gui, MixersAlign *dialog, int x, int y);
+       int handle_event();
+
+       MixersAlign *dialog;
+       MixersAlignWindow *gui;
+};
+
+
+class MixersAlignWindow : public BC_Window
+{
+public:
+       MixersAlignWindow(MixersAlign *dialog, int x, int y);
+       ~MixersAlignWindow();
+
+       void create_objects();
+       int resize_event(int w, int h);
+       void load_lists();
+       void default_selection();
+       void update_gui();
+
+       MixersAlign *dialog;
+       BC_Title *mixer_title, *mtrack_title, *atrack_title;
+
+       MixersAlignMixerList *mixer_list;
+       MixersAlignMTrackList *mtrack_list;
+       MixersAlignATrackList *atrack_list;
+       MixersAlignMatch *match;
+       MixersAlignReset *reset;
+       MixersAlignApply *apply;
+       MixersAlignUndo *undo;
+};
+
+
+class MixersAlignARender : public RenderEngine
+{
+public:
+       MixersAlignARender(MWindow *mwindow, EDL *edl);
+       ~MixersAlignARender();
+
+       int render(Samples **samples, int64_t len, int64_t pos);
+};
+
+class MixersAlignPackage : public LoadPackage
+{
+public:
+       MixersAlignPackage();
+       ~MixersAlignPackage();
+
+       MixersAlignMixer *mixer;
+};
+
+class MixersAlignClient : public LoadClient
+{
+public:
+       MixersAlignClient(MixersAlignFarm *farm);
+       ~MixersAlignClient();
+
+        void process_package(LoadPackage *pkg);
+};
+
+class MixersAlignFarm : public LoadServer
+{
+public:
+       MixersAlignFarm(MixersAlign *dialog, int n);
+       ~MixersAlignFarm();
+       void init_packages();
+       LoadClient *new_client();
+       LoadPackage *new_package();
+
+       MixersAlign *dialog;
+};
+
+class MixersAlign : public BC_DialogThread, public FFT
+{
+public:
+       MixersAlign(MWindow *mwindow);
+       ~MixersAlign();
+
+       void start_dialog(int wx, int wy);
+       BC_Window *new_gui();
+       void load_mixers();
+       void load_mtracks();
+       void load_atracks();
+       void handle_done_event(int result);
+       void handle_close_event(int result);
+
+       int mixer_of(Track *track, int &midx);
+       int mixer_of(Track *track) { int midx = -1; return mixer_of(track, midx); }
+       int mmixer_of(int mi) {
+               return mi>=0 && mi<mtracks.size() ? mixer_of(mtracks[mi]->track) : -1;
+       }
+       int amixer_of(int ai) {
+               return ai>=0 && ai<atracks.size() ? mixer_of(atracks[ai]->track) : -1;
+       }
+
+       EDL *mixer_audio_clip(Mixer *mixer);
+       EDL *mixer_master_clip(Track *track);
+       int64_t mixer_tracks_total();
+       void load_master_audio(Track *track);
+       void scan_mixer_audio();
+       void update_progress(int64_t len);
+       void update_match();
+       void update();
+       void process_package(MixersAlignFarm *farm, MixersAlignPackage *package);
+       void apply();
+
+       MixersAlignWindow *ma_gui;
+       int wx, wy;
+       MixersAlignMixers mixers;
+       MixersAlignMTracks mtracks;
+       MixersAlignATracks atracks;
+       MWindow *mwindow;
+
+       EDL *undo_edl;
+       Mutex *farming;
+       MainProgressBar *progress;
+       MixersAlignThread *thread;
+       Mutex *total_lock;
+       int64_t total_rendered;
+       int failed;
+       int64_t master_len;
+       double *master_r, *master_i;
+       double master_start, master_end, master_ss;
+       double audio_start, audio_end;
+};
+
+#endif
diff --git a/cinelerra-5.1/cinelerra/mixersalign.inc b/cinelerra-5.1/cinelerra/mixersalign.inc
new file mode 100644 (file)
index 0000000..7e17048
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __MIXERSALIGN_INC__
+#define __MIXERSALIGN_INC__
+
+class MixersAlignMixer;
+class MixersAlignMixers;
+class MixersAlignMixerList;
+class MixersAlignMTrack;
+class MixersAlignMTracks;
+class MixersAlignMTrackList;
+class MixersAlignATrack;
+class MixersAlignATracks;
+class MixersAlignATrackList;
+class MixersAlignWindow;
+class MixersAlignARender;
+class MixersAlignPackage;
+class MixersAlignClient;
+class MixersAlignFarm;
+class MixersAlign;
+
+#endif
index da6056d..9a49f17 100644 (file)
@@ -80,6 +80,7 @@
 #include "mainsession.h"
 #include "mainundo.h"
 #include "mbuttons.h"
+#include "mixersalign.h"
 #include "mutex.h"
 #include "mwindowgui.h"
 #include "mwindow.h"
@@ -240,6 +241,7 @@ MWindow::MWindow()
        speed_edl = 0;
        proxy_beep = 0;
        shuttle = 0;
+       mixers_align = 0;
 }
 
 
@@ -264,6 +266,7 @@ MWindow::~MWindow()
        delete shuttle;         shuttle = 0;
        delete batch_render;    batch_render = 0;
        delete render;          render = 0;
+       delete mixers_align;    mixers_align = 0;
        commit_commercial();
        if( commercials && !commercials->remove_user() ) commercials = 0;
        close_mixers();
@@ -1549,6 +1552,8 @@ void MWindow::init_menus()
        ILACEFIXMETHODLISTADD(ILACE_FIXMETHOD_NONE);
        ILACEFIXMETHODLISTADD(ILACE_FIXMETHOD_UPONE);
        ILACEFIXMETHODLISTADD(ILACE_FIXMETHOD_DOWNONE);
+
+       mixers_align = new MixersAlign(this);
 }
 
 void MWindow::init_indexes()
index 3add4e7..0331d5c 100644 (file)
@@ -62,6 +62,7 @@
 #include "mainsession.inc"
 #include "mainundo.inc"
 #include "maxchannels.h"
+#include "mixersalign.inc"
 #include "mutex.inc"
 #include "mwindow.inc"
 #include "mwindowgui.inc"
@@ -227,7 +228,6 @@ public:
        void start_mixer();
        int select_zwindow(ZWindow *zwindow);
        void tile_mixers();
-
        int load_filenames(ArrayList<char*> *filenames,
                int load_mode = LOADMODE_REPLACE,
 // Cause the project filename on the top of the window to be updated.
@@ -635,6 +635,8 @@ public:
 // Mixer
        Mutex *zwindows_lock;
        ArrayList<ZWindow*> zwindows;
+       MixersAlign *mixers_align;
+
 // Asset manager
        AWindow *awindow;
 // Automation window
index 6bebe81..b5382c3 100644 (file)
@@ -850,46 +850,22 @@ void Track::synchronize_params(Track *track)
 }
 
 
-
-
-
 int Track::dump(FILE *fp)
 {
-       fprintf(fp,"   Data type %d\n", data_type);
+       fprintf(fp,"   Data type %d, draw %d, gang %d, play %d, record %d, nudge %jd\n",
+               data_type, draw, gang, play, record, nudge);
        fprintf(fp,"   Title %s\n", title);
        fprintf(fp,"   Edits:\n");
        for(Edit* current = edits->first; current; current = NEXT)
-       {
                current->dump(fp);
-       }
        automation->dump(fp);
        fprintf(fp,"   Plugin Sets: %d\n", plugin_set.total);
 
-       for(int i = 0; i < plugin_set.total; i++)
-               plugin_set.values[i]->dump(fp);
-//printf("Track::dump 2\n");
+       for( int i=0; i<plugin_set.total; ++i )
+               plugin_set[i]->dump(fp);
        return 0;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 
 Track::Track() : ListItem<Track>()
 {
index a6f6d73..65c3f31 100644 (file)
@@ -219,8 +219,7 @@ void ZWindow::handle_close_event(int result)
 void ZWindow::change_source(EDL *edl)
 {
        if( this->edl == edl ) return;
-       if( !edl || !this->edl || this->edl->equivalent_output(edl) >= 0 )
-               zgui->playback_engine->refresh_frame(CHANGE_ALL, edl);
+       zgui->playback_engine->refresh_frame(CHANGE_ALL, edl);
        if( this->edl )
                this->edl->remove_user();
        this->edl = edl;
index 5b4d8cc..6e388a0 100644 (file)
@@ -18,8 +18,8 @@
  *
  */
 
-#ifndef __CRIKEYWINDOW_H__
-#define __CRIKEYWINDOW_H__
+#ifndef __SKETCHERWINDOW_H__
+#define __SKETCHERWINDOW_H__
 
 #include "sketcher.h"
 #include "guicast.h"