X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fanalysis_window.cc;h=506e12978183c9e4dc144b981a5e8cdf743a8cf0;hb=cf52d6e4b40111eb04b244ec054055a4ec15dbe0;hp=b8318f45feae0b3967bc444a67e2aa4c207ad2c3;hpb=912da52a539981193941d8739fa6f103b5e406db;p=ardour.git diff --git a/gtk2_ardour/analysis_window.cc b/gtk2_ardour/analysis_window.cc index b8318f45fe..506e129781 100644 --- a/gtk2_ardour/analysis_window.cc +++ b/gtk2_ardour/analysis_window.cc @@ -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 @@ -25,9 +24,9 @@ #include #include -#include -#include -#include +#include "ardour/audioregion.h" +#include "ardour/audioplaylist.h" +#include "ardour/types.h" #include "analysis_window.h" @@ -35,34 +34,32 @@ #include "time_axis_view.h" #include "public_editor.h" #include "selection.h" -#include "regionview.h" +#include "audio_region_view.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; using namespace PBD; AnalysisWindow::AnalysisWindow() - : ArdourDialog(_("analysis window")), - - fft_graph (2048), - - 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")) - + : 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 Spectum, -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); @@ -70,16 +67,16 @@ AnalysisWindow::AnalysisWindow() Gtk::TreeViewColumn* track_col = track_list.get_column(0); Gtk::CellRendererText* renderer = dynamic_cast(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); @@ -91,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() @@ -158,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() { @@ -170,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(); @@ -184,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; @@ -194,10 +203,10 @@ AnalysisWindow::clear_tracklist() // Make sure it's not drawn row[tlcols.graph] = 0; - + delete delete_me; } - + tlmodel->clear(); } @@ -208,125 +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; - AudioRegionSelection ars = s.audio_regions; - - - for (TrackSelection::iterator i = s.tracks.begin(); i != s.tracks.end(); ++i) { - ARDOUR::Playlist *pl = (*i)->playlist(); - RouteUI *rui = dynamic_cast(*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::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 pl + = boost::dynamic_pointer_cast((*i)->playlist()); + + if (!pl) + continue; + + RouteUI *rui = dynamic_cast(*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::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++) { + framecnt_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::iterator j = ars.begin(); j != ars.end(); ++j) { - // Check that the region really is selected on _this_ track/solo - if ( &(*j)->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(); - while ( i < (*j)->region.length() ) { + 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(*j); + if (!arv) + continue; + + // std::cerr << " - " << (*j)->region().name() << ": " << (*j)->region().length() << " samples starting at " << (*j)->region().position() << std::endl; + RouteTimeAxisView *rtav = dynamic_cast(&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++) { + + framecnt_t x = 0; + framecnt_t length = arv->region()->length(); + + while (x < length) { // TODO: What about stereo+ channels? composite all to one, I guess n = fft_graph.windowSize(); - if (i + n >= (*j)->region.length() ) { - n = (*j)->region.length() - i; + if (x + n >= length ) { + n = length - x; } - - n = (*j)->region.read_at(buf, mixbuf, gain, work, (*j)->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(); } @@ -339,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; } @@ -361,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) { @@ -371,5 +405,5 @@ AnalysisWindow::display_model_changed (Gtk::RadioButton *button) } */ } - +