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:
Sakari Bergen 2008-09-26 08:29:30 +00:00
parent 10d57b266c
commit 572fa80aa7
27 changed files with 2120 additions and 9 deletions

View File

@ -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

View File

@ -18,6 +18,7 @@
<menuitem action='AddTrackBus'/>
<separator/>
<menuitem action='addExistingAudioFiles'/>
<menuitem action='importFromSession'/>
<separator/>
<menu name='Export' action='Export'>
<menuitem action='ExportAudio'/>

View File

@ -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);

View File

@ -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);

View File

@ -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;
/**

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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; }

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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;

View File

@ -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 */

View File

@ -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);
}