summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/SConscript1
-rw-r--r--gtk2_ardour/ardour.menus1
-rw-r--r--gtk2_ardour/editor.h1
-rw-r--r--gtk2_ardour/editor_actions.cc2
-rw-r--r--gtk2_ardour/editor_audio_import.cc9
-rw-r--r--gtk2_ardour/playlist_selector.cc29
-rw-r--r--gtk2_ardour/session_import_dialog.cc321
-rw-r--r--gtk2_ardour/session_import_dialog.h101
-rw-r--r--libs/ardour/SConscript6
-rw-r--r--libs/ardour/ardour/audio_playlist_importer.h87
-rw-r--r--libs/ardour/ardour/audio_region_importer.h107
-rw-r--r--libs/ardour/ardour/element_import_handler.h110
-rw-r--r--libs/ardour/ardour/element_importer.h122
-rw-r--r--libs/ardour/ardour/location.h1
-rw-r--r--libs/ardour/ardour/location_importer.h63
-rw-r--r--libs/ardour/ardour/playlist_factory.h4
-rw-r--r--libs/ardour/ardour/session.h3
-rw-r--r--libs/ardour/ardour/tempo_map_importer.h60
-rw-r--r--libs/ardour/audio_playlist_importer.cc221
-rw-r--r--libs/ardour/audio_region_importer.cc398
-rw-r--r--libs/ardour/element_import_handler.cc55
-rw-r--r--libs/ardour/element_importer.cc84
-rw-r--r--libs/ardour/location.cc8
-rw-r--r--libs/ardour/location_importer.cc195
-rw-r--r--libs/ardour/playlist_factory.cc10
-rw-r--r--libs/ardour/session.cc22
-rw-r--r--libs/ardour/tempo_map_importer.cc108
27 files changed, 2120 insertions, 9 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript
index a3cec81c3d..0388910ebd 100644
--- a/gtk2_ardour/SConscript
+++ b/gtk2_ardour/SConscript
@@ -223,6 +223,7 @@ route_time_axis.cc
route_ui.cc
selection.cc
send_ui.cc
+session_import_dialog.cc
session_metadata_dialog.cc
sfdb_ui.cc
simpleline.cc
diff --git a/gtk2_ardour/ardour.menus b/gtk2_ardour/ardour.menus
index a37645dca8..ed4ea0c2a6 100644
--- a/gtk2_ardour/ardour.menus
+++ b/gtk2_ardour/ardour.menus
@@ -18,6 +18,7 @@
<menuitem action='AddTrackBus'/>
<separator/>
<menuitem action='addExistingAudioFiles'/>
+ <menuitem action='importFromSession'/>
<separator/>
<menu name='Export' action='Export'>
<menuitem action='ExportAudio'/>
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index a0918241bd..6374b29d06 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -1213,6 +1213,7 @@ class Editor : public PublicEditor
void add_external_audio_action (Editing::ImportMode);
void external_audio_dialog ();
+ void session_import_dialog ();
int check_whether_and_how_to_import(string, bool all_or_nothing = true);
bool check_multichannel_status (const std::vector<Glib::ustring>& paths);
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index 80b76369d0..fdad190c47 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -754,6 +754,8 @@ Editor::register_actions ()
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, X_("addExternalAudioToRegionList"), _("Import to Region List"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsRegion));
ActionManager::session_sensitive_actions.push_back (act);
+
++ ActionManager::register_action (editor_actions, X_("importFromSession"), _("Import From Session"), mem_fun(*this, &Editor::session_import_dialog));
act = ActionManager::register_toggle_action (editor_actions, X_("toggle-waveform-visible"), _("Show Waveforms"), mem_fun (*this, &Editor::toggle_waveform_visibility));
ActionManager::track_selection_sensitive_actions.push_back (act);
diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc
index 90202aa3d9..a12eb0857f 100644
--- a/gtk2_ardour/editor_audio_import.cc
+++ b/gtk2_ardour/editor_audio_import.cc
@@ -55,6 +55,7 @@
#include "editing.h"
#include "audio_time_axis.h"
#include "midi_time_axis.h"
+#include "session_import_dialog.h"
#include "utils.h"
#include "i18n.h"
@@ -184,6 +185,14 @@ Editor::external_audio_dialog ()
} while (keepRunning);
}
+void
+Editor::session_import_dialog ()
+{
+ SessionImportDialog dialog (*session);
+ ensure_float (dialog);
+ dialog.run ();
+}
+
typedef std::map<PBD::ID,boost::shared_ptr<ARDOUR::Source> > SourceMap;
/**
diff --git a/gtk2_ardour/playlist_selector.cc b/gtk2_ardour/playlist_selector.cc
index 39abfe3dc1..0ca9432fcb 100644
--- a/gtk2_ardour/playlist_selector.cc
+++ b/gtk2_ardour/playlist_selector.cc
@@ -183,6 +183,35 @@ PlaylistSelector::show_for (RouteUI* ruix)
}
}
+ // Add unassigned (imported) playlists to the list
+ list<boost::shared_ptr<Playlist> > unassigned;
+ session->unassigned_playlists (unassigned);
+
+ TreeModel::Row row;
+ TreeModel::Row* selected_row = 0;
+ TreePath this_path;
+
+ row = *(model->append (others.children()));
+ row[columns.text] = _("Imported");
+ proxy = row[columns.playlist];
+ proxy.reset ();
+
+ for (list<boost::shared_ptr<Playlist> >::iterator p = unassigned.begin(); p != unassigned.end(); ++p) {
+ TreeModel::Row child_row;
+
+ child_row = *(model->append (row.children()));
+ child_row[columns.text] = (*p)->name();
+ child_row[columns.playlist] = *p;
+
+ if (*p == this_ds->playlist()) {
+ selected_row = &child_row;
+ }
+
+ if (selected_row != 0) {
+ tree.get_selection()->select (*selected_row);
+ }
+ }
+
show_all ();
select_connection = tree.get_selection()->signal_changed().connect (mem_fun(*this, &PlaylistSelector::selection_changed));
}
diff --git a/gtk2_ardour/session_import_dialog.cc b/gtk2_ardour/session_import_dialog.cc
new file mode 100644
index 0000000000..42eb7c56cb
--- /dev/null
+++ b/gtk2_ardour/session_import_dialog.cc
@@ -0,0 +1,321 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ 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 "session_import_dialog.h"
+
+#include <pbd/failed_constructor.h>
+
+#include <ardour/audio_region_importer.h>
+#include <ardour/audio_playlist_importer.h>
+#include <ardour/location_importer.h>
+#include <ardour/tempo_map_importer.h>
+
+#include <gtkmm2ext/utils.h>
+#include <gtkmm2ext/window_title.h>
+
+#include "prompter.h"
+#include "i18n.h"
+
+using namespace ARDOUR;
+
+SessionImportDialog::SessionImportDialog (ARDOUR::Session & target) :
+ ArdourDialog (_("Import from session")),
+ target (target),
+ file_browse_button (_("Browse"))
+{
+ // File entry
+ file_entry.set_name ("ImportFileNameEntry");
+ file_entry.set_text ("/");
+ Gtkmm2ext::set_size_request_to_display_given_text (file_entry, X_("Kg/quite/a/reasonable/size/for/files/i/think"), 5, 8);
+
+ file_browse_button.set_name ("EditorGTKButton");
+ file_browse_button.signal_clicked().connect (mem_fun(*this, &SessionImportDialog::browse));
+
+ file_hbox.set_spacing (5);
+ file_hbox.set_border_width (5);
+ file_hbox.pack_start (file_entry, true, true);
+ file_hbox.pack_start (file_browse_button, false, false);
+
+ file_frame.add (file_hbox);
+ file_frame.set_border_width (5);
+ file_frame.set_name ("ImportFrom");
+ file_frame.set_label (_("Import from Session"));
+
+ get_vbox()->pack_start (file_frame, false, false);
+
+ // Session browser
+ session_tree = Gtk::TreeStore::create (sb_cols);
+ session_browser.set_model (session_tree);
+
+ session_browser.set_name ("SessionBrowser");
+ session_browser.append_column (_("Elements"), sb_cols.name);
+ session_browser.append_column_editable (_("Import"), sb_cols.queued);
+ session_browser.get_column(0)->set_min_width (180);
+ session_browser.get_column(1)->set_min_width (40);
+ session_browser.get_column(1)->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
+
+ session_scroll.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+ session_scroll.add (session_browser);
+ session_scroll.set_size_request (220, 400);
+
+ // Connect signals
+ Gtk::CellRendererToggle *toggle = dynamic_cast<Gtk::CellRendererToggle *> (session_browser.get_column_cell_renderer (1));
+ toggle->signal_toggled().connect(mem_fun (*this, &SessionImportDialog::update));
+ session_browser.signal_row_activated().connect(mem_fun (*this, &SessionImportDialog::show_info));
+
+ get_vbox()->pack_start (session_scroll, false, false);
+
+ // Tooltips
+ session_browser.set_has_tooltip();
+ session_browser.signal_query_tooltip().connect(mem_fun(*this, &SessionImportDialog::query_tooltip));
+
+ // Buttons
+ cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ cancel_button->signal_clicked().connect (mem_fun (*this, &SessionImportDialog::end_dialog));
+ ok_button = add_button (_("Import"), Gtk::RESPONSE_ACCEPT);
+ ok_button->signal_clicked().connect (mem_fun (*this, &SessionImportDialog::do_merge));
+
+ // prompt signals
+ ElementImporter::Rename.connect (mem_fun (*this, &SessionImportDialog::open_rename_dialog));
+ ElementImporter::Prompt.connect (mem_fun (*this, &SessionImportDialog::open_prompt_dialog));
+
+ // Finalize
+ show_all();
+}
+
+void
+SessionImportDialog::load_session (const string& filename)
+{
+ tree.read (filename);
+ AudioRegionImportHandler *region_handler;
+
+ region_handler = new AudioRegionImportHandler (tree, target);
+ handlers.push_back (HandlerPtr(region_handler));
+ handlers.push_back (HandlerPtr(new AudioPlaylistImportHandler (tree, target, *region_handler)));
+ handlers.push_back (HandlerPtr(new UnusedAudioPlaylistImportHandler (tree, target, *region_handler)));
+ handlers.push_back (HandlerPtr(new LocationImportHandler (tree, target)));
+ handlers.push_back (HandlerPtr(new TempoMapImportHandler (tree, target)));
+
+ fill_list();
+
+ if (ElementImportHandler::dirty()) {
+ // Warn user
+ string txt = _("Some elements had errors in them. Please see the log for details");
+ Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
+ msg.run();
+ }
+}
+
+void
+SessionImportDialog::fill_list ()
+{
+ session_tree->clear();
+
+ // Loop through element types
+ for (HandlerList::iterator handler = handlers.begin(); handler != handlers.end(); ++handler) {
+ Gtk::TreeModel::iterator iter = session_tree->append();
+ Gtk::TreeModel::Row row = *iter;
+ row[sb_cols.name] = (*handler)->get_info();
+ row[sb_cols.queued] = false;
+ row[sb_cols.element] = ElementPtr(); // "Null" pointer
+
+ // Loop through elements
+ ElementList &elements = (*handler)->elements;
+ for (ElementList::iterator element = elements.begin(); element != elements.end(); ++element) {
+ iter = session_tree->append(row.children());
+ Gtk::TreeModel::Row child = *iter;
+ child[sb_cols.name] = (*element)->get_name();
+ child[sb_cols.queued] = false;
+ child[sb_cols.element] = *element;
+ }
+ }
+}
+
+void
+SessionImportDialog::browse ()
+{
+ Gtk::FileChooserDialog dialog(_("Import from session"), browse_action());
+ dialog.set_transient_for(*this);
+ dialog.set_filename (file_entry.get_text());
+
+ dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
+
+ int result = dialog.run();
+
+ if (result == Gtk::RESPONSE_OK) {
+ string filename = dialog.get_filename();
+
+ if (filename.length()) {
+ file_entry.set_text (filename);
+ load_session (filename);
+ }
+ }
+}
+
+void
+SessionImportDialog::do_merge ()
+{
+
+ // element types
+ Gtk::TreeModel::Children types = session_browser.get_model()->children();
+ Gtk::TreeModel::Children::iterator ti;
+ for (ti = types.begin(); ti != types.end(); ++ti) {
+ // elements
+ Gtk::TreeModel::Children elements = ti->children();
+ Gtk::TreeModel::Children::iterator ei;
+ for (ei = elements.begin(); ei != elements.end(); ++ei) {
+ if ((*ei)[sb_cols.queued]) {
+ ElementPtr element = (*ei)[sb_cols.element];
+ element->move();
+ }
+ }
+ }
+
+ end_dialog();
+
+ if (ElementImportHandler::errors()) {
+ // Warn user
+ string txt = _("Some elements had errors in them. Please see the log for details");
+ Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
+ msg.run();
+ }
+}
+
+
+void
+SessionImportDialog::update (string path)
+{
+ Gtk::TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
+
+ // Select all elements if element type is selected
+ if (path.size() == 1) {
+ {
+ // Prompt user for verification
+ string txt = _("This will select all elements of this type!");
+ Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
+ if (msg.run() == Gtk::RESPONSE_CANCEL) {
+ (*cell)[sb_cols.queued] = false;
+ return;
+ }
+ }
+
+ Gtk::TreeModel::Children elements = cell->children();
+ Gtk::TreeModel::Children::iterator ei;
+ for (ei = elements.begin(); ei != elements.end(); ++ei) {
+ ElementPtr element = (*ei)[sb_cols.element];
+ if (element->prepare_move()) {
+ (*ei)[sb_cols.queued] = true;
+ } else {
+ (*cell)[sb_cols.queued] = false; // Not all are selected
+ }
+ }
+ return;
+ }
+
+ ElementPtr element = (*cell)[sb_cols.element];
+ if ((*cell)[sb_cols.queued]) {
+ if (!element->prepare_move()) {
+ (*cell)[sb_cols.queued] = false;
+ }
+ } else {
+ element->cancel_move();
+ }
+}
+
+void
+SessionImportDialog::show_info(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column)
+{
+ if (path.size() == 1) {
+ return;
+ }
+
+ Gtk::TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
+ ElementPtr element = (*cell)[sb_cols.element];
+ string info = element->get_info();
+
+ Gtk::MessageDialog msg (info, false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, true);
+ msg.run();
+}
+
+bool
+SessionImportDialog::query_tooltip(int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip)
+{
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* column;
+ int cell_x, cell_y;
+
+ // Get element
+ session_browser.get_path_at_pos (x, y, path, column, cell_x, cell_y);
+ if (path.gobj() == 0) {
+ return false;
+ }
+ Gtk::TreeModel::iterator row = session_browser.get_model()->get_iter (path);
+ //--row; // FIXME Strange offset in rows, if someone figures this out, please fix
+ ElementPtr element = (*row)[sb_cols.element];
+ if (element.get() == 0) {
+ return false;
+ }
+
+ // Prepare tooltip
+ tooltip->set_text(element->get_info());
+
+ return true;
+}
+
+void
+SessionImportDialog::end_dialog ()
+{
+ hide_all();
+
+ set_modal (false);
+ ok_button->set_sensitive(true);
+}
+
+std::pair<bool, string>
+SessionImportDialog::open_rename_dialog (string text, string name)
+{
+ ArdourPrompter prompter(true);
+ string new_name;
+
+ prompter.set_name ("Prompter");
+ prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
+ prompter.set_prompt (text);
+ prompter.set_initial_text (name);
+
+ if (prompter.run() == Gtk::RESPONSE_ACCEPT) {
+ prompter.get_result (new_name);
+ if (new_name.length()) {
+ name = new_name;
+ }
+ return std::make_pair (true, new_name);
+ }
+ return std::make_pair (false, new_name);
+}
+
+bool
+SessionImportDialog::open_prompt_dialog (string text)
+{
+ Gtk::MessageDialog msg (text, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
+ if (msg.run() == Gtk::RESPONSE_OK) {
+ return true;
+ }
+ return false;
+}
diff --git a/gtk2_ardour/session_import_dialog.h b/gtk2_ardour/session_import_dialog.h
new file mode 100644
index 0000000000..22cccd1262
--- /dev/null
+++ b/gtk2_ardour/session_import_dialog.h
@@ -0,0 +1,101 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __session_import_dialog_h__
+#define __session_import_dialog_h__
+
+#include <string>
+#include <list>
+#include <utility>
+
+#include <boost/shared_ptr.hpp>
+#include <gtkmm.h>
+
+#include <pbd/xml++.h>
+#include <ardour/element_importer.h>
+#include <ardour/element_import_handler.h>
+
+#include "ardour_dialog.h"
+
+using std::string;
+
+namespace ARDOUR {
+ class Session;
+}
+
+class SessionImportDialog : public ArdourDialog
+{
+ private:
+ typedef boost::shared_ptr<ARDOUR::ElementImportHandler> HandlerPtr;
+ typedef std::list<HandlerPtr> HandlerList;
+
+ typedef boost::shared_ptr<ARDOUR::ElementImporter> ElementPtr;
+ typedef std::list<ElementPtr> ElementList;
+
+ public:
+ SessionImportDialog (ARDOUR::Session & target);
+
+ virtual Gtk::FileChooserAction browse_action() const { return Gtk::FILE_CHOOSER_ACTION_OPEN; }
+
+ private:
+
+ void load_session (const string& filename);
+ void fill_list ();
+ void browse ();
+ void do_merge ();
+ void end_dialog ();
+ void update (string path);
+ void show_info(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column);
+ bool query_tooltip(int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip);
+
+ std::pair<bool, string> open_rename_dialog (string text, string name);
+ bool open_prompt_dialog (string text);
+
+ // Data
+ HandlerList handlers;
+ XMLTree tree;
+ ARDOUR::Session &target;
+
+ // GUI
+ Gtk::Frame file_frame;
+ Gtk::HBox file_hbox;
+ Gtk::Entry file_entry;
+ Gtk::Button file_browse_button;
+
+ struct SessionBrowserColumns : public Gtk::TreeModel::ColumnRecord
+ {
+ public:
+ Gtk::TreeModelColumn<std::string> name;
+ Gtk::TreeModelColumn<bool> queued;
+ Gtk::TreeModelColumn<ElementPtr> element;
+
+ SessionBrowserColumns() { add (name); add (queued); add (element); }
+ };
+
+ SessionBrowserColumns sb_cols;
+ Glib::RefPtr<Gtk::TreeStore> session_tree;
+ Gtk::TreeView session_browser;
+ Gtk::ScrolledWindow session_scroll;
+
+ Gtk::Button* ok_button;
+ Gtk::Button* cancel_button;
+};
+
+#endif
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 352d1b26f6..156daf2bc0 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -36,6 +36,7 @@ audio_buffer.cc
audio_diskstream.cc
audio_library.cc
audio_playlist.cc
+audio_playlist_importer.cc
audio_port.cc
audio_track.cc
audioanalyser.cc
@@ -43,6 +44,7 @@ audioengine.cc
audiofile_tagger.cc
audiofilesource.cc
audioregion.cc
+audio_region_importer.cc
audiosource.cc
auditioner.cc
auto_bundle.cc
@@ -64,6 +66,8 @@ cycle_timer.cc
default_click.cc
directory_names.cc
diskstream.cc
+element_importer.cc
+element_import_handler.cc
enums.cc
event_type_map.cc
export_channel_configuration.cc
@@ -96,6 +100,7 @@ jack_port.cc
jack_slave.cc
ladspa_plugin.cc
location.cc
+location_importer.cc
meter.cc
midi_buffer.cc
midi_clock_slave.cc
@@ -159,6 +164,7 @@ svn_revision.cc
tape_file_matcher.cc
template_utils.cc
tempo.cc
+tempo_map_importer.cc
track.cc
transient_detector.cc
user_bundle.cc
diff --git a/libs/ardour/ardour/audio_playlist_importer.h b/libs/ardour/ardour/audio_playlist_importer.h
new file mode 100644
index 0000000000..a3e72f18c8
--- /dev/null
+++ b/libs/ardour/ardour/audio_playlist_importer.h
@@ -0,0 +1,87 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_audio_playlist_importer_h__
+#define __ardour_audio_playlist_importer_h__
+
+#include <list>
+
+#include <boost/shared_ptr.hpp>
+
+#include <pbd/xml++.h>
+#include <pbd/id.h>
+
+#include <ardour/element_importer.h>
+#include <ardour/element_import_handler.h>
+#include <ardour/types.h>
+
+#include "i18n.h"
+
+namespace ARDOUR {
+
+class AudioRegionImportHandler;
+class AudioRegionImporter;
+
+class AudioPlaylistImportHandler : public ElementImportHandler
+{
+ public:
+ AudioPlaylistImportHandler (XMLTree const & source, Session & session, AudioRegionImportHandler & region_handler, const char * nodename = "Playlists");
+ virtual ~AudioPlaylistImportHandler () {}
+ virtual string get_info () const;
+
+ void get_regions (XMLNode const & node, ElementList & list);
+ void update_region_id (XMLProperty* id_prop);
+
+ protected:
+ AudioRegionImportHandler & region_handler;
+};
+
+class UnusedAudioPlaylistImportHandler : public AudioPlaylistImportHandler
+{
+ public:
+ UnusedAudioPlaylistImportHandler (XMLTree const & source, Session & session, AudioRegionImportHandler & region_handler) :
+ AudioPlaylistImportHandler (source, session, region_handler, X_("UnusedPlaylists")) { }
+ string get_info () const { return _("Audio Playlists (unused)"); }
+};
+
+class AudioPlaylistImporter : public ElementImporter
+{
+ public:
+ AudioPlaylistImporter (XMLTree const & source, Session & session, AudioPlaylistImportHandler & handler, XMLNode const & node);
+
+ string get_info () const;
+ bool prepare_move ();
+ void cancel_move ();
+ void move ();
+
+ void set_diskstream (PBD::ID const & id);
+
+ private:
+ typedef std::list<boost::shared_ptr<AudioRegionImporter> > RegionList;
+
+ AudioPlaylistImportHandler & handler;
+ XMLNode xml_playlist;
+ PBD::ID diskstream_id;
+ RegionList regions;
+};
+
+} // namespace ARDOUR
+
+#endif
diff --git a/libs/ardour/ardour/audio_region_importer.h b/libs/ardour/ardour/audio_region_importer.h
new file mode 100644
index 0000000000..a2205390ab
--- /dev/null
+++ b/libs/ardour/ardour/audio_region_importer.h
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_audio_region_importer_h__
+#define __ardour_audio_region_importer_h__
+
+#include <list>
+#include <map>
+#include <utility>
+
+#include <boost/shared_ptr.hpp>
+
+#include <pbd/xml++.h>
+#include <pbd/id.h>
+#include <pbd/filesystem.h>
+#include <ardour/types.h>
+#include <ardour/element_importer.h>
+#include <ardour/element_import_handler.h>
+
+namespace ARDOUR {
+
+class Region;
+
+class AudioRegionImportHandler : public ElementImportHandler
+{
+ public:
+ // Inerface implementation
+ AudioRegionImportHandler (XMLTree const & source, Session & session);
+ string get_info () const;
+
+ void create_regions_from_children (XMLNode const & node, ElementList & list);
+
+ // Source management
+ bool check_source (string const & filename) const;
+ void add_source (string const & filename, boost::shared_ptr<Source> const & source);
+ boost::shared_ptr<Source> const & get_source (string const & filename) const;
+
+ // Id management
+ void register_id (PBD::ID & old_id, PBD::ID & new_id);
+ PBD::ID const & get_new_id (PBD::ID & old_id) const;
+
+ private:
+ // Source management
+ typedef std::map<string, boost::shared_ptr<Source> > SourceMap;
+ typedef std::pair<string, boost::shared_ptr<Source> > SourcePair;
+ SourceMap sources;
+
+ // Id management
+ typedef std::map<PBD::ID, PBD::ID> IdMap;
+ typedef std::pair<PBD::ID, PBD::ID> IdPair;
+ IdMap id_map;
+};
+
+class AudioRegionImporter : public ElementImporter
+{
+ public:
+ AudioRegionImporter (XMLTree const & source, Session & session, AudioRegionImportHandler & handler, XMLNode const & node);
+
+ // Interface implementation
+ string get_info () const;
+ bool prepare_move ();
+ void cancel_move ();
+ void move ();
+
+ // other stuff
+ void add_sources_to_session ();
+ XMLNode const & get_xml ();
+
+ private:
+
+ XMLNode xml_region;
+ AudioRegionImportHandler & handler;
+ PBD::ID old_id;
+ PBD::ID id;
+ std::list<string> filenames;
+
+ bool parse_xml_region ();
+ bool parse_source_xml ();
+ PBD::sys::path get_sound_dir (XMLTree const & tree);
+
+ void prepare_region ();
+ void prepare_sources ();
+ std::vector<boost::shared_ptr<Region> > region;
+ bool region_prepared;
+ bool sources_prepared;
+};
+
+} // namespace ARDOUR
+
+#endif
diff --git a/libs/ardour/ardour/element_import_handler.h b/libs/ardour/ardour/element_import_handler.h
new file mode 100644
index 0000000000..9393c31559
--- /dev/null
+++ b/libs/ardour/ardour/element_import_handler.h
@@ -0,0 +1,110 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_element_import_handler_h__
+#define __ardour_element_import_handler_h__
+
+#include <string>
+#include <list>
+
+#include <boost/shared_ptr.hpp>
+
+using std::string;
+class XMLTree;
+
+namespace ARDOUR {
+
+class Session;
+class ElementImporter;
+
+/// Virtual interface class for element import handlers
+class ElementImportHandler
+{
+ public:
+ typedef boost::shared_ptr<ElementImporter> ElementPtr;
+ typedef std::list<ElementPtr> ElementList;
+
+ /** ElementImportHandler constructor
+ * The constructor should find everything from the XML Tree it can handle
+ * and create respective Elements stored in elements.
+ *
+ * @param source XML tree to be parsed
+ * @see elements
+ */
+ ElementImportHandler (XMLTree const & source, ARDOUR::Session & session) :
+ source (source), session (session) { }
+
+ virtual ~ElementImportHandler ();
+
+ /** Gets a textual representation of the element type
+ * @return textual representation of element type
+ */
+ virtual string get_info () const = 0;
+
+ /// Elements this handler handles
+ ElementList elements;
+
+ /* For checking duplicates names against queued elements */
+
+ /** Checks whether or not an element with some name is queued or not
+ * @param name name to check
+ * @return true if name is not used
+ */
+ bool check_name (const string & name) const;
+
+ /// Adds name to the list of used names
+ void add_name (string name);
+
+ /// Removes name from the list of used names
+ void remove_name (const string & name);
+
+ /// Checks wheter or not all elements can be imported cleanly
+ static bool dirty () { return _dirty; }
+
+ /// Sets handler dirty
+ static void set_dirty () { _dirty = true; }
+
+ /// Checks wheter or not all elements were imported cleanly
+ static bool errors () { return _errors; }
+
+ /// Sets handler dirty
+ static void set_errors () { _errors = true; }
+
+ protected:
+ /// Source session XML tree
+ XMLTree const & source;
+
+ /// Destination session
+ ARDOUR::Session & session;
+
+ /// Session XML readability
+ static bool _dirty;
+
+ /// Errors post initialization
+ static bool _errors;
+
+ private:
+ /// List of names for duplicate checking
+ std::list<string> names;
+};
+
+} // namespace ARDOUR
+
+#endif
diff --git a/libs/ardour/ardour/element_importer.h b/libs/ardour/ardour/element_importer.h
new file mode 100644
index 0000000000..34ab0a7cc6
--- /dev/null
+++ b/libs/ardour/ardour/element_importer.h
@@ -0,0 +1,122 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_element_importer_h__
+#define __ardour_element_importer_h__
+
+#include <string>
+#include <utility>
+
+#include <sigc++/signal.h>
+
+#include <ardour/types.h>
+
+using std::string;
+
+class XMLTree;
+namespace ARDOUR {
+
+class Session;
+
+/// Virtual interface class for element importers
+class ElementImporter
+{
+ public:
+
+ ElementImporter (XMLTree const & source, ARDOUR::Session & session);
+ virtual ~ElementImporter () {};
+
+ /** Returns the element name
+ * @return the name of the element
+ */
+ virtual string get_name () const { return name; };
+
+ /** Gets a textual representation of the element
+ * @return a textual representation on this specific element
+ */
+ virtual string get_info () const = 0;
+
+ /** Prepares to move element
+ * Should take care of all tasks that need to be done
+ * before moving the element. This includes prompting
+ * the user for more information if necessary.
+ *
+ * If the element can be moved, queued should be set to true.
+ *
+ * @return whther or not the element could be prepared for moving
+ */
+ virtual bool prepare_move () = 0;
+
+ /** Cancels moving of element
+ * If the element has been set to be moved, this cancels the move.
+ * queued should be set to false.
+ */
+ virtual void cancel_move () = 0;
+
+ /** Moves the element to the taget session
+ * In addition to actually adding the element to the session
+ * changing ids, renaming files etc. should be taken care of.
+ */
+ virtual void move () = 0;
+
+ /// Check if element is broken. Cannot be moved if broken.
+ bool broken () { return _broken; }
+
+ /// Signal that requests for anew name
+ static sigc::signal <std::pair<bool, string>, string, string> Rename;
+
+ /// Signal for ok/cancel prompting
+ static sigc::signal <bool, string> Prompt;
+
+ protected:
+ /// Source XML-tree
+ XMLTree const & source;
+
+ /// Target session
+ ARDOUR::Session & session;
+
+ /// Ture if the element has been prepared and queued for importing
+ bool queued;
+
+ /// Name of element
+ string name;
+
+ /// The sample rate of the session from which we are importing
+ nframes_t sample_rate;
+
+ /// Converts smpte time to a string
+ string smpte_to_string(SMPTE::Time & time) const;
+
+ /// Converts samples so that times match the sessions sample rate
+ nframes_t rate_convert_samples (nframes_t samples) const;
+
+ /// Converts samples so that times match the sessions sample rate (for straight use in XML)
+ string rate_convert_samples (string const & samples) const;
+
+ /// Set element broken
+ void set_broken () { _broken = true; }
+
+ private:
+ bool _broken;
+};
+
+} // namespace ARDOUR
+
+#endif
diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h
index d5b672a89d..ae0ec5acd8 100644
--- a/libs/ardour/ardour/location.h
+++ b/libs/ardour/ardour/location.h
@@ -99,6 +99,7 @@ class Location : public PBD::StatefulDestructible
void set_cd (bool yn, void *src);
void set_is_end (bool yn, void* src);
void set_is_start (bool yn, void* src);
+ void set_is_range_marker (bool yn, void* src);
bool is_auto_punch () const { return _flags & IsAutoPunch; }
bool is_auto_loop () const { return _flags & IsAutoLoop; }
diff --git a/libs/ardour/ardour/location_importer.h b/libs/ardour/ardour/location_importer.h
new file mode 100644
index 0000000000..7066151383
--- /dev/null
+++ b/libs/ardour/ardour/location_importer.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_location_importer_h__
+#define __ardour_location_importer_h__
+
+#include <ardour/element_importer.h>
+#include <ardour/element_import_handler.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <pbd/xml++.h>
+#include <ardour/location.h>
+#include <ardour/types.h>
+
+namespace ARDOUR {
+
+class LocationImportHandler : public ElementImportHandler
+{
+ public:
+ LocationImportHandler (XMLTree const & source, Session & session);
+ string get_info () const;
+};
+
+class LocationImporter : public ElementImporter
+{
+ public:
+ LocationImporter (XMLTree const & source, Session & session, LocationImportHandler & handler, XMLNode const & node);
+ ~LocationImporter ();
+
+ string get_info () const;
+ bool prepare_move ();
+ void cancel_move ();
+ void move ();
+
+ private:
+ LocationImportHandler & handler;
+ XMLNode xml_location;
+ Location * location;
+
+ void parse_xml ();
+};
+
+} // namespace ARDOUR
+
+#endif
diff --git a/libs/ardour/ardour/playlist_factory.h b/libs/ardour/ardour/playlist_factory.h
index a28e2611d9..239fa49a04 100644
--- a/libs/ardour/ardour/playlist_factory.h
+++ b/libs/ardour/ardour/playlist_factory.h
@@ -31,9 +31,9 @@ class Session;
class PlaylistFactory {
public:
- static sigc::signal<void,boost::shared_ptr<Playlist> > PlaylistCreated;
+ static sigc::signal<void,boost::shared_ptr<Playlist>, bool> PlaylistCreated;
- static boost::shared_ptr<Playlist> create (Session&, const XMLNode&, bool hidden = false);
+ static boost::shared_ptr<Playlist> create (Session&, const XMLNode&, bool hidden = false, bool unused = false);
static boost::shared_ptr<Playlist> create (DataType type, Session&, string name, bool hidden = false);
static boost::shared_ptr<Playlist> create (boost::shared_ptr<const Playlist>, string name, bool hidden = false);
static boost::shared_ptr<Playlist> create (boost::shared_ptr<const Playlist>, nframes_t start, nframes_t cnt, string name, bool hidden = false);
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index fa074071c5..83e3200224 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -685,7 +685,8 @@ class Session : public PBD::StatefulDestructible
/* playlist management */
boost::shared_ptr<Playlist> playlist_by_name (string name);
- void add_playlist (boost::shared_ptr<Playlist>);
+ void unassigned_playlists (std::list<boost::shared_ptr<Playlist> > & list);
+ void add_playlist (boost::shared_ptr<Playlist>, bool unused = false);
sigc::signal<void,boost::shared_ptr<Playlist> > PlaylistAdded;
sigc::signal<void,boost::shared_ptr<Playlist> > PlaylistRemoved;
diff --git a/libs/ardour/ardour/tempo_map_importer.h b/libs/ardour/ardour/tempo_map_importer.h
new file mode 100644
index 0000000000..6c2a057943
--- /dev/null
+++ b/libs/ardour/ardour/tempo_map_importer.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_tempo_map_importer_h__
+#define __ardour_tempo_map_importer_h__
+
+#include <boost/shared_ptr.hpp>
+
+#include <pbd/xml++.h>
+
+#include <ardour/element_importer.h>
+#include <ardour/element_import_handler.h>
+#include <ardour/tempo.h>
+#include <ardour/types.h>
+
+namespace ARDOUR {
+
+class TempoMapImportHandler : public ElementImportHandler
+{
+ public:
+ TempoMapImportHandler (XMLTree const & source, Session & session);
+ string get_info () const;
+};
+
+class TempoMapImporter : public ElementImporter
+{
+ private:
+ typedef boost::shared_ptr<XMLNode> XMLNodePtr;
+ public:
+ TempoMapImporter (XMLTree const & source, Session & session, XMLNode const & node);
+
+ virtual string get_info () const;
+ virtual bool prepare_move ();
+ virtual void cancel_move ();
+ virtual void move ();
+
+ private:
+ XMLNode xml_tempo_map;
+};
+
+} // namespace ARDOUR
+
+#endif
diff --git a/libs/ardour/audio_playlist_importer.cc b/libs/ardour/audio_playlist_importer.cc
new file mode 100644
index 0000000000..d6a2b2f9fb
--- /dev/null
+++ b/libs/ardour/audio_playlist_importer.cc
@@ -0,0 +1,221 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ 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/audio_playlist_importer.h>
+
+#include <sstream>
+
+#include <pbd/failed_constructor.h>
+#include <pbd/compose.h>
+#include <pbd/error.h>
+
+#include <ardour/audio_region_importer.h>
+#include <ardour/session.h>
+#include <ardour/playlist.h>
+#include <ardour/playlist_factory.h>
+
+using namespace PBD;
+using namespace ARDOUR;
+
+/**** Handler ***/
+AudioPlaylistImportHandler::AudioPlaylistImportHandler (XMLTree const & source, Session & session, AudioRegionImportHandler & region_handler, const char * nodename) :
+ ElementImportHandler (source, session),
+ region_handler (region_handler)
+{
+ XMLNode const * root = source.root();
+ XMLNode const * playlists;
+
+ if (!(playlists = root->child (nodename))) {
+ throw failed_constructor();
+ }
+
+ XMLNodeList const & pl_children = playlists->children();
+ for (XMLNodeList::const_iterator it = pl_children.begin(); it != pl_children.end(); ++it) {
+ const XMLProperty* type = (*it)->property("type");
+ if ( !type || type->value() == "audio" ) {
+ try {
+ elements.push_back (ElementPtr ( new AudioPlaylistImporter (source, session, *this, **it)));
+ } catch (failed_constructor err) {
+ set_dirty();
+ }
+ }
+ }
+}
+
+string
+AudioPlaylistImportHandler::get_info () const
+{
+ return _("Audio Playlists");
+}
+
+void
+AudioPlaylistImportHandler::get_regions (XMLNode const & node, ElementList & list)
+{
+ region_handler.create_regions_from_children (node, list);
+}
+
+void
+AudioPlaylistImportHandler::update_region_id (XMLProperty* id_prop)
+{
+ PBD::ID old_id (id_prop->value());
+ PBD::ID new_id (region_handler.get_new_id (old_id));
+ id_prop->set_value (new_id.to_s());
+}
+
+/*** AudioPlaylistImporter ***/
+AudioPlaylistImporter::AudioPlaylistImporter (XMLTree const & source, Session & session, AudioPlaylistImportHandler & handler, XMLNode const & node) :
+ ElementImporter (source, session),
+ handler (handler),
+ xml_playlist (node),
+ diskstream_id ("0")
+{
+ bool ds_ok = false;
+
+ // Populate region list
+ ElementImportHandler::ElementList elements;
+ handler.get_regions (node, elements);
+ for (ElementImportHandler::ElementList::iterator it = elements.begin(); it != elements.end(); ++it) {
+ regions.push_back (boost::dynamic_pointer_cast<AudioRegionImporter> (*it));
+ }
+
+ // Parse XML
+ XMLPropertyList const & props = xml_playlist.properties();
+ for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) {
+ string prop = (*it)->name();
+ if (!prop.compare("type") || !prop.compare("frozen")) {
+ // All ok
+ } else if (!prop.compare("name")) {
+ name = (*it)->value();
+ } else if (!prop.compare("orig_diskstream_id")) {
+ ds_ok = true;
+ } else {
+ std::cerr << string_compose (X_("AudioPlaylistImporter did not recognise XML-property \"%1\""), prop) << endmsg;
+ }
+ }
+
+ if (!ds_ok) {
+ error << string_compose (X_("AudioPlaylistImporter (%1): did not find XML-property \"orig_diskstream_id\" which is mandatory"), name) << endmsg;
+ throw failed_constructor();
+ }
+}
+
+string
+AudioPlaylistImporter::get_info () const
+{
+ XMLNodeList children = xml_playlist.children();
+ unsigned int regions = 0;
+ std::ostringstream oss;
+
+ for (XMLNodeIterator it = children.begin(); it != children.end(); it++) {
+ if ((*it)->name() == "Region") {
+ ++regions;
+ }
+ }
+
+ oss << regions << " ";
+
+ if (regions == 1) {
+ oss << _("region");
+ } else {
+ oss << _("regions");
+ }
+
+ return oss.str();
+}
+
+bool
+AudioPlaylistImporter::prepare_move ()
+{
+ // Rename
+ while (session.playlist_by_name (name) || !handler.check_name (name)) {
+ std::pair<bool, string> rename_pair = Rename (_("A playlist with this name already exists, please rename it."), name);
+ if (!rename_pair.first) {
+ return false;
+ }
+ name = rename_pair.second;
+ }
+ xml_playlist.property ("name")->set_value (name);
+ handler.add_name (name);
+
+ queued = true;
+ return true;
+}
+
+void
+AudioPlaylistImporter::cancel_move ()
+{
+ handler.remove_name (name);
+ queued = false;
+}
+
+void
+AudioPlaylistImporter::move ()
+{
+ boost::shared_ptr<Playlist> playlist;
+
+ // Update diskstream id
+ xml_playlist.property ("orig_diskstream_id")->set_value (diskstream_id.to_s());
+
+ // Update region XML in playlist and prepare sources
+ xml_playlist.remove_nodes("Region");
+ for (RegionList::iterator it = regions.begin(); it != regions.end(); ++it) {
+ xml_playlist.add_child_copy ((*it)->get_xml());
+ (*it)->add_sources_to_session();
+ if ((*it)->broken()) {
+ handler.set_dirty();
+ set_broken();
+ return; // TODO clean up?
+ }
+ }
+
+ // Update region ids in crossfades
+ XMLNodeList crossfades = xml_playlist.children("Crossfade");
+ for (XMLNodeIterator it = crossfades.begin(); it != crossfades.end(); ++it) {
+ XMLProperty* in = (*it)->property("in");
+ XMLProperty* out = (*it)->property("out");
+ if (!in || !out) {
+ error << string_compose (X_("AudioPlaylistImporter (%1): did not find the \"in\" or \"out\" property from a crossfade"), name) << endmsg;
+ }
+
+ handler.update_region_id (in);
+ handler.update_region_id (out);
+
+ // rate convert length and position
+ XMLProperty* length = (*it)->property("length");
+ if (length) {
+ length->set_value (rate_convert_samples (length->value()));
+ }
+
+ XMLProperty* position = (*it)->property("position");
+ if (position) {
+ position->set_value (rate_convert_samples (position->value()));
+ }
+ }
+
+ // Create playlist
+ playlist = PlaylistFactory::create (session, xml_playlist, false, true);
+}
+
+void
+AudioPlaylistImporter::set_diskstream (PBD::ID const & id)
+{
+ diskstream_id = id;
+}
+
diff --git a/libs/ardour/audio_region_importer.cc b/libs/ardour/audio_region_importer.cc
new file mode 100644
index 0000000000..ab8261a369
--- /dev/null
+++ b/libs/ardour/audio_region_importer.cc
@@ -0,0 +1,398 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ 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/audio_region_importer.h>
+
+#include <sstream>
+
+#include <pbd/failed_constructor.h>
+#include <pbd/compose.h>
+#include <pbd/error.h>
+
+#include <ardour/session.h>
+#include <ardour/region.h>
+#include <ardour/source_factory.h>
+#include <ardour/region_factory.h>
+#include <ardour/session_directory.h>
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace ARDOUR;
+
+/**** Handler ***/
+AudioRegionImportHandler::AudioRegionImportHandler (XMLTree const & source, Session & session) :
+ ElementImportHandler (source, session)
+{
+ XMLNode const * root = source.root();
+ XMLNode const * regions;
+
+ if (!(regions = root->child (X_("Regions")))) {
+ throw failed_constructor();
+ }
+
+ create_regions_from_children (*regions, elements);
+}
+
+void
+AudioRegionImportHandler::create_regions_from_children (XMLNode const & node, ElementList & list)
+{
+ XMLNodeList const & children = node.children();
+ for (XMLNodeList::const_iterator it = children.begin(); it != children.end(); ++it) {
+ XMLProperty const * type = (*it)->property("type");
+ if (!(*it)->name().compare ("Region") && (!type || type->value() == "audio") ) {
+ try {
+ list.push_back (ElementPtr ( new AudioRegionImporter (source, session, *this, **it)));
+ } catch (failed_constructor err) {
+ set_dirty();
+ }
+ }
+ }
+}
+
+string
+AudioRegionImportHandler::get_info () const
+{
+ return _("Audio Regions");
+}
+
+bool
+AudioRegionImportHandler::check_source (string const & filename) const
+{
+ return (sources.find (filename) != sources.end());
+}
+
+void
+AudioRegionImportHandler::add_source (string const & filename, boost::shared_ptr<Source> const & source)
+{
+ sources.insert (SourcePair (filename, source));
+}
+
+boost::shared_ptr<Source> const &
+AudioRegionImportHandler::get_source (string const & filename) const
+{
+ return (sources.find (filename))->second;
+}
+
+void
+AudioRegionImportHandler::register_id (PBD::ID & old_id, PBD::ID & new_id)
+{
+ id_map.insert (IdPair (old_id, new_id));
+}
+
+PBD::ID const &
+AudioRegionImportHandler::get_new_id (PBD::ID & old_id) const
+{
+ return (id_map.find (old_id))->second;
+}
+
+/*** AudioRegionImporter ***/
+AudioRegionImporter::AudioRegionImporter (XMLTree const & source, Session & session, AudioRegionImportHandler & handler, XMLNode const & node) :
+ ElementImporter (source, session),
+ xml_region (node),
+ handler (handler),
+ old_id ("0"),
+ region_prepared (false),
+ sources_prepared (false)
+{
+ if (!parse_xml_region () || !parse_source_xml ()) {
+ throw failed_constructor();
+ }
+ handler.register_id (old_id, id);
+}
+
+string
+AudioRegionImporter::get_info () const
+{
+ nframes_t length, position;
+ SMPTE::Time length_time, position_time;
+ std::ostringstream oss;
+
+ // Get sample positions
+ std::istringstream iss_length(xml_region.property ("length")->value());
+ iss_length >> length;
+ std::istringstream iss_position(xml_region.property ("position")->value());
+ iss_position >> position;
+
+ // Convert to smpte
+ session.sample_to_smpte(length, length_time, true, false);
+ session.sample_to_smpte(position, position_time, true, false);
+
+ // return info
+ oss << _("Length: ") <<
+ smpte_to_string(length_time) <<
+ _("\nPosition: ") <<
+ smpte_to_string(position_time) <<
+ _("\nChannels: ") <<
+ xml_region.property ("channels")->value();
+
+
+ return oss.str();
+}
+
+bool
+AudioRegionImporter::prepare_move ()
+{
+ queued = true;
+ return true;
+}
+
+void
+AudioRegionImporter::cancel_move ()
+{
+ queued = false;
+}
+
+void
+AudioRegionImporter::move ()
+{
+ if (!region_prepared) {
+ prepare_region();
+ if (!region_prepared) {
+ return;
+ }
+ }
+
+ if (broken()) {
+ return;
+ }
+
+ session.add_regions (region);
+}
+
+bool
+AudioRegionImporter::parse_xml_region ()
+{
+ XMLPropertyList const & props = xml_region.properties();;
+ bool id_ok = false;
+ bool name_ok = false;
+
+ for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) {
+ string prop = (*it)->name();
+ if (!prop.compare ("type") || !prop.compare ("stretch") ||
+ !prop.compare ("shift") || !prop.compare ("first_edit") ||
+ !prop.compare ("layer") || !prop.compare ("flags") ||
+ !prop.compare ("scale-gain") || !prop.compare("channels") ||
+ prop.find ("master-source-") == 0 || prop.find ("source-") == 0) {
+ // All ok
+ } else if (!prop.compare ("start") || !prop.compare ("length") ||
+ !prop.compare ("position") || !prop.compare ("ancestral-start") ||
+ !prop.compare ("ancestral-length") || !prop.compare ("sync-position")) {
+ // Sample rate conversion
+ (*it)->set_value (rate_convert_samples ((*it)->value()));
+ } else if (!prop.compare("id")) {
+ // get old id and update id
+ old_id = (*it)->value();
+ (*it)->set_value (id.to_s());
+ id_ok = true;
+ } else if (!prop.compare("name")) {
+ // rename region if necessary
+ name = (*it)->value();
+ name = session.new_region_name (name);
+ (*it)->set_value (name);
+ name_ok = true;
+ } else {
+ std::cerr << string_compose (X_("AudioRegionImporter (%1): did not recognise XML-property \"%1\""), name, prop) << endmsg;
+ }
+ }
+
+ if (!id_ok) {
+ error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"id\""), name) << endmsg;
+ return false;
+ }
+
+ if (!name_ok) {
+ error << X_("AudioRegionImporter: did not find necessary XML-property \"name\"") << endmsg;
+ return false;
+ }
+
+ return true;
+}
+
+bool
+AudioRegionImporter::parse_source_xml ()
+{
+ uint32_t channels;
+ char buf[128];
+ PBD::sys::path source_dir = get_sound_dir (source);
+ PBD::sys::path source_path;
+ XMLNode * source_node;
+ XMLProperty *prop;
+
+ // Get XML for sources
+ if (!(source_node = source.root()->child (X_("Sources")))) {
+ return false;
+ }
+ XMLNodeList const & sources = source_node->children();
+
+ // Get source for each channel
+ if (!(prop = xml_region.property ("channels"))) {
+ error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"channels\""), name) << endmsg;
+ return false;
+ }
+
+ channels = atoi (prop->value());
+ for (uint32_t i = 0; i < channels; ++i) {
+ bool source_found = false;
+
+ // Get id for source-n
+ snprintf (buf, sizeof(buf), X_("source-%d"), i);
+ prop = xml_region.property (buf);
+ if (!prop) {
+ error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"%3\""), name, buf) << endmsg;
+ return false;
+ }
+ string source_id = prop->value();
+
+ // Get source
+ for (XMLNodeList::const_iterator it = sources.begin(); it != sources.end(); it++) {
+ prop = (*it)->property ("id");
+ if (prop && !source_id.compare (prop->value())) {
+ source_path = source_dir;
+ prop = (*it)->property ("name");
+ if (!prop) {
+ error << string_compose (X_("AudioRegionImporter (%1): source %2 has no \"name\" property"), name, source_id) << endmsg;
+ return false;
+ }
+ source_path /= prop->value();
+ filenames.push_back (source_path.to_string());
+
+ source_found = true;
+ break;
+ }
+ }
+
+ if (!source_found) {
+ error << string_compose (X_("AudioRegionImporter (%1): could not find all necessary sources"), name) << endmsg;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+PBD::sys::path
+AudioRegionImporter::get_sound_dir (XMLTree const & tree)
+{
+ PBD::sys::path source_dir = tree.filename();
+ source_dir = source_dir.branch_path();
+ SessionDirectory session_dir(source_dir);
+ source_dir = session_dir.sound_path();
+
+ return source_dir;
+}
+
+void
+AudioRegionImporter::prepare_region ()
+{
+ if (region_prepared) {
+ return;
+ }
+
+ SourceList source_list;
+ prepare_sources();
+
+ // Create source list
+ for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
+ source_list.push_back (handler.get_source (*it));
+ }
+
+ // create region and update XML
+ region.push_back (RegionFactory::create (source_list, xml_region));
+ if (*region.begin()) {
+ xml_region = (*region.begin())->get_state();
+ } else {
+ error << string_compose (X_("AudioRegionImporter (%1): could not construct Region"), name) << endmsg;
+ handler.set_errors();
+ }
+
+ region_prepared = true;
+}
+
+void
+AudioRegionImporter::prepare_sources ()
+{
+ if (sources_prepared) {
+ return;
+ }
+
+ Session::import_status status;
+
+ // Get sources that still need to be imported
+ for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
+ if (!handler.check_source (*it)) {
+ status.paths.push_back (*it);
+ }
+ }
+
+ // Prepare rest of import struct TODO quality
+ status.replace_existing_source = false;
+ status.done = false;
+ status.cancel = false;
+ status.freeze = false;
+ status.progress = 0.0;
+ status.quality = SrcBest;
+
+ // import files
+ // TODO: threading & exception handling
+ session.import_audiofiles (status);
+
+ // Add imported sources to handlers map
+ std::vector<Glib::ustring>::iterator file_it = status.paths.begin();
+ for (SourceList::iterator source_it = status.sources.begin(); source_it != status.sources.end(); ++source_it) {
+ if (*source_it) {
+ handler.add_source(*file_it, *source_it);
+ } else {
+ error << string_compose (X_("AudioRegionImporter (%1): could not import all necessary sources"), name) << endmsg;
+ handler.set_errors();
+ set_broken();
+ }
+
+ ++file_it;
+ }
+
+ sources_prepared = true;
+}
+
+void
+AudioRegionImporter::add_sources_to_session ()
+{
+ if (!sources_prepared) {
+ prepare_sources();
+ }
+
+ if (broken()) {
+ return;
+ }
+
+ for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
+ session.add_source (handler.get_source (*it));
+ }
+}
+
+XMLNode const &
+AudioRegionImporter::get_xml ()
+{
+ if(!region_prepared) {
+ prepare_region();
+ }
+
+ return xml_region;
+}
diff --git a/libs/ardour/element_import_handler.cc b/libs/ardour/element_import_handler.cc
new file mode 100644
index 0000000000..013dd3fe44
--- /dev/null
+++ b/libs/ardour/element_import_handler.cc
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ 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/element_import_handler.h>
+
+#include <algorithm>
+
+using namespace ARDOUR;
+
+bool ElementImportHandler::_dirty = false;
+bool ElementImportHandler::_errors = false;
+
+ElementImportHandler::~ElementImportHandler ()
+{
+ _dirty = false;
+ _errors = false;
+}
+
+bool
+ElementImportHandler::check_name (const string & name) const
+{
+ return std::find (names.begin(), names.end(), name) == names.end();
+}
+
+void
+ElementImportHandler::add_name (string name)
+{
+ names.push_back (name);
+}
+
+void
+ElementImportHandler::remove_name (const string & name)
+{
+ std::list<string>::iterator it = std::find (names.begin(), names.end(), name);
+ if (it != names.end()) {
+ names.erase(it);
+ }
+}
diff --git a/libs/ardour/element_importer.cc b/libs/ardour/element_importer.cc
new file mode 100644
index 0000000000..0312f0ef15
--- /dev/null
+++ b/libs/ardour/element_importer.cc
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ 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/element_importer.h>
+
+#include <sstream>
+#include <iomanip>
+
+#include <pbd/convert.h>
+#include <ardour/session.h>
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace ARDOUR;
+
+sigc::signal <std::pair<bool, string>, string, string> ElementImporter::Rename;
+sigc::signal <bool, string> ElementImporter::Prompt;
+
+ElementImporter::ElementImporter (XMLTree const & source, ARDOUR::Session & session) :
+ source (source),
+ session(session),
+ queued (false),
+ _broken (false)
+{
+ // Get samplerate
+ XMLProperty *prop;
+ prop = source.root()->property ("sample-rate");
+ if (prop) {
+ std::istringstream iss (prop->value());
+ iss >> sample_rate;
+ }
+}
+
+string
+ElementImporter::smpte_to_string(SMPTE::Time & time) const
+{
+ std::ostringstream oss;
+ oss << std::setfill('0') << std::right <<
+ std::setw(2) <<
+ time.hours << ":" <<
+ std::setw(2) <<
+ time.minutes << ":" <<
+ std::setw(2) <<
+ time.seconds << ":" <<
+ std::setw(2) <<
+ time.frames;
+
+ return oss.str();
+}
+
+nframes_t
+ElementImporter::rate_convert_samples (nframes_t samples) const
+{
+ if (sample_rate == session.frame_rate()) {
+ return samples;
+ }
+
+ // +0.5 for proper rounding
+ return static_cast<nframes_t> (samples * (static_cast<double> (session.nominal_frame_rate()) / sample_rate) + 0.5);
+}
+
+string
+ElementImporter::rate_convert_samples (string const & samples) const
+{
+ return to_string (rate_convert_samples (atoi (samples)), std::dec);
+}
diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc
index 8dd4bbc636..be34e34349 100644
--- a/libs/ardour/location.cc
+++ b/libs/ardour/location.cc
@@ -247,6 +247,14 @@ Location::set_is_start (bool yn, void *src)
}
void
+Location::set_is_range_marker (bool yn, void *src)
+{
+ if (set_flag_internal (yn, IsRangeMarker)) {
+ FlagsChanged (this, src); /* EMIT SIGNAL */
+ }
+}
+
+void
Location::set_auto_punch (bool yn, void *src)
{
if (is_mark() || _start == _end) {
diff --git a/libs/ardour/location_importer.cc b/libs/ardour/location_importer.cc
new file mode 100644
index 0000000000..31f19ef164
--- /dev/null
+++ b/libs/ardour/location_importer.cc
@@ -0,0 +1,195 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ 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/location_importer.h>
+
+#include <sstream>
+#include <stdexcept>
+
+#include <ardour/session.h>
+#include <pbd/convert.h>
+#include <pbd/failed_constructor.h>
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace ARDOUR;
+
+/**** Handler ***/
+LocationImportHandler::LocationImportHandler (XMLTree const & source, Session & session) :
+ ElementImportHandler (source, session)
+{
+ XMLNode const *root = source.root();
+ XMLNode const * location_node;
+
+ if (!(location_node = root->child ("Locations"))) {
+ throw failed_constructor();
+ }
+
+ // Construct importable locations
+ XMLNodeList const & locations = location_node->children();
+ for (XMLNodeList::const_iterator it = locations.begin(); it != locations.end(); it++) {
+ try {
+ elements.push_back (ElementPtr ( new LocationImporter (source, session, *this, **it)));
+ } catch (failed_constructor err) {
+ _dirty = true;
+ }
+ }
+}
+
+string
+LocationImportHandler::get_info () const
+{
+ return _("Locations");
+}
+
+/*** LocationImporter ***/
+LocationImporter::LocationImporter (XMLTree const & source, Session & session, LocationImportHandler & handler, XMLNode const & node) :
+ ElementImporter (source, session),
+ handler (handler),
+ xml_location (node),
+ location (0)
+ {
+ // Parse XML
+ bool name_ok = false;
+ XMLPropertyList props = xml_location.properties();
+
+ for (XMLPropertyIterator it = props.begin(); it != props.end(); ++it) {
+ string prop = (*it)->name();
+ if (!prop.compare ("id") || !prop.compare ("flags") || !prop.compare ("locked")) {
+ // All ok
+ } else if (!prop.compare ("start") || !prop.compare ("end")) {
+ // Sample rate conversion
+ (*it)->set_value (rate_convert_samples ((*it)->value()));
+ } else if (!prop.compare ("name")) {
+ // rename region if necessary
+ name = (*it)->value();
+ name_ok = true;
+ } else {
+ std::cerr << string_compose (X_("LocationImporter did not recognise XML-property \"%1\""), prop) << endmsg;
+ }
+ }
+
+ if (!name_ok) {
+ error << X_("LocationImporter did not find necessary XML-property \"name\"") << endmsg;
+ throw failed_constructor();
+ }
+}
+
+LocationImporter::~LocationImporter ()
+{
+ if (!queued && location) {
+ delete location;
+ }
+}
+
+string
+LocationImporter::get_info () const
+{
+ nframes_t start, end;
+ SMPTE::Time start_time, end_time;
+
+ // Get sample positions
+ std::istringstream iss_start (xml_location.property ("start")->value());
+ iss_start >> start;
+ std::istringstream iss_end (xml_location.property ("end")->value());
+ iss_end >> end;
+
+ // Convert to smpte
+ session.sample_to_smpte (start, start_time, true, false);
+ session.sample_to_smpte (end, end_time, true, false);
+
+ // return info
+ std::ostringstream oss;
+ if (start == end) {
+ oss << _("Location: ") << smpte_to_string (start_time);
+ } else {
+ oss << _("Range\nstart: ") << smpte_to_string (start_time) <<
+ _("\nend: ") << smpte_to_string (end_time);
+ }
+
+ return oss.str();
+}
+
+bool
+LocationImporter::prepare_move ()
+{
+ try {
+ Location const original (xml_location);
+ location = new Location (original); // Updates id
+ } catch (failed_constructor& err) {
+ throw std::runtime_error (X_("Error in session file!"));
+ return false;
+ }
+
+ std::pair<bool, string> rename_pair;
+
+ if (location->is_auto_punch()) {
+ rename_pair = Rename (_("The location is the Punch range. It will be imported as a normal range.\nYou may rename the imported location:"), name);
+ if (!rename_pair.first) {
+ return false;
+ }
+
+ name = rename_pair.second;
+ location->set_auto_punch (false, this);
+ location->set_is_range_marker (true, this);
+ }
+
+ if (location->is_auto_loop()) {
+ rename_pair = Rename (_("The location is a Loop range. It will be imported as a normal range.\nYou may rename the imported location:"), name);
+ if (!rename_pair.first) { return false; }
+
+ location->set_auto_loop (false, this);
+ location->set_is_range_marker (true, this);
+ }
+
+ // duplicate name checking
+ Locations::LocationList const & locations(session.locations()->list());
+ for (Locations::LocationList::const_iterator it = locations.begin(); it != locations.end(); ++it) {
+ if (!((*it)->name().compare (location->name())) || !handler.check_name (location->name())) {
+ rename_pair = Rename (_("A location with that name already exists.\nYou may rename the imported location:"), name);
+ if (!rename_pair.first) { return false; }
+ name = rename_pair.second;
+ }
+ }
+
+ location->set_name (name);
+ queued = true;
+ return true;
+}
+
+void
+LocationImporter::cancel_move ()
+{
+ queued = false;
+ if (location) {
+ delete location;
+ location = 0;
+ }
+}
+
+void
+LocationImporter::move ()
+{
+ if (!queued) {
+ return;
+ }
+ session.locations()->add (location);
+}
diff --git a/libs/ardour/playlist_factory.cc b/libs/ardour/playlist_factory.cc
index a801bae76c..129ff514af 100644
--- a/libs/ardour/playlist_factory.cc
+++ b/libs/ardour/playlist_factory.cc
@@ -29,10 +29,10 @@
using namespace ARDOUR;
using namespace PBD;
-sigc::signal<void,boost::shared_ptr<Playlist> > PlaylistFactory::PlaylistCreated;
+sigc::signal<void,boost::shared_ptr<Playlist>, bool> PlaylistFactory::PlaylistCreated;
boost::shared_ptr<Playlist>
-PlaylistFactory::create (Session& s, const XMLNode& node, bool hidden)
+PlaylistFactory::create (Session& s, const XMLNode& node, bool hidden, bool unused)
{
const XMLProperty* type = node.property("type");
@@ -46,7 +46,7 @@ PlaylistFactory::create (Session& s, const XMLNode& node, bool hidden)
pl->set_region_ownership ();
if (pl && !hidden) {
- PlaylistCreated (pl);
+ PlaylistCreated (pl, unused);
}
return pl;
}
@@ -62,7 +62,7 @@ PlaylistFactory::create (DataType type, Session& s, string name, bool hidden)
pl = boost::shared_ptr<Playlist> (new MidiPlaylist (s, name, hidden));
if (pl && !hidden) {
- PlaylistCreated (pl);
+ PlaylistCreated (pl, false);
}
return pl;
@@ -84,7 +84,7 @@ PlaylistFactory::create (boost::shared_ptr<const Playlist> old, string name, boo
}
if (pl && !hidden) {
- PlaylistCreated (pl);
+ PlaylistCreated (pl, false);
}
return pl;
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index ffa7d17761..30f93f9646 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -3368,7 +3368,23 @@ Session::playlist_by_name (string name)
}
void
-Session::add_playlist (boost::shared_ptr<Playlist> playlist)
+Session::unassigned_playlists (std::list<boost::shared_ptr<Playlist> > & list)
+{
+ Glib::Mutex::Lock lm (playlist_lock);
+ for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) {
+ list.push_back (*i);
+ }
+ }
+ for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
+ if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) {
+ list.push_back (*i);
+ }
+ }
+}
+
+void
+Session::add_playlist (boost::shared_ptr<Playlist> playlist, bool unused)
{
if (playlist->hidden()) {
return;
@@ -3383,6 +3399,10 @@ Session::add_playlist (boost::shared_ptr<Playlist> playlist)
}
}
+ if (unused) {
+ playlist->release();
+ }
+
set_dirty();
PlaylistAdded (playlist); /* EMIT SIGNAL */
diff --git a/libs/ardour/tempo_map_importer.cc b/libs/ardour/tempo_map_importer.cc
new file mode 100644
index 0000000000..45f2c90dfa
--- /dev/null
+++ b/libs/ardour/tempo_map_importer.cc
@@ -0,0 +1,108 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Sakari Bergen
+
+ 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/tempo_map_importer.h>
+
+#include <sstream>
+
+#include <ardour/session.h>
+#include <pbd/failed_constructor.h>
+#include <pbd/compose.h>
+#include <pbd/error.h>
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace ARDOUR;
+
+/**** Handler ***/
+TempoMapImportHandler::TempoMapImportHandler (XMLTree const & source, Session & session) :
+ ElementImportHandler (source, session)
+{
+ XMLNode const * root = source.root();
+ XMLNode const * tempo_map;
+
+ if (!(tempo_map = root->child (X_("TempoMap")))) {
+ throw failed_constructor();
+ }
+
+ elements.push_back (ElementPtr ( new TempoMapImporter (source, session, *tempo_map)));
+}
+
+string
+TempoMapImportHandler::get_info () const
+{
+ return _("Tempo map");
+}
+
+/*** TempoMapImporter ***/
+TempoMapImporter::TempoMapImporter (XMLTree const & source, Session & session, XMLNode const & node) :
+ ElementImporter (source, session),
+ xml_tempo_map (node)
+{
+ name = _("Tempo Map");
+}
+
+string
+TempoMapImporter::get_info () const
+{
+ std::ostringstream oss;
+ unsigned int tempos = 0;
+ unsigned int meters = 0;
+ XMLNodeList children = xml_tempo_map.children();
+
+ for (XMLNodeIterator it = children.begin(); it != children.end(); it++) {
+ if ((*it)->name() == "Tempo") {
+ tempos++;
+ } else if ((*it)->name() == "Meters") {
+ meters++;
+ }
+ }
+
+ // return info
+ oss << _("Tempo marks: ") << tempos << _("\nMeter marks: ") << meters;
+
+ return oss.str();
+}
+
+bool
+TempoMapImporter::prepare_move ()
+{
+ // Prompt user for verification
+ bool replace = Prompt (_("This will replace the current tempo map!\nAre you shure you want to do this?"));
+
+ if (replace) {
+ queued = true;
+ }
+
+ return replace;
+}
+
+void
+TempoMapImporter::cancel_move ()
+{
+ queued = false;
+}
+
+void
+TempoMapImporter::move ()
+{
+ session.tempo_map().set_state (xml_tempo_map);
+}