show() widgets explicitly in gtk2_ardour/analysis_window.cc
[ardour.git] / gtk2_ardour / analysis_window.cc
1 /*
2     Copyright (C) 2006 Paul Davis
3     Written by Sampo Savolainen
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include <gtkmm2ext/gtk_ui.h>
22 #include <gtkmm/stock.h>
23 #include <gtkmm/label.h>
24 #include <gtkmm/treemodel.h>
25 #include <gtkmm/treeiter.h>
26
27 #include <ardour/audioregion.h>
28 #include <ardour/audioplaylist.h>
29 #include <ardour/types.h>
30
31 #include "analysis_window.h"
32
33 #include "route_ui.h"
34 #include "time_axis_view.h"
35 #include "public_editor.h"
36 #include "selection.h"
37 #include "audio_region_view.h"
38
39 #include "i18n.h"
40
41 using namespace ARDOUR;
42 using namespace PBD;
43
44 AnalysisWindow::AnalysisWindow()
45         : ArdourDialog(_("analysis window")),
46         
47           source_selection_label       (_("Signal source")),
48           source_selection_ranges_rb   (_("Selected ranges")),
49           source_selection_regions_rb  (_("Selected regions")),
50         
51           display_model_label                   (_("Display model")),
52           display_model_composite_separate_rb   (_("Composite graphs for each track")),
53           display_model_composite_all_tracks_rb (_("Composite graph of all tracks")),
54
55           fft_graph (2048)
56 {
57         track_list_ready = false;
58         
59         // Left side: track list + controls
60         tlmodel = Gtk::ListStore::create(tlcols);
61         track_list.set_model (tlmodel);
62         track_list.append_column(_("Track"), tlcols.trackname);
63         track_list.append_column_editable(_("Show"), tlcols.visible);
64         track_list.set_headers_visible(true);
65         track_list.set_reorderable(false);
66         track_list.get_selection()->set_mode (Gtk::SELECTION_NONE);
67
68
69         Gtk::TreeViewColumn* track_col = track_list.get_column(0);
70         Gtk::CellRendererText* renderer = dynamic_cast<Gtk::CellRendererText*>(track_list.get_column_cell_renderer (0));
71         
72         track_col->add_attribute(renderer->property_foreground_gdk(), tlcols.color);
73         track_col->set_expand(true);
74
75
76         tlmodel->signal_row_changed().connect (
77                         mem_fun(*this, &AnalysisWindow::track_list_row_changed) );
78         
79         fft_graph.set_analysis_window(this);
80                 
81         vbox.pack_start(track_list);
82
83
84         // "Signal source"
85         vbox.pack_start(source_selection_label, false, false);
86
87         {
88                 Gtk::RadioButtonGroup group = source_selection_ranges_rb.get_group();
89                 source_selection_regions_rb.set_group(group);
90
91                 source_selection_ranges_rb.set_active();
92                 
93                 vbox.pack_start (source_selection_ranges_rb,  false, false);
94                 vbox.pack_start (source_selection_regions_rb, false, false);
95                 
96                 // "Selected ranges" radio
97                 source_selection_ranges_rb.signal_toggled().connect (
98                                 bind ( mem_fun(*this, &AnalysisWindow::source_selection_changed), &source_selection_ranges_rb));
99
100                 // "Selected regions" radio
101                 source_selection_regions_rb.signal_toggled().connect (
102                                 bind ( mem_fun(*this, &AnalysisWindow::source_selection_changed), &source_selection_regions_rb));
103         }
104         
105         vbox.pack_start(hseparator1, false, false);
106         
107         // "Display model"
108         vbox.pack_start(display_model_label, false, false);
109         {
110                 Gtk::RadioButtonGroup group = display_model_composite_separate_rb.get_group();
111                 display_model_composite_all_tracks_rb.set_group (group);
112                 
113                 display_model_composite_separate_rb.set_active();
114                 
115                 vbox.pack_start (display_model_composite_separate_rb,   false, false);
116                 vbox.pack_start (display_model_composite_all_tracks_rb, false, false);
117
118                 // "Composite graphs for all tracks"
119                 display_model_composite_separate_rb.signal_toggled().connect (
120                                 bind ( mem_fun(*this, &AnalysisWindow::display_model_changed), &display_model_composite_separate_rb));
121                 
122                 // "Composite graph of all tracks"
123                 display_model_composite_all_tracks_rb.signal_toggled().connect (
124                                 bind ( mem_fun(*this, &AnalysisWindow::display_model_changed), &display_model_composite_all_tracks_rb));
125         }
126
127         vbox.pack_start(hseparator2, false, false);
128
129         refresh_button.set_name("EditorGTKButton");
130         refresh_button.set_label(_("Analyze data"));
131
132         refresh_button.signal_clicked().connect ( bind ( mem_fun(*this, &AnalysisWindow::analyze_data), &refresh_button)); 
133
134         vbox.pack_start(refresh_button, false, false, 10);
135         
136         
137         hbox.pack_start(vbox);
138         
139         // Analysis window on the right
140         fft_graph.ensure_style();
141
142         hbox.add(fft_graph);
143         
144         
145
146         // And last we pack the hbox
147         get_vbox()->pack_start(hbox);
148
149         track_list.show_all();
150
151         hbox.show();
152         vbox.show();
153         track_list.show();
154         source_selection_label.show();
155         source_selection_ranges_rb.show();
156         source_selection_regions_rb.show();
157         hseparator1.show();
158         display_model_label.show();
159         display_model_composite_separate_rb.show();
160         display_model_composite_all_tracks_rb.show();
161         hseparator2.show();
162         refresh_button.show();
163
164         //get_vbox()->show();
165 }
166
167 AnalysisWindow::~AnalysisWindow()
168 {
169
170 }
171
172 void
173 AnalysisWindow::set_rangemode()
174 {
175         source_selection_ranges_rb.set_active(true);
176 }
177
178 void
179 AnalysisWindow::set_regionmode()
180 {
181         source_selection_regions_rb.set_active(true);
182 }
183
184 void 
185 AnalysisWindow::track_list_row_changed(const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter)
186 {
187         if (track_list_ready) {
188                 fft_graph.redraw();
189         }
190 }
191
192
193 void
194 AnalysisWindow::clear_tracklist()
195 {
196         // Empty track list & free old graphs
197         Gtk::TreeNodeChildren children = track_list.get_model()->children();
198         
199         for (Gtk::TreeIter i = children.begin(); i != children.end(); i++) {
200                 Gtk::TreeModel::Row row = *i;
201
202                 FFTResult *delete_me = row[tlcols.graph];
203                 if (delete_me == 0)
204                         continue;
205
206                 // Make sure it's not drawn
207                 row[tlcols.graph] = 0;
208                 
209                 delete delete_me;
210         }
211                 
212         tlmodel->clear();
213 }
214
215 void
216 AnalysisWindow::analyze()
217 {
218         analyze_data(&refresh_button);
219 }
220
221 void
222 AnalysisWindow::analyze_data (Gtk::Button *button)
223 {
224         track_list_ready = false;
225         {
226                 Glib::Mutex::Lock lm  (track_list_lock);
227
228                 // Empty track list & free old graphs
229                 clear_tracklist();
230         
231                 // first we gather the FFTResults of all tracks
232         
233                 Sample *buf    = (Sample *) malloc(sizeof(Sample) * fft_graph.windowSize());
234                 Sample *mixbuf = (Sample *) malloc(sizeof(Sample) * fft_graph.windowSize());
235                 float  *gain   = (float *)  malloc(sizeof(float) * fft_graph.windowSize());
236         
237                 Selection s = PublicEditor::instance().get_selection();
238                 TimeSelection ts = s.time;
239                 RegionSelection ars = s.regions;
240         
241                 for (TrackSelection::iterator i = s.tracks.begin(); i != s.tracks.end(); ++i) {
242                         boost::shared_ptr<AudioPlaylist> pl
243                                 = boost::dynamic_pointer_cast<AudioPlaylist>((*i)->playlist());
244
245                         if (!pl)
246                                 continue;
247
248                         RouteUI *rui = dynamic_cast<RouteUI *>(*i);
249                         
250                         // Busses don't have playlists, so we need to check that we actually are working with a playlist
251                         if (!pl || !rui)
252                                 continue;
253
254                         FFTResult *res = fft_graph.prepareResult(rui->color(), rui->route()->name());
255                 
256                         // if timeSelection
257                         if (source_selection_ranges_rb.get_active()) {
258 //                              cerr << "Analyzing ranges on track " << *&rui->route().name() << endl;
259                                 
260                                 for (std::list<AudioRange>::iterator j = ts.begin(); j != ts.end(); ++j) {
261
262                                         nframes_t i = 0;
263                                         int n;
264                         
265                                         while ( i < (*j).length() ) {
266                                                 // TODO: What about stereo+ channels? composite all to one, I guess
267
268                                                 n = fft_graph.windowSize();
269
270                                                 if (i + n >= (*j).length() ) {
271                                                         n = (*j).length() - i;
272                                                 }
273                                 
274                                                 n = pl->read(buf, mixbuf, gain, (*j).start + i, n);
275         
276                                                 if ( n < fft_graph.windowSize()) {
277                                                         for (int j = n; j < fft_graph.windowSize(); j++) {
278                                                                 buf[j] = 0.0;
279                                                         }
280                                                 }
281         
282                                                 res->analyzeWindow(buf);
283                                 
284                                                 i += n;
285                                         }
286                                 }
287                         } else if (source_selection_regions_rb.get_active()) {
288 //                              cerr << "Analyzing selected regions on track " << *&rui->route().name() << endl;
289                                 
290                                 TimeAxisView *current_axis = (*i);
291                                 
292                                 for (RegionSelection::iterator j = ars.begin(); j != ars.end(); ++j) {
293                                         // Check that the region is actually audio (so we can analyze it)
294                                         AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*j);
295                                         if (!arv)
296                                                 continue;
297                                         
298                                         // Check that the region really is selected on _this_ track/solo
299                                         if ( &arv->get_time_axis_view() != current_axis)
300                                                 continue;
301
302 //                                      cerr << " - " << (*j)->region().name() << ": " << (*j)->region().length() << " samples starting at " << (*j)->region().position() << endl;
303                                         nframes_t i = 0;
304                                         int n;
305
306                                         while ( i < arv->region()->length() ) {
307                                                 // TODO: What about stereo+ channels? composite all to one, I guess
308
309                                                 n = fft_graph.windowSize();
310                                                 if (i + n >= arv->region()->length() ) {
311                                                         n = arv->region()->length() - i;
312                                                 }
313
314                                                 n = arv->audio_region()->read_at(buf, mixbuf, gain, arv->region()->position() + i, n);
315         
316                                                 if ( n < fft_graph.windowSize()) {
317                                                         for (int j = n; j < fft_graph.windowSize(); j++) {
318                                                                 buf[j] = 0.0;
319                                                         }
320                                                 }
321         
322                                                 res->analyzeWindow(buf);
323                                 
324                                                 i += n;
325                                         }
326 //                                      cerr << "Found: " << (*j)->get_item_name() << endl;
327
328                                 }
329
330                         }
331                         res->finalize();
332
333                                 
334                         Gtk::TreeModel::Row newrow = *(tlmodel)->append();
335                         newrow[tlcols.trackname]   = rui->route()->name();
336                         newrow[tlcols.visible]     = true;
337                         newrow[tlcols.color]       = rui->color();
338                         newrow[tlcols.graph]       = res;
339                 }       
340
341         
342                 free(buf);
343                 free(mixbuf);
344
345                 track_list_ready = true;
346         } /* end lock */
347         
348         fft_graph.redraw();
349 }
350
351 void
352 AnalysisWindow::source_selection_changed (Gtk::RadioButton *button)
353 {
354         // We are only interested in activation signals, not deactivation signals
355         if (!button->get_active())
356                 return;
357
358         /*
359         cerr << "AnalysisWindow: signal source = ";
360         
361         if (button == &source_selection_ranges_rb) {
362                 cerr << "selected ranges" << endl;
363                 
364         } else if (button == &source_selection_regions_rb) {
365                 cerr << "selected regions" << endl;
366                 
367         } else {
368                 cerr << "unknown?" << endl;
369         }
370         */
371 }
372
373 void
374 AnalysisWindow::display_model_changed (Gtk::RadioButton *button)
375 {
376         // We are only interested in activation signals, not deactivation signals
377         if (!button->get_active())
378                 return;
379
380         /*
381         cerr << "AnalysisWindow: display model = ";
382         
383         if (button == &display_model_composite_separate_rb) {
384                 cerr << "separate composites of tracks" << endl;
385         } else if (button == &display_model_composite_all_tracks_rb) {
386                 cerr << "composite of all tracks" << endl;
387         } else {
388                 cerr << "unknown?" << endl;
389         }
390         */
391 }
392           
393