summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2008-01-25 05:35:46 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2008-01-25 05:35:46 +0000
commitd3f64c28489d2358498b9d7dcfc6fa4228ebd63e (patch)
tree8195496c9330bb4fb279d282598da6dc5c98a361 /gtk2_ardour
parent28e6ad009158ddaea80fd5d800befcbf58ce47ee (diff)
meet rhythm ferret: cute, furry and always on time (ardour build now requires fftw3 & fftw3f, no exceptions, ever)
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2959 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/SConscript8
-rw-r--r--gtk2_ardour/ardour.menus1
-rw-r--r--gtk2_ardour/au_pluginui.h1
-rw-r--r--gtk2_ardour/editor.cc18
-rw-r--r--gtk2_ardour/editor.h6
-rw-r--r--gtk2_ardour/editor_actions.cc3
-rw-r--r--gtk2_ardour/editor_ops.cc82
-rw-r--r--gtk2_ardour/rhythm_ferret.cc376
-rw-r--r--gtk2_ardour/rhythm_ferret.h100
-rw-r--r--gtk2_ardour/time_axis_view.cc35
-rw-r--r--gtk2_ardour/time_axis_view.h5
11 files changed, 633 insertions, 2 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript
index 3ece6ee91c..f8d107a8a9 100644
--- a/gtk2_ardour/SConscript
+++ b/gtk2_ardour/SConscript
@@ -50,6 +50,10 @@ gtkardour.Merge ([
libraries['xml'],
libraries['xslt'],
libraries['samplerate'],
+ libraries['vamp'],
+ libraries['vamphost'],
+ libraries['fftw3f'],
+ libraries['fftw3'],
libraries['jack']
])
@@ -75,7 +79,7 @@ if gtkardour['FFT_ANALYSIS']:
gtkardour.Append(CCFLAGS='-DFFT_ANALYSIS')
if gtkardour['RUBBERBAND']:
- gtkardour.Merge ([ libraries['rubberband'], libraries['vamp'], libraries['fftw3f'], libraries['fftw3'] ])
+ gtkardour.Merge ([ libraries['rubberband'] ])
else:
gtkardour.Merge ([ libraries['soundtouch'] ])
@@ -188,7 +192,6 @@ new_session_dialog.cc
option_editor.cc
opts.cc
pan_automation_time_axis.cc
-
panner.cc
panner2d.cc
panner_ui.cc
@@ -200,6 +203,7 @@ public_editor.cc
redirect_automation_line.cc
redirect_automation_time_axis.cc
redirect_box.cc
+rhythm_ferret.cc
audio_region_editor.cc
region_gain_line.cc
region_selection.cc
diff --git a/gtk2_ardour/ardour.menus b/gtk2_ardour/ardour.menus
index 23a803161b..09d07494dd 100644
--- a/gtk2_ardour/ardour.menus
+++ b/gtk2_ardour/ardour.menus
@@ -161,6 +161,7 @@
<menuitem action='select-prev-route'/>
</menu>
<menu name='Regions' action='Regions'>
+ <menuitem action='split-region-at-transients'/>
<menuitem action='crop'/>
<menuitem action='duplicate-region'/>
<menuitem action='multi-duplicate-region'/>
diff --git a/gtk2_ardour/au_pluginui.h b/gtk2_ardour/au_pluginui.h
index 46e4cde12f..5bec967091 100644
--- a/gtk2_ardour/au_pluginui.h
+++ b/gtk2_ardour/au_pluginui.h
@@ -3,6 +3,7 @@
#include <AppKit/AppKit.h>
#include <Carbon/Carbon.h>
+#include <AudioUnit/AudioUnitCarbonView.h>
#include <AudioUnit/AudioUnit.h>
/* fix up stupid apple macros */
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index 9e3cc60466..cb43a987b5 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -79,6 +79,7 @@
#include "actions.h"
#include "gui_thread.h"
#include "sfdb_ui.h"
+#include "rhythm_ferret.h"
#ifdef FFT_ANALYSIS
#include "analysis_window.h"
@@ -328,6 +329,7 @@ Editor::Editor ()
_dragging_hscrollbar = false;
select_new_marker = false;
zoomed_to_region = false;
+ rhythm_ferret = 0;
scrubbing_direction = 0;
@@ -1161,6 +1163,10 @@ Editor::connect_to_session (Session *t)
_playlist_selector->set_session (session);
nudge_clock.set_session (session);
+ if (rhythm_ferret) {
+ rhythm_ferret->set_session (session);
+ }
+
#ifdef FFT_ANALYSIS
if (analysis_window != 0)
analysis_window->set_session (session);
@@ -4359,3 +4365,15 @@ Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<R
}
}
}
+
+void
+Editor::show_rhythm_ferret ()
+{
+ if (rhythm_ferret == 0) {
+ rhythm_ferret = new RhythmFerret(*this);
+ }
+
+ rhythm_ferret->set_session (session);
+ rhythm_ferret->show ();
+ rhythm_ferret->present ();
+}
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 9e155dc5b9..5ce99636db 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -105,6 +105,7 @@ class StreamView;
class AudioStreamView;
class ControlPoint;
class SoundFileOmega;
+class RhythmFerret;
#ifdef FFT_ANALYSIS
class AnalysisWindow;
#endif
@@ -361,6 +362,8 @@ class Editor : public PublicEditor
void toggle_meter_updating();
+ void show_rhythm_ferret();
+
protected:
void map_transport_state ();
void map_position_change (nframes_t);
@@ -981,6 +984,7 @@ class Editor : public PublicEditor
void normalize_region ();
void denormalize_region ();
void adjust_region_scale_amplitude (bool up);
+ void split_region_at_transients ();
void use_region_as_bar ();
void use_range_as_bar ();
@@ -2061,6 +2065,8 @@ class Editor : public PublicEditor
void select_next_route ();
void select_prev_route ();
+
+ RhythmFerret* rhythm_ferret;
};
#endif /* __ardour_editor_h__ */
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index 4bb0d74aeb..ae1b93e919 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -364,6 +364,9 @@ Editor::register_actions ()
act = ActionManager::register_action (editor_actions, "set-tempo-from-edit-range", _("Set Tempo from Edit Range=Bar"), mem_fun(*this, &Editor::use_range_as_bar));
ActionManager::session_sensitive_actions.push_back (act);
+ act = ActionManager::register_action (editor_actions, "split-region-at-transients", _("Other Temporary Label"), mem_fun(*this, &Editor::split_region_at_transients));
+ ActionManager::session_sensitive_actions.push_back (act);
+
act = ActionManager::register_action (editor_actions, "crop", _("Crop"), mem_fun(*this, &Editor::crop_region_to_selection));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "insert-chunk", _("Insert Chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f));
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index f960f27d0f..0e725aeda2 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -43,10 +43,12 @@
#include <ardour/location.h>
#include <ardour/named_selection.h>
#include <ardour/audio_track.h>
+#include <ardour/audiofilesource.h>
#include <ardour/audioplaylist.h>
#include <ardour/region_factory.h>
#include <ardour/playlist_factory.h>
#include <ardour/reverse.h>
+#include <ardour/transient_detector.h>
#include <ardour/dB.h>
#include "ardour_ui.h"
@@ -5013,3 +5015,83 @@ Editor::define_one_bar (nframes64_t start, nframes64_t end)
session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), &before, &after));
commit_reversible_command ();
}
+
+void
+Editor::split_region_at_transients ()
+{
+ list<nframes64_t> transients;
+
+ if (!session) {
+ return;
+ }
+
+ ExclusiveRegionSelection esr (*this, entered_regionview);
+
+ if (selection->regions.empty()) {
+ return;
+ }
+
+ show_rhythm_ferret ();
+ return;
+#if 0
+
+ cerr << "selection size is " << selection->regions.size() << endl;
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ) {
+
+ RegionSelection::iterator tmp;
+
+ tmp = i;
+ ++tmp;
+
+ cerr << "working on " << (*i)->get_item_name() << endl;
+
+ boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
+
+ if (!ar) {
+ continue;
+ }
+
+ boost::shared_ptr<Playlist> pl = ar->playlist();
+
+ if (!pl) {
+ continue;
+ }
+
+ cerr << "getting transients\n";
+
+ ar->get_transients (transients);
+ nframes64_t start = ar->start();
+ nframes64_t pos = ar->position();
+
+ pl->freeze ();
+ pl->remove_region (ar);
+
+ cerr << "creating new regions from " << transients.size() << " transients\n";
+
+ for (list<nframes64_t>::iterator x = transients.begin(); x != transients.end(); ++x) {
+
+ nframes_t len = (*x) - start;
+
+ string new_name;
+
+ if (session->region_name (new_name, ar->name())) {
+ continue;
+ }
+
+ pl->add_region (RegionFactory::create (ar->get_sources(), start, len, new_name), pos);
+
+ start = (*x);
+ pos += len;
+ }
+
+ pl->thaw ();
+
+ transients.clear ();
+
+ cerr << "done with that one\n";
+
+ i = tmp;
+ }
+#endif
+}
diff --git a/gtk2_ardour/rhythm_ferret.cc b/gtk2_ardour/rhythm_ferret.cc
new file mode 100644
index 0000000000..a52980167f
--- /dev/null
+++ b/gtk2_ardour/rhythm_ferret.cc
@@ -0,0 +1,376 @@
+#include <gtkmm/stock.h>
+#include <gtkmm2ext/utils.h>
+
+#include <pbd/memento_command.h>
+
+#include <ardour/transient_detector.h>
+#include <ardour/audiosource.h>
+#include <ardour/audioregion.h>
+#include <ardour/playlist.h>
+#include <ardour/region_factory.h>
+#include <ardour/session.h>
+
+#include "rhythm_ferret.h"
+#include "audio_region_view.h"
+#include "public_editor.h"
+
+#include "i18n.h"
+
+using namespace std;
+using namespace Gtk;
+using namespace Gdk;
+using namespace PBD;
+using namespace ARDOUR;
+
+/* order of these must match the AnalysisMode enums
+ in rhythm_ferret.h
+*/
+static const gchar * _analysis_mode_strings[] = {
+ N_("Percussive Onset"),
+ N_("Note Onset"),
+ 0
+};
+
+RhythmFerret::RhythmFerret (PublicEditor& e)
+ : ArdourDialog (_("Rhythm Ferret"))
+ , editor (e)
+ , operation_frame (_("Operation"))
+ , selection_frame (_("Selection"))
+ , ferret_frame (_("Analysis"))
+ , logo (0)
+ , region_split_button (operation_button_group, _("Split Region"))
+ , tempo_button (operation_button_group, _("Set Tempo Map"))
+ , region_conform_button (operation_button_group, _("Conform Region"))
+ , analysis_mode_label (_("Mode"))
+ , detection_threshold_adjustment (3, 0, 20, 1, 4)
+ , detection_threshold_scale (detection_threshold_adjustment)
+ , detection_threshold_label (_("Threshold"))
+ , sensitivity_adjustment (40, 0, 100, 1, 10)
+ , sensitivity_scale (sensitivity_adjustment)
+ , sensitivity_label (_("Sensitivity"))
+ , analyze_button (_("Analyze"))
+ , trigger_gap_adjustment (3, 0, 100, 1, 10)
+ , trigger_gap_spinner (trigger_gap_adjustment)
+ , trigger_gap_label (_("Trigger gap (msecs)"))
+ , action_button (Stock::APPLY)
+
+{
+ upper_hpacker.set_spacing (6);
+
+ upper_hpacker.pack_start (operation_frame, true, true);
+ upper_hpacker.pack_start (selection_frame, true, true);
+ upper_hpacker.pack_start (ferret_frame, true, true);
+
+ op_packer.pack_start (region_split_button, false, false);
+ op_packer.pack_start (tempo_button, false, false);
+ op_packer.pack_start (region_conform_button, false, false);
+
+ operation_frame.add (op_packer);
+
+ HBox* box;
+
+ ferret_packer.set_spacing (6);
+ ferret_packer.set_border_width (6);
+
+ vector<string> strings;
+
+ analysis_mode_strings = I18N (_analysis_mode_strings);
+ Gtkmm2ext::set_popdown_strings (analysis_mode_selector, analysis_mode_strings);
+ analysis_mode_selector.set_active_text (analysis_mode_strings.front());
+
+ box = manage (new HBox);
+ box->set_spacing (6);
+ box->pack_start (analysis_mode_label, false, false);
+ box->pack_start (analysis_mode_selector, true, true);
+ ferret_packer.pack_start (*box, false, false);
+
+ box = manage (new HBox);
+ box->set_spacing (6);
+ box->pack_start (detection_threshold_label, false, false);
+ box->pack_start (detection_threshold_scale, true, true);
+ ferret_packer.pack_start (*box, false, false);
+
+ box = manage (new HBox);
+ box->set_spacing (6);
+ box->pack_start (sensitivity_label, false, false);
+ box->pack_start (sensitivity_scale, true, true);
+ ferret_packer.pack_start (*box, false, false);
+
+ box = manage (new HBox);
+ box->set_spacing (6);
+ box->pack_start (trigger_gap_label, false, false);
+ box->pack_start (trigger_gap_spinner, false, false);
+ ferret_packer.pack_start (*box, false, false);
+
+ ferret_packer.pack_start (analyze_button, false, false);
+
+ analyze_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::run_analysis));
+
+ ferret_frame.add (ferret_packer);
+
+ // Glib::RefPtr<Pixbuf> logo_pixbuf ("somefile");
+
+ if (logo) {
+ lower_hpacker.pack_start (*logo, false, false);
+ }
+
+ lower_hpacker.pack_start (operation_clarification_label, false, false);
+ lower_hpacker.pack_start (action_button, false, false);
+
+ action_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::do_action));
+
+ get_vbox()->set_border_width (6);
+ get_vbox()->set_spacing (6);
+ get_vbox()->pack_start (upper_hpacker, true, true);
+ get_vbox()->pack_start (lower_hpacker, false, false);
+
+ show_all ();
+}
+
+RhythmFerret::~RhythmFerret()
+{
+ if (logo) {
+ delete logo;
+ }
+}
+
+RhythmFerret::AnalysisMode
+RhythmFerret::get_analysis_mode () const
+{
+ string str = analysis_mode_selector.get_active_text ();
+
+ if (str == _(_analysis_mode_strings[(int) NoteOnset])) {
+ return NoteOnset;
+ }
+
+ return PercussionOnset;
+}
+
+RhythmFerret::Action
+RhythmFerret::get_action () const
+{
+ if (tempo_button.get_active()) {
+ return DefineTempoMap;
+ } else if (region_conform_button.get_active()) {
+ return ConformRegion;
+ }
+
+ return SplitRegion;
+}
+
+void
+RhythmFerret::run_analysis ()
+{
+ if (!session) {
+ return;
+ }
+
+ RegionSelection& regions (editor.get_selection().regions);
+
+ current_results.clear ();
+
+ if (regions.empty()) {
+ return;
+ }
+
+ for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
+
+ boost::shared_ptr<Readable> rd = boost::static_pointer_cast<AudioRegion> ((*i)->region());
+
+ switch (get_analysis_mode()) {
+ case PercussionOnset:
+ run_percussion_onset_analysis (rd, (*i)->region()->position(), current_results);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
+ (*i)->get_time_axis_view().show_temporary_lines (current_results);
+ }
+
+}
+
+int
+RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr<Readable> readable, nframes64_t offset, vector<nframes64_t>& results)
+{
+ TransientDetector t (session->frame_rate());
+ bool existing_results = !results.empty();
+
+ for (uint32_t i = 0; i < readable->n_channels(); ++i) {
+
+ vector<nframes64_t> these_results;
+
+ t.reset ();
+ t.set_threshold (detection_threshold_adjustment.get_value());
+ t.set_sensitivity (sensitivity_adjustment.get_value());
+
+ if (t.run ("", readable, i, these_results)) {
+ continue;
+ }
+
+ /* translate all transients to give absolute position */
+
+ for (vector<nframes64_t>::iterator i = these_results.begin(); i != these_results.end(); ++i) {
+ (*i) += offset;
+ }
+
+ /* merge */
+
+ results.insert (results.end(), these_results.begin(), these_results.end());
+ }
+
+ if (!results.empty() && (existing_results || readable->n_channels() > 1)) {
+
+ /* now resort to bring transients from different channels together */
+
+ sort (results.begin(), results.end());
+
+ /* remove duplicates or other things that are too close */
+
+ vector<nframes64_t>::iterator i = results.begin();
+ nframes64_t curr = (*i);
+ nframes64_t gap_frames = (nframes64_t) floor (trigger_gap_adjustment.get_value() * (session->frame_rate() / 1000.0));
+
+ ++i;
+
+ while (i != results.end()) {
+ if (((*i) == curr) || (((*i) - curr) < gap_frames)) {
+ i = results.erase (i);
+ } else {
+ ++i;
+ curr = *i;
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+void
+RhythmFerret::do_action ()
+{
+ if (!session || current_results.empty()) {
+ return;
+ }
+
+ switch (get_action()) {
+ case SplitRegion:
+ do_split_action ();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+RhythmFerret::do_split_action ()
+{
+ /* this can/will change the current selection, so work with a copy */
+
+ RegionSelection& regions (editor.get_selection().regions);
+
+ if (regions.empty()) {
+ return;
+ }
+
+ session->begin_reversible_command (_("split regions (rhythm ferret)"));
+
+ for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ) {
+
+ RegionSelection::iterator tmp;
+
+ tmp = i;
+ ++tmp;
+
+ (*i)->get_time_axis_view().hide_temporary_lines ();
+
+ do_region_split ((*i), current_results);
+
+ /* i is invalid at this point */
+
+ i = tmp;
+ }
+
+ session->commit_reversible_command ();
+}
+
+void
+RhythmFerret::do_region_split (RegionView* rv, const vector<nframes64_t>& positions)
+{
+ boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (rv->region());
+
+ if (!ar) {
+ return;
+ }
+
+ boost::shared_ptr<Playlist> pl = ar->playlist();
+
+ if (!pl) {
+ return;
+ }
+
+ vector<nframes64_t>::const_iterator x;
+
+ nframes64_t pos = ar->position();
+
+ XMLNode& before (pl->get_state());
+
+ x = positions.begin();
+
+ while (x != positions.end()) {
+ if ((*x) > pos) {
+ break;
+ }
+ }
+
+ if (x == positions.end()) {
+ return;
+ }
+
+ pl->freeze ();
+ pl->remove_region (ar);
+
+ do {
+
+ /* file start = original start + how far we from the initial position ?
+ */
+
+ nframes64_t file_start = ar->start() + (pos - ar->position());
+
+ /* length = next position - current position
+ */
+
+ nframes64_t len = (*x) - pos;
+
+ string new_name;
+
+ if (session->region_name (new_name, ar->name())) {
+ continue;
+ }
+
+ pl->add_region (RegionFactory::create (ar->get_sources(), file_start, len, new_name), pos);
+
+ pos += len;
+
+ ++x;
+
+ } while (x != positions.end() && (*x) < ar->last_frame());
+
+ pl->thaw ();
+
+ XMLNode& after (pl->get_state());
+
+ session->add_command (new MementoCommand<Playlist>(*pl, &before, &after));
+}
+
+void
+RhythmFerret::set_session (Session* s)
+{
+ ArdourDialog::set_session (s);
+ current_results.clear ();
+}
diff --git a/gtk2_ardour/rhythm_ferret.h b/gtk2_ardour/rhythm_ferret.h
new file mode 100644
index 0000000000..36d4450939
--- /dev/null
+++ b/gtk2_ardour/rhythm_ferret.h
@@ -0,0 +1,100 @@
+#ifndef __gtk2_ardour_rhythm_ferret_h__
+#define __gtk2_ardour_rhythm_ferret_h__
+
+#include <gtkmm/box.h>
+#include <gtkmm/scale.h>
+#include <gtkmm/spinbutton.h>
+#include <gtkmm/radiobutton.h>
+#include <gtkmm/radiobuttongroup.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/image.h>
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/button.h>
+#include <gtkmm/label.h>
+
+#include "ardour_dialog.h"
+
+namespace ARDOUR {
+ class Readable;
+}
+
+class PublicEditor;
+class RegionView;
+
+class RhythmFerret : public ArdourDialog {
+ public:
+ /* order of these enums must match the _analyse_mode_strings
+ in rhythm_ferret.cc
+ */
+ enum AnalysisMode {
+ PercussionOnset,
+ NoteOnset
+ };
+
+ enum Action {
+ SplitRegion,
+ DefineTempoMap,
+ ConformRegion
+ };
+
+ RhythmFerret (PublicEditor&);
+ ~RhythmFerret ();
+
+ void set_session (ARDOUR::Session*);
+
+ private:
+ PublicEditor& editor;
+
+ Gtk::HBox upper_hpacker;
+ Gtk::HBox lower_hpacker;
+
+ Gtk::Frame operation_frame;
+ Gtk::Frame selection_frame;
+ Gtk::Frame ferret_frame;
+
+ Gtk::VBox op_logo_packer;
+ Gtk::Image* logo;
+
+ /* operation frame */
+
+ Gtk::VBox op_packer;
+ Gtk::RadioButtonGroup operation_button_group;
+ Gtk::RadioButton region_split_button;
+ Gtk::RadioButton tempo_button;
+ Gtk::RadioButton region_conform_button;
+
+ /* analysis frame */
+
+ Gtk::VBox ferret_packer;
+ Gtk::ComboBoxText analysis_mode_selector;
+ Gtk::Label analysis_mode_label;
+ Gtk::Adjustment detection_threshold_adjustment;
+ Gtk::HScale detection_threshold_scale;
+ Gtk::Label detection_threshold_label;
+ Gtk::Adjustment sensitivity_adjustment;
+ Gtk::HScale sensitivity_scale;
+ Gtk::Label sensitivity_label;
+ Gtk::Button analyze_button;
+ Gtk::Adjustment trigger_gap_adjustment;
+ Gtk::SpinButton trigger_gap_spinner;
+ Gtk::Label trigger_gap_label;
+
+ Gtk::Label operation_clarification_label;
+ Gtk::Button action_button;
+
+ std::vector<std::string> analysis_mode_strings;
+
+ std::vector<nframes64_t> current_results;
+
+ AnalysisMode get_analysis_mode () const;
+ Action get_action() const;
+
+ void run_analysis ();
+ int run_percussion_onset_analysis (boost::shared_ptr<ARDOUR::Readable> region, nframes64_t offset, std::vector<nframes64_t>& results);
+
+ void do_action ();
+ void do_split_action ();
+ void do_region_split (RegionView* rv, const std::vector<nframes64_t>&);
+};
+
+#endif /* __gtk2_ardour_rhythm_ferret_h__ */
diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc
index c4f5a558ab..c6dc773dd8 100644
--- a/gtk2_ardour/time_axis_view.cc
+++ b/gtk2_ardour/time_axis_view.cc
@@ -43,6 +43,7 @@
#include "public_editor.h"
#include "time_axis_view.h"
#include "simplerect.h"
+#include "simpleline.h"
#include "selection.h"
#include "keyboard.h"
#include "rgb_macros.h"
@@ -1099,3 +1100,37 @@ TimeAxisView::covers_y_position (double y)
return 0;
}
+
+void
+TimeAxisView::show_temporary_lines (const vector<nframes64_t>& pos)
+{
+ while (temp_lines.size()< pos.size()) {
+ ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*canvas_display);
+ l->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();
+ l->property_y1() = 0;
+ l->property_y2() = height;
+ temp_lines.push_back (l);
+ }
+
+ while (temp_lines.size() > pos.size()) {
+ ArdourCanvas::SimpleLine *line = temp_lines.back();
+ temp_lines.pop_back ();
+ delete line;
+ }
+
+ vector<nframes64_t>::const_iterator i;
+ list<ArdourCanvas::SimpleLine*>::iterator l;
+
+ for (i = pos.begin(), l = temp_lines.begin(); i != pos.end() && l != temp_lines.end(); ++i, ++l) {
+ (*l)->property_x1() = editor.frame_to_pixel ((double) *i);
+ (*l)->property_x2() = editor.frame_to_pixel ((double) *i);
+ }
+}
+
+void
+TimeAxisView::hide_temporary_lines ()
+{
+ for (list<ArdourCanvas::SimpleLine*>::iterator l = temp_lines.begin(); l != temp_lines.end(); ++l) {
+ (*l)->hide ();
+ }
+}
diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h
index 2c45325679..c98a72c626 100644
--- a/gtk2_ardour/time_axis_view.h
+++ b/gtk2_ardour/time_axis_view.h
@@ -176,6 +176,9 @@ class TimeAxisView : public virtual AxisView
virtual ARDOUR::RouteGroup* edit_group() const { return 0; }
virtual boost::shared_ptr<ARDOUR::Playlist> playlist() const { return boost::shared_ptr<ARDOUR::Playlist> (); }
+ virtual void show_temporary_lines (const std::vector<nframes64_t>&);
+ virtual void hide_temporary_lines ();
+
virtual void set_samples_per_unit (double);
virtual void show_selection (TimeSelection&);
virtual void hide_selection ();
@@ -322,6 +325,8 @@ class TimeAxisView : public virtual AxisView
void set_height_pixels (uint32_t h);
void color_handler ();
+ list<ArdourCanvas::SimpleLine*> temp_lines;
+
}; /* class TimeAxisView */
#endif /* __ardour_gtk_time_axis_h__ */