Merge with 2.0-ongoing R2988

git-svn-id: svn://localhost/ardour2/branches/3.0@2991 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2008-02-02 17:22:04 +00:00
parent 9f63ab9931
commit 80c3677c83
70 changed files with 1442 additions and 398 deletions

View file

@ -534,6 +534,7 @@ if env['LV2']:
if conf.CheckPKGExists ('\"slv2 >= 0.6.0\"'): if conf.CheckPKGExists ('\"slv2 >= 0.6.0\"'):
libraries['slv2'] = LibraryInfo() libraries['slv2'] = LibraryInfo()
libraries['slv2'].ParseConfig('pkg-config --cflags --libs slv2') libraries['slv2'].ParseConfig('pkg-config --cflags --libs slv2')
env.Append (CCFLAGS="-DHAVE_LV2")
else: else:
print 'Building Ardour with LV2 support requires SLV2 >= 0.6.0' print 'Building Ardour with LV2 support requires SLV2 >= 0.6.0'
print 'WARNING: SLV2 not found, or too old. Ardour will be built without LV2 support.' print 'WARNING: SLV2 not found, or too old. Ardour will be built without LV2 support.'

View file

@ -182,9 +182,12 @@
(gtk_accel_path "<Actions>/Editor/cycle-snap-choice" "3") (gtk_accel_path "<Actions>/Editor/cycle-snap-choice" "3")
(gtk_accel_path "<Actions>/Transport/ToggleAutoReturn" "4") (gtk_accel_path "<Actions>/Transport/ToggleAutoReturn" "4")
(gtk_accel_path "<Actions>/Transport/ToggleClick" "5") (gtk_accel_path "<Actions>/Transport/ToggleClick" "5")
(gtk_accel_path "<Actions>/Editor/tab-to-transient-forwards" "7")
(gtk_accel_path "<Actions>/Editor/tab-to-transient-backwards" "8")
(gtk_accel_path "<Actions>/Editor/set-tempo-from-region" "9") (gtk_accel_path "<Actions>/Editor/set-tempo-from-region" "9")
(gtk_accel_path "<Actions>/Editor/set-tempo-from-edit-range" "0") (gtk_accel_path "<Actions>/Editor/set-tempo-from-edit-range" "0")
;; ;;
;; unbound actions ;; unbound actions
;; ;;

View file

@ -4,11 +4,13 @@
<Option name="ui-rc-file" value="ardour3_ui_dark.rc"/> <Option name="ui-rc-file" value="ardour3_ui_dark.rc"/>
</UI> </UI>
<Canvas> <Canvas>
<Option name="waveform outline" value="0f0f0fcc"/> <Option name="waveform outline" value="0f0f0fc8"/>
<Option name="waveform fill" value="3d475378"/> <Option name="waveform fill" value="3d4753dc"/>
<Option name="selected waveform outline" value="0f0f0fcc"/>
<Option name="selected waveform fill" value="51518ac8"/>
<Option name="clipped waveform" value="ff0000e5"/> <Option name="clipped waveform" value="ff0000e5"/>
<Option name="region base" value="99a7b5aa"/> <Option name="region base" value="99a7b5a0"/>
<Option name="selected region base" value="b591a8ff"/> <Option name="selected region base" value="51518aa0"/>
<Option name="midi frame base" value="698f9d6d"/> <Option name="midi frame base" value="698f9d6d"/>
<Option name="audio track base" value="c6d3d868"/> <Option name="audio track base" value="c6d3d868"/>
<Option name="audio bus base" value="dbd1ea68"/> <Option name="audio bus base" value="dbd1ea68"/>

View file

@ -24,7 +24,7 @@
#include "ardour_dialog.h" #include "ardour_dialog.h"
#include "keyboard.h" #include "keyboard.h"
#include "ardour_ui.h" #include "ardour_ui.h"
#include "splash.h"
ArdourDialog::ArdourDialog (string title, bool modal, bool use_seperator) ArdourDialog::ArdourDialog (string title, bool modal, bool use_seperator)
: Dialog (title, modal, use_seperator) : Dialog (title, modal, use_seperator)
@ -66,3 +66,17 @@ ArdourDialog::on_unmap ()
{ {
Dialog::on_unmap (); Dialog::on_unmap ();
} }
void
ArdourDialog::on_show ()
{
// never allow the splash screen to obscure any dialog
Splash* spl = Splash::instance();
if (spl) {
spl->pop_back ();
}
Dialog::on_show ();
}

View file

@ -43,6 +43,7 @@ class ArdourDialog : public Gtk::Dialog
bool on_enter_notify_event (GdkEventCrossing*); bool on_enter_notify_event (GdkEventCrossing*);
bool on_leave_notify_event (GdkEventCrossing*); bool on_leave_notify_event (GdkEventCrossing*);
void on_unmap (); void on_unmap ();
void on_show ();
ARDOUR::Session *session; ARDOUR::Session *session;

View file

@ -242,6 +242,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog)); ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
/* handle sr mismatch with a dialog */
ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
/* lets get this party started */ /* lets get this party started */
try { try {
@ -403,6 +407,15 @@ ARDOUR_UI::~ARDOUR_UI ()
} }
} }
void
ARDOUR_UI::pop_back_splash ()
{
if (Splash::instance()) {
// Splash::instance()->pop_back();
Splash::instance()->hide ();
}
}
gint gint
ARDOUR_UI::configure_timeout () ARDOUR_UI::configure_timeout ()
{ {
@ -609,6 +622,7 @@ Please consider the possibilities, and perhaps (re)start JACK."));
win.show_all (); win.show_all ();
win.set_position (Gtk::WIN_POS_CENTER); win.set_position (Gtk::WIN_POS_CENTER);
pop_back_splash ();
/* we just don't care about the result, but we want to block */ /* we just don't care about the result, but we want to block */
@ -692,6 +706,8 @@ ARDOUR_UI::check_memory_locking ()
vbox->show(); vbox->show();
hbox.show (); hbox.show ();
pop_back_splash ();
editor->ensure_float (msg); editor->ensure_float (msg);
msg.run (); msg.run ();
} }
@ -725,6 +741,7 @@ ARDOUR_UI::finish()
Ardour was unable to save your session.\n\n\ Ardour was unable to save your session.\n\n\
If you still wish to quit, please use the\n\n\ If you still wish to quit, please use the\n\n\
\"Just quit\" option.")); \"Just quit\" option."));
pop_back_splash();
msg.run (); msg.run ();
return; return;
} }
@ -997,8 +1014,27 @@ ARDOUR_UI::redisplay_recent_sessions ()
get_state_files_in_directory (*i, state_file_paths); get_state_files_in_directory (*i, state_file_paths);
if (state_file_paths.empty()) { vector<string*>* states;
// no state file? vector<const gchar*> item;
string fullpath = (*i).to_string();
/* remove any trailing / */
if (fullpath[fullpath.length()-1] == '/') {
fullpath = fullpath.substr (0, fullpath.length()-1);
}
/* check whether session still exists */
if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
/* session doesn't exist */
cerr << "skipping non-existent session " << fullpath << endl;
continue;
}
/* now get available states for this session */
if ((states = Session::possible_states (fullpath)) == 0) {
/* no state file? */
continue; continue;
} }
@ -1006,8 +1042,6 @@ ARDOUR_UI::redisplay_recent_sessions ()
Gtk::TreeModel::Row row = *(recent_session_model->append()); Gtk::TreeModel::Row row = *(recent_session_model->append());
const string fullpath = (*i).to_string();
row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath); row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
row[recent_session_columns.fullpath] = fullpath; row[recent_session_columns.fullpath] = fullpath;
@ -1153,6 +1187,7 @@ ARDOUR_UI::check_audioengine ()
if (!engine->connected()) { if (!engine->connected()) {
MessageDialog msg (_("Ardour is not connected to JACK\n" MessageDialog msg (_("Ardour is not connected to JACK\n"
"You cannot open or close sessions in this condition")); "You cannot open or close sessions in this condition"));
pop_back_splash ();
msg.run (); msg.run ();
return false; return false;
} }
@ -1309,6 +1344,7 @@ ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t
to create a new track or bus.\n\ to create a new track or bus.\n\
You should save Ardour, exit and\n\ You should save Ardour, exit and\n\
restart JACK with more ports.")); restart JACK with more ports."));
pop_back_splash ();
msg.run (); msg.run ();
} }
} }
@ -1685,6 +1721,7 @@ JACK has either been shutdown or it\n\
disconnected Ardour because Ardour\n\ disconnected Ardour because Ardour\n\
was not fast enough. You can save the\n\ was not fast enough. You can save the\n\
session and/or try to reconnect to JACK .")); session and/or try to reconnect to JACK ."));
pop_back_splash ();
msg.run (); msg.run ();
} }
@ -2026,6 +2063,7 @@ ARDOUR_UI::fontconfig_dialog ()
true, true,
Gtk::MESSAGE_INFO, Gtk::MESSAGE_INFO,
Gtk::BUTTONS_OK); Gtk::BUTTONS_OK);
pop_back_splash ();
msg.show_all (); msg.show_all ();
msg.present (); msg.present ();
msg.run (); msg.run ();
@ -2116,6 +2154,7 @@ ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path
msg.set_name (X_("CleanupDialog")); msg.set_name (X_("CleanupDialog"));
msg.set_wmclass (X_("existing_session"), "Ardour"); msg.set_wmclass (X_("existing_session"), "Ardour");
msg.set_position (Gtk::WIN_POS_MOUSE); msg.set_position (Gtk::WIN_POS_MOUSE);
pop_back_splash ();
switch (msg.run()) { switch (msg.run()) {
case RESPONSE_YES: case RESPONSE_YES:
@ -2325,6 +2364,7 @@ ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be
session_path = new_session_dialog->session_folder(); session_path = new_session_dialog->session_folder();
} }
template_name = Glib::ustring();
switch (new_session_dialog->which_page()) { switch (new_session_dialog->which_page()) {
case NewSessionDialog::OpenPage: case NewSessionDialog::OpenPage:
@ -2374,7 +2414,7 @@ ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be
loadit: loadit:
new_session_dialog->hide (); new_session_dialog->hide ();
if (load_session (session_path, session_name)) { if (load_session (session_path, session_name, template_name)) {
/* force a retry */ /* force a retry */
response = Gtk::RESPONSE_NONE; response = Gtk::RESPONSE_NONE;
} }
@ -2435,6 +2475,7 @@ ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_na
if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) { if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) {
MessageDialog msg (*editor, _("You do not have write access to this session.\n" MessageDialog msg (*editor, _("You do not have write access to this session.\n"
"This prevents the session from being loaded.")); "This prevents the session from being loaded."));
pop_back_splash ();
msg.run (); msg.run ();
goto out; goto out;
} }
@ -2458,6 +2499,7 @@ ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_na
msg.set_title (_("Loading Error")); msg.set_title (_("Loading Error"));
msg.set_secondary_text (_("Click the OK button to try again.")); msg.set_secondary_text (_("Click the OK button to try again."));
msg.set_position (Gtk::WIN_POS_CENTER); msg.set_position (Gtk::WIN_POS_CENTER);
pop_back_splash ();
msg.present (); msg.present ();
int response = msg.run (); int response = msg.run ();
@ -2483,6 +2525,7 @@ ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_na
msg.set_title (_("Loading Error")); msg.set_title (_("Loading Error"));
msg.set_secondary_text (_("Click the OK button to try again.")); msg.set_secondary_text (_("Click the OK button to try again."));
msg.set_position (Gtk::WIN_POS_CENTER); msg.set_position (Gtk::WIN_POS_CENTER);
pop_back_splash ();
msg.present (); msg.present ();
int response = msg.run (); int response = msg.run ();
@ -2555,6 +2598,7 @@ ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_n
catch (...) { catch (...) {
MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path)); MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
pop_back_splash ();
msg.run (); msg.run ();
return -1; return -1;
} }
@ -3031,6 +3075,38 @@ what you would like to do.\n"));
} }
} }
int
ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
{
HBox* hbox = new HBox();
Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
ArdourDialog dialog (_("Sample Rate Mismatch"), true);
Label message (string_compose (_("\
This session was created with a sample rate of %1 Hz\n\
\n\
The audioengine is currently running at %2 Hz\n"), desired, actual));
image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
dialog.set_default_response (RESPONSE_ACCEPT);
dialog.set_position (WIN_POS_CENTER);
message.show();
image->show();
hbox->show();
switch (dialog.run ()) {
case RESPONSE_ACCEPT:
return 0;
default:
return 1;
}
}
void void
ARDOUR_UI::disconnect_from_jack () ARDOUR_UI::disconnect_from_jack ()
{ {

View file

@ -660,7 +660,9 @@ class ARDOUR_UI : public Gtkmm2ext::UI
About* about; About* about;
Splash* splash; Splash* splash;
void pop_back_splash ();
bool shown_flag; bool shown_flag;
/* cleanup */ /* cleanup */
Gtk::MenuItem *cleanup_item; Gtk::MenuItem *cleanup_item;
@ -682,6 +684,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
void disk_underrun_handler (); void disk_underrun_handler ();
int pending_state_dialog (); int pending_state_dialog ();
int sr_mismatch_dialog (nframes_t, nframes_t);
void disconnect_from_jack (); void disconnect_from_jack ();
void reconnect_to_jack (); void reconnect_to_jack ();

View file

@ -52,6 +52,7 @@ ARDOUR_UI::shutdown ()
session->remove_pending_capture_state (); session->remove_pending_capture_state ();
session = 0; session = 0;
} }
ui_config->save_state(); ui_config->save_state();
} }

View file

@ -1220,14 +1220,15 @@ AudioRegionView::set_frame_color ()
uint32_t r,g,b,a; uint32_t r,g,b,a;
if (_selected && should_show_selection) { if (_selected && should_show_selection) {
frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_WaveForm.get(); UINT_TO_RGBA(ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get(), &r, &g, &b, &a);
frame->property_fill_color_rgba() = RGBA_TO_UINT(r, g, b, fill_opacity ? fill_opacity : a);
UINT_TO_RGBA(ARDOUR_UI::config()->canvasvar_FrameBase.get(), &r, &g, &b, &a);
for (vector<ArdourCanvas::WaveView*>::iterator w = waves.begin(); w != waves.end(); ++w) { for (vector<ArdourCanvas::WaveView*>::iterator w = waves.begin(); w != waves.end(); ++w) {
if (_region->muted()) { if (_region->muted()) {
(*w)->property_wave_color() = RGBA_TO_UINT(r, g, b, MUTED_ALPHA); (*w)->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_SelectedWaveForm.get(), MUTED_ALPHA);
} else { } else {
(*w)->property_wave_color() = RGBA_TO_UINT(r, g, b, fill_opacity ? fill_opacity : a);// Lets still use the theme's opacity value if Opaque is not set (*w)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedWaveForm.get();
(*w)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedWaveFormFill.get();
} }
} }
} else { } else {

View file

@ -1,5 +1,7 @@
CANVAS_VARIABLE(canvasvar_WaveForm, "waveform outline") CANVAS_VARIABLE(canvasvar_WaveForm, "waveform outline")
CANVAS_VARIABLE(canvasvar_WaveFormFill, "waveform fill") CANVAS_VARIABLE(canvasvar_WaveFormFill, "waveform fill")
CANVAS_VARIABLE(canvasvar_SelectedWaveForm, "selected waveform outline")
CANVAS_VARIABLE(canvasvar_SelectedWaveFormFill, "selected waveform fill")
CANVAS_VARIABLE(canvasvar_WaveFormClip, "clipped waveform") CANVAS_VARIABLE(canvasvar_WaveFormClip, "clipped waveform")
CANVAS_VARIABLE(canvasvar_FrameBase, "region base") CANVAS_VARIABLE(canvasvar_FrameBase, "region base")
CANVAS_VARIABLE(canvasvar_SelectedFrameBase, "selected region base") CANVAS_VARIABLE(canvasvar_SelectedFrameBase, "selected region base")

View file

@ -1803,12 +1803,25 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
items.push_back (CheckMenuElem (_("Lock"))); items.push_back (CheckMenuElem (_("Lock")));
CheckMenuItem* region_lock_item = static_cast<CheckMenuItem*>(&items.back()); CheckMenuItem* region_lock_item = static_cast<CheckMenuItem*>(&items.back());
fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
if (region->locked()) { if (region->locked()) {
fooc.block (true);
region_lock_item->set_active(); region_lock_item->set_active();
fooc.block (false);
} }
region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
items.push_back (CheckMenuElem (_("Glue to Bars&Beats")));
CheckMenuItem* bbt_glue_item = static_cast<CheckMenuItem*>(&items.back());
switch (region->positional_lock_style()) {
case Region::MusicTime:
bbt_glue_item->set_active (true);
break;
default:
bbt_glue_item->set_active (true);
break;
}
bbt_glue_item->signal_activate().connect (bind (mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime));
items.push_back (CheckMenuElem (_("Mute"))); items.push_back (CheckMenuElem (_("Mute")));
CheckMenuItem* region_mute_item = static_cast<CheckMenuItem*>(&items.back()); CheckMenuItem* region_mute_item = static_cast<CheckMenuItem*>(&items.back());
fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute)); fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
@ -3366,15 +3379,25 @@ Editor::hide_verbose_canvas_cursor ()
verbose_cursor_visible = false; verbose_cursor_visible = false;
} }
double
Editor::clamp_verbose_cursor_x (double x)
{
return min (horizontal_adjustment.get_value() + canvas_width - 75.0, x);
}
double
Editor::clamp_verbose_cursor_y (double y)
{
return min (vertical_adjustment.get_value() + canvas_height - 50.0, y);
}
void void
Editor::set_verbose_canvas_cursor (const string & txt, double x, double y) Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
{ {
/* XXX get origin of canvas relative to root window,
add x and y and check compared to gdk_screen_{width,height}
*/
verbose_canvas_cursor->property_text() = txt.c_str(); verbose_canvas_cursor->property_text() = txt.c_str();
verbose_canvas_cursor->property_x() = x; /* don't get too close to the edge */
verbose_canvas_cursor->property_y() = y; verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
verbose_canvas_cursor->property_y() = clamp_verbose_cursor_x (y);
} }
void void

View file

@ -1019,7 +1019,7 @@ class Editor : public PublicEditor
void toggle_region_mute (); void toggle_region_mute ();
void toggle_region_lock (); void toggle_region_lock ();
void toggle_region_opaque (); void toggle_region_opaque ();
void toggle_region_position_lock (); void set_region_lock_style (ARDOUR::Region::PositionLockStyle);
void raise_region (); void raise_region ();
void raise_region_to_top (); void raise_region_to_top ();
void lower_region (); void lower_region ();
@ -1028,7 +1028,7 @@ class Editor : public PublicEditor
void split_region_at (nframes_t); void split_region_at (nframes_t);
void split_regions_at (nframes_t, RegionSelection&); void split_regions_at (nframes_t, RegionSelection&);
void split_region_at_transients (); void split_region_at_transients ();
void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, std::vector<nframes64_t>&); void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, ARDOUR::AnalysisFeatureList&);
void crop_region_to_selection (); void crop_region_to_selection ();
void crop_region_to (nframes_t start, nframes_t end); void crop_region_to (nframes_t start, nframes_t end);
void set_sync_point (nframes64_t, const RegionSelection&); void set_sync_point (nframes64_t, const RegionSelection&);
@ -1334,6 +1334,8 @@ class Editor : public PublicEditor
void show_verbose_time_cursor (nframes_t frame, double offset = 0, double xpos=-1, double ypos=-1); void show_verbose_time_cursor (nframes_t frame, double offset = 0, double xpos=-1, double ypos=-1);
void show_verbose_duration_cursor (nframes_t start, nframes_t end, double offset = 0, double xpos=-1, double ypos=-1); void show_verbose_duration_cursor (nframes_t start, nframes_t end, double offset = 0, double xpos=-1, double ypos=-1);
double clamp_verbose_cursor_x (double);
double clamp_verbose_cursor_y (double);
/* Canvas event handlers */ /* Canvas event handlers */

View file

@ -377,7 +377,7 @@ Editor::register_actions ()
act = ActionManager::register_action (editor_actions, "tab-to-transient-forwards", _("Move Forward to Transient"), bind (mem_fun(*this, &Editor::tab_to_transient), true)); act = ActionManager::register_action (editor_actions, "tab-to-transient-forwards", _("Move Forward to Transient"), bind (mem_fun(*this, &Editor::tab_to_transient), true));
ActionManager::session_sensitive_actions.push_back (act); ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "tab-to-transient-backwards", _("Move Forward to Transient"), bind (mem_fun(*this, &Editor::tab_to_transient), false)); act = ActionManager::register_action (editor_actions, "tab-to-transient-backwards", _("Move Backwards to Transient"), bind (mem_fun(*this, &Editor::tab_to_transient), false));
ActionManager::session_sensitive_actions.push_back (act); ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "crop", _("Crop"), mem_fun(*this, &Editor::crop_region_to_selection)); act = ActionManager::register_action (editor_actions, "crop", _("Crop"), mem_fun(*this, &Editor::crop_region_to_selection));

View file

@ -19,6 +19,7 @@
#include <cstdlib> #include <cstdlib>
#include <cmath> #include <cmath>
#include <algorithm>
#include <pbd/stacktrace.h> #include <pbd/stacktrace.h>
@ -43,6 +44,7 @@
#include "i18n.h" #include "i18n.h"
using namespace sigc; using namespace sigc;
using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
using namespace Gtk; using namespace Gtk;
@ -245,8 +247,8 @@ bool
Editor::track_canvas_motion (GdkEvent *ev) Editor::track_canvas_motion (GdkEvent *ev)
{ {
if (verbose_cursor_visible) { if (verbose_cursor_visible) {
verbose_canvas_cursor->property_x() = ev->motion.x + 20; verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (ev->motion.x + 20);
verbose_canvas_cursor->property_y() = ev->motion.y + 20; verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (ev->motion.y + 20);
} }
#ifdef GTKOSX #ifdef GTKOSX

View file

@ -3382,7 +3382,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
} }
if (sync_frame - sync_offset <= sync_frame) { if (sync_frame - sync_offset <= sync_frame) {
pending_region_position = sync_frame + (sync_dir*sync_offset); pending_region_position = sync_frame - (sync_dir*sync_offset);
} else { } else {
pending_region_position = 0; pending_region_position = 0;
} }

View file

@ -57,6 +57,7 @@
#include "ardour_ui.h" #include "ardour_ui.h"
#include "editor.h" #include "editor.h"
#include "time_axis_view.h" #include "time_axis_view.h"
#include "route_time_axis.h"
#include "audio_time_axis.h" #include "audio_time_axis.h"
#include "automation_time_axis.h" #include "automation_time_axis.h"
#include "streamview.h" #include "streamview.h"
@ -1659,7 +1660,6 @@ Editor::temporal_zoom_region ()
ensure_entered_region_selected (true); ensure_entered_region_selected (true);
if (selection->regions.empty()) { if (selection->regions.empty()) {
info << _("cannot set loop: no region selected") << endmsg;
return; return;
} }
@ -3540,13 +3540,11 @@ Editor::cut_copy (CutCopyOp op)
switch (current_mouse_mode()) { switch (current_mouse_mode()) {
case MouseObject: case MouseObject:
cerr << "cutting in object mode\n";
if (!selection->regions.empty() || !selection->points.empty()) { if (!selection->regions.empty() || !selection->points.empty()) {
begin_reversible_command (opname + _(" objects")); begin_reversible_command (opname + _(" objects"));
if (!selection->regions.empty()) { if (!selection->regions.empty()) {
cerr << "have regions to cut" << endl;
cut_copy_regions (op); cut_copy_regions (op);
if (op == Cut) { if (op == Cut) {
@ -3565,7 +3563,6 @@ Editor::cut_copy (CutCopyOp op)
commit_reversible_command (); commit_reversible_command ();
break; // terminate case statement here break; // terminate case statement here
} }
cerr << "nope, now cutting time range" << endl;
if (!selection->time.empty()) { if (!selection->time.empty()) {
/* don't cause suprises */ /* don't cause suprises */
break; break;
@ -3575,9 +3572,7 @@ Editor::cut_copy (CutCopyOp op)
case MouseRange: case MouseRange:
if (selection->time.empty()) { if (selection->time.empty()) {
nframes64_t start, end; nframes64_t start, end;
cerr << "no time selection, get edit op range" << endl;
if (!get_edit_op_range (start, end)) { if (!get_edit_op_range (start, end)) {
cerr << "no edit op range" << endl;
return; return;
} }
selection->set ((TimeAxisView*) 0, start, end); selection->set ((TimeAxisView*) 0, start, end);
@ -4375,6 +4370,15 @@ Editor::toggle_region_lock ()
} }
} }
void
Editor::set_region_lock_style (Region::PositionLockStyle ps)
{
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
(*i)->region()->set_position_lock_style (ps);
}
}
void void
Editor::toggle_region_mute () Editor::toggle_region_mute ()
{ {
@ -5016,28 +5020,67 @@ Editor::define_one_bar (nframes64_t start, nframes64_t end)
const Meter& m (session->tempo_map().meter_at (start)); const Meter& m (session->tempo_map().meter_at (start));
/* region length = 1 bar */ /* length = 1 bar */
/* 1 bar = how many beats per bar */
double beats_per_bar = m.beats_per_bar();
/* now we want frames per beat. /* now we want frames per beat.
we have frames per bar, and beats per bar, so ... we have frames per bar, and beats per bar, so ...
*/ */
double frames_per_beat = length / beats_per_bar; double frames_per_beat = length / m.beats_per_bar();
/* beats per minute = */ /* beats per minute = */
double beats_per_minute = (session->frame_rate() * 60.0) / frames_per_beat; double beats_per_minute = (session->frame_rate() * 60.0) / frames_per_beat;
/* now decide whether to:
(a) set global tempo
(b) add a new tempo marker
*/
const TempoSection& t (session->tempo_map().tempo_section_at (start)); const TempoSection& t (session->tempo_map().tempo_section_at (start));
bool do_global = false;
if ((session->tempo_map().n_tempos() == 1) && (session->tempo_map().n_meters() == 1)) {
/* only 1 tempo & 1 meter: ask if the user wants to set the tempo
at the start, or create a new marker
*/
vector<string> options;
options.push_back (_("Set global tempo"));
options.push_back (_("Add new marker"));
options.push_back (_("Cancel"));
Choice c (_("Do you want to set the global tempo or add new tempo marker?"),
options);
switch (c.run()) {
case 0:
do_global = true;
break;
case 2:
return;
default:
do_global = false;
}
} else {
/* more than 1 tempo and/or meter section already, go ahead do the "usual":
if the marker is at the region starter, change it, otherwise add
a new tempo marker
*/
}
begin_reversible_command (_("set tempo from region")); begin_reversible_command (_("set tempo from region"));
XMLNode& before (session->tempo_map().get_state()); XMLNode& before (session->tempo_map().get_state());
if (t.frame() == start) { if (do_global) {
session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
} else if (t.frame() == start) {
session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type()); session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
} else { } else {
session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start); session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
@ -5052,7 +5095,7 @@ Editor::define_one_bar (nframes64_t start, nframes64_t end)
void void
Editor::split_region_at_transients () Editor::split_region_at_transients ()
{ {
vector<nframes64_t> positions; AnalysisFeatureList positions;
if (!session) { if (!session) {
return; return;
@ -5088,7 +5131,7 @@ Editor::split_region_at_transients ()
} }
void void
Editor::split_region_at_points (boost::shared_ptr<Region> r, vector<nframes64_t>& positions) Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions)
{ {
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r); boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
@ -5106,7 +5149,7 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, vector<nframes64_t>
return; return;
} }
vector<nframes64_t>::const_iterator x; AnalysisFeatureList::const_iterator x;
nframes64_t pos = ar->position(); nframes64_t pos = ar->position();
@ -5163,30 +5206,52 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, vector<nframes64_t>
void void
Editor::tab_to_transient (bool forward) Editor::tab_to_transient (bool forward)
{ {
AnalysisFeatureList positions;
vector<nframes64_t> positions;
if (!session) { if (!session) {
return; return;
} }
nframes64_t pos = session->audible_frame ();
if (!selection->tracks.empty()) {
for (TrackSelection::iterator t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
if (rtv) {
boost::shared_ptr<Diskstream> ds = rtv->get_diskstream();
if (ds) {
boost::shared_ptr<Playlist> pl = rtv->get_diskstream()->playlist ();
if (pl) {
nframes64_t result = pl->find_next_transient (pos, forward ? 1 : -1);
if (result >= 0) {
positions.push_back (result);
}
}
}
}
}
} else {
ExclusiveRegionSelection esr (*this, entered_regionview); ExclusiveRegionSelection esr (*this, entered_regionview);
if (selection->regions.empty()) { if (selection->regions.empty()) {
return; return;
} }
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (selection->regions.front()->region()); for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
(*r)->region()->get_transients (positions);
if (!ar) { }
return;
} }
ar->get_transients (positions); TransientDetector::cleanup_transients (positions, session->frame_rate(), 3.0);
nframes64_t pos = session->audible_frame ();
if (forward) { if (forward) {
vector<nframes64_t>::iterator x; AnalysisFeatureList::iterator x;
for (x = positions.begin(); x != positions.end(); ++x) { for (x = positions.begin(); x != positions.end(); ++x) {
if ((*x) > pos) { if ((*x) > pos) {
@ -5199,7 +5264,7 @@ Editor::tab_to_transient (bool forward)
} }
} else { } else {
vector<nframes64_t>::reverse_iterator x; AnalysisFeatureList::reverse_iterator x;
for (x = positions.rbegin(); x != positions.rend(); ++x) { for (x = positions.rbegin(); x != positions.rend(); ++x) {
if ((*x) < pos) { if ((*x) < pos) {

View file

@ -365,10 +365,14 @@ Editor::edit_tempo_section (TempoSection* section)
tempo_dialog.get_bbt_time(when); tempo_dialog.get_bbt_time(when);
bpm = max (0.01, bpm); bpm = max (0.01, bpm);
cerr << "Editing tempo section to be at " << when << endl;
session->tempo_map().dump (cerr);
begin_reversible_command (_("replace tempo mark")); begin_reversible_command (_("replace tempo mark"));
XMLNode &before = session->tempo_map().get_state(); XMLNode &before = session->tempo_map().get_state();
session->tempo_map().replace_tempo (*section, Tempo (bpm,nt)); session->tempo_map().replace_tempo (*section, Tempo (bpm,nt));
session->tempo_map().dump (cerr);
session->tempo_map().move_tempo (*section, when); session->tempo_map().move_tempo (*section, when);
session->tempo_map().dump (cerr);
XMLNode &after = session->tempo_map().get_state(); XMLNode &after = session->tempo_map().get_state();
session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), &before, &after)); session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), &before, &after));
commit_reversible_command (); commit_reversible_command ();

View file

@ -553,10 +553,12 @@ EngineControl::setup_engine ()
error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg; error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
return -1; return -1;
} }
cerr << "JACK COMMAND: ";
for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) { for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
cerr << (*i) << ' ';
jackdrc << (*i) << ' '; jackdrc << (*i) << ' ';
} }
cerr << endl;
jackdrc << endl; jackdrc << endl;
jackdrc.close (); jackdrc.close ();
@ -915,7 +917,7 @@ EngineControl::find_jack_servers (vector<string>& strings)
_NSGetExecutablePath (execpath, &pathsz); _NSGetExecutablePath (execpath, &pathsz);
Glib::ustring path (Glib::path_get_dirname (execpath)); string path (Glib::path_get_dirname (execpath));
path += "/jackd"; path += "/jackd";
if (Glib::file_test (path, FILE_TEST_EXISTS)) { if (Glib::file_test (path, FILE_TEST_EXISTS)) {
@ -937,8 +939,36 @@ EngineControl::find_jack_servers (vector<string>& strings)
PathScanner scanner; PathScanner scanner;
vector<string *> *jack_servers; vector<string *> *jack_servers;
std::map<string,int> un; std::map<string,int> un;
char *p;
bool need_minimal_path = false;
path = getenv ("PATH"); p = getenv ("PATH");
if (p && *p) {
path = p;
} else {
need_minimal_path = true;
}
#ifdef __APPLE__
// many mac users don't have PATH set up to include
// likely installed locations of JACK
need_minimal_path = true;
#endif
if (need_minimal_path) {
if (path.empty()) {
path = "/usr/bin:/bin:/usr/local/bin:/opt/local/bin";
} else {
path += ":/usr/local/bin:/opt/local/bin";
}
}
#ifdef __APPLE__
// push it back into the environment so that auto-started JACK can find it.
// XXX why can't we just expect OS X users to have PATH set correctly? we can't ...
setenv ("PATH", path.c_str(), 1);
#endif
jack_servers = scanner (path, jack_server_filter, 0, false, true); jack_servers = scanner (path, jack_server_filter, 0, false, true);

View file

@ -38,7 +38,9 @@
#include <ardour/plugin.h> #include <ardour/plugin.h>
#include <ardour/plugin_insert.h> #include <ardour/plugin_insert.h>
#include <ardour/ladspa_plugin.h> #include <ardour/ladspa_plugin.h>
#ifdef HAVE_LV2
#include <ardour/lv2_plugin.h> #include <ardour/lv2_plugin.h>
#endif
#include <lrdf.h> #include <lrdf.h>
@ -385,8 +387,9 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr<Automat
if (plugin->parameter_is_input (port_index)) { if (plugin->parameter_is_input (port_index)) {
boost::shared_ptr<LadspaPlugin> lp; boost::shared_ptr<LadspaPlugin> lp;
#ifdef HAVE_LV2
boost::shared_ptr<LV2Plugin> lv2p; boost::shared_ptr<LV2Plugin> lv2p;
#endif
if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) { if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) {
// FIXME: not all plugins have a numeric unique ID // FIXME: not all plugins have a numeric unique ID
@ -409,6 +412,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr<Automat
return control_ui; return control_ui;
} }
#ifdef HAVE_LV2
} else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin>(plugin)) != 0) { } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin>(plugin)) != 0) {
SLV2Port port = lv2p->slv2_port(port_index); SLV2Port port = lv2p->slv2_port(port_index);
@ -428,6 +432,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr<Automat
slv2_scale_points_free(points); slv2_scale_points_free(points);
return control_ui; return control_ui;
} }
#endif
} }
if (desc.toggled) { if (desc.toggled) {
@ -757,7 +762,9 @@ GenericPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui)
{ {
vector<string> enums; vector<string> enums;
boost::shared_ptr<LadspaPlugin> lp; boost::shared_ptr<LadspaPlugin> lp;
#ifdef HAVE_LV2
boost::shared_ptr<LV2Plugin> lv2p; boost::shared_ptr<LV2Plugin> lv2p;
#endif
if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) { if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) {
// all LADPSA plugins have a numeric unique ID // all LADPSA plugins have a numeric unique ID
@ -777,6 +784,7 @@ GenericPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui)
lrdf_free_setting_values(defaults); lrdf_free_setting_values(defaults);
} }
#ifdef HAVE_LV2
} else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin>(plugin)) != 0) { } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin>(plugin)) != 0) {
SLV2Port port = lv2p->slv2_port(port_index); SLV2Port port = lv2p->slv2_port(port_index);
@ -797,6 +805,7 @@ GenericPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui)
} }
slv2_scale_points_free(points); slv2_scale_points_free(points);
#endif
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -971,6 +971,8 @@ NewSessionDialog::reset_recent()
i != session_directories.end(); ++i) i != session_directories.end(); ++i)
{ {
std::vector<sys::path> state_file_paths; std::vector<sys::path> state_file_paths;
std::vector<std::string*>* states;
const string fullpath = (*i).to_string();
// now get available states for this session // now get available states for this session
@ -981,27 +983,36 @@ NewSessionDialog::reset_recent()
continue; continue;
} }
std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths)); /* check whether session still exists */
if (!Glib::file_test(fullpath, Glib::FILE_TEST_EXISTS)) {
/* session doesn't exist */
continue;
}
/* now get available states for this session */
if ((states = ARDOUR::Session::possible_states (fullpath)) == 0) {
/* no state file? */
continue;
}
Gtk::TreeModel::Row row = *(recent_model->append()); Gtk::TreeModel::Row row = *(recent_model->append());
const string fullpath = (*i).to_string();
row[recent_columns.visible_name] = Glib::path_get_basename (fullpath); row[recent_columns.visible_name] = Glib::path_get_basename (fullpath);
row[recent_columns.fullpath] = fullpath; row[recent_columns.fullpath] = fullpath;
if (state_file_names.size() > 1) { if (states->size()) {
// add the children /* add the children */
for (std::vector<std::string>::iterator i2 = state_file_names.begin(); for (std::vector<std::string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
i2 != state_file_names.end(); ++i2)
{
Gtk::TreeModel::Row child_row = *(recent_model->append (row.children())); Gtk::TreeModel::Row child_row = *(recent_model->append (row.children()));
child_row[recent_columns.visible_name] = *i2; child_row[recent_columns.visible_name] = **i2;
child_row[recent_columns.fullpath] = fullpath; child_row[recent_columns.fullpath] = fullpath;
delete *i2;
} }
} }
} }

View file

@ -254,7 +254,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
virtual void restore_editing_space () = 0; virtual void restore_editing_space () = 0;
virtual nframes64_t get_preferred_edit_position (bool ignore_playhead = false) = 0; virtual nframes64_t get_preferred_edit_position (bool ignore_playhead = false) = 0;
virtual void toggle_meter_updating() = 0; virtual void toggle_meter_updating() = 0;
virtual void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, std::vector<nframes64_t>&) = 0; virtual void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, ARDOUR::AnalysisFeatureList&) = 0;
#ifdef WITH_CMT #ifdef WITH_CMT
virtual void add_imageframe_time_axis(const std::string & track_name, void*) = 0; virtual void add_imageframe_time_axis(const std::string & track_name, void*) = 0;

View file

@ -13,6 +13,7 @@
#include "rhythm_ferret.h" #include "rhythm_ferret.h"
#include "audio_region_view.h" #include "audio_region_view.h"
#include "public_editor.h" #include "public_editor.h"
#include "utils.h"
#include "i18n.h" #include "i18n.h"
@ -57,9 +58,9 @@ RhythmFerret::RhythmFerret (PublicEditor& e)
{ {
upper_hpacker.set_spacing (6); 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); upper_hpacker.pack_start (ferret_frame, true, true);
upper_hpacker.pack_start (selection_frame, true, true);
upper_hpacker.pack_start (operation_frame, true, true);
op_packer.pack_start (region_split_button, false, false); op_packer.pack_start (region_split_button, false, false);
op_packer.pack_start (tempo_button, false, false); op_packer.pack_start (tempo_button, false, false);
@ -108,14 +109,16 @@ RhythmFerret::RhythmFerret (PublicEditor& e)
ferret_frame.add (ferret_packer); ferret_frame.add (ferret_packer);
// Glib::RefPtr<Pixbuf> logo_pixbuf ("somefile"); logo = manage (new Gtk::Image (::get_icon (X_("ferret_02"))));
if (logo) { if (logo) {
lower_hpacker.pack_start (*logo, false, false); lower_hpacker.pack_start (*logo, false, false);
} }
lower_hpacker.pack_start (operation_clarification_label, false, false); lower_hpacker.pack_start (operation_clarification_label, true, true);
lower_hpacker.pack_start (action_button, false, false); lower_hpacker.pack_start (action_button, false, false);
lower_hpacker.set_border_width (6);
lower_hpacker.set_spacing (6);
action_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::do_action)); action_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::do_action));
@ -194,13 +197,13 @@ RhythmFerret::run_analysis ()
} }
int int
RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr<Readable> readable, nframes64_t offset, vector<nframes64_t>& results) RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr<Readable> readable, nframes64_t offset, AnalysisFeatureList& results)
{ {
TransientDetector t (session->frame_rate()); TransientDetector t (session->frame_rate());
for (uint32_t i = 0; i < readable->n_channels(); ++i) { for (uint32_t i = 0; i < readable->n_channels(); ++i) {
vector<nframes64_t> these_results; AnalysisFeatureList these_results;
t.reset (); t.reset ();
t.set_threshold (detection_threshold_adjustment.get_value()); t.set_threshold (detection_threshold_adjustment.get_value());
@ -212,38 +215,18 @@ RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr<Readable> readabl
/* translate all transients to give absolute position */ /* translate all transients to give absolute position */
for (vector<nframes64_t>::iterator i = these_results.begin(); i != these_results.end(); ++i) { for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) {
(*i) += offset; (*x) += offset;
} }
/* merge */ /* merge */
results.insert (results.end(), these_results.begin(), these_results.end()); results.insert (results.end(), these_results.begin(), these_results.end());
these_results.clear ();
} }
if (!results.empty()) { if (!results.empty()) {
TransientDetector::cleanup_transients (results, session->frame_rate(), trigger_gap_adjustment.get_value());
/* 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; return 0;

View file

@ -84,17 +84,17 @@ class RhythmFerret : public ArdourDialog {
std::vector<std::string> analysis_mode_strings; std::vector<std::string> analysis_mode_strings;
std::vector<nframes64_t> current_results; ARDOUR::AnalysisFeatureList current_results;
AnalysisMode get_analysis_mode () const; AnalysisMode get_analysis_mode () const;
Action get_action() const; Action get_action() const;
void run_analysis (); void run_analysis ();
int run_percussion_onset_analysis (boost::shared_ptr<ARDOUR::Readable> region, nframes64_t offset, std::vector<nframes64_t>& results); int run_percussion_onset_analysis (boost::shared_ptr<ARDOUR::Readable> region, nframes64_t offset, ARDOUR::AnalysisFeatureList& results);
void do_action (); void do_action ();
void do_split_action (); void do_split_action ();
void do_region_split (RegionView* rv, const std::vector<nframes64_t>&); void do_region_split (RegionView* rv, const ARDOUR::AnalysisFeatureList&);
}; };
#endif /* __gtk2_ardour_rhythm_ferret_h__ */ #endif /* __gtk2_ardour_rhythm_ferret_h__ */

View file

@ -14,6 +14,8 @@ using namespace Glib;
using namespace std; using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
Splash* Splash::the_splash = 0;
Splash::Splash () Splash::Splash ()
{ {
sys::path splash_file; sys::path splash_file;
@ -47,6 +49,14 @@ Splash::Splash ()
darea.signal_expose_event().connect (mem_fun (*this, &Splash::expose)); darea.signal_expose_event().connect (mem_fun (*this, &Splash::expose));
add (darea); add (darea);
the_splash = this;
}
void
Splash::pop_back ()
{
set_keep_above (false);
} }
void void

View file

@ -34,6 +34,10 @@ class Splash : public Gtk::Window
Splash (); Splash ();
~Splash () {} ~Splash () {}
static Splash* instance() { return the_splash; }
void pop_back ();
bool expose (GdkEventExpose*); bool expose (GdkEventExpose*);
bool on_button_release_event (GdkEventButton*); bool on_button_release_event (GdkEventButton*);
void on_realize (); void on_realize ();
@ -41,6 +45,8 @@ class Splash : public Gtk::Window
void message (const std::string& msg); void message (const std::string& msg);
private: private:
static Splash* the_splash;
Glib::RefPtr<Gdk::Pixbuf> pixbuf; Glib::RefPtr<Gdk::Pixbuf> pixbuf;
Gtk::DrawingArea darea; Gtk::DrawingArea darea;
Glib::RefPtr<Pango::Layout> layout; Glib::RefPtr<Pango::Layout> layout;

View file

@ -243,7 +243,6 @@ TempoDialog::get_note_type ()
} }
} }
cerr << "returning " << note_type << " based on " << text << endl;
return note_type; return note_type;
} }

View file

@ -1104,7 +1104,7 @@ TimeAxisView::covers_y_position (double y)
} }
void void
TimeAxisView::show_temporary_lines (const vector<nframes64_t>& pos) TimeAxisView::show_temporary_lines (const AnalysisFeatureList& pos)
{ {
while (temp_lines.size()< pos.size()) { while (temp_lines.size()< pos.size()) {
ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*canvas_display); ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*canvas_display);
@ -1120,7 +1120,7 @@ TimeAxisView::show_temporary_lines (const vector<nframes64_t>& pos)
delete line; delete line;
} }
vector<nframes64_t>::const_iterator i; AnalysisFeatureList::const_iterator i;
list<ArdourCanvas::SimpleLine*>::iterator l; list<ArdourCanvas::SimpleLine*>::iterator l;
for (i = pos.begin(), l = temp_lines.begin(); i != pos.end() && l != temp_lines.end(); ++i, ++l) { for (i = pos.begin(), l = temp_lines.begin(); i != pos.end() && l != temp_lines.end(); ++i, ++l) {

View file

@ -172,7 +172,7 @@ class TimeAxisView : public virtual AxisView
virtual ARDOUR::RouteGroup* edit_group() const { return 0; } virtual ARDOUR::RouteGroup* edit_group() const { return 0; }
virtual boost::shared_ptr<ARDOUR::Playlist> playlist() const { return boost::shared_ptr<ARDOUR::Playlist> (); } 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 show_temporary_lines (const ARDOUR::AnalysisFeatureList&);
virtual void hide_temporary_lines (); virtual void hide_temporary_lines ();
virtual void set_samples_per_unit (double); virtual void set_samples_per_unit (double);

View file

@ -466,6 +466,16 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
int ret = false; int ret = false;
switch (ev->keyval) { switch (ev->keyval) {
case GDK_Tab:
ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_nabla, GdkModifierType(ev->state));
break;
// some X and/or GDK implementations do Shift-Tab -> GDK_ISO_Left_Tab
case GDK_ISO_Left_Tab:
ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_nabla, GdkModifierType(ev->state));
break;
case GDK_Up: case GDK_Up:
ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_uparrow, GdkModifierType(ev->state)); ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_uparrow, GdkModifierType(ev->state));
break; break;

View file

@ -31,6 +31,7 @@ amp.cc
audio_buffer.cc audio_buffer.cc
auto_bundle.cc auto_bundle.cc
user_bundle.cc user_bundle.cc
analyser.cc
audioanalyser.cc audioanalyser.cc
audio_diskstream.cc audio_diskstream.cc
audio_library.cc audio_library.cc

119
libs/ardour/analyser.cc Normal file
View file

@ -0,0 +1,119 @@
/*
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.
*/
#include <ardour/analyser.h>
#include <ardour/audiofilesource.h>
#include <ardour/transient_detector.h>
#include <pbd/pthread_utils.h>
#include <pbd/convert.h>
using namespace std;
using namespace sigc;
using namespace ARDOUR;
using namespace PBD;
Analyser* Analyser::the_analyser = 0;
Glib::StaticMutex Analyser::analysis_queue_lock = GLIBMM_STATIC_MUTEX_INIT;
Glib::Cond* Analyser::SourcesToAnalyse = 0;
list<boost::weak_ptr<Source> > Analyser::analysis_queue;
Analyser::Analyser ()
{
}
Analyser::~Analyser ()
{
}
static void
analyser_work ()
{
Analyser::work ();
}
void
Analyser::init ()
{
SourcesToAnalyse = new Glib::Cond();
Glib::Thread::create (sigc::ptr_fun (analyser_work), false);
}
void
Analyser::queue_source_for_analysis (boost::shared_ptr<Source> src, bool force)
{
if (!src->can_be_analysed()) {
return;
}
if (!force && src->has_been_analysed()) {
return;
}
Glib::Mutex::Lock lm (analysis_queue_lock);
analysis_queue.push_back (boost::weak_ptr<Source>(src));
SourcesToAnalyse->broadcast ();
}
void
Analyser::work ()
{
PBD::ThreadCreated (pthread_self(), string ("analyser-") + to_string (pthread_self(), std::dec));
while (true) {
analysis_queue_lock.lock ();
wait:
if (analysis_queue.empty()) {
SourcesToAnalyse->wait (analysis_queue_lock);
}
if (analysis_queue.empty()) {
goto wait;
}
boost::shared_ptr<Source> src (analysis_queue.front().lock());
analysis_queue.pop_front();
analysis_queue_lock.unlock ();
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) {
analyse_audio_file_source (afs);
}
}
}
void
Analyser::analyse_audio_file_source (boost::shared_ptr<AudioFileSource> src)
{
AnalysisFeatureList results;
TransientDetector td (src->sample_rate());
if (td.run (src->get_transients_path(), src.get(), 0, results) == 0) {
src->set_been_analysed (true);
} else {
src->set_been_analysed (false);
}
}

View file

@ -0,0 +1,35 @@
#ifndef __ardour_analyser_h__
#define __ardour_analyser_h__
#include <glibmm/thread.h>
#include <boost/shared_ptr.hpp>
namespace ARDOUR {
class AudioFileSource;
class Source;
class TransientDetector;
class Analyser {
public:
Analyser();
~Analyser ();
static void init ();
static void queue_source_for_analysis (boost::shared_ptr<Source>, bool force);
static void work ();
private:
static Analyser* the_analyser;
static Glib::StaticMutex analysis_queue_lock;
static Glib::Cond* SourcesToAnalyse;
static std::list<boost::weak_ptr<Source> > analysis_queue;
static void analyse_audio_file_source (boost::shared_ptr<AudioFileSource>);
};
}
#endif /* __ardour_analyser_h__ */

View file

@ -125,6 +125,8 @@ class AudioFileSource : public AudioSource {
virtual void handle_header_position_change () {} virtual void handle_header_position_change () {}
bool can_be_analysed() const { return _length > 0; }
protected: protected:
/* constructor to be called for existing external-to-session files */ /* constructor to be called for existing external-to-session files */

View file

@ -134,7 +134,7 @@ class AudioRegion : public Region
void resume_fade_in (); void resume_fade_in ();
void resume_fade_out (); void resume_fade_out ();
int get_transients (std::vector<nframes64_t>&, bool force_new = false); int get_transients (AnalysisFeatureList&, bool force_new = false);
private: private:
friend class RegionFactory; friend class RegionFactory;
@ -170,6 +170,7 @@ class AudioRegion : public Region
void fade_out_changed (); void fade_out_changed ();
void source_offset_changed (); void source_offset_changed ();
void listen_to_my_curves (); void listen_to_my_curves ();
void listen_to_my_sources ();
boost::shared_ptr<AutomationList> _fade_in; boost::shared_ptr<AutomationList> _fade_in;
FadeShape _fade_in_shape; FadeShape _fade_in_shape;
@ -187,11 +188,6 @@ class AudioRegion : public Region
AudioRegion (boost::shared_ptr<const AudioRegion>); AudioRegion (boost::shared_ptr<const AudioRegion>);
int set_live_state (const XMLNode&, Change&, bool send); int set_live_state (const XMLNode&, Change&, bool send);
std::vector<nframes64_t> _transients;
bool valid_transients;
void invalidate_transients ();
void cleanup_transients (std::vector<nframes64_t>&);
}; };
} /* namespace ARDOUR */ } /* namespace ARDOUR */

View file

@ -111,14 +111,12 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
int prepare_for_peakfile_writes (); int prepare_for_peakfile_writes ();
void done_with_peakfile_writes (bool done = true); void done_with_peakfile_writes (bool done = true);
std::vector<nframes64_t> transients;
std::string get_transients_path() const;
protected: protected:
static bool _build_missing_peakfiles; static bool _build_missing_peakfiles;
static bool _build_peakfiles; static bool _build_peakfiles;
bool _peaks_built; bool _peaks_built;
bool _analysed;
mutable Glib::Mutex _lock; mutable Glib::Mutex _lock;
mutable Glib::Mutex _peaks_ready_lock; mutable Glib::Mutex _peaks_ready_lock;
Glib::ustring peakpath; Glib::ustring peakpath;
@ -147,8 +145,6 @@ 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, 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); bool intermediate_peaks_ready_signal, nframes_t frames_per_peak);
int load_transients (const std::string&);
private: private:
int peakfile; int peakfile;
nframes_t peak_leftover_cnt; nframes_t peak_leftover_cnt;

View file

@ -53,6 +53,7 @@ CONFIG_VARIABLE (float, track_buffer_seconds, "track-buffer-seconds", 5.0)
CONFIG_VARIABLE (uint32_t, disk_choice_space_threshold, "disk-choice-space-threshold", 57600000) CONFIG_VARIABLE (uint32_t, disk_choice_space_threshold, "disk-choice-space-threshold", 57600000)
CONFIG_VARIABLE (SampleFormat, native_file_data_format, "native-file-data-format", ARDOUR::FormatFloat) CONFIG_VARIABLE (SampleFormat, native_file_data_format, "native-file-data-format", ARDOUR::FormatFloat)
CONFIG_VARIABLE (HeaderFormat, native_file_header_format, "native-file-header-format", ARDOUR::WAVE) CONFIG_VARIABLE (HeaderFormat, native_file_header_format, "native-file-header-format", ARDOUR::WAVE)
CONFIG_VARIABLE (bool, auto_analyse_audio, "auto-analyse-audio", true)
/* OSC */ /* OSC */

View file

@ -96,6 +96,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
void duplicate (boost::shared_ptr<Region>, nframes_t position, float times); void duplicate (boost::shared_ptr<Region>, nframes_t position, float times);
void nudge_after (nframes_t start, nframes_t distance, bool forwards); void nudge_after (nframes_t start, nframes_t distance, bool forwards);
void shuffle (boost::shared_ptr<Region>, int dir); void shuffle (boost::shared_ptr<Region>, int dir);
void update_after_tempo_map_change ();
boost::shared_ptr<Playlist> cut (list<AudioRange>&, bool result_is_hidden = true); boost::shared_ptr<Playlist> cut (list<AudioRange>&, bool result_is_hidden = true);
boost::shared_ptr<Playlist> copy (list<AudioRange>&, bool result_is_hidden = true); boost::shared_ptr<Playlist> copy (list<AudioRange>&, bool result_is_hidden = true);
@ -110,6 +111,8 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
nframes64_t find_next_region_boundary (nframes64_t frame, int dir); nframes64_t find_next_region_boundary (nframes64_t frame, int dir);
bool region_is_shuffle_constrained (boost::shared_ptr<Region>); bool region_is_shuffle_constrained (boost::shared_ptr<Region>);
nframes64_t find_next_transient (nframes64_t position, int dir);
template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>, void *), void *arg); template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>, void *), void *arg);
template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>)); template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>));

View file

@ -73,6 +73,11 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
range_guarantoor = USHRT_MAX range_guarantoor = USHRT_MAX
}; };
enum PositionLockStyle {
AudioTime,
MusicTime
};
static const Flag DefaultFlags = Flag (Opaque|DefaultFadeIn|DefaultFadeOut|FadeIn|FadeOut); static const Flag DefaultFlags = Flag (Opaque|DefaultFadeIn|DefaultFadeOut|FadeIn|FadeOut);
static Change FadeChanged; static Change FadeChanged;
@ -130,6 +135,9 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); } bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); }
bool can_move() const { return !(_flags & (Locked|PositionLocked)); } bool can_move() const { return !(_flags & (Locked|PositionLocked)); }
PositionLockStyle positional_lock_style() const { return _positional_lock_style; }
void set_position_lock_style (PositionLockStyle ps);
virtual bool should_save_state () const { return !(_flags & DoNotSaveState); }; virtual bool should_save_state () const { return !(_flags & DoNotSaveState); };
void freeze (); void freeze ();
@ -156,6 +164,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
void set_position (nframes_t, void *src); void set_position (nframes_t, void *src);
void set_position_on_top (nframes_t, void *src); void set_position_on_top (nframes_t, void *src);
void special_set_position (nframes_t); void special_set_position (nframes_t);
void update_position_after_tempo_map_change ();
void nudge_position (nframes64_t, void *src); void nudge_position (nframes64_t, void *src);
bool at_natural_position () const; bool at_natural_position () const;
@ -213,6 +222,13 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
virtual bool is_dependent() const { return false; } virtual bool is_dependent() const { return false; }
virtual bool depends_on (boost::shared_ptr<Region> other) const { return false; } virtual bool depends_on (boost::shared_ptr<Region> other) const { return false; }
virtual int get_transients (AnalysisFeatureList&, bool force_new = false) {
// no transients, but its OK
return 0;
}
void invalidate_transients ();
protected: protected:
friend class RegionFactory; friend class RegionFactory;
@ -226,8 +242,6 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
Region (boost::shared_ptr<Source> src, const XMLNode&); Region (boost::shared_ptr<Source> src, const XMLNode&);
Region (const SourceList& srcs, const XMLNode&); Region (const SourceList& srcs, const XMLNode&);
/* this one is for derived types of derived types */
Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType, layer_t = 0, Flag flags = DefaultFlags); Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType, layer_t = 0, Flag flags = DefaultFlags);
protected: protected:
@ -236,6 +250,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
void send_change (Change); void send_change (Change);
void trim_to_internal (nframes_t position, nframes_t length, void *src); void trim_to_internal (nframes_t position, nframes_t length, void *src);
void set_position_internal (nframes_t pos, bool allow_bbt_recompute);
bool copied() const { return _flags & Copied; } bool copied() const { return _flags & Copied; }
void maybe_uncopy (); void maybe_uncopy ();
@ -256,6 +271,7 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
nframes_t _last_length; nframes_t _last_length;
nframes_t _position; nframes_t _position;
nframes_t _last_position; nframes_t _last_position;
PositionLockStyle _positional_lock_style;
nframes_t _sync_position; nframes_t _sync_position;
layer_t _layer; layer_t _layer;
mutable RegionEditState _first_edit; mutable RegionEditState _first_edit;
@ -264,6 +280,9 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
nframes64_t _ancestral_length; nframes64_t _ancestral_length;
float _stretch; float _stretch;
float _shift; float _shift;
BBT_Time _bbt_time;
AnalysisFeatureList _transients;
bool _valid_transients;
mutable uint32_t _read_data_count; ///< modified in read() mutable uint32_t _read_data_count; ///< modified in read()
Change _pending_changed; Change _pending_changed;
uint64_t _last_layer_op; ///< timestamp uint64_t _last_layer_op; ///< timestamp

View file

@ -389,7 +389,10 @@ class Session : public PBD::StatefulDestructible
nframes_t get_maximum_extent () const; nframes_t get_maximum_extent () const;
nframes_t current_end_frame() const { return end_location->start(); } nframes_t current_end_frame() const { return end_location->start(); }
nframes_t current_start_frame() const { return start_location->start(); } nframes_t current_start_frame() const { return start_location->start(); }
// "actual" sample rate of session, set by current audioengine rate, pullup/down etc.
nframes_t frame_rate() const { return _current_frame_rate; } nframes_t frame_rate() const { return _current_frame_rate; }
// "native" sample rate of session, regardless of current audioengine rate, pullup/down etc
nframes_t nominal_frame_rate() const { return _nominal_frame_rate; }
nframes_t frames_per_hour() const { return _frames_per_hour; } nframes_t frames_per_hour() const { return _frames_per_hour; }
double frames_per_smpte_frame() const { return _frames_per_smpte_frame; } double frames_per_smpte_frame() const { return _frames_per_smpte_frame; }
@ -433,6 +436,9 @@ class Session : public PBD::StatefulDestructible
sigc::signal<void,string> StateSaved; sigc::signal<void,string> StateSaved;
sigc::signal<void> StateReady; sigc::signal<void> StateReady;
vector<string*>* possible_states() const;
static vector<string*>* possible_states(string path);
XMLNode& get_state(); XMLNode& get_state();
int set_state(const XMLNode& node); // not idempotent int set_state(const XMLNode& node); // not idempotent
XMLNode& get_template(); XMLNode& get_template();
@ -624,6 +630,12 @@ class Session : public PBD::StatefulDestructible
sigc::signal<int,boost::shared_ptr<ARDOUR::Playlist> > AskAboutPlaylistDeletion; sigc::signal<int,boost::shared_ptr<ARDOUR::Playlist> > AskAboutPlaylistDeletion;
/* handlers should return 0 for "ignore the rate mismatch"
and !0 for "do not use this session"
*/
static sigc::signal<int,nframes_t, nframes_t> AskAboutSampleRateMismatch;
/* handlers should return !0 for use pending state, 0 for /* handlers should return !0 for use pending state, 0 for
ignore it. ignore it.
*/ */
@ -981,6 +993,7 @@ class Session : public PBD::StatefulDestructible
bool waiting_for_sync_offset; bool waiting_for_sync_offset;
nframes_t _base_frame_rate; nframes_t _base_frame_rate;
nframes_t _current_frame_rate; //this includes video pullup offset nframes_t _current_frame_rate; //this includes video pullup offset
nframes_t _nominal_frame_rate; //ignores audioengine setting, "native" SR
int transport_sub_state; int transport_sub_state;
mutable gint _record_status; mutable gint _record_status;
volatile nframes_t _transport_frame; volatile nframes_t _transport_frame;

View file

@ -35,6 +35,7 @@ class SilentFileSource : public AudioFileSource {
void set_length (nframes_t len); void set_length (nframes_t len);
bool destructive() const { return false; } bool destructive() const { return false; }
bool can_be_analysed() const { return false; }
protected: protected:

View file

@ -78,14 +78,27 @@ class Source : public SessionObject, public ARDOUR::Readable
static sigc::signal<void,Source*> SourceCreated; static sigc::signal<void,Source*> SourceCreated;
sigc::signal<void,boost::shared_ptr<Source> > Switched; sigc::signal<void,boost::shared_ptr<Source> > Switched;
bool has_been_analysed() const;
virtual bool can_be_analysed() const { return false; }
virtual void set_been_analysed (bool yn);
virtual bool check_for_analysis_data_on_disk();
sigc::signal<void> AnalysisChanged;
AnalysisFeatureList transients;
std::string get_transients_path() const;
int load_transients (const std::string&);
protected: protected:
void update_length (nframes_t pos, nframes_t cnt); void update_length (nframes_t pos, nframes_t cnt);
DataType _type; DataType _type;
time_t _timestamp; time_t _timestamp;
nframes_t _length; nframes_t _length;
bool _analysed;
mutable Glib::Mutex _analysis_lock;
Glib::Mutex _playlist_lock;
Glib::Mutex playlist_lock;
typedef std::map<boost::shared_ptr<ARDOUR::Playlist>, uint32_t > PlaylistMap; typedef std::map<boost::shared_ptr<ARDOUR::Playlist>, uint32_t > PlaylistMap;
PlaylistMap _playlists; PlaylistMap _playlists;

View file

@ -279,6 +279,10 @@ class TempoMap : public PBD::StatefulDestructible
void bbt_time_with_metric (nframes_t, BBT_Time&, const Metric&) const; void bbt_time_with_metric (nframes_t, BBT_Time&, const Metric&) const;
void change_existing_tempo_at (nframes_t, double bpm, double note_type); void change_existing_tempo_at (nframes_t, double bpm, double note_type);
void change_initial_tempo (double bpm, double note_type);
int n_tempos () const;
int n_meters () const;
sigc::signal<void,ARDOUR::Change> StateChanged; sigc::signal<void,ARDOUR::Change> StateChanged;

View file

@ -34,17 +34,23 @@ class TransientDetector : public AudioAnalyser
TransientDetector (float sample_rate); TransientDetector (float sample_rate);
~TransientDetector(); ~TransientDetector();
static std::string operational_identifier();
void set_threshold (float); void set_threshold (float);
void set_sensitivity (float); void set_sensitivity (float);
float get_threshold () const; float get_threshold () const;
float get_sensitivity () const; float get_sensitivity () const;
int run (const std::string& path, Readable*, uint32_t channel, std::vector<nframes64_t>& results); int run (const std::string& path, Readable*, uint32_t channel, AnalysisFeatureList& results);
static void cleanup_transients (AnalysisFeatureList&, float sr, float gap_msecs);
protected: protected:
std::vector<nframes64_t>* current_results; AnalysisFeatureList* current_results;
int use_features (Vamp::Plugin::FeatureSet&, std::ostream*); int use_features (Vamp::Plugin::FeatureSet&, std::ostream*);
static std::string _op_id;
}; };
} /* namespace */ } /* namespace */

View file

@ -392,6 +392,8 @@ namespace ARDOUR {
int opts; // really RubberBandStretcher::Options int opts; // really RubberBandStretcher::Options
}; };
typedef std::list<nframes64_t> AnalysisFeatureList;
} // namespace ARDOUR } // namespace ARDOUR
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);

View file

@ -17,6 +17,10 @@
*/ */
#include <ardour/audio_buffer.h> #include <ardour/audio_buffer.h>
#include <pbd/error.h>
#include <errno.h>
#include "i18n.h"
#ifdef __x86_64__ #ifdef __x86_64__
static const int CPU_CACHE_ALIGN = 64; static const int CPU_CACHE_ALIGN = 64;
@ -24,6 +28,8 @@ static const int CPU_CACHE_ALIGN = 64;
static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */ static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
#endif #endif
using namespace PBD;
namespace ARDOUR { namespace ARDOUR {
@ -63,7 +69,10 @@ AudioBuffer::resize (size_t size)
#ifdef NO_POSIX_MEMALIGN #ifdef NO_POSIX_MEMALIGN
_data = (Sample *) malloc(sizeof(Sample) * _capacity); _data = (Sample *) malloc(sizeof(Sample) * _capacity);
#else #else
posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Sample) * _capacity); if (posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Sample) * _capacity)) {
fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
CPU_CACHE_ALIGN, sizeof (Sample) * _capacity, strerror (errno)) << endmsg;
}
#endif #endif
_owns_data = true; _owns_data = true;

View file

@ -39,6 +39,7 @@
#include <ardour/ardour.h> #include <ardour/ardour.h>
#include <ardour/audioengine.h> #include <ardour/audioengine.h>
#include <ardour/analyser.h>
#include <ardour/audio_diskstream.h> #include <ardour/audio_diskstream.h>
#include <ardour/utils.h> #include <ardour/utils.h>
#include <ardour/configuration.h> #include <ardour/configuration.h>
@ -1569,6 +1570,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
s->update_header (capture_info.front()->start, when, twhen); s->update_header (capture_info.front()->start, when, twhen);
s->set_captured_for (_name); s->set_captured_for (_name);
s->mark_immutable (); s->mark_immutable ();
Analyser::queue_source_for_analysis (s, true);
} }
} }

View file

@ -18,13 +18,19 @@ using namespace ARDOUR;
AudioAnalyser::AudioAnalyser (float sr, AnalysisPluginKey key) AudioAnalyser::AudioAnalyser (float sr, AnalysisPluginKey key)
: sample_rate (sr) : sample_rate (sr)
, plugin (0)
, plugin_key (key) , plugin_key (key)
{ {
/* create VAMP plugin and initialize */
if (initialize_plugin (plugin_key, sample_rate)) {
error << string_compose (_("cannot load VAMP plugin \"%1\""), key) << endmsg;
throw failed_constructor();
}
} }
AudioAnalyser::~AudioAnalyser () AudioAnalyser::~AudioAnalyser ()
{ {
delete plugin;
} }
int int
@ -73,29 +79,28 @@ int
AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel) AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel)
{ {
ofstream ofile; ofstream ofile;
Plugin::FeatureSet onsets; Plugin::FeatureSet features;
int ret = -1; int ret = -1;
bool done = false; bool done = false;
Sample* data = 0; Sample* data = 0;
nframes64_t len = src->readable_length(); nframes64_t len = src->readable_length();
nframes64_t pos = 0; nframes64_t pos = 0;
float* bufs[1] = { 0 }; float* bufs[1] = { 0 };
string tmp_path;
if (!path.empty()) { if (!path.empty()) {
ofile.open (path.c_str());
/* store data in tmp file, not the real one */
tmp_path = path;
tmp_path += ".tmp";
ofile.open (tmp_path.c_str());
if (!ofile) { if (!ofile) {
goto out; 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]; data = new Sample[bufsize];
bufs[0] = data; bufs[0] = data;
@ -108,7 +113,6 @@ AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel)
to_read = min ((len - pos), bufsize); to_read = min ((len - pos), bufsize);
if (src->read (data, pos, to_read, channel) != to_read) { if (src->read (data, pos, to_read, channel) != to_read) {
cerr << "bad read\n";
goto out; goto out;
} }
@ -118,9 +122,9 @@ AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel)
memset (data + to_read, 0, (bufsize - to_read)); memset (data + to_read, 0, (bufsize - to_read));
} }
onsets = plugin->process (bufs, RealTime::fromSeconds ((double) pos / sample_rate)); features = plugin->process (bufs, RealTime::fromSeconds ((double) pos / sample_rate));
if (use_features (onsets, (path.empty() ? &ofile : 0))) { if (use_features (features, (path.empty() ? 0 : &ofile))) {
goto out; goto out;
} }
@ -133,9 +137,9 @@ AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel)
/* finish up VAMP plugin */ /* finish up VAMP plugin */
onsets = plugin->getRemainingFeatures (); features = plugin->getRemainingFeatures ();
if (use_features (onsets, (path.empty() ? &ofile : 0))) { if (use_features (features, (path.empty() ? &ofile : 0))) {
goto out; goto out;
} }
@ -146,10 +150,14 @@ AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel)
ofile.close (); ofile.close ();
if (ret) { if (ret) {
g_remove (path.c_str()); g_remove (tmp_path.c_str());
} else if (!path.empty()) {
/* move the data file to the requested path */
g_rename (tmp_path.c_str(), path.c_str());
} }
if (data) { if (data) {
delete data; delete [] data;
} }
return ret; return ret;

View file

@ -857,14 +857,17 @@ void
AudioEngine::halted (void *arg) AudioEngine::halted (void *arg)
{ {
AudioEngine* ae = static_cast<AudioEngine *> (arg); AudioEngine* ae = static_cast<AudioEngine *> (arg);
bool was_running = ae->_running;
ae->_running = false; ae->_running = false;
ae->_buffer_size = 0; ae->_buffer_size = 0;
ae->_frame_rate = 0; ae->_frame_rate = 0;
ae->_jack = 0; ae->_jack = 0;
if (was_running) {
ae->Halted(); /* EMIT SIGNAL */ ae->Halted(); /* EMIT SIGNAL */
} }
}
uint32_t uint32_t
AudioEngine::n_physical_outputs () const AudioEngine::n_physical_outputs () const

View file

@ -66,12 +66,12 @@ void
AudioRegion::init () AudioRegion::init ()
{ {
_scale_amplitude = 1.0; _scale_amplitude = 1.0;
valid_transients = false;
set_default_fades (); set_default_fades ();
set_default_envelope (); set_default_envelope ();
listen_to_my_curves (); listen_to_my_curves ();
listen_to_my_sources ();
} }
/* constructor for use by derived types only */ /* constructor for use by derived types only */
@ -122,6 +122,7 @@ AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t len
, _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0)) , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
{ {
init (); init ();
listen_to_my_sources ();
} }
/** Create a new AudioRegion, that is part of an existing one */ /** Create a new AudioRegion, that is part of an existing one */
@ -172,9 +173,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
} }
_scale_amplitude = other->_scale_amplitude; _scale_amplitude = other->_scale_amplitude;
valid_transients = false;
assert(_type == DataType::AUDIO); assert(_type == DataType::AUDIO);
listen_to_my_sources ();
} }
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other) AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
@ -183,15 +184,14 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
, _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0)) , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0)) , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
{ {
assert(_type == DataType::AUDIO);
_scale_amplitude = other->_scale_amplitude; _scale_amplitude = other->_scale_amplitude;
valid_transients = false;
_envelope = other->_envelope; _envelope = other->_envelope;
set_default_fades (); set_default_fades ();
listen_to_my_curves (); listen_to_my_curves ();
listen_to_my_sources ();
assert(_type == DataType::AUDIO);
} }
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node) AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
@ -206,13 +206,13 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
} }
init (); init ();
valid_transients = false;
if (set_state (node)) { if (set_state (node)) {
throw failed_constructor(); throw failed_constructor();
} }
assert(_type == DataType::AUDIO); assert(_type == DataType::AUDIO);
listen_to_my_sources ();
} }
AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node) AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
@ -228,6 +228,7 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
} }
assert(_type == DataType::AUDIO); assert(_type == DataType::AUDIO);
listen_to_my_sources ();
} }
AudioRegion::~AudioRegion () AudioRegion::~AudioRegion ()
@ -235,10 +236,11 @@ AudioRegion::~AudioRegion ()
} }
void void
AudioRegion::invalidate_transients () AudioRegion::listen_to_my_sources ()
{ {
valid_transients = false; for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
_transients.clear (); (*i)->AnalysisChanged.connect (mem_fun (*this, &AudioRegion::invalidate_transients));
}
} }
void void
@ -1256,53 +1258,73 @@ AudioRegion::audio_source (uint32_t n) const
return boost::dynamic_pointer_cast<AudioSource>(source(n)); return boost::dynamic_pointer_cast<AudioSource>(source(n));
} }
void
AudioRegion::cleanup_transients (vector<nframes64_t>& t)
{
sort (t.begin(), t.end());
/* remove duplicates or other things that are too close */
vector<nframes64_t>::iterator i = t.begin();
nframes64_t curr = (*i);
/* XXX force a 3msec gap - use a config variable */
nframes64_t gap_frames = (nframes64_t) floor (3.0 * (playlist()->session().frame_rate() / 1000.0));
++i;
while (i != t.end()) {
if (((*i) == curr) || (((*i) - curr) < gap_frames)) {
i = t.erase (i);
} else {
++i;
curr = *i;
}
}
}
int int
AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new) AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
{ {
if (!playlist()) { boost::shared_ptr<Playlist> pl = playlist();
if (!pl) {
return -1; return -1;
} }
if (valid_transients && !force_new) { if (_valid_transients && !force_new) {
results = _transients; results = _transients;
return 0; return 0;
} }
TransientDetector t (playlist()->session().frame_rate()); SourceList::iterator s;
for (s = _sources.begin() ; s != _sources.end(); ++s) {
if (!(*s)->has_been_analysed()) {
cerr << "For " << name() << " source " << (*s)->name() << " has not been analyzed\n";
break;
}
}
if (s == _sources.end()) {
/* all sources are analyzed, merge data from each one */
for (s = _sources.begin() ; s != _sources.end(); ++s) {
/* find the set of transients within the bounds of this region */
AnalysisFeatureList::iterator low = lower_bound ((*s)->transients.begin(),
(*s)->transients.end(),
_start);
AnalysisFeatureList::iterator high = upper_bound ((*s)->transients.begin(),
(*s)->transients.end(),
_start + _length);
/* and add them */
results.insert (results.end(), low, high);
}
TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
/* translate all transients to current position */
for (AnalysisFeatureList::iterator x = results.begin(); x != results.end(); ++x) {
(*x) -= _start;
(*x) += _position;
}
_transients = results;
_valid_transients = true;
return 0;
}
TransientDetector t (pl->session().frame_rate());
bool existing_results = !results.empty(); bool existing_results = !results.empty();
_transients.clear (); _transients.clear ();
valid_transients = false; _valid_transients = false;
for (uint32_t i = 0; i < n_channels(); ++i) { for (uint32_t i = 0; i < n_channels(); ++i) {
vector<nframes64_t> these_results; AnalysisFeatureList these_results;
t.reset (); t.reset ();
@ -1312,7 +1334,7 @@ AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
/* translate all transients to give absolute position */ /* translate all transients to give absolute position */
for (vector<nframes64_t>::iterator i = these_results.begin(); i != these_results.end(); ++i) { for (AnalysisFeatureList::iterator i = these_results.begin(); i != these_results.end(); ++i) {
(*i) += _position; (*i) += _position;
} }
@ -1329,20 +1351,19 @@ AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
*/ */
results.insert (results.end(), _transients.begin(), _transients.end()); results.insert (results.end(), _transients.begin(), _transients.end());
cleanup_transients (results); TransientDetector::cleanup_transients (results, pl->session().frame_rate(), 3.0);
} }
/* make sure ours are clean too */ /* make sure ours are clean too */
cleanup_transients (_transients); TransientDetector::cleanup_transients (_transients, pl->session().frame_rate(), 3.0);
} }
valid_transients = true; _valid_transients = true;
return 0; return 0;
} }
extern "C" { extern "C" {
int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit) int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit)

View file

@ -919,50 +919,3 @@ 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);
}

View file

@ -82,6 +82,7 @@ setup_enum_writer ()
Location::Flags _Location_Flags; Location::Flags _Location_Flags;
RouteGroup::Flag _RouteGroup_Flag; RouteGroup::Flag _RouteGroup_Flag;
Region::Flag _Region_Flag; Region::Flag _Region_Flag;
Region::PositionLockStyle _Region_PositionLockStyle;
Track::FreezeState _Track_FreezeState; Track::FreezeState _Track_FreezeState;
AutomationList::InterpolationStyle _AutomationList_InterpolationStyle; AutomationList::InterpolationStyle _AutomationList_InterpolationStyle;
@ -364,6 +365,10 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (Region, DoNotSaveState); REGISTER_CLASS_ENUM (Region, DoNotSaveState);
REGISTER_BITS (_Region_Flag); REGISTER_BITS (_Region_Flag);
REGISTER_CLASS_ENUM (Region, AudioTime);
REGISTER_CLASS_ENUM (Region, MusicTime);
REGISTER_BITS (_Region_PositionLockStyle);
REGISTER_CLASS_ENUM (Track, NoFreeze); REGISTER_CLASS_ENUM (Track, NoFreeze);
REGISTER_CLASS_ENUM (Track, Frozen); REGISTER_CLASS_ENUM (Track, Frozen);
REGISTER_CLASS_ENUM (Track, UnFrozen); REGISTER_CLASS_ENUM (Track, UnFrozen);

View file

@ -43,6 +43,7 @@
#include <midi++/mmc.h> #include <midi++/mmc.h>
#include <ardour/ardour.h> #include <ardour/ardour.h>
#include <ardour/analyser.h>
#include <ardour/audio_library.h> #include <ardour/audio_library.h>
#include <ardour/configuration.h> #include <ardour/configuration.h>
#include <ardour/profile.h> #include <ardour/profile.h>
@ -300,6 +301,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
setup_hardware_optimization (try_optimization); setup_hardware_optimization (try_optimization);
SourceFactory::init (); SourceFactory::init ();
Analyser::init ();
/* singleton - first object is "it" */ /* singleton - first object is "it" */
new PluginManager (); new PluginManager ();

View file

@ -37,6 +37,7 @@
#include <ardour/region.h> #include <ardour/region.h>
#include <ardour/region_factory.h> #include <ardour/region_factory.h>
#include <ardour/playlist_factory.h> #include <ardour/playlist_factory.h>
#include <ardour/transient_detector.h>
#include "i18n.h" #include "i18n.h"
@ -1428,6 +1429,65 @@ Playlist::regions_touched (nframes_t start, nframes_t end)
return rlist; return rlist;
} }
nframes64_t
Playlist::find_next_transient (nframes64_t from, int dir)
{
RegionLock rlock (this);
AnalysisFeatureList points;
AnalysisFeatureList these_points;
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
if (dir > 0) {
if ((*i)->last_frame() < from) {
continue;
}
} else {
if ((*i)->first_frame() > from) {
continue;
}
}
(*i)->get_transients (these_points);
/* add first frame, just, err, because */
these_points.push_back ((*i)->first_frame());
points.insert (points.end(), these_points.begin(), these_points.end());
these_points.clear ();
}
if (points.empty()) {
return -1;
}
TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
bool reached = false;
if (dir > 0) {
for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
if ((*x) >= from) {
reached = true;
}
if (reached && (*x) > from) {
return *x;
}
}
} else {
for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
if ((*x) <= from) {
reached = true;
}
if (reached && (*x) < from) {
return *x;
}
}
}
return -1;
}
boost::shared_ptr<Region> boost::shared_ptr<Region>
Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir) Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir)
@ -2259,3 +2319,18 @@ Playlist::region_is_shuffle_constrained (boost::shared_ptr<Region>)
return false; return false;
} }
void
Playlist::update_after_tempo_map_change ()
{
RegionLock rlock (const_cast<Playlist*> (this));
RegionList copy (regions);
freeze ();
for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
(*i)->update_position_after_tempo_map_change ();
}
thaw ();
}

View file

@ -75,13 +75,8 @@ ARDOUR::read_recent_sessions (RecentSessions& rs)
break; break;
} }
if (!access(newpair.second.c_str(), R_OK)) {
rs.push_back (newpair); rs.push_back (newpair);
} }
}
// This deletes any missing sessions
ARDOUR::write_recent_sessions (rs);
/* display sorting should be done in the GUI, otherwise the /* display sorting should be done in the GUI, otherwise the
* natural order will be broken * natural order will be broken

View file

@ -21,6 +21,7 @@
#include <cmath> #include <cmath>
#include <climits> #include <climits>
#include <algorithm> #include <algorithm>
#include <sstream>
#include <sigc++/bind.h> #include <sigc++/bind.h>
#include <sigc++/class_slot.h> #include <sigc++/class_slot.h>
@ -28,11 +29,13 @@
#include <glibmm/thread.h> #include <glibmm/thread.h>
#include <pbd/xml++.h> #include <pbd/xml++.h>
#include <pbd/stacktrace.h> #include <pbd/stacktrace.h>
#include <pbd/enumwriter.h>
#include <ardour/region.h> #include <ardour/region.h>
#include <ardour/playlist.h> #include <ardour/playlist.h>
#include <ardour/session.h> #include <ardour/session.h>
#include <ardour/source.h> #include <ardour/source.h>
#include <ardour/tempo.h>
#include <ardour/region_factory.h> #include <ardour/region_factory.h>
#include <ardour/filter.h> #include <ardour/filter.h>
@ -59,6 +62,8 @@ Region::Region (Session& s, nframes_t start, nframes_t length, const string& nam
, _start(start) , _start(start)
, _length(length) , _length(length)
, _position(0) , _position(0)
, _last_position(0)
, _positional_lock_style(AudioTime)
, _sync_position(_start) , _sync_position(_start)
, _layer(layer) , _layer(layer)
, _first_edit(EditChangesNothing) , _first_edit(EditChangesNothing)
@ -70,7 +75,6 @@ Region::Region (Session& s, nframes_t start, nframes_t length, const string& nam
/* no sources at this point */ /* no sources at this point */
} }
/** Basic Region constructor (single source) */ /** Basic Region constructor (single source) */
Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags) Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
: Automatable(src->session(), name) : Automatable(src->session(), name)
@ -79,6 +83,8 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
, _start(start) , _start(start)
, _length(length) , _length(length)
, _position(0) , _position(0)
, _last_position(0)
, _positional_lock_style(AudioTime)
, _sync_position(_start) , _sync_position(_start)
, _layer(layer) , _layer(layer)
, _first_edit(EditChangesNothing) , _first_edit(EditChangesNothing)
@ -86,6 +92,8 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
, _ancestral_start (start) , _ancestral_start (start)
, _ancestral_length (length) , _ancestral_length (length)
, _stretch (1.0) , _stretch (1.0)
, _shift (0.0)
, _valid_transients(false)
, _read_data_count(0) , _read_data_count(0)
, _pending_changed(Change (0)) , _pending_changed(Change (0))
, _last_layer_op(0) , _last_layer_op(0)
@ -96,6 +104,7 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src)); src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
assert(_sources.size() > 0); assert(_sources.size() > 0);
_positional_lock_style = AudioTime;
} }
/** Basic Region constructor (many sources) */ /** Basic Region constructor (many sources) */
@ -106,6 +115,8 @@ Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const
, _start(start) , _start(start)
, _length(length) , _length(length)
, _position(0) , _position(0)
, _last_position(0)
, _positional_lock_style(AudioTime)
, _sync_position(_start) , _sync_position(_start)
, _layer(layer) , _layer(layer)
, _first_edit(EditChangesNothing) , _first_edit(EditChangesNothing)
@ -141,6 +152,8 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
, _start(other->_start + offset) , _start(other->_start + offset)
, _length(length) , _length(length)
, _position(0) , _position(0)
, _last_position(0)
, _positional_lock_style(other->_positional_lock_style)
, _sync_position(_start) , _sync_position(_start)
, _layer(layer) , _layer(layer)
, _first_edit(EditChangesNothing) , _first_edit(EditChangesNothing)
@ -148,6 +161,8 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
, _ancestral_start (other->_ancestral_start + offset) , _ancestral_start (other->_ancestral_start + offset)
, _ancestral_length (length) , _ancestral_length (length)
, _stretch (1.0) , _stretch (1.0)
, _shift (0.0)
, _valid_transients(false)
, _read_data_count(0) , _read_data_count(0)
, _pending_changed(Change (0)) , _pending_changed(Change (0))
, _last_layer_op(0) , _last_layer_op(0)
@ -185,6 +200,8 @@ Region::Region (boost::shared_ptr<const Region> other)
, _start(other->_start) , _start(other->_start)
, _length(other->_length) , _length(other->_length)
, _position(other->_position) , _position(other->_position)
, _last_position(other->_last_position)
, _positional_lock_style(other->_positional_lock_style)
, _sync_position(other->_sync_position) , _sync_position(other->_sync_position)
, _layer(other->_layer) , _layer(other->_layer)
, _first_edit(EditChangesID) , _first_edit(EditChangesID)
@ -192,6 +209,8 @@ Region::Region (boost::shared_ptr<const Region> other)
, _ancestral_start (_start) , _ancestral_start (_start)
, _ancestral_length (_length) , _ancestral_length (_length)
, _stretch (1.0) , _stretch (1.0)
, _shift (0.0)
, _valid_transients(false)
, _read_data_count(0) , _read_data_count(0)
, _pending_changed(Change(0)) , _pending_changed(Change(0))
, _last_layer_op(other->_last_layer_op) , _last_layer_op(other->_last_layer_op)
@ -229,6 +248,8 @@ Region::Region (const SourceList& srcs, const XMLNode& node)
, _start(0) , _start(0)
, _length(0) , _length(0)
, _position(0) , _position(0)
, _last_position(0)
, _positional_lock_style(AudioTime)
, _sync_position(_start) , _sync_position(_start)
, _layer(0) , _layer(0)
, _first_edit(EditChangesNothing) , _first_edit(EditChangesNothing)
@ -267,6 +288,8 @@ Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
, _start(0) , _start(0)
, _length(0) , _length(0)
, _position(0) , _position(0)
, _last_position(0)
, _positional_lock_style(AudioTime)
, _sync_position(_start) , _sync_position(_start)
, _layer(0) , _layer(0)
, _first_edit(EditChangesNothing) , _first_edit(EditChangesNothing)
@ -373,6 +396,7 @@ Region::set_length (nframes_t len, void *src)
first_edit (); first_edit ();
maybe_uncopy (); maybe_uncopy ();
invalidate_transients ();
if (!_frozen) { if (!_frozen) {
recompute_at_end (); recompute_at_end ();
@ -449,6 +473,37 @@ Region::special_set_position (nframes_t pos)
_position = pos; _position = pos;
} }
void
Region::set_position_lock_style (PositionLockStyle ps)
{
boost::shared_ptr<Playlist> pl (playlist());
if (!pl) {
return;
}
_positional_lock_style = ps;
if (_positional_lock_style == MusicTime) {
pl->session().tempo_map().bbt_time (_position, _bbt_time);
}
}
void
Region::update_position_after_tempo_map_change ()
{
boost::shared_ptr<Playlist> pl (playlist());
if (!pl || _positional_lock_style != MusicTime) {
return;
}
TempoMap& map (pl->session().tempo_map());
nframes_t pos = map.frame_time (_bbt_time);
set_position_internal (pos, false);
}
void void
Region::set_position (nframes_t pos, void *src) Region::set_position (nframes_t pos, void *src)
{ {
@ -456,6 +511,12 @@ Region::set_position (nframes_t pos, void *src)
return; return;
} }
set_position_internal (pos, true);
}
void
Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
{
if (_position != pos) { if (_position != pos) {
_last_position = _position; _last_position = _position;
_position = pos; _position = pos;
@ -470,6 +531,15 @@ Region::set_position (nframes_t pos, void *src)
_last_length = _length; _last_length = _length;
_length = max_frames - _position; _length = max_frames - _position;
} }
if (allow_bbt_recompute && _positional_lock_style == MusicTime) {
boost::shared_ptr<Playlist> pl (playlist());
if (pl) {
pl->session().tempo_map().bbt_time (_position, _bbt_time);
}
}
invalidate_transients ();
} }
/* do this even if the position is the same. this helps out /* do this even if the position is the same. this helps out
@ -563,6 +633,7 @@ Region::set_start (nframes_t pos, void *src)
_start = pos; _start = pos;
_flags = Region::Flag (_flags & ~WholeFile); _flags = Region::Flag (_flags & ~WholeFile);
first_edit (); first_edit ();
invalidate_transients ();
send_change (StartChanged); send_change (StartChanged);
} }
@ -974,9 +1045,9 @@ Region::state (bool full_state)
node->add_property ("length", buf); node->add_property ("length", buf);
snprintf (buf, sizeof (buf), "%u", _position); snprintf (buf, sizeof (buf), "%u", _position);
node->add_property ("position", buf); node->add_property ("position", buf);
snprintf (buf, sizeof (buf), "%Ld", _ancestral_start); snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_start);
node->add_property ("ancestral-start", buf); node->add_property ("ancestral-start", buf);
snprintf (buf, sizeof (buf), "%Ld", _ancestral_length); snprintf (buf, sizeof (buf), "%" PRIi64, _ancestral_length);
node->add_property ("ancestral-length", buf); node->add_property ("ancestral-length", buf);
snprintf (buf, sizeof (buf), "%.12g", _stretch); snprintf (buf, sizeof (buf), "%.12g", _stretch);
node->add_property ("stretch", buf); node->add_property ("stretch", buf);
@ -1007,6 +1078,13 @@ Region::state (bool full_state)
snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position); snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
node->add_property ("sync-position", buf); node->add_property ("sync-position", buf);
if (_positional_lock_style != AudioTime) {
node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
stringstream str;
str << _bbt_time;
node->add_property ("bbt-position", str.str());
}
return *node; return *node;
} }
@ -1095,6 +1173,27 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
_sync_position = _start; _sync_position = _start;
} }
if ((prop = node.property ("positional-lock-style")) != 0) {
_positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
if (_positional_lock_style == MusicTime) {
if ((prop = node.property ("bbt-position")) == 0) {
/* missing BBT info, revert to audio time locking */
_positional_lock_style = AudioTime;
} else {
if (sscanf (prop->value().c_str(), "%d|%d|%d",
&_bbt_time.bars,
&_bbt_time.beats,
&_bbt_time.ticks) != 3) {
_positional_lock_style = AudioTime;
}
}
}
} else {
_positional_lock_style = AudioTime;
}
/* XXX FIRST EDIT !!! */ /* XXX FIRST EDIT !!! */
/* these 3 properties never change as a result of any editing */ /* these 3 properties never change as a result of any editing */
@ -1261,7 +1360,8 @@ Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
void void
Region::source_deleted (boost::shared_ptr<Source>) Region::source_deleted (boost::shared_ptr<Source>)
{ {
delete this; _sources.clear ();
drop_references ();
} }
vector<string> vector<string>
@ -1397,3 +1497,10 @@ Region::apply (Filter& filter)
} }
void
Region::invalidate_transients ()
{
_valid_transients = false;
_transients.clear ();
}

View file

@ -80,6 +80,7 @@
#include <ardour/filename_extensions.h> #include <ardour/filename_extensions.h>
#include <ardour/session_directory.h> #include <ardour/session_directory.h>
#include <ardour/tape_file_matcher.h> #include <ardour/tape_file_matcher.h>
#include <ardour/analyser.h>
#ifdef HAVE_LIBLO #ifdef HAVE_LIBLO
#include <ardour/osc.h> #include <ardour/osc.h>
@ -107,6 +108,7 @@ Session::mix_buffers_with_gain_t Session::mix_buffers_with_gain = 0;
Session::mix_buffers_no_gain_t Session::mix_buffers_no_gain = 0; Session::mix_buffers_no_gain_t Session::mix_buffers_no_gain = 0;
sigc::signal<int> Session::AskAboutPendingState; sigc::signal<int> Session::AskAboutPendingState;
sigc::signal<int,nframes_t,nframes_t> Session::AskAboutSampleRateMismatch;
sigc::signal<void> Session::SendFeedback; sigc::signal<void> Session::SendFeedback;
sigc::signal<void> Session::SMPTEOffsetChanged; sigc::signal<void> Session::SMPTEOffsetChanged;
@ -2771,6 +2773,14 @@ Session::add_source (boost::shared_ptr<Source> source)
source->GoingAway.connect (sigc::bind (mem_fun (this, &Session::remove_source), boost::weak_ptr<Source> (source))); source->GoingAway.connect (sigc::bind (mem_fun (this, &Session::remove_source), boost::weak_ptr<Source> (source)));
set_dirty(); set_dirty();
} }
boost::shared_ptr<AudioFileSource> afs;
if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
if (Config->get_auto_analyse_audio()) {
Analyser::queue_source_for_analysis (source, false);
}
}
} }
void void
@ -3726,6 +3736,15 @@ void
Session::tempo_map_changed (Change ignored) Session::tempo_map_changed (Change ignored)
{ {
clear_clicks (); clear_clicks ();
for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
(*i)->update_after_tempo_map_change ();
}
for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
(*i)->update_after_tempo_map_change ();
}
set_dirty (); set_dirty ();
} }

View file

@ -141,6 +141,9 @@ Session::first_stage_init (string fullpath, string snapshot_name)
set_history_depth (Config->get_history_depth()); set_history_depth (Config->get_history_depth());
_current_frame_rate = _engine.frame_rate (); _current_frame_rate = _engine.frame_rate ();
_nominal_frame_rate = _current_frame_rate;
_base_frame_rate = _current_frame_rate;
_tempo_map = new TempoMap (_current_frame_rate); _tempo_map = new TempoMap (_current_frame_rate);
_tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed)); _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
@ -236,9 +239,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
waiting_for_sync_offset = false; waiting_for_sync_offset = false;
} }
_current_frame_rate = 48000;
_base_frame_rate = 48000;
last_smpte_when = 0; last_smpte_when = 0;
_smpte_offset = 0; _smpte_offset = 0;
_smpte_offset_negative = true; _smpte_offset_negative = true;
@ -920,16 +920,16 @@ Session::state(bool full_state)
// store libardour version, just in case // store libardour version, just in case
char buf[16]; char buf[16];
snprintf(buf, sizeof(buf)-1, "%d.%d.%d", snprintf(buf, sizeof(buf), "%d.%d.%d", libardour3_major_version, libardour3_minor_version, libardour3_micro_version);
libardour_major_version, libardour_minor_version, libardour_micro_version);
node->add_property("version", string(buf)); node->add_property("version", string(buf));
/* store configuration settings */ /* store configuration settings */
if (full_state) { if (full_state) {
/* store the name */
node->add_property ("name", _name); node->add_property ("name", _name);
snprintf (buf, sizeof (buf), "%" PRId32, _nominal_frame_rate);
node->add_property ("sample-rate", buf);
if (session_dirs.size() > 1) { if (session_dirs.size() > 1) {
@ -1149,7 +1149,6 @@ Session::set_state (const XMLNode& node)
_state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave); _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
if (node.name() != X_("Session")){ if (node.name() != X_("Session")){
fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg; fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
return -1; return -1;
@ -1159,6 +1158,17 @@ Session::set_state (const XMLNode& node)
_name = prop->value (); _name = prop->value ();
} }
if ((prop = node.property (X_("sample-rate"))) != 0) {
_nominal_frame_rate = atoi (prop->value());
if (_nominal_frame_rate != _current_frame_rate) {
if (AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate)) {
return -1;
}
}
}
setup_raid_path(_session_dir->root_path().to_string()); setup_raid_path(_session_dir->root_path().to_string());
if ((prop = node.property (X_("id-counter"))) != 0) { if ((prop = node.property (X_("id-counter"))) != 0) {
@ -2067,6 +2077,56 @@ Session::auto_save()
save_state (_current_snapshot_name); save_state (_current_snapshot_name);
} }
static bool
state_file_filter (const string &str, void *arg)
{
return (str.length() > strlen(statefile_suffix) &&
str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
}
struct string_cmp {
bool operator()(const string* a, const string* b) {
return *a < *b;
}
};
static string*
remove_end(string* state)
{
string statename(*state);
string::size_type start,end;
if ((start = statename.find_last_of ('/')) != string::npos) {
statename = statename.substr (start+1);
}
if ((end = statename.rfind(".ardour")) == string::npos) {
end = statename.length();
}
return new string(statename.substr (0, end));
}
vector<string *> *
Session::possible_states (string path)
{
PathScanner scanner;
vector<string*>* states = scanner (path, state_file_filter, 0, false, false);
transform(states->begin(), states->end(), states->begin(), remove_end);
string_cmp cmp;
sort (states->begin(), states->end(), cmp);
return states;
}
vector<string *> *
Session::possible_states () const
{
return possible_states(_path);
}
RouteGroup * RouteGroup *
Session::add_edit_group (string name) Session::add_edit_group (string name)
{ {

View file

@ -27,19 +27,22 @@
#include <cmath> #include <cmath>
#include <iomanip> #include <iomanip>
#include <algorithm> #include <algorithm>
#include <fstream>
#include <glibmm/thread.h> #include <glibmm/thread.h>
#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>
#include <pbd/xml++.h> #include <pbd/xml++.h>
#include <pbd/pthread_utils.h> #include <pbd/pthread_utils.h>
#include <ardour/source.h> #include <ardour/source.h>
#include <ardour/playlist.h> #include <ardour/playlist.h>
#include <ardour/session.h>
#include <ardour/transient_detector.h>
#include "i18n.h" #include "i18n.h"
using std::min; using namespace std;
using std::max;
using namespace ARDOUR; using namespace ARDOUR;
Source::Source (Session& s, const string& name, DataType type) Source::Source (Session& s, const string& name, DataType type)
@ -49,6 +52,7 @@ Source::Source (Session& s, const string& name, DataType type)
// not true.. is this supposed to be an assertion? // not true.. is this supposed to be an assertion?
//assert(_name.find("/") == string::npos); //assert(_name.find("/") == string::npos);
_analysed = false;
_timestamp = 0; _timestamp = 0;
_length = 0; _length = 0;
_in_use = 0; _in_use = 0;
@ -60,6 +64,7 @@ Source::Source (Session& s, const XMLNode& node)
{ {
_timestamp = 0; _timestamp = 0;
_length = 0; _length = 0;
_analysed = false;
_in_use = 0; _in_use = 0;
if (set_state (node) || _type == DataType::NIL) { if (set_state (node) || _type == DataType::NIL) {
@ -135,7 +140,7 @@ Source::add_playlist (boost::shared_ptr<Playlist> pl)
{ {
std::pair<PlaylistMap::iterator,bool> res; std::pair<PlaylistMap::iterator,bool> res;
std::pair<boost::shared_ptr<Playlist>, uint32_t> newpair (pl, 1); std::pair<boost::shared_ptr<Playlist>, uint32_t> newpair (pl, 1);
Glib::Mutex::Lock lm (playlist_lock); Glib::Mutex::Lock lm (_playlist_lock);
res = _playlists.insert (newpair); res = _playlists.insert (newpair);
@ -157,7 +162,7 @@ Source::remove_playlist (boost::weak_ptr<Playlist> wpl)
} }
PlaylistMap::iterator x; PlaylistMap::iterator x;
Glib::Mutex::Lock lm (playlist_lock); Glib::Mutex::Lock lm (_playlist_lock);
if ((x = _playlists.find (pl)) != _playlists.end()) { if ((x = _playlists.find (pl)) != _playlists.end()) {
if (x->second > 1) { if (x->second > 1) {
@ -173,3 +178,90 @@ Source::used () const
{ {
return _playlists.size(); return _playlists.size();
} }
bool
Source::has_been_analysed() const
{
Glib::Mutex::Lock lm (_analysis_lock);
return _analysed;
}
void
Source::set_been_analysed (bool yn)
{
{
Glib::Mutex::Lock lm (_analysis_lock);
_analysed = yn;
}
if (yn) {
AnalysisChanged(); // EMIT SIGNAL
}
}
int
Source::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
Source::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 += TransientDetector::operational_identifier();
parts.push_back (s);
return Glib::build_filename (parts);
}
bool
Source::check_for_analysis_data_on_disk ()
{
/* looks to see if the analysis files for this source are on disk.
if so, mark us already analysed.
*/
string path = get_transients_path ();
bool ok = true;
if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
ok = false;
}
// XXX add other tests here as appropriate
set_been_analysed (ok);
return ok;
}

View file

@ -111,6 +111,7 @@ boost::shared_ptr<Source>
SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes, float sr) SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes, float sr)
{ {
boost::shared_ptr<Source> ret (new SilentFileSource (s, node, nframes, sr)); boost::shared_ptr<Source> ret (new SilentFileSource (s, node, nframes, sr));
// no analysis data - the file is non-existent
SourceCreated (ret); SourceCreated (ret);
return ret; return ret;
} }
@ -136,6 +137,7 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
return boost::shared_ptr<Source>(); return boost::shared_ptr<Source>();
} }
ret->check_for_analysis_data_on_disk ();
SourceCreated (ret); SourceCreated (ret);
return ret; return ret;
} }
@ -151,6 +153,7 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
return boost::shared_ptr<Source>(); return boost::shared_ptr<Source>();
} }
ret->check_for_analysis_data_on_disk ();
SourceCreated (ret); SourceCreated (ret);
return ret; return ret;
} }
@ -163,13 +166,14 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
return boost::shared_ptr<Source>(); return boost::shared_ptr<Source>();
} }
ret->check_for_analysis_data_on_disk ();
SourceCreated (ret); SourceCreated (ret);
return ret; return ret;
#endif #endif
} else if (type == DataType::MIDI) { } else if (type == DataType::MIDI) {
boost::shared_ptr<Source> ret (new SMFSource (s, node)); boost::shared_ptr<Source> ret (new SMFSource (s, node));
ret->check_for_analysis_data_on_disk ();
SourceCreated (ret); SourceCreated (ret);
return ret; return ret;
} }
@ -190,6 +194,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
return boost::shared_ptr<Source>(); return boost::shared_ptr<Source>();
} }
ret->check_for_analysis_data_on_disk ();
if (announce) { if (announce) {
SourceCreated (ret); SourceCreated (ret);
} }
@ -201,6 +206,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
if (setup_peakfile (ret, defer_peaks)) { if (setup_peakfile (ret, defer_peaks)) {
return boost::shared_ptr<Source>(); return boost::shared_ptr<Source>();
} }
ret->check_for_analysis_data_on_disk ();
if (announce) { if (announce) {
SourceCreated (ret); SourceCreated (ret);
} }
@ -213,6 +219,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
return boost::shared_ptr<Source>(); return boost::shared_ptr<Source>();
} }
ret->check_for_analysis_data_on_disk ();
if (announce) { if (announce) {
SourceCreated (ret); SourceCreated (ret);
} }
@ -225,6 +232,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
// FIXME: flags? // FIXME: flags?
boost::shared_ptr<Source> ret (new SMFSource (s, path, SMFSource::Flag(0))); boost::shared_ptr<Source> ret (new SMFSource (s, path, SMFSource::Flag(0)));
ret->check_for_analysis_data_on_disk ();
if (announce) { if (announce) {
SourceCreated (ret); SourceCreated (ret);
} }
@ -253,6 +261,8 @@ SourceFactory::createWritable (DataType type, Session& s, std::string path, bool
return boost::shared_ptr<Source>(); return boost::shared_ptr<Source>();
} }
// no analysis data - this is a new file
if (announce) { if (announce) {
SourceCreated (ret); SourceCreated (ret);
} }
@ -262,6 +272,8 @@ SourceFactory::createWritable (DataType type, Session& s, std::string path, bool
boost::shared_ptr<Source> ret (new SMFSource (s, path)); boost::shared_ptr<Source> ret (new SMFSource (s, path));
// no analysis data - this is a new file
if (announce) { if (announce) {
SourceCreated (ret); SourceCreated (ret);
} }

View file

@ -246,29 +246,49 @@ TempoMap::~TempoMap ()
int int
TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when) TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when)
{ {
if (when == section.start()) { if (when == section.start() || !section.movable()) {
return -1; return -1;
} }
if (!section.movable()) {
return 1;
}
Glib::RWLock::WriterLock lm (lock); Glib::RWLock::WriterLock lm (lock);
MetricSectionSorter cmp; MetricSectionSorter cmp;
BBT_Time corrected (when);
if (dynamic_cast<MeterSection*>(&section) != 0) { if (when.beats != 1) {
if (corrected.beats > 1) {
corrected.beats = 1;
corrected.bars++;
}
}
corrected.ticks = 0;
section.set_start (corrected); /* position by audio frame, then recompute BBT timestamps from the audio ones */
nframes_t frame = frame_time (when);
// cerr << "nominal frame time = " << frame << endl;
nframes_t prev_frame = round_to_type (frame, -1, Beat);
nframes_t next_frame = round_to_type (frame, 1, Beat);
// cerr << "previous beat at " << prev_frame << " next at " << next_frame << endl;
/* use the closest beat */
if ((frame - prev_frame) < (next_frame - frame)) {
frame = prev_frame;
} else {
frame = next_frame;
}
// cerr << "actual frame time = " << frame << endl;
section.set_frame (frame);
// cerr << "frame time = " << section.frame() << endl;
timestamp_metrics (false);
// cerr << "new BBT time = " << section.start() << endl;
metrics->sort (cmp);
} else {
/* positioned at bar start already, so just put it there */
section.set_start (when);
metrics->sort (cmp); metrics->sort (cmp);
timestamp_metrics (true); timestamp_metrics (true);
}
return 0; return 0;
} }
@ -289,7 +309,6 @@ TempoMap::move_meter (MeterSection& meter, const BBT_Time& when)
} }
} }
void void
TempoMap::remove_tempo (const TempoSection& tempo) TempoMap::remove_tempo (const TempoSection& tempo)
{ {
@ -417,6 +436,7 @@ TempoMap::replace_tempo (TempoSection& existing, const Tempo& replacement)
replaced = true; replaced = true;
timestamp_metrics (true); timestamp_metrics (true);
break; break;
} }
} }
@ -493,6 +513,21 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement)
} }
} }
void
TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
{
Tempo newtempo (beats_per_minute, note_type);
TempoSection* t;
for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
*((Tempo*) t) = newtempo;
StateChanged (Change (0));
break;
}
}
}
void void
TempoMap::change_existing_tempo_at (nframes_t where, double beats_per_minute, double note_type) TempoMap::change_existing_tempo_at (nframes_t where, double beats_per_minute, double note_type)
{ {
@ -582,6 +617,8 @@ TempoMap::timestamp_metrics (bool use_bbt)
if (use_bbt) { if (use_bbt) {
// cerr << "\n\n\n ######################\nTIMESTAMP via BBT ##############\n" << endl;
nframes_t current = 0; nframes_t current = 0;
nframes_t section_frames; nframes_t section_frames;
BBT_Time start; BBT_Time start;
@ -611,42 +648,68 @@ TempoMap::timestamp_metrics (bool use_bbt)
} else { } else {
// cerr << "\n\n\n ######################\nTIMESTAMP via AUDIO ##############\n" << endl;
bool first = true; bool first = true;
MetricSection* prev = 0;
for (i = metrics->begin(); i != metrics->end(); ++i) { for (i = metrics->begin(); i != metrics->end(); ++i) {
BBT_Time bbt; BBT_Time bbt;
Metric metric (*meter, *tempo);
bbt_time_with_metric ((*i)->frame(), bbt, Metric (*meter, *tempo)); if (prev) {
metric.set_start (prev->start());
} else {
// metric will be at frames=0 bbt=1|1|0 by default
// which is correct for our purpose
}
bbt_time_with_metric ((*i)->frame(), bbt, metric);
// cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => "; // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
if (first) { if (first) {
first = false; first = false;
} else { } else {
if (bbt.beats != 1 || bbt.ticks != 0) {
if (bbt.ticks > Meter::ticks_per_beat/2) {
/* round up to next beat */
bbt.beats += 1;
}
bbt.ticks = 0;
if (bbt.beats != 1) {
/* round up to next bar */
bbt.bars += 1; bbt.bars += 1;
bbt.beats = 1; bbt.beats = 1;
bbt.ticks = 0;
} }
} }
// cerr << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << endl; //s cerr << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << endl;
(*i)->set_start (bbt); (*i)->set_start (bbt);
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) { if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
tempo = t; tempo = t;
// cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
} else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) { } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
meter = m; meter = m;
// cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
} else { } else {
fatal << _("programming error: unhandled MetricSection type") << endmsg; fatal << _("programming error: unhandled MetricSection type") << endmsg;
/*NOTREACHED*/ /*NOTREACHED*/
} }
prev = (*i);
} }
} }
// dump (cerr); // dump (cerr);
// cerr << "###############################################\n\n\n" << endl;
} }
TempoMap::Metric TempoMap::Metric
@ -741,6 +804,8 @@ TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& me
double xtra_beats = 0; double xtra_beats = 0;
double beats = 0; double beats = 0;
// cerr << "---- BBT time for " << frame << " using metric @ " << metric.frame() << " BBT " << metric.start() << endl;
const double beats_per_bar = metric.meter().beats_per_bar(); const double beats_per_bar = metric.meter().beats_per_bar();
const double frames_per_bar = metric.meter().frames_per_bar (metric.tempo(), _frame_rate); const double frames_per_bar = metric.meter().frames_per_bar (metric.tempo(), _frame_rate);
const double beat_frames = metric.tempo().frames_per_beat (_frame_rate, metric.meter()); const double beat_frames = metric.tempo().frames_per_beat (_frame_rate, metric.meter());
@ -749,10 +814,13 @@ TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& me
frame_diff = frame - metric.frame(); frame_diff = frame - metric.frame();
// cerr << "----\tdelta = " << frame_diff << endl;
xtra_bars = (uint32_t) floor (frame_diff / frames_per_bar); xtra_bars = (uint32_t) floor (frame_diff / frames_per_bar);
frame_diff -= (uint32_t) floor (xtra_bars * frames_per_bar); frame_diff -= (uint32_t) floor (xtra_bars * frames_per_bar);
xtra_beats = (double) frame_diff / beat_frames; xtra_beats = (double) frame_diff / beat_frames;
// cerr << "---\tmeaning " << xtra_bars << " xtra bars and " << xtra_beats << " xtra beats\n";
/* and set the returned value */ /* and set the returned value */
@ -772,9 +840,9 @@ TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& me
bbt.ticks = (uint32_t)( round((beats - floor(beats)) *(double) Meter::ticks_per_beat)); bbt.ticks = (uint32_t)( round((beats - floor(beats)) *(double) Meter::ticks_per_beat));
bbt.beats = (uint32_t) floor(beats); bbt.beats = (uint32_t) floor(beats);
// cerr << "-----\t RETURN " << bbt << endl;
} }
nframes_t nframes_t
TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) const TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) const
{ {
@ -834,17 +902,27 @@ TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo,
beat = 1; beat = 1;
++bar; ++bar;
++beats_counted; ++beats_counted;
if (beat > beats_per_bar) {
/* this is a fractional beat at the end of a fractional bar
so it should only count for the fraction
*/
beats_counted -= (ceil(beats_per_bar) - beats_per_bar);
}
} else { } else {
++beat; ++beat;
++beats_counted; ++beats_counted;
if (beat > beats_per_bar) {
/* this is a fractional beat at the end of a fractional bar
so it should only count for the fraction */
beats_counted -= (ceil(beats_per_bar) - beats_per_bar);
}
} }
} }
// cerr << "Counted " << beats_counted << " from " << start << " to " << end
// << " bpb were " << beats_per_bar
// << " fpb was " << beat_frames
// << endl;
frames = (nframes_t) floor (beats_counted * beat_frames); frames = (nframes_t) floor (beats_counted * beat_frames);
return frames; return frames;
@ -1052,7 +1130,6 @@ TempoMap::round_to_beat_subdivision (nframes_t fr, int sub_num)
} }
nframes_t nframes_t
TempoMap::round_to_type (nframes_t frame, int dir, BBTPointType type) TempoMap::round_to_type (nframes_t frame, int dir, BBTPointType type)
{ {
Metric metric = metric_at (frame); Metric metric = metric_at (frame);
@ -1191,7 +1268,9 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
if (i == metrics->end()) { if (i == metrics->end()) {
limit = upper; limit = upper;
// cerr << "== limit set to end of request @ " << limit << endl;
} else { } else {
// cerr << "== limit set to next metric @ " << (*i)->frame() << endl;
limit = (*i)->frame(); limit = (*i)->frame();
} }
@ -1224,6 +1303,10 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
beat++; beat++;
} }
// cerr << "out of beats, @ end ? " << (i == metrics->end()) << " out of bpb ? "
// << (beat > ceil(beats_per_bar))
// << endl;
if (beat > ceil(beats_per_bar) || i != metrics->end()) { if (beat > ceil(beats_per_bar) || i != metrics->end()) {
/* we walked an entire bar. its /* we walked an entire bar. its
@ -1245,9 +1328,11 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
if (beat > ceil (beats_per_bar)) { if (beat > ceil (beats_per_bar)) {
/* next bar goes where the numbers suggest */ /* next bar goes where the numbers suggest */
current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar); current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar);
// cerr << "++ next bar from numbers\n";
} else { } else {
/* next bar goes where the next metric is */ /* next bar goes where the next metric is */
current = limit; current = limit;
// cerr << "++ next bar at next metric\n";
} }
bar++; bar++;
beat = 1; beat = 1;
@ -1275,6 +1360,9 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
beat = 1; beat = 1;
} }
current = (*i)->frame ();
// cerr << "loop around with current @ " << current << endl;
beats_per_bar = meter->beats_per_bar (); beats_per_bar = meter->beats_per_bar ();
frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate); frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
beat_frames = tempo->frames_per_beat (_frame_rate, *meter); beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
@ -1419,3 +1507,32 @@ TempoMap::dump (std::ostream& o) const
} }
} }
int
TempoMap::n_tempos() const
{
Glib::RWLock::ReaderLock lm (lock);
int cnt = 0;
for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
if (dynamic_cast<const TempoSection*>(*i) != 0) {
cnt++;
}
}
return cnt;
}
int
TempoMap::n_meters() const
{
Glib::RWLock::ReaderLock lm (lock);
int cnt = 0;
for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
if (dynamic_cast<const MeterSection*>(*i) != 0) {
cnt++;
}
}
return cnt;
}

View file

@ -6,20 +6,36 @@ using namespace Vamp;
using namespace ARDOUR; using namespace ARDOUR;
using namespace std; using namespace std;
string TransientDetector::_op_id;
TransientDetector::TransientDetector (float sr) TransientDetector::TransientDetector (float sr)
: AudioAnalyser (sr, X_("libardourvampplugins:percussiononsets")) : AudioAnalyser (sr, X_("libardourvampplugins:percussiononsets"))
{ {
if (_op_id.empty()) {
_op_id = X_("libardourvampplugins:percussiononsets");
// XXX this should load the above-named plugin and get the current version
_op_id += ":2";
}
} }
TransientDetector::~TransientDetector() TransientDetector::~TransientDetector()
{ {
} }
string
TransientDetector::operational_identifier()
{
return _op_id;
}
int int
TransientDetector::run (const std::string& path, Readable* src, uint32_t channel, vector<nframes64_t>& results) TransientDetector::run (const std::string& path, Readable* src, uint32_t channel, AnalysisFeatureList& results)
{ {
current_results = &results; current_results = &results;
int ret = analyse (path, src, channel); int ret = analyse (path, src, channel);
current_results = 0; current_results = 0;
return ret; return ret;
} }
@ -59,3 +75,42 @@ TransientDetector::set_sensitivity (float val)
plugin->setParameter ("sensitivity", val); plugin->setParameter ("sensitivity", val);
} }
} }
void
TransientDetector::cleanup_transients (AnalysisFeatureList& t, float sr, float gap_msecs)
{
if (t.empty()) {
return;
}
t.sort ();
/* remove duplicates or other things that are too close */
AnalysisFeatureList::iterator i = t.begin();
AnalysisFeatureList::iterator f, b;
const nframes64_t gap_frames = (nframes64_t) floor (gap_msecs * (sr / 1000.0));
while (i != t.end()) {
// move front iterator to just past i, and back iterator the same place
f = i;
++f;
b = f;
// move f until we find a new value that is far enough away
while ((f != t.end()) && (((*f) - (*i)) < gap_frames)) {
++f;
}
i = f;
// if f moved forward from b, we had duplicates/too-close points: get rid of them
if (b != f) {
t.erase (b, f);
}
}
}

View file

@ -18,7 +18,8 @@ gnomecanvasmm.Merge([libraries['glibmm2'],
libraries['libgnomecanvas2'], libraries['libgnomecanvas2'],
libraries['cairomm']]) libraries['cairomm']])
gnomecanvasmm.Append(CXXFLAGS = ["-DGLIBMM_PROPERTIES_ENABLED", "-DGLIBMM_EXCEPTIONS_ENABLED"]) if gnomecanvasmm['IS_OSX']:
gnomecanvasmm.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
libgnomecanvasmm = gnomecanvasmm.SharedLibrary('libgnomecanvasmm', gnomecanvasmm_files) libgnomecanvasmm = gnomecanvasmm.SharedLibrary('libgnomecanvasmm', gnomecanvasmm_files)
Default(libgnomecanvasmm) Default(libgnomecanvasmm)

View file

@ -9,6 +9,9 @@ Import('env libraries install_prefix')
midi2 = env.Copy() midi2 = env.Copy()
midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glibmm2'], libraries['glib2'], libraries['pbd'], libraries['jack'] ]) midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glibmm2'], libraries['glib2'], libraries['pbd'], libraries['jack'] ])
if midi2['IS_OSX']:
midi2.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
domain = 'midipp' domain = 'midipp'
midi2.Append(DOMAIN=domain,MAJOR=2,MINOR=1,MICRO=1) midi2.Append(DOMAIN=domain,MAJOR=2,MINOR=1,MICRO=1)

View file

@ -57,6 +57,8 @@ public:
OutputList getOutputDescriptors() const; OutputList getOutputDescriptors() const;
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp); FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures(); FeatureSet getRemainingFeatures();
@ -226,6 +228,7 @@ protected:
float **m_buffers; float **m_buffers;
float m_inputSampleRate; float m_inputSampleRate;
RealTime m_timestamp; RealTime m_timestamp;
bool m_unrun;
OutputList m_outputs; OutputList m_outputs;
void processBlock(FeatureSet& allFeatureSets, RealTime timestamp); void processBlock(FeatureSet& allFeatureSets, RealTime timestamp);
@ -254,6 +257,12 @@ PluginBufferingAdapter::getOutputDescriptors() const
return m_impl->getOutputDescriptors(); return m_impl->getOutputDescriptors();
} }
void
PluginBufferingAdapter::reset()
{
m_impl->reset();
}
PluginBufferingAdapter::FeatureSet PluginBufferingAdapter::FeatureSet
PluginBufferingAdapter::process(const float *const *inputBuffers, PluginBufferingAdapter::process(const float *const *inputBuffers,
RealTime timestamp) RealTime timestamp)
@ -277,7 +286,8 @@ PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_queue(0), m_queue(0),
m_buffers(0), m_buffers(0),
m_inputSampleRate(inputSampleRate), m_inputSampleRate(inputSampleRate),
m_timestamp() m_timestamp(RealTime::zeroTime),
m_unrun(true)
{ {
m_outputs = plugin->getOutputDescriptors(); m_outputs = plugin->getOutputDescriptors();
} }
@ -333,8 +343,8 @@ PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_
} }
} }
std::cerr << "PluginBufferingAdapter::initialise: stepSize " << m_inputStepSize << " -> " << m_stepSize // std::cerr << "PluginBufferingAdapter::initialise: stepSize " << m_inputStepSize << " -> " << m_stepSize
<< ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl; // << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
// current implementation breaks if step is greater than block // current implementation breaks if step is greater than block
if (m_stepSize > m_blockSize) { if (m_stepSize > m_blockSize) {
@ -365,12 +375,28 @@ PluginBufferingAdapter::Impl::getOutputDescriptors() const
return outs; return outs;
} }
void
PluginBufferingAdapter::Impl::reset()
{
m_timestamp = RealTime::zeroTime;
m_unrun = true;
for (size_t i = 0; i < m_queue.size(); ++i) {
m_queue[i]->reset();
}
}
PluginBufferingAdapter::FeatureSet PluginBufferingAdapter::FeatureSet
PluginBufferingAdapter::Impl::process(const float *const *inputBuffers, PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp) RealTime timestamp)
{ {
FeatureSet allFeatureSets; FeatureSet allFeatureSets;
if (m_unrun) {
m_timestamp = timestamp;
m_unrun = false;
}
// queue the new input // queue the new input
for (size_t i = 0; i < m_channels; ++i) { for (size_t i = 0; i < m_channels; ++i) {

View file

@ -81,6 +81,8 @@ public:
OutputList getOutputDescriptors() const; OutputList getOutputDescriptors() const;
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp); FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures(); FeatureSet getRemainingFeatures();

View file

@ -143,7 +143,7 @@ PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t
m_pluginChannels = minch; m_pluginChannels = minch;
std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl; // std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
} else if (m_inputChannels > maxch) { } else if (m_inputChannels > maxch) {
@ -155,18 +155,18 @@ PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t
m_buffer = new float *[1]; m_buffer = new float *[1];
m_buffer[0] = new float[blockSize]; m_buffer[0] = new float[blockSize];
std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl; // std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl;
} else { } else {
std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl; // std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
} }
m_pluginChannels = maxch; m_pluginChannels = maxch;
} else { } else {
std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl; // std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl;
m_pluginChannels = m_inputChannels; m_pluginChannels = m_inputChannels;
} }

View file

@ -8,6 +8,9 @@
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2007 Chris Cannam and QMUL.
This file is based in part on Don Cross's public domain FFT
implementation.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without files (the "Software"), to deal in the Software without
@ -38,28 +41,33 @@
#include <cmath> #include <cmath>
/** /**
* If you want to compile using FFTW instead of the built-in FFT * If you want to compile using FFTW instead of the built-in FFT
* implementation for the PluginInputDomainAdapter, define HAVE_FFTW3 * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
* in the Makefile. * in the Makefile.
* *
* Remember that FFTW is licensed under the GPL (unlike this SDK, which * Be aware that FFTW is licensed under the GPL -- unlike this SDK,
* is licensed liberally in order to permit closed-source usage), so * which is provided under a more liberal BSD license in order to
* you should not define this symbol unless your code is also under the * permit use in closed source applications. The use of FFTW would
* GPL. Also, parties redistributing this SDK for use in other * mean that your code would need to be licensed under the GPL as
* programs should be careful _not_ to define this symbol in order not * well. Do not define this symbol unless you understand and accept
* to affect the stated license of this SDK. * the implications of this.
* *
* Note: This code uses FFTW_MEASURE, and will perform badly on its * Parties such as Linux distribution packagers who redistribute this
* first invocation unless the host has saved and restored FFTW wisdom * SDK for use in other programs should _not_ define this symbol, as
* (see the FFTW documentation). * it would change the effective licensing terms under which the SDK
* was available to third party developers.
*
* The default is not to use FFTW, and to use the built-in FFT instead.
*
* Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on
* its first invocation unless the host has saved and restored FFTW
* wisdom (see the FFTW documentation).
*/ */
#ifdef HAVE_FFTW3 #ifdef HAVE_FFTW3
#include <fftw3.h> #include <fftw3.h>
#endif #endif
namespace Vamp { namespace Vamp {
namespace HostExt { namespace HostExt {

View file

@ -1,4 +1,4 @@
#ifndef __ardour_svn_revision_h__ #ifndef __ardour_svn_revision_h__
#define __ardour_svn_revision_h__ #define __ardour_svn_revision_h__
static const char* ardour_svn_revision = "2918"; static const char* ardour_svn_revision = "2985";
#endif #endif