diff options
Diffstat (limited to 'gtk2_ardour')
-rw-r--r-- | gtk2_ardour/ardour_ui.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/export_channel_selector.cc | 8 | ||||
-rw-r--r-- | gtk2_ardour/export_channel_selector.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/export_dialog.cc | 97 | ||||
-rw-r--r-- | gtk2_ardour/export_dialog.h | 22 | ||||
-rw-r--r-- | gtk2_ardour/export_format_dialog.cc | 23 | ||||
-rw-r--r-- | gtk2_ardour/export_format_dialog.h | 8 | ||||
-rw-r--r-- | gtk2_ardour/export_range_markers_dialog.cc | 209 | ||||
-rw-r--r-- | gtk2_ardour/export_range_markers_dialog.h | 66 | ||||
-rw-r--r-- | gtk2_ardour/export_timespan_selector.cc | 19 | ||||
-rw-r--r-- | gtk2_ardour/export_timespan_selector.h | 3 | ||||
-rw-r--r-- | gtk2_ardour/icons/soundcloud.png | bin | 0 -> 1140 bytes | |||
-rw-r--r-- | gtk2_ardour/soundcloud_export_selector.cc | 110 | ||||
-rw-r--r-- | gtk2_ardour/soundcloud_export_selector.h | 41 | ||||
-rw-r--r-- | gtk2_ardour/system_exec.cc | 808 | ||||
-rw-r--r-- | gtk2_ardour/system_exec.h | 201 | ||||
-rw-r--r-- | gtk2_ardour/transcode_ffmpeg.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/video_monitor.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/wscript | 2 |
19 files changed, 261 insertions, 1364 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 8487d1d547..90809c907f 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -123,7 +123,7 @@ typedef uint64_t microseconds_t; #include "video_server_dialog.h" #include "add_video_dialog.h" #include "transcode_video_dialog.h" -#include "system_exec.h" +#include "pbd/system_exec.h" #include "i18n.h" diff --git a/gtk2_ardour/export_channel_selector.cc b/gtk2_ardour/export_channel_selector.cc index 10e3135b53..20155471af 100644 --- a/gtk2_ardour/export_channel_selector.cc +++ b/gtk2_ardour/export_channel_selector.cc @@ -458,15 +458,15 @@ RegionExportChannelSelector::RegionExportChannelSelector (ARDOUR::Session * _ses raw_button.set_label (string_compose (_("Region contents without fades nor region gain (channels: %1)"), region_chans)); raw_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection)); - vbox.pack_start (raw_button); + vbox.pack_start (raw_button, false, false); fades_button.set_label (string_compose (_("Region contents with fades and region gain (channels: %1)"), region_chans)); fades_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection)); - vbox.pack_start (fades_button); + vbox.pack_start (fades_button, false, false); processed_button.set_label (string_compose (_("Track output (channels: %1)"), track_chans)); processed_button.signal_toggled ().connect (sigc::mem_fun (*this, &RegionExportChannelSelector::handle_selection)); - vbox.pack_start (processed_button); + vbox.pack_start (processed_button, false, false); sync_with_manager(); vbox.show_all_children (); @@ -541,7 +541,7 @@ TrackExportChannelSelector::TrackExportChannelSelector (ARDOUR::Session * sessio // Options options_box.pack_start(region_contents_button); options_box.pack_start(track_output_button); - main_layout.pack_start(options_box); + main_layout.pack_start(options_box, false, false); // Track scroller track_scroller.add (track_view); diff --git a/gtk2_ardour/export_channel_selector.h b/gtk2_ardour/export_channel_selector.h index 984026a748..734aa8e57b 100644 --- a/gtk2_ardour/export_channel_selector.h +++ b/gtk2_ardour/export_channel_selector.h @@ -122,7 +122,7 @@ class PortExportChannelSelector : public ExportChannelSelector typedef Gtk::TreeModelColumn<Glib::RefPtr<Gtk::ListStore> > ComboCol; ComboCol port_list_col; - /* Channel struct, that represents the selected port and it's name */ + /* Channel struct, that represents the selected port and its name */ struct Channel { public: diff --git a/gtk2_ardour/export_dialog.cc b/gtk2_ardour/export_dialog.cc index 1458747786..dfba7550ac 100644 --- a/gtk2_ardour/export_dialog.cc +++ b/gtk2_ardour/export_dialog.cc @@ -141,68 +141,26 @@ ExportDialog::init () } void -ExportDialog::expanded_changed () -{ - set_resizable(advanced->get_expanded()); -} - -void ExportDialog::init_gui () { Gtk::Alignment * preset_align = Gtk::manage (new Gtk::Alignment()); preset_align->add (*preset_selector); preset_align->set_padding (0, 12, 0, 0); - get_vbox()->pack_start (*preset_align, false, false, 0); - - Gtk::VPaned * advanced_paned = Gtk::manage (new Gtk::VPaned()); - - Gtk::VBox* timespan_vbox = Gtk::manage (new Gtk::VBox()); - timespan_vbox->set_spacing (12); - timespan_vbox->set_border_width (12); - - Gtk::Alignment * timespan_align = Gtk::manage (new Gtk::Alignment()); - timespan_label = Gtk::manage (new Gtk::Label (_("Time Span"), Gtk::ALIGN_LEFT)); - timespan_align->add (*timespan_selector); - timespan_align->set_padding (0, 0, 18, 0); - timespan_vbox->pack_start (*timespan_label, false, false, 0); - timespan_vbox->pack_start (*timespan_align, true, true, 0); - advanced_paned->pack1(*timespan_vbox, true, false); - - Gtk::VBox* channels_vbox = Gtk::manage (new Gtk::VBox()); - channels_vbox->set_spacing (12); - channels_vbox->set_border_width (12); - - Gtk::Alignment * channels_align = Gtk::manage (new Gtk::Alignment()); - channels_label = Gtk::manage (new Gtk::Label (_("Channels"), Gtk::ALIGN_LEFT)); - channels_align->add (*channel_selector); - channels_align->set_padding (0, 12, 18, 0); - channels_vbox->pack_start (*channels_label, false, false, 0); - channels_vbox->pack_start (*channels_align, true, true, 0); - advanced_paned->pack2(*channels_vbox, channel_selector_is_expandable(), false); - - get_vbox()->pack_start (*file_notebook, false, false, 0); - get_vbox()->pack_start (warning_widget, false, false, 0); - get_vbox()->pack_start (progress_widget, false, false, 0); - - advanced = Gtk::manage (new Gtk::Expander (_("Time span and channel options"))); - advanced->property_expanded().signal_changed().connect( - sigc::mem_fun(*this, &ExportDialog::expanded_changed)); - advanced->add (*advanced_paned); - - if (channel_selector_is_expandable()) { - advanced_sizegroup = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_VERTICAL); - advanced_sizegroup->add_widget(*timespan_selector); - advanced_sizegroup->add_widget(*channel_selector); - } - get_vbox()->pack_start (*advanced, true, true); + Gtk::VBox * file_format_selector = Gtk::manage (new Gtk::VBox()); + file_format_selector->set_homogeneous (false); + file_format_selector->pack_start (*preset_align, false, false, 0); + file_format_selector->pack_start (*file_notebook, false, false, 0); + file_format_selector->pack_start (*soundcloud_selector, false, false, 0); - Pango::AttrList bold; - Pango::Attribute b = Pango::Attribute::create_attr_weight (Pango::WEIGHT_BOLD); - bold.insert (b); + export_notebook.append_page (*file_format_selector, _("File format")); + export_notebook.append_page (*timespan_selector, _("Time Span")); + export_notebook.append_page (*channel_selector, _("Channels")); + + get_vbox()->pack_start (export_notebook, true, true, 0); + get_vbox()->pack_end (warning_widget, false, false, 0); + get_vbox()->pack_end (progress_widget, false, false, 0); - timespan_label->set_attributes (bold); - channels_label->set_attributes (bold); } void @@ -211,6 +169,7 @@ ExportDialog::init_components () preset_selector.reset (new ExportPresetSelector ()); timespan_selector.reset (new ExportTimespanSelectorMultiple (_session, profile_manager)); channel_selector.reset (new PortExportChannelSelector (_session, profile_manager)); + soundcloud_selector.reset (new SoundcloudExportSelector ()); file_notebook.reset (new ExportFileNotebook ()); } @@ -301,10 +260,33 @@ ExportDialog::show_conflicting_files () } void +ExportDialog::soundcloud_upload_progress(double total, double now, std::string title) +{ + soundcloud_selector->do_progress_callback(total, now, title); + +} + +void ExportDialog::do_export () { try { profile_manager->prepare_for_export (); + handler->upload_username = soundcloud_selector->username(); + handler->upload_password = soundcloud_selector->password(); + handler->upload_public = soundcloud_selector->upload_public(); + handler->upload_open = soundcloud_selector->upload_open(); + + handler->SoundcloudProgress.connect_same_thread( + *this, + boost::bind(&ExportDialog::soundcloud_upload_progress, this, _1, _2, _3) + ); +#if 0 + handler->SoundcloudProgress.connect( + *this, invalidator (*this), + boost::bind(&ExportDialog::soundcloud_upload_progress, this, _1, _2, _3), + gui_context() + ); +#endif handler->do_export (); show_progress (); } catch(std::exception & e) { @@ -418,6 +400,7 @@ ExportRangeDialog::init_components () preset_selector.reset (new ExportPresetSelector ()); timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, range_id)); channel_selector.reset (new PortExportChannelSelector (_session, profile_manager)); + soundcloud_selector.reset (new SoundcloudExportSelector ()); file_notebook.reset (new ExportFileNotebook ()); } @@ -431,6 +414,7 @@ ExportSelectionDialog::init_components () preset_selector.reset (new ExportPresetSelector ()); timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, X_("selection"))); channel_selector.reset (new PortExportChannelSelector (_session, profile_manager)); + soundcloud_selector.reset (new SoundcloudExportSelector ()); file_notebook.reset (new ExportFileNotebook ()); } @@ -444,8 +428,7 @@ void ExportRegionDialog::init_gui () { ExportDialog::init_gui (); - - channels_label->set_text (_("Source")); + export_notebook.set_tab_label_text(*export_notebook.get_nth_page(2), _("Source")); } void @@ -456,6 +439,7 @@ ExportRegionDialog::init_components () preset_selector.reset (new ExportPresetSelector ()); timespan_selector.reset (new ExportTimespanSelectorSingle (_session, profile_manager, loc_id)); channel_selector.reset (new RegionExportChannelSelector (_session, profile_manager, region, track)); + soundcloud_selector.reset (new SoundcloudExportSelector ()); file_notebook.reset (new ExportFileNotebook ()); } @@ -471,5 +455,6 @@ StemExportDialog::init_components () preset_selector.reset (new ExportPresetSelector ()); timespan_selector.reset (new ExportTimespanSelectorMultiple (_session, profile_manager)); channel_selector.reset (new TrackExportChannelSelector (_session, profile_manager)); + soundcloud_selector.reset (new SoundcloudExportSelector ()); file_notebook.reset (new ExportFileNotebook ()); } diff --git a/gtk2_ardour/export_dialog.h b/gtk2_ardour/export_dialog.h index 756a3e7b53..315780750e 100644 --- a/gtk2_ardour/export_dialog.h +++ b/gtk2_ardour/export_dialog.h @@ -32,6 +32,7 @@ #include "export_file_notebook.h" #include "export_preset_selector.h" #include "ardour_dialog.h" +#include "soundcloud_export_selector.h" #include <gtkmm.h> @@ -43,7 +44,8 @@ namespace ARDOUR { class ExportTimespanSelector; class ExportChannelSelector; -class ExportDialog : public ArdourDialog { +class ExportDialog : public ArdourDialog, public PBD::ScopedConnectionList +{ public: @@ -75,26 +77,22 @@ class ExportDialog : public ArdourDialog { // Must initialize all the shared_ptrs below virtual void init_components (); - // Override if the channel selector should not be grown - virtual bool channel_selector_is_expandable() { return true; } - boost::scoped_ptr<ExportPresetSelector> preset_selector; boost::scoped_ptr<ExportTimespanSelector> timespan_selector; boost::scoped_ptr<ExportChannelSelector> channel_selector; boost::scoped_ptr<ExportFileNotebook> file_notebook; + boost::scoped_ptr<SoundcloudExportSelector> soundcloud_selector; Gtk::VBox warning_widget; Gtk::VBox progress_widget; - Gtk::Label * timespan_label; - Gtk::Label * channels_label; + /*** GUI components ***/ + Gtk::Notebook export_notebook; private: void init (); - void expanded_changed(); - void notify_errors (bool force = false); void close_dialog (); @@ -112,10 +110,7 @@ class ExportDialog : public ArdourDialog { PublicEditor & editor; StatusPtr status; - /*** GUI components ***/ - Glib::RefPtr<Gtk::SizeGroup> advanced_sizegroup; - Gtk::Expander * advanced; /* Warning area */ @@ -138,6 +133,8 @@ class ExportDialog : public ArdourDialog { float previous_progress; // Needed for gtk bug workaround + void soundcloud_upload_progress(double total, double now, std::string title); + /* Buttons */ Gtk::Button * cancel_button; @@ -170,9 +167,6 @@ class ExportRegionDialog : public ExportDialog public: ExportRegionDialog (PublicEditor & editor, ARDOUR::AudioRegion const & region, ARDOUR::AudioTrack & track); - protected: - virtual bool channel_selector_is_expandable() { return false; } - private: void init_gui (); void init_components (); diff --git a/gtk2_ardour/export_format_dialog.cc b/gtk2_ardour/export_format_dialog.cc index c5d1573d54..69c494e090 100644 --- a/gtk2_ardour/export_format_dialog.cc +++ b/gtk2_ardour/export_format_dialog.cc @@ -51,6 +51,9 @@ ExportFormatDialog::ExportFormatDialog (FormatPtr format, bool new_dialog) : silence_end_checkbox (_("Add silence at end:")), silence_end_clock ("silence_end", true, "", true, false, true), + upload_checkbox(_("Upload to Soundcloud")), + command_label(_("Command to run post-export\n(%f=full path & filename, %d=directory, %b=basename, %u=username, %p=password):")), + format_table (3, 4), compatibility_label (_("Compatibility"), Gtk::ALIGN_LEFT), quality_label (_("Quality"), Gtk::ALIGN_LEFT), @@ -113,6 +116,10 @@ ExportFormatDialog::ExportFormatDialog (FormatPtr format, bool new_dialog) : silence_table.attach (silence_end_checkbox, 1, 2, 2, 3); silence_table.attach (silence_end_clock, 2, 3, 2, 3); + get_vbox()->pack_start (upload_checkbox, false, false); + get_vbox()->pack_start (command_label, false, false); + get_vbox()->pack_start (command_entry, false, false); + /* Format table */ init_format_table(); @@ -142,6 +149,8 @@ ExportFormatDialog::ExportFormatDialog (FormatPtr format, bool new_dialog) : with_cue.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_cue)); with_toc.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_toc)); + upload_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_upload)); + command_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_command)); cue_toc_vbox.pack_start (with_cue, false, false); cue_toc_vbox.pack_start (with_toc, false, false); @@ -296,6 +305,8 @@ ExportFormatDialog::load_state (FormatPtr spec) } tag_checkbox.set_active (spec->tag()); + upload_checkbox.set_active (spec->upload()); + command_entry.set_text (spec->command()); } void @@ -718,6 +729,18 @@ ExportFormatDialog::update_with_toc () } void +ExportFormatDialog::update_upload () +{ + manager.select_upload (upload_checkbox.get_active()); +} + +void +ExportFormatDialog::update_command () +{ + manager.set_command (command_entry.get_text()); +} + +void ExportFormatDialog::update_description() { std::string text = ": " + format->description(false); diff --git a/gtk2_ardour/export_format_dialog.h b/gtk2_ardour/export_format_dialog.h index 8d37ded2cd..42ed1a9886 100644 --- a/gtk2_ardour/export_format_dialog.h +++ b/gtk2_ardour/export_format_dialog.h @@ -175,6 +175,12 @@ class ExportFormatDialog : public ArdourDialog, public PBD::ScopedConnectionList Gtk::CheckButton silence_end_checkbox; AudioClock silence_end_clock; + /* Upload */ + + Gtk::CheckButton upload_checkbox; + Gtk::Label command_label; + Gtk::Entry command_entry; + /* Format table */ struct CompatibilityCols : public Gtk::TreeModelColumnRecord @@ -307,6 +313,8 @@ class ExportFormatDialog : public ArdourDialog, public PBD::ScopedConnectionList void update_with_toc (); void update_with_cue (); + void update_upload (); + void update_command (); Gtk::TreeView sample_format_view; Gtk::TreeView dither_type_view; diff --git a/gtk2_ardour/export_range_markers_dialog.cc b/gtk2_ardour/export_range_markers_dialog.cc index 4b99162974..e69de29bb2 100644 --- a/gtk2_ardour/export_range_markers_dialog.cc +++ b/gtk2_ardour/export_range_markers_dialog.cc @@ -1,209 +0,0 @@ -/* - Copyright (C) 2006 Paul Davis - Author: Andre Raue - - 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 <sys/stat.h> - -#include <sstream> - -#include "ardour/audioengine.h" -#include "ardour/sndfile_helpers.h" - -#include "ardour_ui.h" -#include "export_range_markers_dialog.h" - -#include "i18n.h" - -using namespace Gtk; -using namespace ARDOUR; -using namespace PBD; -using namespace std; - -ExportRangeMarkersDialog::ExportRangeMarkersDialog (PublicEditor& editor) - : ExportDialog(editor) -{ - set_title (_("Export Ranges")); - file_frame.set_label (_("Export to Directory")); - - do_not_allow_export_cd_markers(); - - total_duration = 0; - current_range_marker_index = 0; -} - -Gtk::FileChooserAction -ExportRangeMarkersDialog::browse_action () const -{ - return Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER; -} - -void -ExportRangeMarkersDialog::export_data () -{ - getSession().locations()->apply(*this, &ExportRangeMarkersDialog::process_range_markers_export); -} - -void -ExportRangeMarkersDialog::process_range_markers_export(Locations::LocationList& locations) -{ - Locations::LocationList::iterator locationIter; - current_range_marker_index = 0; - init_progress_computing(locations); - - for (locationIter = locations.begin(); locationIter != locations.end(); ++locationIter) { - Location *currentLocation = (*locationIter); - - if(currentLocation->is_range_marker()){ - // init filename - string filepath = get_target_filepath( - get_selected_file_name(), - currentLocation->name(), - get_selected_header_format()); - - initSpec(filepath); - - spec.start_frame = currentLocation->start(); - spec.end_frame = currentLocation->end(); - - if (getSession().start_export(spec)){ - // if export fails - return; - } - - // wait until export of this range finished - gtk_main_iteration(); - - while (spec.running){ - if(gtk_events_pending()){ - gtk_main_iteration(); - }else { - usleep(10000); - } - } - - current_range_marker_index++; - - getSession().stop_export (spec); - } - } - - spec.running = false; -} - - -string -ExportRangeMarkersDialog::get_target_filepath(string path, string filename, string postfix) -{ - string target_path = path; - if ((target_path.find_last_of ('/')) != string::npos) { - target_path += '/'; - } - - string target_filepath = target_path + filename + postfix; - struct stat statbuf; - - for(int counter=1; (stat (target_filepath.c_str(), &statbuf) == 0); counter++){ - // while file exists - ostringstream scounter; - scounter.flush(); - scounter << counter; - - target_filepath = - target_path + filename + "_" + scounter.str() + postfix; - } - - return target_filepath; -} - -bool -ExportRangeMarkersDialog::is_filepath_valid(string &filepath) -{ - // sanity check file name first - struct stat statbuf; - - if (filepath.empty()) { - // warning dialog - string txt = _("Please enter a valid target directory."); - MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); - msg.run(); - return false; - } - - if ( (stat (filepath.c_str(), &statbuf) != 0) || - (!S_ISDIR (statbuf.st_mode)) ) { - string txt = _("Please select an existing target directory. Files are not allowed!"); - MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); - msg.run(); - return false; - } - - // directory needs to exist and be writable - string dirpath = Glib::path_get_dirname (filepath); - if (!exists_and_writable (dirpath)) { - string txt = _("Cannot write file in: ") + dirpath; - MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true); - msg.run(); - return false; - } - - return true; -} - -void -ExportRangeMarkersDialog::init_progress_computing(Locations::LocationList& locations) -{ - // flush vector - range_markers_durations_aggregated.resize(0); - - framecnt_t duration_before_current_location = 0; - Locations::LocationList::iterator locationIter; - - for (locationIter = locations.begin(); locationIter != locations.end(); ++locationIter) { - Location *currentLocation = (*locationIter); - - if(currentLocation->is_range_marker()){ - range_markers_durations_aggregated.push_back (duration_before_current_location); - - framecnt_t duration = currentLocation->end() - currentLocation->start(); - - range_markers_durations.push_back (duration); - duration_before_current_location += duration; - } - } - - total_duration = duration_before_current_location; -} - - -gint -ExportRangeMarkersDialog::progress_timeout () -{ - double progress = 0.0; - - if (current_range_marker_index >= range_markers_durations.size()){ - progress = 1.0; - } else{ - progress = ((double) range_markers_durations_aggregated[current_range_marker_index] + - (spec.progress * (double) range_markers_durations[current_range_marker_index])) / - (double) total_duration; - } - - set_progress_fraction( progress ); - return TRUE; -} diff --git a/gtk2_ardour/export_range_markers_dialog.h b/gtk2_ardour/export_range_markers_dialog.h index b0a29b5dc2..e69de29bb2 100644 --- a/gtk2_ardour/export_range_markers_dialog.h +++ b/gtk2_ardour/export_range_markers_dialog.h @@ -1,66 +0,0 @@ -/* - Copyright (C) 2006 Andre Raue - - 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 __export_range_markers_dialog_h__ -#define __export_range_markers_dialog_h__ - -#include "ardour/location.h" - -#include "export_dialog.h" - - -class ExportRangeMarkersDialog : public ExportDialog -{ - public: - ExportRangeMarkersDialog (PublicEditor&); - - Gtk::FileChooserAction browse_action() const; - - protected: - virtual bool is_filepath_valid(string &filepath); - - void export_data(); - - bool wants_dir() { return true; } - - private: - // keeps the duration of all range_markers before the current - vector<nframes_t> range_markers_durations_aggregated; - vector<nframes_t> range_markers_durations; - // duration of all range markers - nframes_t total_duration; - // index of range marker, that get's exported right now - unsigned int current_range_marker_index; - - // sets value of progress bar - virtual gint progress_timeout (); - - // initializes range_markers_durations_aggregated, range_markers_durations - // and total_duration - void init_progress_computing(ARDOUR::Locations::LocationList& locations); - - // searches for a filename like "<filename><nr>.<postfix>" in path, that - // does not exist - string get_target_filepath(string path, string filename, string postfix); - - void process_range_markers_export(ARDOUR::Locations::LocationList&); -}; - - -#endif // __export_range_markers_dialog_h__ diff --git a/gtk2_ardour/export_timespan_selector.cc b/gtk2_ardour/export_timespan_selector.cc index f239ab194b..53b7dc9fe0 100644 --- a/gtk2_ardour/export_timespan_selector.cc +++ b/gtk2_ardour/export_timespan_selector.cc @@ -105,6 +105,9 @@ ExportTimespanSelector::ExportTimespanSelector (ARDOUR::Session * session, Profi /* Range view */ range_list = Gtk::ListStore::create (range_cols); + // order by location start times + range_list->set_sort_column(range_cols.location, Gtk::SORT_ASCENDING); + range_list->set_sort_func(range_cols.location, sigc::mem_fun(*this, &ExportTimespanSelector::location_sorter)); range_view.set_model (range_list); range_view.set_headers_visible (true); } @@ -114,6 +117,22 @@ ExportTimespanSelector::~ExportTimespanSelector () } +int +ExportTimespanSelector::location_sorter(Gtk::TreeModel::iterator a, Gtk::TreeModel::iterator b) +{ + Location *l1 = (*a)[range_cols.location]; + Location *l2 = (*b)[range_cols.location]; + const Location *ls = _session->locations()->session_range_location(); + + // always sort session range first + if (l1 == ls) + return -1; + if (l2 == ls) + return +1; + + return l1->start() - l2->start(); +} + void ExportTimespanSelector::add_range_to_selection (ARDOUR::Location const * loc) { diff --git a/gtk2_ardour/export_timespan_selector.h b/gtk2_ardour/export_timespan_selector.h index 2118a57b83..1c4a952913 100644 --- a/gtk2_ardour/export_timespan_selector.h +++ b/gtk2_ardour/export_timespan_selector.h @@ -84,6 +84,7 @@ class ExportTimespanSelector : public Gtk::VBox, public ARDOUR::SessionHandlePtr void update_range_name (std::string const & path, std::string const & new_text); void set_selection_state_of_all_timespans (bool); + int location_sorter(Gtk::TreeModel::iterator a, Gtk::TreeModel::iterator b); /*** GUI components ***/ @@ -127,7 +128,7 @@ class ExportTimespanSelector : public Gtk::VBox, public ARDOUR::SessionHandlePtr Gtk::ScrolledWindow range_scroller; }; -/// Allows seleting multiple timespans +/// Allows selecting multiple timespans class ExportTimespanSelectorMultiple : public ExportTimespanSelector { public: diff --git a/gtk2_ardour/icons/soundcloud.png b/gtk2_ardour/icons/soundcloud.png Binary files differnew file mode 100644 index 0000000000..39c50fe7b3 --- /dev/null +++ b/gtk2_ardour/icons/soundcloud.png diff --git a/gtk2_ardour/soundcloud_export_selector.cc b/gtk2_ardour/soundcloud_export_selector.cc new file mode 100644 index 0000000000..1ecab514ab --- /dev/null +++ b/gtk2_ardour/soundcloud_export_selector.cc @@ -0,0 +1,110 @@ +/* soundcloud_export_selector.cpp *************************************************** + + Adapted for Ardour by Ben Loftis, March 2012 + + Licence GPL: + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +*************************************************************************************/ +#include "ardour/soundcloud_upload.h" +#include "soundcloud_export_selector.h" + +#include <pbd/error.h> +#include "pbd/openuri.h" + +#include <sys/stat.h> +#include <sys/types.h> +#include <iostream> +#include <glib/gstdio.h> + +#include "i18n.h" + +using namespace PBD; + +#include "ardour/session_metadata.h" +#include "utils.h" + +SoundcloudExportSelector::SoundcloudExportSelector() : + sc_table (4, 3), + soundcloud_public_checkbox (_("Make file(s) public")), + soundcloud_username_label (_("User Email"), 1.0, 0.5), + soundcloud_password_label (_("Password"), 1.0, 0.5), + soundcloud_open_checkbox (_("Open uploaded files in browser")), + progress_bar() +{ + + + soundcloud_public_checkbox.set_name ("ExportCheckbox"); + soundcloud_username_label.set_name ("ExportFormatLabel"); + soundcloud_username_entry.set_name ("ExportFormatDisplay"); + soundcloud_password_label.set_name ("ExportFormatLabel"); + soundcloud_password_entry.set_name ("ExportFormatDisplay"); + + soundcloud_username_entry.set_text (ARDOUR::SessionMetadata::Metadata()->user_email()); + soundcloud_password_entry.set_visibility(false); + + Gtk::Frame *sc_frame = manage(new Gtk::Frame); + sc_frame->set_border_width(4); + sc_frame->set_shadow_type(Gtk::SHADOW_ETCHED_OUT); + sc_frame->set_name("soundcloud_export_box"); + pack_start(*sc_frame, false, false); + + sc_table.set_border_width(4); + sc_table.set_col_spacings (5); + sc_table.set_row_spacings (5); + sc_frame->add (sc_table); + + // sc_table.attach ( *( manage (new EventBox (::get_icon (X_("soundcloud"))))) , 0, 1, 0, 1); + sc_table.attach ( *(Gtk::manage (new Gtk::Image (get_icon (X_("soundcloud"))))) , 0, 1, 0, 2); + + sc_table.attach (soundcloud_public_checkbox, 2, 3, 1, 2); + sc_table.attach (soundcloud_username_label, 0, 1, 3, 4); + sc_table.attach (soundcloud_username_entry, 1, 3, 3, 4); + sc_table.attach (soundcloud_password_label, 0, 1, 5, 6); + sc_table.attach (soundcloud_password_entry, 1, 3, 5, 6); + sc_table.attach (soundcloud_open_checkbox, 2, 3, 7, 8); + + pack_end(progress_bar, false, false); + sc_frame->show_all(); +} + + +int +SoundcloudExportSelector::do_progress_callback(double ultotal, double ulnow, const std::string &filename) +{ + std::cerr << "SoundcloudExportSelector::do_progress_callback(" << ultotal << ", " << ulnow << ", " << filename << ")..." << std::endl; + if (soundcloud_cancel) { + progress_bar.set_fraction (0); + // cancel_button.set_label (""); + return -1; + } + + double fraction = 0.0; + if (ultotal != 0) { + fraction = ulnow / ultotal; + } + + progress_bar.set_fraction ( fraction ); + + std::string prog; + prog = string_compose (_("%1: %2 of %3 bytes uploaded"), filename, ulnow, ultotal); + progress_bar.set_text( prog ); + + + return 0; +} + diff --git a/gtk2_ardour/soundcloud_export_selector.h b/gtk2_ardour/soundcloud_export_selector.h new file mode 100644 index 0000000000..7962ba8b06 --- /dev/null +++ b/gtk2_ardour/soundcloud_export_selector.h @@ -0,0 +1,41 @@ +/*soundcloud_export_selector.h*********************************************** + + Adapted for Ardour by Ben Loftis, March 2012 + +*****************************************************************************/ + +#include <string> +#include <fstream> +#include <iostream> +#include <stdio.h> +#include <cstring> +#include <string> +#include <sstream> +#include <vector> +#include <gtkmm.h> +#include <gtkmm/progressbar.h> + +class SoundcloudExportSelector : public Gtk::VBox, public ARDOUR::SessionHandlePtr +{ + public: + SoundcloudExportSelector (); + int do_progress_callback (double ultotal, double ulnow, const std::string &filename); + std::string username () { return soundcloud_username_entry.get_text (); } + std::string password () { return soundcloud_password_entry.get_text (); } + bool upload_public () { return soundcloud_public_checkbox.get_active (); } + bool upload_open () { return soundcloud_open_checkbox.get_active (); } + void cancel () { soundcloud_cancel = true; } + + private: + Gtk::Table sc_table; + Gtk::CheckButton soundcloud_public_checkbox; + Gtk::Label soundcloud_username_label; + Gtk::Entry soundcloud_username_entry; + Gtk::Label soundcloud_password_label; + Gtk::Entry soundcloud_password_entry; + Gtk::CheckButton soundcloud_open_checkbox; + bool soundcloud_cancel; + Gtk::ProgressBar progress_bar; + +}; + diff --git a/gtk2_ardour/system_exec.cc b/gtk2_ardour/system_exec.cc deleted file mode 100644 index 59f3647e51..0000000000 --- a/gtk2_ardour/system_exec.cc +++ /dev/null @@ -1,808 +0,0 @@ -/* - Copyright (C) 2010 Paul Davis - Copyright 2005-2008 Lennart Poettering - Author: Robin Gareus <robin@gareus.org> - - 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> - -#include <assert.h> -#include <dirent.h> - -#ifdef __WIN32__ -#include <windows.h> -#else -#include <fcntl.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <sys/resource.h> -#endif - - -#include "system_exec.h" - -using namespace std; -void * interposer_thread (void *arg); - -static void close_fd (int& fd) { if (fd >= 0) ::close (fd); fd = -1; } - -#ifndef __WIN32__ -/* - * This function was part of libasyncns. - * LGPL v2.1 - * Copyright 2005-2008 Lennart Poettering - */ -static int close_allv(const int except_fds[]) { - struct rlimit rl; - int fd; - -#ifdef __linux__ - - DIR *d; - - assert(except_fds); - - if ((d = opendir("/proc/self/fd"))) { - struct dirent *de; - - while ((de = readdir(d))) { - int found; - long l; - char *e = NULL; - int i; - - if (de->d_name[0] == '.') - continue; - - errno = 0; - l = strtol(de->d_name, &e, 10); - if (errno != 0 || !e || *e) { - closedir(d); - errno = EINVAL; - return -1; - } - - fd = (int) l; - - if ((long) fd != l) { - closedir(d); - errno = EINVAL; - return -1; - } - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - found = 0; - for (i = 0; except_fds[i] >= 0; i++) - if (except_fds[i] == fd) { - found = 1; - break; - } - - if (found) continue; - - if (close(fd) < 0) { - int saved_errno; - - saved_errno = errno; - closedir(d); - errno = saved_errno; - - return -1; - } - } - - closedir(d); - return 0; - } - -#endif - - if (getrlimit(RLIMIT_NOFILE, &rl) < 0) - return -1; - - for (fd = 0; fd < (int) rl.rlim_max; fd++) { - int i; - - if (fd <= 3) - continue; - - for (i = 0; except_fds[i] >= 0; i++) - if (except_fds[i] == fd) - continue; - - if (close(fd) < 0 && errno != EBADF) - return -1; - } - - return 0; -} -#endif /* not on windows */ - - -SystemExec::SystemExec (std::string c, std::string a) - : cmd(c) -{ - pthread_mutex_init(&write_lock, NULL); - thread_active=false; - pid = 0; - pin[1] = -1; - nicelevel = 0; - envp = NULL; - argp = NULL; -#ifdef __WIN32__ - stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE; - stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE; - stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE; -#endif - make_envp(); - make_argp(a); -} - -SystemExec::SystemExec (std::string c, char **a) - : cmd(c) , argp(a) -{ - pthread_mutex_init(&write_lock, NULL); - thread_active=false; - pid = 0; - pin[1] = -1; - nicelevel = 0; - envp = NULL; -#ifdef __WIN32__ - stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE; - stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE; - stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE; - make_wargs(a); -#endif - make_envp(); -} - -SystemExec::~SystemExec () -{ - terminate (); - if (envp) { - for (int i=0;envp[i];++i) { - free(envp[i]); - } - free (envp); - } - if (argp) { - for (int i=0;argp[i];++i) { - free(argp[i]); - } - free (argp); - } -#ifdef __WIN32__ - if (w_args) free(w_args); -#endif - pthread_mutex_destroy(&write_lock); -} - -void * -interposer_thread (void *arg) { - SystemExec *sex = static_cast<SystemExec *>(arg); - sex->output_interposer(); - pthread_exit(0); - return 0; -} - -#ifdef __WIN32__ /* Windows Process */ - -/* HELPER FUNCTIONS */ - -static void create_pipe (HANDLE *pipe, bool in) { - SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE }; - HANDLE tmpHandle; - if (in) { - if (!CreatePipe(&pipe[0], &tmpHandle, &secAtt, 1024 * 1024)) return; - if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(), &pipe[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) return; - } else { - if (!CreatePipe(&tmpHandle, &pipe[1], &secAtt, 1024 * 1024)) return; - if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(), &pipe[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) return; - } - CloseHandle(tmpHandle); -} - -static void destroy_pipe (HANDLE pipe[2]) { - if (pipe[0] != INVALID_HANDLE_VALUE) { - CloseHandle(pipe[0]); - pipe[0] = INVALID_HANDLE_VALUE; - } - if (pipe[1] != INVALID_HANDLE_VALUE) { - CloseHandle(pipe[1]); - pipe[1] = INVALID_HANDLE_VALUE; - } -} - -static BOOL CALLBACK my_terminateApp(HWND hwnd, LPARAM procId) -{ - DWORD currentProcId = 0; - GetWindowThreadProcessId(hwnd, ¤tProcId); - if (currentProcId == (DWORD)procId) - PostMessage(hwnd, WM_CLOSE, 0, 0); - return TRUE; -} - -/* PROCESS API */ - -void -SystemExec::make_envp() { - ;/* environemt is copied over with CreateProcess(...,env=0 ,..) */ -} - -void -SystemExec::make_wargs(char **a) { - std::string wa = cmd; - if (cmd[0] != '"' && cmd[cmd.size()] != '"' && strchr(cmd.c_str(), ' ')) { wa = "\"" + cmd + "\""; } - std::replace(cmd.begin(), cmd.end(), '/', '\\' ); - char **tmp = a; - while (tmp && *tmp) { - wa.append(" \""); - wa.append(*tmp); - wa.append("\""); - tmp++; - } - w_args = strdup(wa.c_str()); -} - -void -SystemExec::make_argp(std::string args) { - std::string wa = cmd; - if (cmd[0] != '"' && cmd[cmd.size()] != '"' && strchr(cmd.c_str(), ' ')) { wa = "\"" + cmd + "\""; } - std::replace(cmd.begin(), cmd.end(), '/', '\\' ); - wa.append(" "); - wa.append(args); - w_args = strdup(wa.c_str()); -} - -void -SystemExec::terminate () -{ - ::pthread_mutex_lock(&write_lock); - if (pid) { - /* terminate */ - EnumWindows(my_terminateApp, (LPARAM)pid->dwProcessId); - PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0); - - /* kill ! */ - TerminateProcess(pid->hProcess, 0xf291); - - CloseHandle(pid->hThread); - CloseHandle(pid->hProcess); - destroy_pipe(stdinP); - destroy_pipe(stdoutP); - destroy_pipe(stderrP); - delete pid; - pid=0; - } - ::pthread_mutex_unlock(&write_lock); -} - -int -SystemExec::wait (int options) -{ - while (is_running()) { - WaitForSingleObject(pid->hProcess, INFINITE); - Sleep(20); - } - return 0; -} - -bool -SystemExec::is_running () -{ - return pid?true:false; -} - -int -SystemExec::start (int stderr_mode) -{ - char* working_dir = 0; - - if (pid) { return 0; } - - pid = new PROCESS_INFORMATION; - memset(pid, 0, sizeof(PROCESS_INFORMATION)); - - create_pipe(stdinP, true); - create_pipe(stdoutP, false); - - if (stderr_mode == 2) { - /* merge stout & stderr */ - DuplicateHandle(GetCurrentProcess(), stdoutP[1], GetCurrentProcess(), &stderrP[1], 0, TRUE, DUPLICATE_SAME_ACCESS); - } else if (stderr_mode == 1) { - //TODO read/flush this pipe or close it... - create_pipe(stderrP, false); - } else { - //TODO: keep stderr of this process mode. - } - - bool success = false; - STARTUPINFOA startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, - (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT, - (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT, - 0, 0, 0, - STARTF_USESTDHANDLES, - 0, 0, 0, - stdinP[0], stdoutP[1], stderrP[1] - }; - - success = CreateProcess(0, w_args, - 0, 0, /* bInheritHandles = */ TRUE, - (CREATE_NO_WINDOW&0) | CREATE_UNICODE_ENVIRONMENT | (0&CREATE_NEW_CONSOLE), - /*env = */ 0, - working_dir, - &startupInfo, pid); - - if (stdinP[0] != INVALID_HANDLE_VALUE) { - CloseHandle(stdinP[0]); - stdinP[0] = INVALID_HANDLE_VALUE; - } - if (stdoutP[1] != INVALID_HANDLE_VALUE) { - CloseHandle(stdoutP[1]); - stdoutP[1] = INVALID_HANDLE_VALUE; - } - if (stderrP[1] != INVALID_HANDLE_VALUE) { - CloseHandle(stderrP[1]); - stderrP[1] = INVALID_HANDLE_VALUE; - } - - if (!success) { - CloseHandle(pid->hThread); - CloseHandle(pid->hProcess); - destroy_pipe(stdinP); - destroy_pipe(stdoutP); - destroy_pipe(stderrP); - delete pid; - pid=0; - return -1; - } - - int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this); - thread_active=true; - if (rv) { - thread_active=false; - terminate(); - return -2; - } - Sleep(20); - return 0; -} - -void -SystemExec::output_interposer() -{ - DWORD bytesRead = 0; - char data[BUFSIZ]; -#if 0 // untested code to set up nonblocking - unsigned long l = 1; - ioctlsocket(stdoutP[0], FIONBIO, &l); -#endif - while(1) { -#if 0 // for non-blocking pipes.. - DWORD bytesAvail = 0; - PeekNamedPipe(stdoutP[0], 0, 0, 0, &bytesAvail, 0); - if (bytesAvail < 1) {Sleep(500); printf("N/A\n"); continue;} -#endif - if (stdoutP[0] == INVALID_HANDLE_VALUE) break; - if (!ReadFile(stdoutP[0], data, BUFSIZ, &bytesRead, 0)) break; - if (bytesRead < 1) continue; /* actually not needed; but this is safe. */ - data[bytesRead] = 0; - ReadStdout(data, bytesRead);/* EMIT SIGNAL */ - } - Terminated();/* EMIT SIGNAL */ -} - -void -SystemExec::close_stdin() -{ - if (stdinP[0]!= INVALID_HANDLE_VALUE) FlushFileBuffers(stdinP[0]); - if (stdinP[1]!= INVALID_HANDLE_VALUE) FlushFileBuffers(stdinP[1]); - Sleep(200); - destroy_pipe(stdinP); -} - -int -SystemExec::write_to_stdin(std::string d, size_t len) -{ - const char *data; - DWORD r,c; - - ::pthread_mutex_lock(&write_lock); - - data=d.c_str(); - if (len == 0) { - len=(d.length()); - } - c=0; - while (c < len) { - if (!WriteFile(stdinP[1], data+c, len-c, &r, NULL)) { - if (GetLastError() == 0xE8 /*NT_STATUS_INVALID_USER_BUFFER*/) { - Sleep(100); - continue; - } else { - fprintf(stderr, "SYSTEM-EXEC: stdin write error.\n"); - break; - } - } - c += r; - } - ::pthread_mutex_unlock(&write_lock); - return c; -} - - -/* end windows process */ -#else -/* UNIX/POSIX process */ - -extern char **environ; -void -SystemExec::make_envp() { - int i=0; - envp = (char **) calloc(1, sizeof(char*)); - /* copy current environment */ - for (i=0;environ[i];++i) { - envp[i] = strdup(environ[i]); - envp = (char **) realloc(envp, (i+2) * sizeof(char*)); - } - envp[i] = 0; -} - -void -SystemExec::make_argp(std::string args) { - int argn = 1; - char *cp1; - char *cp2; - - char *carg = strdup(args.c_str()); - - argp = (char **) malloc((argn + 1) * sizeof(char *)); - if (argp == (char **) 0) { - free(carg); - return; // FATAL - } - - argp[0] = strdup(cmd.c_str()); - - /* TODO: quotations and escapes - * http://stackoverflow.com/questions/1511797/convert-string-to-argv-in-c - * - * It's actually not needed. All relevant invocations specify 'argp' directly. - * Only 'xjadeo -L -R' uses this function and that uses neither quotations - * nor arguments with white-space. - */ - for (cp1 = cp2 = carg; *cp2 != '\0'; ++cp2) { - if (*cp2 == ' ') { - *cp2 = '\0'; - argp[argn++] = strdup(cp1); - cp1 = cp2 + 1; - argp = (char **) realloc(argp, (argn + 1) * sizeof(char *)); - } - } - if (cp2 != cp1) { - argp[argn++] = strdup(cp1); - argp = (char **) realloc(argp, (argn + 1) * sizeof(char *)); - } - argp[argn] = (char *) 0; - free(carg); -} - - - -void -SystemExec::terminate () -{ - ::pthread_mutex_lock(&write_lock); - - /* close stdin in an attempt to get the child to exit cleanly. - */ - - close_stdin(); - - if (pid) { - ::usleep(50000); - sched_yield(); - wait(WNOHANG); - } - - /* if pid is non-zero, the child task is still executing (i.e. it did - * not exit in response to stdin being closed). try to kill it. - */ - - if (pid) { - ::kill(pid, SIGTERM); - ::usleep(50000); - sched_yield(); - wait(WNOHANG); - } - - /* if pid is non-zero, the child task is STILL executing after being - * sent SIGTERM. Act tough ... send SIGKILL - */ - - if (pid) { - ::fprintf(stderr, "Process is still running! trying SIGKILL\n"); - ::kill(pid, SIGKILL); - } - - wait(); - if (thread_active) pthread_join(thread_id_tt, NULL); - thread_active = false; - ::pthread_mutex_unlock(&write_lock); -} - -int -SystemExec::wait (int options) -{ - int status=0; - int ret; - - if (pid==0) return -1; - - ret = waitpid (pid, &status, options); - - if (ret == pid) { - if (WEXITSTATUS(status) || WIFSIGNALED(status)) { - pid=0; - } - } else { - if (ret != 0) { - if (errno == ECHILD) { - /* no currently running children, reset pid */ - pid=0; - } - } /* else the process is still running */ - } - return status; -} - -bool -SystemExec::is_running () -{ - int status=0; - if (pid==0) return false; - if (::waitpid(pid, &status, WNOHANG)==0) return true; - return false; -} - -int -SystemExec::start (int stderr_mode) -{ - if (is_running()) { - return 0; // mmh what to return here? - } - int r; - - if (::pipe(pin) < 0 || ::pipe(pout) < 0 || ::pipe(pok) < 0) { - /* Something unexpected went wrong creating a pipe. */ - return -1; - } - - r = ::fork(); - if (r < 0) { - /* failed to fork */ - return -2; - } - - if (r > 0) { - /* main */ - pid=r; - - /* check if execve was successful. */ - close_fd(pok[1]); - char buf; - for ( ;; ) { - ssize_t n = ::read(pok[0], &buf, 1 ); - if ( n==1 ) { - /* child process returned from execve */ - pid=0; - close_fd(pok[0]); - close_fd(pin[1]); - close_fd(pin[0]); - close_fd(pout[1]); - close_fd(pout[0]); - pin[1] = -1; - return -3; - } else if ( n==-1 ) { - if ( errno==EAGAIN || errno==EINTR ) - continue; - } - break; - } - close_fd(pok[0]); - /* child started successfully */ - -#if 0 -/* use fork for output-interposer - * it will run in a separated process - */ - /* catch stdout thread */ - r = ::fork(); - if (r < 0) { - // failed to fork - terminate(); - return -2; - } - if (r == 0) { - /* 2nd child process - catch stdout */ - close_fd(pin[1]); - close_fd(pout[1]); - output_interposer(); - exit(0); - } - close_fd(pout[1]); - close_fd(pin[0]); - close_fd(pout[0]); -#else /* use pthread */ - close_fd(pout[1]); - close_fd(pin[0]); - int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this); - - thread_active=true; - if (rv) { - thread_active=false; - terminate(); - return -2; - } -#endif - return 0; /* all systems go - return to main */ - } - - /* child process - exec external process */ - close_fd(pok[0]); - ::fcntl(pok[1], F_SETFD, FD_CLOEXEC); - - close_fd(pin[1]); - if (pin[0] != STDIN_FILENO) { - ::dup2(pin[0], STDIN_FILENO); - } - close_fd(pin[0]); - close_fd(pout[0]); - if (pout[1] != STDOUT_FILENO) { - ::dup2(pout[1], STDOUT_FILENO); - } - - if (stderr_mode == 2) { - /* merge STDERR into output */ - if (pout[1] != STDERR_FILENO) { - ::dup2(pout[1], STDERR_FILENO); - } - } else if (stderr_mode == 1) { - /* ignore STDERR */ - ::close(STDERR_FILENO); - } else { - /* keep STDERR */ - } - - if (pout[1] != STDOUT_FILENO && pout[1] != STDERR_FILENO) { - close_fd(pout[1]); - } - - if (nicelevel !=0) { - ::nice(nicelevel); - } - -#if 0 - /* chdir to executable dir */ - char *directory; - directory = strdup(cmd.c_str()); - if (strrchr(directory, '/') != (char *) 0) { - ::chdir(directory); - } - free(directory); -#endif - -#ifdef HAVE_SIGSET - sigset(SIGPIPE, SIG_DFL); -#else - signal(SIGPIPE, SIG_DFL); -#endif - - int good_fds[1] = { -1 }; - close_allv(good_fds); - - ::execve(argp[0], argp, envp); - /* if we reach here something went wrong.. */ - char buf = 0; - (void) ::write(pok[1], &buf, 1 ); - close_fd(pok[1]); - exit(-1); - return -1; -} - -void -SystemExec::output_interposer() -{ - int rfd=pout[0]; - char buf[BUFSIZ]; - ssize_t r; - unsigned long l = 1; - - ioctl(rfd, FIONBIO, &l); // set non-blocking I/O - - for (;fcntl(rfd, F_GETFL)!=-1;) { - r = read(rfd, buf, sizeof(buf)); - if (r < 0 && (errno == EINTR || errno == EAGAIN)) { - ::usleep(1000); - continue; - } - if (r <= 0) { - break; - } - buf[r]=0; - std::string rv = std::string(buf,r); // TODO: check allocation strategy - ReadStdout(rv, r);/* EMIT SIGNAL */ - } - Terminated();/* EMIT SIGNAL */ -} - -void -SystemExec::close_stdin() -{ - if (pin[1]<0) return; - close_fd(pin[0]); - close_fd(pin[1]); - close_fd(pout[0]); - close_fd(pout[1]); -} - -int -SystemExec::write_to_stdin(std::string d, size_t len) -{ - const char *data; - ssize_t r; - size_t c; - ::pthread_mutex_lock(&write_lock); - - data=d.c_str(); - if (len == 0) { - len=(d.length()); - } - c=0; - while (c < len) { - for (;;) { - r=::write(pin[1], data+c, len-c); - if (r < 0 && (errno == EINTR || errno == EAGAIN)) { - sleep(1); - continue; - } - if ((size_t) r != (len-c)) { - ::pthread_mutex_unlock(&write_lock); - return c; - } - break; - } - c += r; - } - fsync(pin[1]); - ::pthread_mutex_unlock(&write_lock); - return c; -} - -#endif // end UNIX process diff --git a/gtk2_ardour/system_exec.h b/gtk2_ardour/system_exec.h deleted file mode 100644 index cf8518f547..0000000000 --- a/gtk2_ardour/system_exec.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - Copyright (C) 2010 Paul Davis - Author: Robin Gareus <robin@gareus.org> - - 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_system_exec_h__ -#define __ardour_system_exec_h__ - -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#endif -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif -#ifndef STDERR_FILENO -#define STDERR_FILENO 2 -#endif - -#include <string> -#include <pthread.h> -#include <signal.h> -#ifdef NOPBD /* outside ardour */ -#include <sigc++/bind.h> -#include <sigc++/signal.h> -#else -#include <pbd/signals.h> -#endif - -/** @class: SystemExec - * @brief execute an external command - * - * This class allows launche an external command-line application - * opening a full-duplex connection to its standard I/O. - * - * In Ardour context it is used to launch xjadeo and ffmpeg. - * - * The \ref write_to_stdin function provides for injecting data into STDIN - * of the child-application while output of the program to STDOUT/STDERR is - * forwarded using the \ref ReadStdout signal. - * \ref Terminated is sent if the child application exits. - * - */ -class SystemExec -{ - public: - /** prepare execution of a program with 'execve' - * - * This function takes over the existing environment variable and provides - * an easy way to speciy command-line arguments for the new process. - * - * Note: The argument parser does not interpret quotation-marks and splits - * arugments on whitespace. The argument string can be empty. - * The alternative constructor below allows to specify quoted parameters - * incl. whitespace. - * - * @param c program pathname that identifies the new process image file. - * @param a string of commandline-arguments to be passed to the new program. - */ - SystemExec (std::string c, std::string a = ""); - /** similar to \ref SystemExec but allows to specify custom arguments - * - * @param c program pathname that identifies the new process image file. - * @param a array of argument strings passed to the new program as 'argv'. - * it must be terminated by a null pointer (see the 'evecve' - * POSIX-C documentation for more information) - * The array must be dynamically allocated using malloc or strdup. - * Unless they're NULL, the array itself and each of its content - * memory is freed() in the destructor. - * - */ - SystemExec (std::string c, char ** a); - virtual ~SystemExec (); - - /** fork and execute the given program - * - * @param stderr_mode select what to do with program's standard error - * output: - * '0': keep STDERR; mix it with parent-process' STDERR - * '1': ignore STDERR of child-program - * '2': merge STDERR into STDOUT and send it with the - * ReadStdout signal. - * @return If the process is already running or was launched successfully - * the function returns zero (0). A negative number indicates an error. - */ - int start (int stderr_mode = 1); - /** kill running child-process - * - * if a child process exists trt to shut it down by closing its STDIN. - * if the program dies not react try SIGTERM and eventually SIGKILL - */ - void terminate (); - /** check if the child programm is (still) running. - * - * This function calls waitpid(WNOHANG) to check the state of the - * child-process. - * @return true if the program is (still) running. - */ - bool is_running (); - /** call the waitpid system-call with the pid of the child-program - * - * Basically what \ref terminate uses internally. - * - * This function is only useful if you want to control application - * termination yourself (eg timeouts or progress-dialog). - * @param option flags - see waitpid manual - * @return status info from waitpid call (not waitpid's return value) - * or -1 if the child-program is not running. - */ - int wait (int options=0); - /** closes both STDIN and STDOUT connections to/from - * the child-program. - * With the output-interposer thread gone, the program - * should terminate. - * used by \ref terminate() - */ - void close_stdin (); - /** write into child-program's STDIN - * @param d data to write - * @param len length of data to write, if it is 0 (zero), d.length() is - * used to determine the number of bytes to transmit. - * @return number of bytes written. - */ - int write_to_stdin (std::string d, size_t len=0); - - /** The ReadStdout signal is emitted when the application writes to STDOUT. - * it passes the written data and its length in bytes as arguments to the bound - * slot(s). - */ -#ifdef NOPBD /* outside ardour */ - sigc::signal<void, std::string,size_t> ReadStdout; -#else - PBD::Signal2<void, std::string,size_t> ReadStdout; -#endif - - /** The Terminated signal is emitted when application terminates. */ -#ifdef NOPBD /* outside ardour */ - sigc::signal<void> Terminated; -#else - PBD::Signal0<void> Terminated; -#endif - - /** interposer to emit signal for writes to STDOUT/ERR. - * - * Thread that reads the stdout of the forked - * process and signal-sends it to the main thread. - * It also emits the Terminated() signal once - * the the forked process closes it's stdout. - * - * Note: it's actually 'private' function but used - * by the internal pthread, which only has a pointer - * to this instance and thus can only access public fn. - */ - void output_interposer (); - - protected: - std::string cmd; ///< path to command - set when creating the class - int nicelevel; ///< process nice level - defaults to 0 - - void make_argp(std::string); - void make_envp(); - - char **argp; - char **envp; - - private: -#ifdef __WIN32__ - PROCESS_INFORMATION *pid; - HANDLE stdinP[2]; - HANDLE stdoutP[2]; - HANDLE stderrP[2]; - char *w_args; - void make_wargs(char **); -#else - pid_t pid; -#endif - pthread_mutex_t write_lock; - - int fdin; ///< file-descriptor for writing to child's STDIN. This variable is identical to pin[1] but also used as status check if the stdin pipe is open: <0 means closed. - int pok[2]; - int pin[2]; - int pout[2]; - - pthread_t thread_id_tt; - bool thread_active; -}; - -#endif /* __ardour_system_exec_h__ */ diff --git a/gtk2_ardour/transcode_ffmpeg.h b/gtk2_ardour/transcode_ffmpeg.h index 61267ac853..e25a68da91 100644 --- a/gtk2_ardour/transcode_ffmpeg.h +++ b/gtk2_ardour/transcode_ffmpeg.h @@ -22,7 +22,7 @@ #include <string> #include "ardour/types.h" -#include "system_exec.h" +#include "pbd/system_exec.h" /** @class TranscodeFfmpeg diff --git a/gtk2_ardour/video_monitor.h b/gtk2_ardour/video_monitor.h index 59264fa012..80273cf5e3 100644 --- a/gtk2_ardour/video_monitor.h +++ b/gtk2_ardour/video_monitor.h @@ -26,7 +26,7 @@ #include "ardour/types.h" #include "ardour/session.h" #include "ardour/session_handle.h" -#include "system_exec.h" +#include "pbd/system_exec.h" namespace ARDOUR { class Session; diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 9883fa49e2..aac1f3a49b 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -211,6 +211,7 @@ gtk2_ardour_sources = [ 'shuttle_control.cc', 'simpleline.cc', 'simplerect.cc', + 'soundcloud_export_selector.cc', 'splash.cc', 'speaker_dialog.cc', 'startup.cc', @@ -245,7 +246,6 @@ gtk2_ardour_sources = [ 'add_video_dialog.cc', 'editor_videotimeline.cc', 'video_timeline.cc', - 'system_exec.cc', 'video_monitor.cc', 'transcode_ffmpeg.cc', 'transcode_video_dialog.cc', |