Skip silent sources on session-archive -- fixes #7699
[ardour.git] / gtk2_ardour / analysis_window.cc
index f742afd7274a9a66ee901236919c3962e75d198c..91e6d133624a4479415cf9732f6a59c0e0f5f36b 100644 (file)
@@ -16,7 +16,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
 */
 
 #include <gtkmm2ext/gtk_ui.h>
@@ -25,9 +24,9 @@
 #include <gtkmm/treemodel.h>
 #include <gtkmm/treeiter.h>
 
-#include <ardour/audioregion.h>
-#include <ardour/audioplaylist.h>
-#include <ardour/types.h>
+#include "ardour/audioregion.h"
+#include "ardour/audioplaylist.h"
+#include "ardour/types.h"
 
 #include "analysis_window.h"
 
 #include "selection.h"
 #include "audio_region_view.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace ARDOUR;
 using namespace PBD;
 
 AnalysisWindow::AnalysisWindow()
-       : ArdourDialog(_("analysis window")),
-       
-         source_selection_label       (_("Signal source")),
-         source_selection_ranges_rb   (_("Selected ranges")),
-         source_selection_regions_rb  (_("Selected regions")),
-       
-         display_model_label                   (_("Display model")),
-         display_model_composite_separate_rb   (_("Composite graphs for each track")),
-         display_model_composite_all_tracks_rb (_("Composite graph of all tracks")),
-
-         fft_graph (2048)
+       : source_selection_label       (_("Signal source"))
+       , source_selection_ranges_rb   (_("Selected ranges"))
+       , source_selection_regions_rb  (_("Selected regions"))
+       , show_minmax_button           (_("Show frequency power range"))
+       , show_normalized_button       (_("Fit dB range"))
+       , show_proportional_button     (_("Proportional Spectrum, -18dB"))
+       , fft_graph                    (16384)
 {
+       set_name  (_("FFT analysis window"));
+       set_title (_("Spectral Analysis"));
+
        track_list_ready = false;
-       
+
        // Left side: track list + controls
        tlmodel = Gtk::ListStore::create(tlcols);
        track_list.set_model (tlmodel);
        track_list.append_column(_("Track"), tlcols.trackname);
-       track_list.append_column_editable(_("Visible"), tlcols.visible);
+       track_list.append_column_editable(_("Show"), tlcols.visible);
        track_list.set_headers_visible(true);
        track_list.set_reorderable(false);
        track_list.get_selection()->set_mode (Gtk::SELECTION_NONE);
@@ -69,16 +67,16 @@ AnalysisWindow::AnalysisWindow()
 
        Gtk::TreeViewColumn* track_col = track_list.get_column(0);
        Gtk::CellRendererText* renderer = dynamic_cast<Gtk::CellRendererText*>(track_list.get_column_cell_renderer (0));
-       
+
        track_col->add_attribute(renderer->property_foreground_gdk(), tlcols.color);
        track_col->set_expand(true);
 
 
        tlmodel->signal_row_changed().connect (
-                       mem_fun(*this, &AnalysisWindow::track_list_row_changed) );
-       
+                       sigc::mem_fun(*this, &AnalysisWindow::track_list_row_changed) );
+
        fft_graph.set_analysis_window(this);
-               
+
        vbox.pack_start(track_list);
 
 
@@ -90,66 +88,60 @@ AnalysisWindow::AnalysisWindow()
                source_selection_regions_rb.set_group(group);
 
                source_selection_ranges_rb.set_active();
-               
+
                vbox.pack_start (source_selection_ranges_rb,  false, false);
                vbox.pack_start (source_selection_regions_rb, false, false);
-               
+
                // "Selected ranges" radio
                source_selection_ranges_rb.signal_toggled().connect (
-                               bind ( mem_fun(*this, &AnalysisWindow::source_selection_changed), &source_selection_ranges_rb));
+                               sigc::bind ( sigc::mem_fun(*this, &AnalysisWindow::source_selection_changed), &source_selection_ranges_rb));
 
                // "Selected regions" radio
                source_selection_regions_rb.signal_toggled().connect (
-                               bind ( mem_fun(*this, &AnalysisWindow::source_selection_changed), &source_selection_regions_rb));
-       }
-       
-       vbox.pack_start(hseparator1, false, false);
-       
-       // "Display model"
-       vbox.pack_start(display_model_label, false, false);
-       {
-               Gtk::RadioButtonGroup group = display_model_composite_separate_rb.get_group();
-               display_model_composite_all_tracks_rb.set_group (group);
-               
-               display_model_composite_separate_rb.set_active();
-               
-               vbox.pack_start (display_model_composite_separate_rb,   false, false);
-               vbox.pack_start (display_model_composite_all_tracks_rb, false, false);
-
-               // "Composite graphs for all tracks"
-               display_model_composite_separate_rb.signal_toggled().connect (
-                               bind ( mem_fun(*this, &AnalysisWindow::display_model_changed), &display_model_composite_separate_rb));
-               
-               // "Composite graph of all tracks"
-               display_model_composite_all_tracks_rb.signal_toggled().connect (
-                               bind ( mem_fun(*this, &AnalysisWindow::display_model_changed), &display_model_composite_all_tracks_rb));
+                               sigc::bind ( sigc::mem_fun(*this, &AnalysisWindow::source_selection_changed), &source_selection_regions_rb));
        }
 
-       vbox.pack_start(hseparator2, false, false);
+       // Analyze button
 
        refresh_button.set_name("EditorGTKButton");
-       refresh_button.set_label(_("Analyze data"));
+       refresh_button.set_label(_("Re-analyze data"));
+
 
-       refresh_button.signal_clicked().connect ( bind ( mem_fun(*this, &AnalysisWindow::analyze_data), &refresh_button)); 
+       refresh_button.signal_clicked().connect ( sigc::bind ( sigc::mem_fun(*this, &AnalysisWindow::analyze_data), &refresh_button));
 
        vbox.pack_start(refresh_button, false, false, 10);
-       
-       
-       hbox.pack_start(vbox);
-       
+
+       vbox.pack_start(hseparator1, false, false);
+
+       // Feature checkboxes
+
+       // normalize, fit y-range
+       show_normalized_button.signal_toggled().connect( sigc::mem_fun(*this, &AnalysisWindow::show_normalized_changed));
+       vbox.pack_start(show_normalized_button, false, false);
+
+       // minmax
+       show_minmax_button.signal_toggled().connect( sigc::mem_fun(*this, &AnalysisWindow::show_minmax_changed));
+       vbox.pack_start(show_minmax_button, false, false);
+
+       // pink-noise / proportional spectrum
+       show_proportional_button.signal_toggled().connect( sigc::mem_fun(*this, &AnalysisWindow::show_proportional_changed));
+       vbox.pack_start(show_proportional_button, false, false);
+
+
+
+       hbox.pack_start(vbox, Gtk::PACK_SHRINK);
+
        // Analysis window on the right
        fft_graph.ensure_style();
 
        hbox.add(fft_graph);
-       
-       
 
-       // And last we pack the hbox
-       get_vbox()->pack_start(hbox);
 
-       track_list.show_all();
 
-       get_vbox()->show_all();
+       // And last we pack the hbox
+       add(hbox);
+       show_all();
+       track_list.show_all();
 }
 
 AnalysisWindow::~AnalysisWindow()
@@ -157,6 +149,24 @@ AnalysisWindow::~AnalysisWindow()
 
 }
 
+void
+AnalysisWindow::show_minmax_changed()
+{
+       fft_graph.set_show_minmax(show_minmax_button.get_active());
+}
+
+void
+AnalysisWindow::show_normalized_changed()
+{
+       fft_graph.set_show_normalized(show_normalized_button.get_active());
+}
+
+void
+AnalysisWindow::show_proportional_changed()
+{
+       fft_graph.set_show_proportioanl(show_proportional_button.get_active());
+}
+
 void
 AnalysisWindow::set_rangemode()
 {
@@ -169,8 +179,8 @@ AnalysisWindow::set_regionmode()
        source_selection_regions_rb.set_active(true);
 }
 
-void 
-AnalysisWindow::track_list_row_changed(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter)
+void
+AnalysisWindow::track_list_row_changed(const Gtk::TreeModel::Path& /*path*/, const Gtk::TreeModel::iterator& /*iter*/)
 {
        if (track_list_ready) {
                fft_graph.redraw();
@@ -183,7 +193,7 @@ AnalysisWindow::clear_tracklist()
 {
        // Empty track list & free old graphs
        Gtk::TreeNodeChildren children = track_list.get_model()->children();
-       
+
        for (Gtk::TreeIter i = children.begin(); i != children.end(); i++) {
                Gtk::TreeModel::Row row = *i;
 
@@ -193,10 +203,10 @@ AnalysisWindow::clear_tracklist()
 
                // Make sure it's not drawn
                row[tlcols.graph] = 0;
-               
+
                delete delete_me;
        }
-               
+
        tlmodel->clear();
 }
 
@@ -207,135 +217,150 @@ AnalysisWindow::analyze()
 }
 
 void
-AnalysisWindow::analyze_data (Gtk::Button *button)
+AnalysisWindow::analyze_data (Gtk::Button * /*button*/)
 {
        track_list_ready = false;
        {
-               Glib::Mutex::Lock lm  (track_list_lock);
+               Glib::Threads::Mutex::Lock lm  (track_list_lock);
 
                // Empty track list & free old graphs
                clear_tracklist();
-       
+
                // first we gather the FFTResults of all tracks
-       
+
                Sample *buf    = (Sample *) malloc(sizeof(Sample) * fft_graph.windowSize());
                Sample *mixbuf = (Sample *) malloc(sizeof(Sample) * fft_graph.windowSize());
                float  *gain   = (float *)  malloc(sizeof(float) * fft_graph.windowSize());
-               char   *work   = (char *)   malloc(sizeof(char) * fft_graph.windowSize());
-       
-               Selection s = PublicEditor::instance().get_selection();
-               TimeSelection ts = s.time;
-               RegionSelection ars = s.regions;
-       
-       
-               for (TrackSelection::iterator i = s.tracks.begin(); i != s.tracks.end(); ++i) {
-                       ARDOUR::AudioPlaylist *pl
-                               = dynamic_cast<ARDOUR::AudioPlaylist*>((*i)->playlist());
-
-                       if (!pl)
-                               continue;
-
-                       RouteUI *rui = dynamic_cast<RouteUI *>(*i);
-                       
-                       // Busses don't have playlists, so we need to check that we actually are working with a playlist
-                       if (!pl || !rui)
-                               continue;
-
-                       FFTResult *res = fft_graph.prepareResult(rui->color(), rui->route()->name());
-               
-                       // if timeSelection
-                       if (source_selection_ranges_rb.get_active()) {
-//                             cerr << "Analyzing ranges on track " << *&rui->route().name() << endl;
-                               
-                               for (std::list<ARDOUR::AudioRange>::iterator j = ts.begin(); j != ts.end(); ++j) {
-
-                                       jack_nframes_t i = 0;
+
+               Selection& s (PublicEditor::instance().get_selection());
+
+
+               // if timeSelection
+               if (source_selection_ranges_rb.get_active()) {
+                       TimeSelection ts = s.time;
+
+                       for (TrackSelection::iterator i = s.tracks.begin(); i != s.tracks.end(); ++i) {
+                               boost::shared_ptr<AudioPlaylist> pl
+                                       = boost::dynamic_pointer_cast<AudioPlaylist>((*i)->playlist());
+
+                               if (!pl)
+                                       continue;
+
+                               RouteUI *rui = dynamic_cast<RouteUI *>(*i);
+                               int n_inputs = rui->route()->n_inputs().n_audio(); // FFT is audio only
+
+                               // Busses don't have playlists, so we need to check that we actually are working with a playlist
+                               if (!pl || !rui)
+                                       continue;
+
+                               // std::cerr << "Analyzing ranges on track " << rui->route()->name() << std::endl;
+
+                               FFTResult *res = fft_graph.prepareResult(rui->route_color(), rui->route()->name());
+                               for (std::list<AudioRange>::iterator j = ts.begin(); j != ts.end(); ++j) {
+
                                        int n;
-                       
-                                       while ( i < (*j).length() ) {
-                                               // TODO: What about stereo+ channels? composite all to one, I guess
+                                       for (int channel = 0; channel < n_inputs; channel++) {
+                                               samplecnt_t x = 0;
 
-                                               n = fft_graph.windowSize();
+                                               while (x < j->length()) {
+                                                       // TODO: What about stereo+ channels? composite all to one, I guess
 
-                                               if (i + n >= (*j).length() ) {
-                                                       n = (*j).length() - i;
-                                               }
-                               
-                                               n = pl->read(buf, mixbuf, gain, work, (*j).start + i, n);
-       
-                                               if ( n < fft_graph.windowSize()) {
-                                                       for (int j = n; j < fft_graph.windowSize(); j++) {
-                                                               buf[j] = 0.0;
+                                                       n = fft_graph.windowSize();
+
+                                                       if (x + n >= (*j).length() ) {
+                                                               n = (*j).length() - x;
+                                                       }
+
+                                                       n = pl->read(buf, mixbuf, gain, (*j).start + x, n, channel);
+
+                                                       if ( n < fft_graph.windowSize()) {
+                                                               for (int j = n; j < fft_graph.windowSize(); j++) {
+                                                                       buf[j] = 0.0;
+                                                               }
                                                        }
+
+                                                       res->analyzeWindow(buf);
+
+                                                       x += n;
                                                }
-       
-                                               res->analyzeWindow(buf);
-                               
-                                               i += n;
                                        }
                                }
-                       } else if (source_selection_regions_rb.get_active()) {
-//                             cerr << "Analyzing selected regions on track " << *&rui->route().name() << endl;
-                               
-                               TimeAxisView *current_axis = (*i);
-                               
-                               for (std::set<RegionView *>::iterator j = ars.begin(); j != ars.end(); ++j) {
-                                       // Check that the region is actually audio (so we can analyze it)
-                                       AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*j);
-                                       if (!arv)
-                                               continue;
-                                       
-                                       // Check that the region really is selected on _this_ track/solo
-                                       if ( &arv->get_time_axis_view() != current_axis)
-                                               continue;
-
-//                                     cerr << " - " << (*j)->region().name() << ": " << (*j)->region().length() << " samples starting at " << (*j)->region().position() << endl;
-                                       jack_nframes_t i = 0;
-                                       int n;
+                               res->finalize();
+
+                               Gtk::TreeModel::Row newrow = *(tlmodel)->append();
+                               newrow[tlcols.trackname]   = rui->route()->name();
+                               newrow[tlcols.visible]     = true;
+                               newrow[tlcols.color]       = rui->route_color ();
+                               newrow[tlcols.graph]       = res;
+                       }
+               } else if (source_selection_regions_rb.get_active()) {
+                       RegionSelection ars = s.regions;
+                       // std::cerr << "Analyzing selected regions" << std::endl;
+
+                       for (RegionSelection::iterator j = ars.begin(); j != ars.end(); ++j) {
+                               // Check that the region is actually audio (so we can analyze it)
+                               AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*j);
+                               if (!arv)
+                                       continue;
+
+                               // std::cerr << " - " << (*j)->region().name() << ": " << (*j)->region().length() << " samples starting at " << (*j)->region().position() << std::endl;
+                               RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(&arv->get_time_axis_view());
+                               if (!rtav) {
+                                       /* shouldn't happen... */
+                                       continue;
+                               }
+                               FFTResult *res = fft_graph.prepareResult(rtav->color(), arv->get_item_name());
+                               int n;
+                               for (unsigned int channel = 0; channel < arv->region()->n_channels(); channel++) {
+
+                                       samplecnt_t x = 0;
+                                       samplecnt_t length = arv->region()->length();
 
-                                       while ( i < arv->region().length() ) {
+                                       while (x < length) {
                                                // TODO: What about stereo+ channels? composite all to one, I guess
 
                                                n = fft_graph.windowSize();
-                                               if (i + n >= arv->region().length() ) {
-                                                       n = arv->region().length() - i;
+                                               if (x + n >= length ) {
+                                                       n = length - x;
                                                }
 
-                                               n = arv->audio_region().read_at(buf, mixbuf, gain, work, arv->region().position() + i, n);
-       
+                                               memset (buf, 0, n * sizeof (Sample));
+                                               n = arv->audio_region()->read_at(buf, mixbuf, gain, arv->region()->position() + x, n, channel);
+
+                                               if (n == 0)
+                                                       break;
+
                                                if ( n < fft_graph.windowSize()) {
                                                        for (int j = n; j < fft_graph.windowSize(); j++) {
                                                                buf[j] = 0.0;
                                                        }
                                                }
-       
+
                                                res->analyzeWindow(buf);
-                               
-                                               i += n;
+                                               x += n;
                                        }
-//                                     cerr << "Found: " << (*j)->get_item_name() << endl;
-
                                }
+                               // std::cerr << "Found: " << (*j)->get_item_name() << std::endl;
+                               res->finalize();
+
+                               Gtk::TreeModel::Row newrow = *(tlmodel)->append();
+                               newrow[tlcols.trackname]   = arv->get_item_name();
+                               newrow[tlcols.visible]     = true;
+                               newrow[tlcols.color]       = rtav->color();
+                               newrow[tlcols.graph]       = res;
 
                        }
-                       res->finalize();
 
-                               
-                       Gtk::TreeModel::Row newrow = *(tlmodel)->append();
-                       newrow[tlcols.trackname]   = rui->route()->name();
-                       newrow[tlcols.visible]     = true;
-                       newrow[tlcols.color]       = rui->color();
-                       newrow[tlcols.graph]       = res;
-               }       
+               }
+
 
-       
                free(buf);
                free(mixbuf);
-               free(work);
+               free(gain);
 
                track_list_ready = true;
        } /* end lock */
-       
+
        fft_graph.redraw();
 }
 
@@ -348,13 +373,13 @@ AnalysisWindow::source_selection_changed (Gtk::RadioButton *button)
 
        /*
        cerr << "AnalysisWindow: signal source = ";
-       
+
        if (button == &source_selection_ranges_rb) {
                cerr << "selected ranges" << endl;
-               
+
        } else if (button == &source_selection_regions_rb) {
                cerr << "selected regions" << endl;
-               
+
        } else {
                cerr << "unknown?" << endl;
        }
@@ -370,7 +395,7 @@ AnalysisWindow::display_model_changed (Gtk::RadioButton *button)
 
        /*
        cerr << "AnalysisWindow: display model = ";
-       
+
        if (button == &display_model_composite_separate_rb) {
                cerr << "separate composites of tracks" << endl;
        } else if (button == &display_model_composite_all_tracks_rb) {
@@ -380,5 +405,5 @@ AnalysisWindow::display_model_changed (Gtk::RadioButton *button)
        }
        */
 }
-         
+