mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-09 23:25:43 +01:00
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
This commit is contained in:
parent
28e6ad0091
commit
d3f64c2848
29 changed files with 1231 additions and 116 deletions
|
|
@ -793,9 +793,16 @@ def prep_libcheck(topenv, libinfo):
|
|||
prep_libcheck(env, env)
|
||||
|
||||
|
||||
#
|
||||
# these are part of the Ardour source tree because they are C++
|
||||
#
|
||||
|
||||
libraries['vamp'] = LibraryInfo (LIBS='vampsdk',
|
||||
LIBPATH='#libs/vamp-sdk',
|
||||
CPPPATH='#libs/vamp-sdk/vamp')
|
||||
libraries['vamphost'] = LibraryInfo (LIBS='vamphostsdk',
|
||||
LIBPATH='#libs/vamp-sdk',
|
||||
CPPPATH='#libs/vamp-sdk/vamp')
|
||||
|
||||
env['RUBBERBAND'] = False
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'/>
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
376
gtk2_ardour/rhythm_ferret.cc
Normal file
376
gtk2_ardour/rhythm_ferret.cc
Normal file
|
|
@ -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 ();
|
||||
}
|
||||
100
gtk2_ardour/rhythm_ferret.h
Normal file
100
gtk2_ardour/rhythm_ferret.h
Normal file
|
|
@ -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__ */
|
||||
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ sndfilesource.cc
|
|||
source.cc
|
||||
source_factory.cc
|
||||
tempo.cc
|
||||
transient_detector.cc
|
||||
utils.cc
|
||||
version.cc
|
||||
mix.cc
|
||||
|
|
@ -267,11 +268,15 @@ ardour.Merge ([
|
|||
libraries['pbd'],
|
||||
libraries['midi++2'],
|
||||
libraries['glib2'],
|
||||
libraries['glibmm2']
|
||||
libraries['glibmm2'],
|
||||
libraries['vamp'],
|
||||
libraries['vamphost'],
|
||||
libraries['fftw3f'],
|
||||
libraries['fftw3'],
|
||||
])
|
||||
|
||||
if ardour['RUBBERBAND']:
|
||||
ardour.Merge ([ libraries['rubberband'], libraries['vamp'], libraries['fftw3f'] ])
|
||||
ardour.Merge ([ libraries['rubberband']])
|
||||
timefx_sources += [ 'rb_effect.cc' ]
|
||||
else:
|
||||
ardour.Merge ([ libraries['soundtouch'] ])
|
||||
|
|
|
|||
74
libs/ardour/ardour/audioanalyser.h
Normal file
74
libs/ardour/ardour/audioanalyser.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright (C) 2008 Paul Davis
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __ardour_audioanalyser_h__
|
||||
#define __ardour_audioanalyser_h__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <fstream>
|
||||
#include <vamp-sdk/Plugin.h>
|
||||
#include <ardour/audioregion.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Readable;
|
||||
class Session;
|
||||
|
||||
class AudioAnalyser {
|
||||
|
||||
public:
|
||||
typedef Vamp::Plugin AnalysisPlugin;
|
||||
typedef std::string AnalysisPluginKey;
|
||||
|
||||
AudioAnalyser (float sample_rate, AnalysisPluginKey key);
|
||||
virtual ~AudioAnalyser();
|
||||
|
||||
/* analysis object should provide a run method
|
||||
that accepts a path to write the results to (optionally empty)
|
||||
a boost::shared_ptr<Readable> to read data from
|
||||
and a reference to a type-specific container to return the
|
||||
results.
|
||||
*/
|
||||
|
||||
void reset ();
|
||||
|
||||
protected:
|
||||
float sample_rate;
|
||||
AnalysisPlugin* plugin;
|
||||
AnalysisPluginKey plugin_key;
|
||||
|
||||
nframes64_t bufsize;
|
||||
nframes64_t stepsize;
|
||||
|
||||
int initialize_plugin (AnalysisPluginKey name, float sample_rate);
|
||||
int analyse (const std::string& path, boost::shared_ptr<Readable>, uint32_t channel);
|
||||
|
||||
/* instances of an analysis object will have this method called
|
||||
whenever there are results to process. if out is non-null,
|
||||
the data should be written to the stream it points to.
|
||||
*/
|
||||
|
||||
virtual int use_features (Vamp::Plugin::FeatureSet&, std::ostream*) = 0;
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#endif /* __ardour_audioanalyser_h__ */
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
#define __ardour_audio_region_h__
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include <pbd/fastlog.h>
|
||||
#include <pbd/undo.h>
|
||||
|
|
@ -59,6 +60,7 @@ class AudioRegion : public Region
|
|||
bool speed_mismatch (float) const;
|
||||
|
||||
boost::shared_ptr<AudioSource> source (uint32_t n=0) const { if (n < sources.size()) return sources[n]; else return sources[0]; }
|
||||
const SourceList& get_sources() const { return sources; }
|
||||
|
||||
void set_scale_amplitude (gain_t);
|
||||
gain_t scale_amplitude() const { return _scale_amplitude; }
|
||||
|
|
@ -82,11 +84,16 @@ class AudioRegion : public Region
|
|||
nframes_t offset, nframes_t cnt,
|
||||
uint32_t chan_n=0, double samples_per_unit= 1.0) const;
|
||||
|
||||
/* Readable interface */
|
||||
|
||||
virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const;
|
||||
virtual nframes64_t readable_length() const { return length(); }
|
||||
|
||||
virtual nframes_t read_at (Sample *buf, Sample *mixdown_buf,
|
||||
float *gain_buf, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0) const;
|
||||
float *gain_buf, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0) const;
|
||||
|
||||
nframes_t master_read_at (Sample *buf, Sample *mixdown_buf,
|
||||
float *gain_buf,
|
||||
|
|
@ -146,7 +153,7 @@ class AudioRegion : public Region
|
|||
|
||||
AudioRegion (boost::shared_ptr<AudioSource>, nframes_t start, nframes_t length);
|
||||
AudioRegion (boost::shared_ptr<AudioSource>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
AudioRegion (SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
AudioRegion (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
AudioRegion (boost::shared_ptr<const AudioRegion>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
AudioRegion (boost::shared_ptr<const AudioRegion>);
|
||||
AudioRegion (boost::shared_ptr<AudioSource>, const XMLNode&);
|
||||
|
|
@ -161,10 +168,11 @@ class AudioRegion : public Region
|
|||
void recompute_gain_at_start ();
|
||||
|
||||
nframes_t _read_at (const SourceList&, Sample *buf, Sample *mixdown_buffer,
|
||||
float *gain_buffer, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0) const;
|
||||
float *gain_buffer, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0,
|
||||
bool raw = false) const;
|
||||
|
||||
bool verify_start (nframes_t position);
|
||||
bool verify_length (nframes_t& length);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
|
|||
|
||||
virtual nframes_t natural_position() const { return 0; }
|
||||
|
||||
/* returns the number of items in this `audio_source' */
|
||||
nframes64_t readable_length() const { return _length; }
|
||||
uint32_t n_channels() const { return 1; }
|
||||
|
||||
virtual nframes_t length() const {
|
||||
return _length;
|
||||
|
|
@ -65,6 +66,15 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
|
|||
|
||||
virtual nframes_t available_peaks (double zoom) const;
|
||||
|
||||
/* stopgap until nframes_t becomes nframes64_t. this function is needed by the Readable interface */
|
||||
|
||||
virtual nframes64_t read (Sample *dst, nframes64_t start, nframes64_t cnt, int channel) const {
|
||||
/* XXX currently ignores channel, assuming that source is always mono, which
|
||||
historically has been true.
|
||||
*/
|
||||
return read (dst, (nframes_t) start, (nframes_t) cnt);
|
||||
}
|
||||
|
||||
virtual nframes_t read (Sample *dst, nframes_t start, nframes_t cnt) const;
|
||||
virtual nframes_t write (Sample *src, nframes_t cnt);
|
||||
|
||||
|
|
@ -112,6 +122,9 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
|
|||
int prepare_for_peakfile_writes ();
|
||||
void done_with_peakfile_writes (bool done = true);
|
||||
|
||||
std::vector<nframes64_t> transients;
|
||||
std::string get_transients_path() const;
|
||||
|
||||
protected:
|
||||
static bool _build_missing_peakfiles;
|
||||
static bool _build_peakfiles;
|
||||
|
|
@ -146,6 +159,8 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
|
|||
int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force,
|
||||
bool intermediate_peaks_ready_signal, nframes_t frames_per_peak);
|
||||
|
||||
int load_transients (const std::string&);
|
||||
|
||||
private:
|
||||
int peakfile;
|
||||
nframes_t peak_leftover_cnt;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ class PluginManager {
|
|||
PluginManager ();
|
||||
~PluginManager ();
|
||||
|
||||
/* realtime plugin APIs */
|
||||
|
||||
ARDOUR::PluginInfoList &vst_plugin_info () { return _vst_plugin_info; }
|
||||
ARDOUR::PluginInfoList &ladspa_plugin_info () { return _ladspa_plugin_info; }
|
||||
ARDOUR::PluginInfoList &lv2_plugin_info () { return _lv2_plugin_info; }
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <pbd/statefuldestructible.h>
|
||||
|
||||
#include <ardour/ardour.h>
|
||||
#include <ardour/readable.h>
|
||||
|
||||
class XMLNode;
|
||||
|
||||
|
|
@ -40,7 +41,7 @@ enum RegionEditState {
|
|||
EditChangesID = 2
|
||||
};
|
||||
|
||||
class Region : public PBD::StatefulDestructible, public boost::enable_shared_from_this<Region>
|
||||
class Region : public PBD::StatefulDestructible, public Readable, public boost::enable_shared_from_this<Region>
|
||||
{
|
||||
public:
|
||||
enum Flag {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class RegionFactory {
|
|||
nframes_t length, std::string name,
|
||||
layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (boost::shared_ptr<Source>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (boost::shared_ptr<Region>);
|
||||
static boost::shared_ptr<Region> create (Session&, XMLNode&, bool);
|
||||
static boost::shared_ptr<Region> create (SourceList &, const XMLNode&);
|
||||
|
|
|
|||
|
|
@ -252,6 +252,9 @@ class Session : public PBD::StatefulDestructible
|
|||
std::string peak_dir () const;
|
||||
std::string dead_sound_dir () const;
|
||||
std::string automation_dir () const;
|
||||
std::string analysis_dir() const;
|
||||
|
||||
int ensure_subdirs ();
|
||||
|
||||
Glib::ustring peak_path (Glib::ustring) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,13 +28,14 @@
|
|||
#include <pbd/statefuldestructible.h>
|
||||
|
||||
#include <ardour/ardour.h>
|
||||
#include <ardour/readable.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Session;
|
||||
class Playlist;
|
||||
|
||||
class Source : public PBD::StatefulDestructible
|
||||
class Source : public PBD::StatefulDestructible, public ARDOUR::Readable
|
||||
{
|
||||
public:
|
||||
Source (Session&, std::string name);
|
||||
|
|
|
|||
52
libs/ardour/ardour/transient_detector.h
Normal file
52
libs/ardour/ardour/transient_detector.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2008 Paul Davis
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __ardour_transient_detector_h__
|
||||
#define __ardour_transient_detector_h__
|
||||
|
||||
#include <ardour/audioanalyser.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class AudioSource;
|
||||
class Session;
|
||||
|
||||
class TransientDetector : public AudioAnalyser
|
||||
{
|
||||
|
||||
public:
|
||||
TransientDetector (float sample_rate);
|
||||
~TransientDetector();
|
||||
|
||||
void set_threshold (float);
|
||||
void set_sensitivity (float);
|
||||
|
||||
float get_threshold () const;
|
||||
float get_sensitivity () const;
|
||||
|
||||
int run (const std::string& path, boost::shared_ptr<Readable>, uint32_t channel, std::vector<nframes64_t>& results);
|
||||
|
||||
protected:
|
||||
std::vector<nframes64_t>* current_results;
|
||||
int use_features (Vamp::Plugin::FeatureSet&, std::ostream*);
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#endif /* __ardour_audioanalyser_h__ */
|
||||
157
libs/ardour/audioanalyser.cc
Normal file
157
libs/ardour/audioanalyser.cc
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
#include <vamp-sdk/hostext/PluginLoader.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
#include <glibmm/fileutils.h>
|
||||
#include <glib/gstdio.h> // for g_remove()
|
||||
|
||||
#include <pbd/error.h>
|
||||
|
||||
#include <ardour/audioanalyser.h>
|
||||
#include <ardour/readable.h>
|
||||
#include <ardour/readable.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Vamp;
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
|
||||
AudioAnalyser::AudioAnalyser (float sr, AnalysisPluginKey key)
|
||||
: sample_rate (sr)
|
||||
, plugin (0)
|
||||
, plugin_key (key)
|
||||
{
|
||||
}
|
||||
|
||||
AudioAnalyser::~AudioAnalyser ()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
AudioAnalyser::initialize_plugin (AnalysisPluginKey key, float sr)
|
||||
{
|
||||
using namespace Vamp::HostExt;
|
||||
|
||||
PluginLoader* loader (PluginLoader::getInstance());
|
||||
|
||||
plugin = loader->loadPlugin (key, sr, PluginLoader::ADAPT_ALL);
|
||||
|
||||
if (!plugin) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((bufsize = plugin->getPreferredBlockSize ()) == 0) {
|
||||
bufsize = 65536;
|
||||
}
|
||||
|
||||
if ((stepsize = plugin->getPreferredStepSize()) == 0) {
|
||||
stepsize = bufsize;
|
||||
}
|
||||
|
||||
if (plugin->getMinChannelCount() > 1) {
|
||||
delete plugin;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!plugin->initialise (1, stepsize, bufsize)) {
|
||||
delete plugin;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
AudioAnalyser::reset ()
|
||||
{
|
||||
if (plugin) {
|
||||
plugin->reset ();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
AudioAnalyser::analyse (const string& path, boost::shared_ptr<Readable> src, uint32_t channel)
|
||||
{
|
||||
ofstream ofile;
|
||||
Plugin::FeatureSet onsets;
|
||||
int ret = -1;
|
||||
bool done = false;
|
||||
Sample* data = 0;
|
||||
nframes64_t len = src->readable_length();
|
||||
nframes64_t pos = 0;
|
||||
float* bufs[1] = { 0 };
|
||||
|
||||
if (!path.empty()) {
|
||||
ofile.open (path.c_str());
|
||||
if (!ofile) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* create VAMP percussion onset plugin and initialize */
|
||||
|
||||
if (plugin == 0) {
|
||||
if (initialize_plugin (plugin_key, sample_rate)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
data = new Sample[bufsize];
|
||||
bufs[0] = data;
|
||||
|
||||
while (!done) {
|
||||
|
||||
nframes64_t to_read;
|
||||
|
||||
/* read from source */
|
||||
|
||||
to_read = min ((len - pos), bufsize);
|
||||
|
||||
if (src->read (data, pos, to_read, channel) != to_read) {
|
||||
cerr << "bad read\n";
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* zero fill buffer if necessary */
|
||||
|
||||
if (to_read != bufsize) {
|
||||
memset (data + to_read, 0, (bufsize - to_read));
|
||||
}
|
||||
|
||||
onsets = plugin->process (bufs, RealTime::fromSeconds ((double) pos / sample_rate));
|
||||
|
||||
if (use_features (onsets, (path.empty() ? &ofile : 0))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
pos += stepsize;
|
||||
|
||||
if (pos >= len) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* finish up VAMP plugin */
|
||||
|
||||
onsets = plugin->getRemainingFeatures ();
|
||||
|
||||
if (use_features (onsets, (path.empty() ? &ofile : 0))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
/* works even if it has not been opened */
|
||||
ofile.close ();
|
||||
|
||||
if (ret) {
|
||||
g_remove (path.c_str());
|
||||
}
|
||||
if (data) {
|
||||
delete data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include <cmath>
|
||||
#include <climits>
|
||||
#include <cfloat>
|
||||
#include <algorithm>
|
||||
|
||||
#include <set>
|
||||
|
||||
|
|
@ -110,15 +111,15 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
|
|||
listen_to_my_curves ();
|
||||
}
|
||||
|
||||
AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
|
||||
AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
|
||||
: Region (start, length, name, layer, flags),
|
||||
_fade_in (0.0, 2.0, 1.0, false),
|
||||
_fade_out (0.0, 2.0, 1.0, false),
|
||||
_envelope (0.0, 2.0, 1.0, false)
|
||||
{
|
||||
/* basic AudioRegion constructor */
|
||||
|
||||
for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
|
||||
|
||||
for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
|
||||
sources.push_back (*i);
|
||||
master_sources.push_back (*i);
|
||||
(*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
|
||||
|
|
@ -437,12 +438,20 @@ AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nfra
|
|||
}
|
||||
}
|
||||
|
||||
nframes64_t
|
||||
AudioRegion::read (Sample* buf, nframes64_t position, nframes64_t cnt, int channel) const
|
||||
{
|
||||
/* raw read, no fades, no gain, nada */
|
||||
return _read_at (sources, buf, 0, 0, _position + position, cnt, channel, 0, 0, true);
|
||||
}
|
||||
|
||||
nframes_t
|
||||
AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position,
|
||||
nframes_t cnt,
|
||||
uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
|
||||
{
|
||||
return _read_at (sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames);
|
||||
/* regular diskstream/butler read complete with fades etc */
|
||||
return _read_at (sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames, false);
|
||||
}
|
||||
|
||||
nframes_t
|
||||
|
|
@ -455,13 +464,16 @@ AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_bu
|
|||
nframes_t
|
||||
AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
|
||||
nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
|
||||
uint32_t chan_n,
|
||||
nframes_t read_frames,
|
||||
nframes_t skip_frames,
|
||||
bool raw) const
|
||||
{
|
||||
nframes_t internal_offset;
|
||||
nframes_t buf_offset;
|
||||
nframes_t to_read;
|
||||
|
||||
if (muted()) {
|
||||
if (muted() && !raw) {
|
||||
return 0; /* read nothing */
|
||||
}
|
||||
|
||||
|
|
@ -484,14 +496,16 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
return 0; /* read nothing */
|
||||
}
|
||||
|
||||
if (opaque()) {
|
||||
if (opaque() || raw) {
|
||||
/* overwrite whatever is there */
|
||||
mixdown_buffer = buf + buf_offset;
|
||||
} else {
|
||||
mixdown_buffer += buf_offset;
|
||||
}
|
||||
|
||||
_read_data_count = 0;
|
||||
if (!raw) {
|
||||
_read_data_count = 0;
|
||||
}
|
||||
|
||||
if (chan_n < n_channels()) {
|
||||
|
||||
|
|
@ -500,7 +514,9 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
return 0; /* "read nothing" */
|
||||
}
|
||||
|
||||
_read_data_count += srcs[chan_n]->read_data_count();
|
||||
if (!raw) {
|
||||
_read_data_count += srcs[chan_n]->read_data_count();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -512,37 +528,41 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
|
||||
/* no fades required */
|
||||
|
||||
goto merge;
|
||||
if (!raw) {
|
||||
goto merge;
|
||||
}
|
||||
}
|
||||
|
||||
/* fade in */
|
||||
|
||||
if (_flags & FadeIn) {
|
||||
|
||||
nframes_t fade_in_length = (nframes_t) _fade_in.back()->when;
|
||||
|
||||
/* see if this read is within the fade in */
|
||||
|
||||
if (internal_offset < fade_in_length) {
|
||||
|
||||
nframes_t limit;
|
||||
|
||||
limit = min (to_read, fade_in_length - internal_offset);
|
||||
|
||||
_fade_in.get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
|
||||
|
||||
for (nframes_t n = 0; n < limit; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
if (!raw) {
|
||||
|
||||
if (_flags & FadeIn) {
|
||||
|
||||
nframes_t fade_in_length = (nframes_t) _fade_in.back()->when;
|
||||
|
||||
/* see if this read is within the fade in */
|
||||
|
||||
if (internal_offset < fade_in_length) {
|
||||
|
||||
nframes_t limit;
|
||||
|
||||
limit = min (to_read, fade_in_length - internal_offset);
|
||||
|
||||
_fade_in.get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
|
||||
|
||||
for (nframes_t n = 0; n < limit; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* fade out */
|
||||
|
||||
if (_flags & FadeOut) {
|
||||
|
||||
/* see if some part of this read is within the fade out */
|
||||
|
||||
|
||||
/* fade out */
|
||||
|
||||
if (_flags & FadeOut) {
|
||||
|
||||
/* see if some part of this read is within the fade out */
|
||||
|
||||
/* ................. >| REGION
|
||||
_length
|
||||
|
||||
|
|
@ -553,65 +573,66 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
|--------------|
|
||||
^internal_offset
|
||||
^internal_offset + to_read
|
||||
|
||||
we need the intersection of [internal_offset,internal_offset+to_read] with
|
||||
[_length - fade_out_length, _length]
|
||||
|
||||
|
||||
we need the intersection of [internal_offset,internal_offset+to_read] with
|
||||
[_length - fade_out_length, _length]
|
||||
|
||||
*/
|
||||
|
||||
|
||||
nframes_t fade_out_length = (nframes_t) _fade_out.back()->when;
|
||||
nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
|
||||
nframes_t fade_interval_end = min(internal_offset + to_read, _length);
|
||||
|
||||
if (fade_interval_end > fade_interval_start) {
|
||||
/* (part of the) the fade out is in this buffer */
|
||||
nframes_t fade_out_length = (nframes_t) _fade_out.back()->when;
|
||||
nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
|
||||
nframes_t fade_interval_end = min(internal_offset + to_read, _length);
|
||||
|
||||
nframes_t limit = fade_interval_end - fade_interval_start;
|
||||
nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
|
||||
nframes_t fade_offset = fade_interval_start - internal_offset;
|
||||
|
||||
_fade_out.get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
|
||||
|
||||
for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
|
||||
mixdown_buffer[m] *= gain_buffer[n];
|
||||
if (fade_interval_end > fade_interval_start) {
|
||||
/* (part of the) the fade out is in this buffer */
|
||||
|
||||
nframes_t limit = fade_interval_end - fade_interval_start;
|
||||
nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
|
||||
nframes_t fade_offset = fade_interval_start - internal_offset;
|
||||
|
||||
_fade_out.get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
|
||||
|
||||
for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
|
||||
mixdown_buffer[m] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Regular gain curves */
|
||||
|
||||
if (envelope_active()) {
|
||||
_envelope.get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
|
||||
|
||||
if (_scale_amplitude != 1.0f) {
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
|
||||
}
|
||||
} else {
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
} else if (_scale_amplitude != 1.0f) {
|
||||
Session::apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
|
||||
}
|
||||
|
||||
merge:
|
||||
|
||||
if (!opaque()) {
|
||||
|
||||
/* gack. the things we do for users.
|
||||
*/
|
||||
|
||||
buf += buf_offset;
|
||||
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
buf[n] += mixdown_buffer[n];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Regular gain curves */
|
||||
|
||||
if (envelope_active()) {
|
||||
_envelope.get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
|
||||
|
||||
if (_scale_amplitude != 1.0f) {
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
|
||||
}
|
||||
} else {
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
} else if (_scale_amplitude != 1.0f) {
|
||||
Session::apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
|
||||
}
|
||||
|
||||
merge:
|
||||
|
||||
if (!opaque()) {
|
||||
|
||||
/* gack. the things we do for users.
|
||||
*/
|
||||
|
||||
buf += buf_offset;
|
||||
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
buf[n] += mixdown_buffer[n];
|
||||
}
|
||||
}
|
||||
|
||||
return to_read;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@
|
|||
#include <ctime>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <glibmm/fileutils.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
|
||||
#include <pbd/xml++.h>
|
||||
#include <pbd/pthread_utils.h>
|
||||
|
|
@ -38,6 +40,7 @@
|
|||
#include <ardour/audiosource.h>
|
||||
#include <ardour/cycle_timer.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/transient_detector.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
|
@ -917,3 +920,50 @@ AudioSource::update_length (nframes_t pos, nframes_t cnt)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
AudioSource::load_transients (const string& path)
|
||||
{
|
||||
ifstream file (path.c_str());
|
||||
|
||||
if (!file) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
transients.clear ();
|
||||
|
||||
stringstream strstr;
|
||||
double val;
|
||||
|
||||
while (file.good()) {
|
||||
file >> val;
|
||||
|
||||
if (!file.fail()) {
|
||||
nframes64_t frame = (nframes64_t) floor (val * _session.frame_rate());
|
||||
transients.push_back (frame);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string
|
||||
AudioSource::get_transients_path () const
|
||||
{
|
||||
vector<string> parts;
|
||||
string s;
|
||||
|
||||
/* old sessions may not have the analysis directory */
|
||||
|
||||
_session.ensure_subdirs ();
|
||||
|
||||
s = _session.analysis_dir ();
|
||||
parts.push_back (s);
|
||||
|
||||
s = _id.to_s();
|
||||
s += '.';
|
||||
s += X_("transients");
|
||||
parts.push_back (s);
|
||||
|
||||
return Glib::build_filename (parts);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ RegionFactory::create (Session& session, XMLNode& node, bool yn)
|
|||
}
|
||||
|
||||
boost::shared_ptr<Region>
|
||||
RegionFactory::create (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Region::Flag flags, bool announce)
|
||||
RegionFactory::create (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Region::Flag flags, bool announce)
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> arp (new AudioRegion (srcs, start, length, name, layer, flags));
|
||||
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include <glibmm/thread.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
#include <glibmm/fileutils.h>
|
||||
|
||||
#include <pbd/error.h>
|
||||
#include <glibmm/thread.h>
|
||||
|
|
@ -290,7 +291,8 @@ Session::Session (AudioEngine &eng,
|
|||
|
||||
first_stage_init (fullpath, snapshot_name);
|
||||
|
||||
new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
|
||||
new_session = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
|
||||
|
||||
if (new_session) {
|
||||
if (create (new_session, mix_template, compute_initial_length())) {
|
||||
destroy ();
|
||||
|
|
|
|||
|
|
@ -469,19 +469,14 @@ Session::setup_raid_path (string path)
|
|||
}
|
||||
|
||||
int
|
||||
Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
|
||||
Session::ensure_subdirs ()
|
||||
{
|
||||
string dir;
|
||||
|
||||
if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session dir \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = peak_dir ();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -492,7 +487,7 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
|
|||
dir = sound_dir ();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -500,17 +495,39 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
|
|||
dir = dead_sound_dir ();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session dead sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = export_dir ();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session export dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = analysis_dir ();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
|
||||
{
|
||||
|
||||
if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ensure_subdirs ()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check new_session so we don't overwrite an existing one */
|
||||
|
||||
|
|
@ -559,7 +576,6 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
|
|||
|
||||
_state_of_the_state = Clean;
|
||||
|
||||
|
||||
save_state ("");
|
||||
|
||||
return 0;
|
||||
|
|
@ -2044,6 +2060,14 @@ Session::automation_dir () const
|
|||
return res;
|
||||
}
|
||||
|
||||
string
|
||||
Session::analysis_dir () const
|
||||
{
|
||||
string res = _path;
|
||||
res += "analysis/";
|
||||
return res;
|
||||
}
|
||||
|
||||
string
|
||||
Session::template_dir ()
|
||||
{
|
||||
|
|
@ -2808,7 +2832,7 @@ Session::cleanup_sources (Session::cleanup_report& rep)
|
|||
newpath += dead_sound_dir_name;
|
||||
|
||||
if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
62
libs/ardour/transient_detector.cc
Normal file
62
libs/ardour/transient_detector.cc
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include <ardour/transient_detector.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace Vamp;
|
||||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
|
||||
TransientDetector::TransientDetector (float sr)
|
||||
: AudioAnalyser (sr, X_("vamp-example-plugins:percussiononsets"))
|
||||
{
|
||||
cerr << "plugin in constructor = " << plugin << endl;
|
||||
}
|
||||
|
||||
TransientDetector::~TransientDetector()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
TransientDetector::run (const std::string& path, boost::shared_ptr<Readable> src, uint32_t channel, vector<nframes64_t>& results)
|
||||
{
|
||||
current_results = &results;
|
||||
int ret = analyse (path, src, channel);
|
||||
current_results = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
TransientDetector::use_features (Plugin::FeatureSet& features, ostream* out)
|
||||
{
|
||||
const Plugin::FeatureList& fl (features[0]);
|
||||
|
||||
for (Plugin::FeatureList::const_iterator f = fl.begin(); f != fl.end(); ++f) {
|
||||
|
||||
if ((*f).hasTimestamp) {
|
||||
|
||||
if (out) {
|
||||
(*out) << (*f).timestamp.toString() << endl;
|
||||
}
|
||||
|
||||
current_results->push_back (RealTime::realTime2Frame ((*f).timestamp, sample_rate));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
TransientDetector::set_threshold (float val)
|
||||
{
|
||||
if (plugin) {
|
||||
plugin->setParameter ("threshold", val);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TransientDetector::set_sensitivity (float val)
|
||||
{
|
||||
if (plugin) {
|
||||
plugin->setParameter ("sensitivity", val);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue