Add Import from session -functionality
git-svn-id: svn://localhost/ardour2/branches/3.0@3805 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
10d57b266c
commit
572fa80aa7
|
@ -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
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<menuitem action='AddTrackBus'/>
|
||||
<separator/>
|
||||
<menuitem action='addExistingAudioFiles'/>
|
||||
<menuitem action='importFromSession'/>
|
||||
<separator/>
|
||||
<menu name='Export' action='Export'>
|
||||
<menuitem action='ExportAudio'/>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 ⌖
|
||||
|
||||
// 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -246,6 +246,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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue