Merge branch 'mingw-updates' of https://github.com/mojofunk/ardour into cairocanvas
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 19 May 2014 21:19:43 +0000 (17:19 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 19 May 2014 21:19:43 +0000 (17:19 -0400)
52 files changed:
export/Soundcloud upload (lossless).format [new file with mode: 0644]
export/Soundcloud upload (lossy).format [new file with mode: 0644]
gtk2_ardour/ardour_ui.cc
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_canvas.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/editor_rulers.cc
gtk2_ardour/export_channel_selector.cc
gtk2_ardour/export_channel_selector.h
gtk2_ardour/export_dialog.cc
gtk2_ardour/export_dialog.h
gtk2_ardour/export_format_dialog.cc
gtk2_ardour/export_format_dialog.h
gtk2_ardour/export_range_markers_dialog.cc
gtk2_ardour/export_range_markers_dialog.h
gtk2_ardour/export_timespan_selector.cc
gtk2_ardour/export_timespan_selector.h
gtk2_ardour/icons/soundcloud.png [new file with mode: 0644]
gtk2_ardour/linux_vst_gui_support.cc
gtk2_ardour/session_dialog.cc
gtk2_ardour/soundcloud_export_selector.cc [new file with mode: 0644]
gtk2_ardour/soundcloud_export_selector.h [new file with mode: 0644]
gtk2_ardour/wscript
libs/ardour/ardour/export_format_manager.h
libs/ardour/ardour/export_format_specification.h
libs/ardour/ardour/export_handler.h
libs/ardour/ardour/soundcloud_upload.h [new file with mode: 0644]
libs/ardour/ardour/system_exec.h
libs/ardour/audio_track.cc
libs/ardour/export_format_manager.cc
libs/ardour/export_format_specification.cc
libs/ardour/export_handler.cc
libs/ardour/soundcloud_upload.cc [new file with mode: 0644]
libs/ardour/system_exec.cc
libs/ardour/tempo.cc
libs/ardour/thread_buffers.cc
libs/ardour/vst_info_file.cc
libs/ardour/vst_plugin.cc
libs/ardour/wscript
libs/backends/dummy/dummy_audiobackend.cc
libs/backends/dummy/dummy_audiobackend.h
libs/backends/wavesaudio/wavesapi/miscutils/UMicroseconds.cpp
libs/fst/scanner.cc
libs/gtkmm2ext/gtkmm2ext/idle_adjustment.h
libs/gtkmm2ext/idle_adjustment.cc
libs/pbd/pbd/system_exec.h
libs/pbd/system_exec.cc
libs/surfaces/frontier/tranzport/tranzport_control_protocol.h
libs/surfaces/mackie/timer.h
libs/surfaces/tranzport/wheel.cc

diff --git a/export/Soundcloud upload (lossless).format b/export/Soundcloud upload (lossless).format
new file mode 100644 (file)
index 0000000..eb966af
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ExportFormatSpecification name="Soundcloud upload (lossless)" id="14f5b271-86b3-48c6-9ee2-133f46fe06c1" with-cue="false" with-toc="false" upload="true" command="">
+  <Encoding id="F_FLAC" type="T_Sndfile" extension="flac" name="FLAC" has-sample-format="true" channel-limit="8"/>
+  <SampleRate rate="1"/>
+  <SRCQuality quality="SRC_SincBest"/>
+  <EncodingOptions>
+    <Option name="sample-format" value="SF_16"/>
+    <Option name="dithering" value="D_Shaped"/>
+    <Option name="tag-metadata" value="true"/>
+    <Option name="tag-support" value="true"/>
+    <Option name="broadcast-info" value="false"/>
+  </EncodingOptions>
+  <Processing>
+    <Normalize enabled="false" target="1"/>
+    <Silence>
+      <Start>
+        <Trim enabled="false"/>
+        <Add enabled="false">
+          <Duration format="Timecode" hours="0" minutes="0" seconds="0" frames="0"/>
+        </Add>
+      </Start>
+      <End>
+        <Trim enabled="false"/>
+        <Add enabled="false">
+          <Duration format="Timecode" hours="0" minutes="0" seconds="0" frames="0"/>
+        </Add>
+      </End>
+    </Silence>
+  </Processing>
+</ExportFormatSpecification>
diff --git a/export/Soundcloud upload (lossy).format b/export/Soundcloud upload (lossy).format
new file mode 100644 (file)
index 0000000..d948b1d
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ExportFormatSpecification name="Soundcloud upload (lossy)" id="a42eb2fe-2470-4aa9-8027-798ba625592a" with-cue="false" with-toc="false" upload="true" command="">
+  <Encoding id="F_Ogg" type="T_Sndfile" extension="ogg" name="Ogg Vorbis" has-sample-format="false" channel-limit="256"/>
+  <SampleRate rate="44100"/>
+  <SRCQuality quality="SRC_SincBest"/>
+  <EncodingOptions>
+    <Option name="sample-format" value="SF_Vorbis"/>
+    <Option name="dithering" value="D_Shaped"/>
+    <Option name="tag-metadata" value="true"/>
+    <Option name="tag-support" value="true"/>
+    <Option name="broadcast-info" value="false"/>
+  </EncodingOptions>
+  <Processing>
+    <Normalize enabled="false" target="1"/>
+    <Silence>
+      <Start>
+        <Trim enabled="false"/>
+        <Add enabled="false">
+          <Duration format="Timecode" hours="0" minutes="0" seconds="0" frames="0"/>
+        </Add>
+      </Start>
+      <End>
+        <Trim enabled="false"/>
+        <Add enabled="false">
+          <Duration format="Timecode" hours="0" minutes="0" seconds="0" frames="0"/>
+        </Add>
+      </End>
+    </Silence>
+  </Processing>
+</ExportFormatSpecification>
index 00ac6fb634306487701f039a7b0960a48cdce266..4f1c85f6b4c3e7ad2cd6e8799ef08fb6489f27b1 100644 (file)
@@ -3384,8 +3384,6 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
 
        setup_order_hint();
 
-       PBD::ScopedConnection idle_connection;
-
        string template_path = add_route_dialog->track_template();
 
        if (!template_path.empty()) {
@@ -3427,8 +3425,6 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
                session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
                break;
        }
-
-       /* idle connection will end at scope end */
 }
 
 void
index f111aa18b1d1dd1bd7b0067e296aa4e10cb5c0b0..559196a68531b540cf60536e0e14d75fbc33fe31 100644 (file)
@@ -4873,7 +4873,7 @@ Editor::region_view_removed ()
        _summary->set_dirty ();
 }
 
-TimeAxisView*
+RouteTimeAxisView*
 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
 {
        TrackViewList::const_iterator j = track_views.begin ();
index 1398936979151d3a31207efad60c46b3e081e805..a5a5a43d5c024740f6d774f254fa911ab4e2e725 100644 (file)
@@ -1045,7 +1045,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        /* track views */
        TrackViewList track_views;
        std::pair<TimeAxisView*, double> trackview_by_y_position (double);
-       TimeAxisView* axis_view_from_route (boost::shared_ptr<ARDOUR::Route>) const;
+       RouteTimeAxisView* axis_view_from_route (boost::shared_ptr<ARDOUR::Route>) const;
 
        TrackViewList get_tracks_for_range_action () const;
 
index 3b9c5dea379608c88c022783ca97950ccb81372b..1736da96cb4a8e45ec4ae270095f71a52ec881dd 100644 (file)
@@ -60,10 +60,6 @@ using namespace Glib;
 using namespace Gtkmm2ext;
 using namespace Editing;
 
-/* XXX this is a hack. it ought to be the maximum value of an framepos_t */
-
-const double max_canvas_coordinate = (double) UINT32_MAX;
-
 void
 Editor::initialize_canvas ()
 {
@@ -213,7 +209,7 @@ Editor::initialize_canvas ()
        }
 
 
-       _canvas_bottom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, max_canvas_coordinate, 20));
+       _canvas_bottom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
        /* this thing is transparent */
        _canvas_bottom_rect->set_fill (false);
        _canvas_bottom_rect->set_outline (false);
index a3c07b86726fac58e0dcc15f38c480228fbc3fcb..8869df8cfb41c1571c916f6c9be115062001a779 100644 (file)
 
 #include "ardour/audioengine.h"
 #include "ardour/audioregion.h"
+#include "ardour/audio_track.h"
 #include "ardour/dB.h"
 #include "ardour/midi_region.h"
+#include "ardour/midi_track.h"
 #include "ardour/operations.h"
 #include "ardour/region_factory.h"
 #include "ardour/session.h"
@@ -641,38 +643,40 @@ RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const
 void
 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
 {
-       assert (!_views.empty ());
+       double delta_layer = 0;
+       int delta_time_axis_view = 0;
 
-       /* Find the TimeAxisView that the pointer is now over */
-       pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+       assert (!_views.empty ());
 
-       /* Bail early if we're not over a track */
-       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv.first);
+       /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
 
-       if (!rtv || !rtv->is_track()) {
-               _editor->verbose_cursor()->hide ();
-               return;
-       }
+       /* Find the TimeAxisView that the pointer is now over */
+       pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+       TimeAxisView* tv = r.first;
 
-       if (first_move && tv.first->view()->layer_display() == Stacked) {
-               tv.first->view()->set_layer_display (Expanded);
-       }
+       if (tv) {
 
-       /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
+               double layer = r.second;
+       
+               if (first_move && tv->view()->layer_display() == Stacked) {
+                       tv->view()->set_layer_display (Expanded);
+               }
 
-       /* Here's the current pointer position in terms of time axis view and layer */
-       int const current_pointer_time_axis_view = find_time_axis_view (tv.first);
-       double const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
+               /* Here's the current pointer position in terms of time axis view and layer */
+               int const current_pointer_time_axis_view = find_time_axis_view (tv);
+               double const current_pointer_layer = tv->layer_display() == Overlaid ? 0 : layer;
+               
+               /* Work out the change in y */
 
+               delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
+               delta_layer = current_pointer_layer - _last_pointer_layer;
+       }
+       
        /* Work out the change in x */
        framepos_t pending_region_position;
        double const x_delta = compute_x_delta (event, &pending_region_position);
 
-       /* Work out the change in y */
-
-       int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
-       double delta_layer = current_pointer_layer - _last_pointer_layer;
-
+       /* Verify change in y */
        if (!y_movement_allowed (delta_time_axis_view, delta_layer)) {
                /* this y movement is not allowed, so do no y movement this time */
                delta_time_axis_view = 0;
@@ -725,59 +729,71 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                        this_delta_layer = - i->layer;
                }
 
-               /* The TimeAxisView that this region is now on */
-               TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view];
+               if (tv) {
 
-               /* Ensure it is moved from stacked -> expanded if appropriate */
-               if (tv->view()->layer_display() == Stacked) {
-                       tv->view()->set_layer_display (Expanded);
-               }
+                       /* The TimeAxisView that this region is now on */
+                       TimeAxisView* current_tv = _time_axis_views[i->time_axis_view + delta_time_axis_view];
+
+                       /* Ensure it is moved from stacked -> expanded if appropriate */
+                       if (current_tv->view()->layer_display() == Stacked) {
+                               current_tv->view()->set_layer_display (Expanded);
+                       }
                
-               /* We're only allowed to go -ve in layer on Expanded views */
-               if (tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) {
-                       this_delta_layer = - i->layer;
-               }
+                       /* We're only allowed to go -ve in layer on Expanded views */
+                       if (current_tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) {
+                               this_delta_layer = - i->layer;
+                       }
                
-               /* Set height */
-               rv->set_height (tv->view()->child_height ());
+                       /* Set height */
+                       rv->set_height (current_tv->view()->child_height ());
                
-               /* Update show/hidden status as the region view may have come from a hidden track,
-                  or have moved to one.
-               */
-               if (tv->hidden ()) {
-                       rv->get_canvas_group()->hide ();
-               } else {
-                       rv->get_canvas_group()->show ();
-               }
+                       /* Update show/hidden status as the region view may have come from a hidden track,
+                          or have moved to one.
+                       */
+                       if (current_tv->hidden ()) {
+                               rv->get_canvas_group()->hide ();
+                       } else {
+                               rv->get_canvas_group()->show ();
+                       }
 
-               /* Update the DraggingView */
-               i->time_axis_view += delta_time_axis_view;
-               i->layer += this_delta_layer;
+                       /* Update the DraggingView */
+                       i->time_axis_view += delta_time_axis_view;
+                       i->layer += this_delta_layer;
 
-               if (_brushing) {
-                       _editor->mouse_brush_insert_region (rv, pending_region_position);
-               } else {
-                       double x = 0;
-                       double y = 0;
+                       if (_brushing) {
+                               _editor->mouse_brush_insert_region (rv, pending_region_position);
+                       } else {
+                               double x = 0;
+                               double y = 0;
 
-                       /* Get the y coordinate of the top of the track that this region is now on */
-                       tv->canvas_display()->item_to_canvas (x, y);
+                               /* Get the y coordinate of the top of the track that this region is now on */
+                               current_tv->canvas_display()->item_to_canvas (x, y);
 
-                       /* And adjust for the layer that it should be on */
-                       StreamView* cv = tv->view ();
-                       switch (cv->layer_display ()) {
-                       case Overlaid:
-                               break;
-                       case Stacked:
-                               y += (cv->layers() - i->layer - 1) * cv->child_height ();
-                               break;
-                       case Expanded:
-                               y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height ();
-                               break;
-                       }
+                               /* And adjust for the layer that it should be on */
+                               StreamView* cv = current_tv->view ();
+                               switch (cv->layer_display ()) {
+                               case Overlaid:
+                                       break;
+                               case Stacked:
+                                       y += (cv->layers() - i->layer - 1) * cv->child_height ();
+                                       break;
+                               case Expanded:
+                                       y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height ();
+                                       break;
+                               }
 
-                       /* Now move the region view */
+                               /* Now move the region view */
+                               rv->move (x_delta, y - rv->get_canvas_group()->position().y);
+                       }
+               } else {
+                       double y = 0;
+                       double x = 0;
+                       
+                       TimeAxisView* last = _time_axis_views.back();
+                       last->canvas_display()->item_to_canvas (x, y);
+                       y += last->effective_height();
                        rv->move (x_delta, y - rv->get_canvas_group()->position().y);
+                       i->time_axis_view = -1;
                }
 
        } /* foreach region */
@@ -927,12 +943,36 @@ RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred)
        _editor->maybe_locate_with_edit_preroll (_editor->get_selection().regions.start());
 }
 
+RouteTimeAxisView*
+RegionMoveDrag::create_destination_time_axis (boost::shared_ptr<Region> region)
+{                      
+       /* Add a new track of the correct type, and return the RouteTimeAxisView that is created to display the
+          new track.
+        */
+                       
+       try {
+               if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
+                       list<boost::shared_ptr<AudioTrack> > audio_tracks;
+                       audio_tracks = _editor->session()->new_audio_track (region->n_channels(), region->n_channels(), ARDOUR::Normal, 0, 1, region->name());
+                       return _editor->axis_view_from_route (audio_tracks.front());
+               } else {
+                       ChanCount one_midi_port (DataType::MIDI, 1);
+                       list<boost::shared_ptr<MidiTrack> > midi_tracks;
+                       midi_tracks = _editor->session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
+                       return _editor->axis_view_from_route (midi_tracks.front());
+               }                                               
+       } catch (...) {
+               error << _("Could not create new track after region placed in the drop zone") << endmsg;
+               return 0;
+       }
+}
+
 void
 RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed_tracks*/, framecnt_t const drag_delta)
 {
        RegionSelection new_views;
        PlaylistSet modified_playlists;
-       list<RegionView*> views_to_delete;
+       RouteTimeAxisView* new_time_axis_view = 0;      
 
        if (_brushing) {
                /* all changes were made during motion event handlers */
@@ -952,7 +992,9 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed
        }
 
        /* insert the regions into their new playlists */
-       for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+       for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end();) {
+
+               RouteTimeAxisView* dest_rtv = 0;
 
                if (i->view->region()->locked() || i->view->region()->video_locked()) {
                        continue;
@@ -965,27 +1007,31 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed
                } else {
                        where = i->view->region()->position();
                }
-
-               RegionView* new_view = insert_region_into_playlist (
-                       i->view->region(), dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]), i->layer, where, modified_playlists
-                       );
-
-               if (new_view == 0) {
-                       continue;
+               
+               if (i->time_axis_view < 0) {
+                       if (!new_time_axis_view) {
+                               new_time_axis_view = create_destination_time_axis (i->view->region());
+                       }
+                       dest_rtv = new_time_axis_view;
+               } else {
+                       dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
+               }               
+               
+               if (dest_rtv != 0) {
+                       RegionView* new_view = insert_region_into_playlist (i->view->region(), dest_rtv, i->layer, where, modified_playlists);
+                       if (new_view != 0) {
+                               new_views.push_back (new_view);
+                       }
                }
+       
+               /* Delete the copy of the view that was used for dragging. Need to play safe with the iterator
+                  since deletion will automagically remove it from _views, thus invalidating i as an iterator.
+                */
 
-               new_views.push_back (new_view);
-
-               /* we don't need the copied RegionView any more */
-               views_to_delete.push_back (i->view);
-       }
-
-       /* Delete views that are no longer needed; we can't do this directly in the iteration over _views
-          because when views are deleted they are automagically removed from _views, which messes
-          up the iteration.
-       */
-       for (list<RegionView*>::iterator i = views_to_delete.begin(); i != views_to_delete.end(); ++i) {
-               delete *i;
+               list<DraggingView>::const_iterator next = i;
+               ++next;
+               delete i->view;
+               i = next;
        }
 
        /* If we've created new regions either by copying or moving
@@ -1013,6 +1059,7 @@ RegionMoveDrag::finished_no_copy (
        PlaylistSet modified_playlists;
        PlaylistSet frozen_playlists;
        set<RouteTimeAxisView*> views_to_update;
+       RouteTimeAxisView* new_time_axis_view = 0;
 
        if (_brushing) {
                /* all changes were made during motion event handlers */
@@ -1029,15 +1076,26 @@ RegionMoveDrag::finished_no_copy (
        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
 
                RegionView* rv = i->view;
-
-               RouteTimeAxisView* const dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
-               double const dest_layer = i->layer;
+               RouteTimeAxisView* dest_rtv = 0;
 
                if (rv->region()->locked() || rv->region()->video_locked()) {
                        ++i;
                        continue;
                }
+               
+               if (i->time_axis_view < 0) {
+                       if (!new_time_axis_view) {
+                               new_time_axis_view = create_destination_time_axis (rv->region());
+                       }
+                       dest_rtv = new_time_axis_view;
+               } else {
+                       dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
+               }
+                       
+               assert (dest_rtv);
 
+               double const dest_layer = i->layer;
+               
                views_to_update.insert (dest_rtv);
 
                framepos_t where;
index 0bcfed99799a11d33f8d8517a1da7a71bc8554ed..7907701e635c5badf31bd8d76ac578cba16eb1f8 100644 (file)
@@ -378,6 +378,7 @@ private:
        void add_stateful_diff_commands_for_playlists (PlaylistSet const &);
 
        void collect_new_region_view (RegionView *);
+       RouteTimeAxisView* create_destination_time_axis (boost::shared_ptr<ARDOUR::Region>);
 
        bool _copy;
        RegionView* _new_region_view;
index 0a5ebf74102f45d1ff5d778e2ba80bebeb81a7f1..6b1612a3ecec54052b124c3ce8de20c4e4b49493 100644 (file)
@@ -1854,13 +1854,13 @@ sample_to_clock_parts ( framepos_t sample,
        long millisecs;
 
        left = sample;
-       hrs = left / (sample_rate * 60 * 60);
-       left -= hrs * sample_rate * 60 * 60;
-       mins = left / (sample_rate * 60);
-       left -= mins * sample_rate * 60;
-       secs = left / sample_rate;
-       left -= secs * sample_rate;
-       millisecs = left * 1000 / sample_rate;
+       hrs = left / (sample_rate * 60 * 60 * 1000);
+       left -= hrs * sample_rate * 60 * 60 * 1000;
+       mins = left / (sample_rate * 60 * 1000);
+       left -= mins * sample_rate * 60 * 1000;
+       secs = left / (sample_rate * 1000);
+       left -= secs * sample_rate * 1000;
+       millisecs = left / sample_rate;
 
        *millisecs_p = millisecs;
        *secs_p = secs;
@@ -1880,7 +1880,7 @@ Editor::set_minsec_ruler_scale (framepos_t lower, framepos_t upper)
                return;
        }
 
-       fr = _session->frame_rate();
+       fr = _session->frame_rate() * 1000;
 
        /* to prevent 'flashing' */
        if (lower > (spacer = (framepos_t)(128 * Editor::get_current_zoom ()))) {
@@ -1889,7 +1889,7 @@ Editor::set_minsec_ruler_scale (framepos_t lower, framepos_t upper)
                lower = 0;
        }
        upper += spacer;
-       framecnt_t const range = upper - lower;
+       framecnt_t const range = (upper - lower) * 1000;
 
        if (range <  (fr / 50)) {
                minsec_mark_interval =  fr / 1000; /* show 1/1000 seconds */
@@ -1989,7 +1989,7 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
        }
 
        *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * minsec_nmarks);
-       pos = ((((framepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval;
+       pos = (((1000 * (framepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval;
        switch (minsec_ruler_scale) {
        case minsec_show_seconds:
                for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
@@ -2006,7 +2006,7 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
                                (*marks)[n].style = GtkCustomRulerMarkMicro;
                        }
                        (*marks)[n].label = g_strdup (buf);
-                       (*marks)[n].position = pos;
+                       (*marks)[n].position = pos/1000.0;
                }
          break;
        case minsec_show_minutes:
@@ -2024,7 +2024,7 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
                         }
                         (*marks)[n].label = g_strdup (buf);
-                        (*marks)[n].position = pos;
+                        (*marks)[n].position = pos/1000.0;
                 }
          break;
        case minsec_show_hours:
@@ -2038,14 +2038,14 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
                         }
                         (*marks)[n].label = g_strdup (buf);
-                        (*marks)[n].position = pos;
+                        (*marks)[n].position = pos/1000.0;
                 }
              break;
        case minsec_show_frames:
                for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
                        sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
                        if (millisecs % minsec_mark_modulo == 0) {
-                               if (secs == 0) {
+                               if (millisecs == 0) {
                                        (*marks)[n].style = GtkCustomRulerMarkMajor;
                                } else {
                                        (*marks)[n].style = GtkCustomRulerMarkMinor;
@@ -2056,7 +2056,7 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*
                                (*marks)[n].style = GtkCustomRulerMarkMicro;
                        }
                        (*marks)[n].label = g_strdup (buf);
-                       (*marks)[n].position = pos;
+                       (*marks)[n].position = pos/1000.0;
                }
          break;
        }
index 10e3135b53b7b8f7de3774e7f99cdecef1c9416f..20155471af11c5d87edab625d15c65066a238045 100644 (file)
@@ -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);
index bc165273c73f1b66e81d32a6303253bae6348e68..3dbb9b8265494b553c1db24675dde6cc26a0e706 100644 (file)
@@ -126,7 +126,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:
index 6351c512c19cc1d0dee757e3fd72e50a0cfa9396..76b62cde57fd2b3e397c2e933afe89e63976e55f 100644 (file)
@@ -140,69 +140,27 @@ ExportDialog::init ()
        progress_widget.hide_all();
 }
 
-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 ());
 }
 
@@ -300,11 +259,34 @@ ExportDialog::show_conflicting_files ()
        dialog.run();
 }
 
+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 ());
 }
index 756a3e7b53a4fda2f5b0288262157b7e894d445c..315780750e6c9813c066502dcdcd5f68465d2b2d 100644 (file)
@@ -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 ();
index c5d1573d54bff71de2a897a866fa62eff3e74fa7..69c494e09043528f50347c2b0b0f64ad32d1a863 100644 (file)
@@ -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
@@ -717,6 +728,18 @@ ExportFormatDialog::update_with_toc ()
        manager.select_with_toc (with_toc.get_active());
 }
 
+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()
 {
index 3e38cf09d662a55b3e67c8dbfb9706f7d4e3d9df..6b92625e7a4668503526e2b45effd6e6896b8be9 100644 (file)
@@ -179,6 +179,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
@@ -311,6 +317,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;
index 97a8dba25fa7de301c4eca26d70e8d2689476989..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -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 {
-                                       Glib::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;
-}
index b0a29b5dc291e737acde9a06fd1756e756ed7ec5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -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__
index d6ca02fe0387ab91e5d4395ad2a415608eff5d1a..61d813d2229cf4b751b651517657777d8904eb57 100644 (file)
@@ -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)
 {
index 5556f5f676eb4dae77abfa03a16b0e628b592d69..12166709911688721999564836dc900eb2aea847 100644 (file)
@@ -89,6 +89,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 ***/
 
@@ -132,7 +133,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
new file mode 100644 (file)
index 0000000..39c50fe
Binary files /dev/null and b/gtk2_ardour/icons/soundcloud.png differ
index 469246f5170f38724c6181e1e1d8237451c6e873..5eaf485c7569587ff45bce90c1d9d70828e33282 100644 (file)
@@ -336,9 +336,9 @@ void* gui_event_loop (void* ptr)
        VSTState* vstfx;
        int LXVST_sched_timer_interval = 40; //ms, 25fps
        XEvent event;
-       struct timeval clock1, clock2;
+       uint64_t clock1, clock2;
        
-       gettimeofday(&clock1, NULL);
+       clock1 = g_get_monotonic_time();
        /*The 'Forever' loop - runs the plugin UIs etc - based on the FST gui event loop*/
        
        while (!gui_quit)
@@ -382,12 +382,12 @@ void* gui_event_loop (void* ptr)
                
                /*See if its time for us to do a scheduled event pass on all the plugins*/
 
-               gettimeofday(&clock2, NULL);
-               const int elapsed_time = (clock2.tv_sec - clock1.tv_sec) * 1000 + (clock2.tv_usec - clock1.tv_usec) / 1000;
+               clock2 = g_get_monotonic_time();
+               const int64_t elapsed_time_ms = (clock2 - clock1) / 1000;
 
-               if((LXVST_sched_timer_interval != 0) && elapsed_time >= LXVST_sched_timer_interval)
+               if((LXVST_sched_timer_interval != 0) && elapsed_time_ms >= LXVST_sched_timer_interval)
                {
-                       //printf("elapsed %d ms ^= %.2f Hz\n", elapsed_time, 1000.0/(double)elapsed_time); // DEBUG
+                       //printf("elapsed %d ms ^= %.2f Hz\n", elapsed_time_ms, 1000.0/(double)elapsed_time_ms); // DEBUG
                        pthread_mutex_lock (&plugin_mutex);
                    
 again:
@@ -463,7 +463,7 @@ again:
                        }
                        pthread_mutex_unlock (&plugin_mutex);
 
-                       gettimeofday(&clock1, NULL);
+                       clock1 = g_get_monotonic_time();
                }
        }
 
index 996dab1cc4144f21eb93282b173fcfd3018938f1..90779c53704aa76149d1d28875fe48aa41f18c35 100644 (file)
@@ -1034,6 +1034,7 @@ void
 SessionDialog::existing_session_selected ()
 {
        _existing_session_chooser_used = true;
+       recent_session_display.get_selection()->unselect_all();
        /* mark this sensitive in case we come back here after a failed open
         * attempt and the user has hacked up the fix. sigh.
         */
diff --git a/gtk2_ardour/soundcloud_export_selector.cc b/gtk2_ardour/soundcloud_export_selector.cc
new file mode 100644 (file)
index 0000000..1ecab51
--- /dev/null
@@ -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 (file)
index 0000000..7962ba8
--- /dev/null
@@ -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;
+       
+};
+
index 920f71bd7db343efb917b1aa7fe376e92a34e5d8..2cfd2ea4977da5b2fbd801337aac28c19e2e6afa 100644 (file)
@@ -204,6 +204,7 @@ gtk2_ardour_sources = [
         'session_option_editor.cc',
         'sfdb_ui.cc',
         'shuttle_control.cc',
+        'soundcloud_export_selector.cc',
         'splash.cc',
         'speaker_dialog.cc',
         'startup.cc',
index 9a95111509b888b6f148bf3460dc58598ef7d41c..dad7d84b72f58b4406318fee6c98f7a8a475e48c 100644 (file)
@@ -100,6 +100,8 @@ class LIBARDOUR_API ExportFormatManager : public PBD::ScopedConnectionList
 
        void select_with_cue (bool);
        void select_with_toc (bool);
+       void select_upload (bool);
+       void set_command (std::string);
        void select_src_quality (ExportFormatBase::SRCQuality value);
        void select_trim_beginning (bool value);
        void select_silence_beginning (AnyTime const & time);
index 1593990d3592c43e9732b3b3fec5c21941a41397..d41fe3e97ac8edf756394a42208b2966109f520d 100644 (file)
@@ -96,6 +96,8 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
        void set_tag (bool tag_it) { _tag = tag_it; }
        void set_with_cue (bool yn) { _with_cue = yn; }
        void set_with_toc (bool yn) { _with_toc = yn; }
+       void set_upload (bool yn) { _upload = yn; }
+       void set_command (std::string command) { _command = command; }
 
        void set_silence_beginning (AnyTime const & value) { _silence_beginning = value; }
        void set_silence_end (AnyTime const & value) { _silence_end = value; }
@@ -125,6 +127,8 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
        float normalize_target () const { return _normalize_target; }
        bool with_toc() const { return _with_toc; }
        bool with_cue() const { return _with_cue; }
+       bool upload() const { return _upload; }
+       std::string command() const { return _command; }
 
        bool tag () const { return _tag && supports_tagging; }
 
@@ -174,6 +178,8 @@ class LIBARDOUR_API ExportFormatSpecification : public ExportFormatBase {
        float           _normalize_target;
        bool            _with_toc;
        bool            _with_cue;
+       bool            _upload;
+       std::string     _command;
 
        /* serialization helpers */
 
index 1bc80a80e976693c7e194ca7c2fcfaf23634680e..25a87045a8d815b66c36fba9f27a6410e0886c73 100644 (file)
@@ -31,6 +31,7 @@
 #include "ardour/session.h"
 #include "ardour/libardour_visibility.h"
 #include "ardour/types.h"
+#include "pbd/signals.h"
 
 namespace AudioGrapher {
        class BroadcastInfo;
@@ -68,7 +69,7 @@ class LIBARDOUR_API ExportElementFactory
        Session & session;
 };
 
-class LIBARDOUR_API ExportHandler : public ExportElementFactory
+class LIBARDOUR_API ExportHandler : public ExportElementFactory, public sigc::trackable
 {
   public:
        struct FileSpec {
@@ -95,6 +96,8 @@ class LIBARDOUR_API ExportHandler : public ExportElementFactory
        friend boost::shared_ptr<ExportHandler> Session::get_export_handler();
        ExportHandler (Session & session);
 
+       void command_output(std::string output, size_t size);
+
   public:
        ~ExportHandler ();
 
@@ -105,6 +108,17 @@ class LIBARDOUR_API ExportHandler : public ExportElementFactory
 
        std::string get_cd_marker_filename(std::string filename, CDMarkerFormat format);
 
+       /** signal emitted when soundcloud export reports progress updates during upload.
+        * The parameters are total and current bytes downloaded, and the current filename
+        */
+       PBD::Signal3<void, double, double, std::string> SoundcloudProgress;
+
+       /* upload credentials & preferences */
+       std::string upload_username;
+       std::string upload_password;
+       bool upload_public;
+       bool upload_open;
+
   private:
 
        void handle_duplicate_format_extensions();
diff --git a/libs/ardour/ardour/soundcloud_upload.h b/libs/ardour/ardour/soundcloud_upload.h
new file mode 100644 (file)
index 0000000..6b8700e
--- /dev/null
@@ -0,0 +1,55 @@
+/* soundcloud_upload.h ******************************************************
+
+       Adapted for Ardour by Ben Loftis, March 2012
+
+*****************************************************************************/
+
+#ifndef __ardour_soundcloud_upload_h__
+#define __ardour_soundcloud_upload_h__
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <cstring>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include "curl/curl.h"
+#include "ardour/session_handle.h"
+#include "ardour/export_handler.h"
+#include "pbd/signals.h"
+
+//--- struct to store XML file
+struct MemoryStruct {
+       char *memory;
+       size_t size;
+};
+
+
+class SoundcloudUploader
+{
+public:
+       SoundcloudUploader();
+       ~SoundcloudUploader();
+
+       std::string     Get_Auth_Token(std::string username, std::string password);
+       std::string Upload (std::string file_path, std::string title, std::string token, bool ispublic, ARDOUR::ExportHandler *caller);
+       static int progress_callback(void *caller, double dltotal, double dlnow, double ultotal, double ulnow);
+
+
+private:
+
+       void            setcUrlOptions();
+
+       CURL *curl_handle;
+       CURLM *multi_handle;
+       char errorBuffer[CURL_ERROR_SIZE];      // storage for cUrl error message
+
+       std::string title;
+       ARDOUR::ExportHandler *caller;
+
+};
+
+#endif /* __ardour_soundcloud_upload_h__ */
index 40e429720ef9371448b0315a38baf1532ffaa4a6..ae865c7bff7ce040b87449688dfa8a54ae898c0e 100644 (file)
@@ -32,6 +32,7 @@ class LIBARDOUR_API SystemExec
 public:
        SystemExec (std::string c, std::string a = "");
        SystemExec (std::string c, char ** a);
+       SystemExec (std::string c, const std::map<char, std::string> subs);
        ~SystemExec ();
 
        int start (int stderr_mode = 1) {
index 8e14fff40225e36cc05d3ed562f7e07d756a16c1..94201882e7b29e6bdfc2d4f429f1b2c7bce2dce5 100644 (file)
@@ -369,6 +369,13 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
 
        process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!diskstream->record_enabled() && _session.transport_rolling()));
 
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
+               if (d) {
+                       d->flush_buffers (nframes);
+               }
+       }
+
        need_butler = diskstream->commit (playback_distance);
 
        return 0;
index 890623c114b0f5a562aa28705f3e225b58dd94ea..3ee940ffb6367ff50c5ddf2e7d6dda521deda007 100644 (file)
@@ -293,6 +293,20 @@ ExportFormatManager::select_with_toc (bool value)
        check_for_description_change ();
 }
 
+void
+ExportFormatManager::select_upload (bool value)
+{
+       current_selection->set_upload (value);
+       check_for_description_change ();
+}
+
+void
+ExportFormatManager::set_command (std::string command)
+{
+       current_selection->set_command (command);
+       check_for_description_change ();
+}
+
 void
 ExportFormatManager::select_trim_beginning (bool value)
 {
index b139faeee2997d8401a9e4de77dfe2547254ff74..8b921519f71fd9ccf60ab44f4651d85f93f166db 100644 (file)
@@ -170,6 +170,8 @@ ExportFormatSpecification::ExportFormatSpecification (Session & s)
        , _normalize_target (1.0)
        , _with_toc (false)
        , _with_cue (false)
+       , _upload (false)
+       , _command ("")
 {
        format_ids.insert (F_None);
        endiannesses.insert (E_FileDefault);
@@ -244,6 +246,8 @@ ExportFormatSpecification::get_state ()
        root->add_property ("id", _id.to_s());
        root->add_property ("with-cue", _with_cue ? "true" : "false");
        root->add_property ("with-toc", _with_toc ? "true" : "false");
+       root->add_property ("upload", _upload ? "true" : "false");
+       root->add_property ("command", _command);
 
        node = root->add_child ("Encoding");
        node->add_property ("id", enum_2_string (format_id()));
@@ -321,6 +325,18 @@ ExportFormatSpecification::set_state (const XMLNode & root)
                _with_toc = false;
        }
        
+       if ((prop = root.property ("upload"))) {
+               _upload = string_is_affirmative (prop->value());
+       } else {
+               _upload = false;
+       }
+       
+       if ((prop = root.property ("command"))) {
+               _command = prop->value();
+       } else {
+               _command = "";
+       }
+
        /* Encoding and SRC */
 
        if ((child = root.child ("Encoding"))) {
@@ -590,6 +606,14 @@ ExportFormatSpecification::description (bool include_name)
                components.push_back ("CUE");
        }
 
+       if (_upload) {
+               components.push_back ("Upload");
+       }
+
+       if (!_command.empty()) {
+               components.push_back ("+");
+       }
+
        string desc;
        if (include_name) {
                desc = _name + ": ";
index 20abc80de1995866ff8befb89228d04bd1e83845..c9f20d182e7bc4dce63a82be58d39f4d8cdd2bcd 100644 (file)
 #include "ardour/export_status.h"
 #include "ardour/export_format_specification.h"
 #include "ardour/export_filename.h"
+#include "ardour/soundcloud_upload.h"
+#include "ardour/system_exec.h"
+#include "pbd/openuri.h"
+#include "pbd/basename.h"
 #include "ardour/session_metadata.h"
 
 #include "i18n.h"
@@ -277,6 +281,13 @@ ExportHandler::process_normalize ()
        return 0;
 }
 
+void
+ExportHandler::command_output(std::string output, size_t size)
+{
+       std::cerr << "command: " << size << ", " << output << std::endl;
+       info << output << endmsg;
+}
+
 void
 ExportHandler::finish_timespan ()
 {
@@ -297,13 +308,77 @@ ExportHandler::finish_timespan ()
                        AudiofileTagger::tag_file(filename, *SessionMetadata::Metadata());
                }
 
+               if (!fmt->command().empty()) {
+
+#if 0                  // would be nicer with C++11 initialiser...
+                       std::map<char, std::string> subs {
+                               { 'f', filename },
+                               { 'd', Glib::path_get_dirname(filename) },
+                               { 'b', PBD::basename_nosuffix(filename) },
+                               { 'u', upload_username },
+                               { 'p', upload_password}
+                       };
+#endif
+
+                       PBD::ScopedConnection command_connection;
+                       std::map<char, std::string> subs;
+                       subs.insert (std::pair<char, std::string> ('f', filename));
+                       subs.insert (std::pair<char, std::string> ('d', Glib::path_get_dirname(filename)));
+                       subs.insert (std::pair<char, std::string> ('b', PBD::basename_nosuffix(filename)));
+                       subs.insert (std::pair<char, std::string> ('u', upload_username));
+                       subs.insert (std::pair<char, std::string> ('p', upload_password));
+
+
+                       std::cerr << "running command: " << fmt->command() << "..." << std::endl;
+                       ARDOUR::SystemExec *se = new ARDOUR::SystemExec(fmt->command(), subs);
+                       se->ReadStdout.connect_same_thread(command_connection, boost::bind(&ExportHandler::command_output, this, _1, _2));
+                       if (se->start (2) == 0) {
+                               // successfully started
+                               std::cerr << "started!" << std::endl;
+                               while (se->is_running ()) {
+                                       // wait for system exec to terminate
+                                       // std::cerr << "waiting..." << std::endl;
+                                       usleep (1000);
+                               }
+                       }
+                       std::cerr << "done! deleting..." << std::endl;
+                       delete (se);
+               }
+
+               if (fmt->upload()) {
+                       SoundcloudUploader *soundcloud_uploader = new SoundcloudUploader;
+                       std::string token = soundcloud_uploader->Get_Auth_Token(upload_username, upload_password);
+                       std::cerr
+                               << "uploading "
+                               << filename << std::endl
+                               << "username = " << upload_username
+                               << ", password = " << upload_password
+                               << " - token = " << token << " ..."
+                               << std::endl;
+                       std::string path = soundcloud_uploader->Upload (
+                                       filename,
+                                       PBD::basename_nosuffix(filename), // title
+                                       token,
+                                       upload_public,
+                                       this);
+
+                       if (path.length() != 0) {
+                               if (upload_open) {
+                               std::cerr << "opening " << path << " ..." << std::endl;
+                               open_uri(path.c_str());  // open the soundcloud website to the new file
+                               }
+                       } else {
+                               error << _("upload to Soundcloud failed.  Perhaps your email or password are incorrect?\n") << endmsg;
+                       }
+                       delete soundcloud_uploader;
+               }
                config_map.erase (config_map.begin());
        }
 
        start_timespan ();
 }
 
-/*** CD Marker sutff ***/
+/*** CD Marker stuff ***/
 
 struct LocationSortByStart {
     bool operator() (Location *a, Location *b) {
diff --git a/libs/ardour/soundcloud_upload.cc b/libs/ardour/soundcloud_upload.cc
new file mode 100644 (file)
index 0000000..f003d5a
--- /dev/null
@@ -0,0 +1,349 @@
+/* soundcloud_export.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 "pbd/xml++.h"
+#include <pbd/error.h>
+//#include "pbd/filesystem.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <iostream>
+#include <glib/gstdio.h>
+
+#include "i18n.h"
+
+using namespace PBD;
+
+// static const std::string base_url = "http://api.soundcloud.com/tracks/13158665?client_id=";
+
+size_t
+WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
+{
+       register int realsize = (int)(size * nmemb);
+       struct MemoryStruct *mem = (struct MemoryStruct *)data;
+
+       mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
+
+       if (mem->memory) {
+               memcpy(&(mem->memory[mem->size]), ptr, realsize);
+               mem->size += realsize;
+               mem->memory[mem->size] = 0;
+       }
+       return realsize;
+}
+
+SoundcloudUploader::SoundcloudUploader()
+{
+       curl_handle = curl_easy_init();
+       multi_handle = curl_multi_init();
+}
+
+std::string
+SoundcloudUploader::Get_Auth_Token( std::string username, std::string password )
+{
+       struct MemoryStruct xml_page;
+       xml_page.memory = NULL;
+       xml_page.size = 0;
+
+       setcUrlOptions();
+
+       curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+       curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &xml_page);
+
+       struct curl_httppost *formpost=NULL;
+       struct curl_httppost *lastptr=NULL;
+
+       /* Fill in the filename field */ 
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "client_id",
+                       CURLFORM_COPYCONTENTS, "e7ac891eef866f139773cf8102b7a719",
+                       CURLFORM_END);
+
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "client_secret",
+                       CURLFORM_COPYCONTENTS, "d78f34d19f09d26731801a0cb0f382c4",
+                       CURLFORM_END);
+
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "grant_type",
+                       CURLFORM_COPYCONTENTS, "password",
+                       CURLFORM_END);
+
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "username",
+                       CURLFORM_COPYCONTENTS, username.c_str(),
+                       CURLFORM_END);
+
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "password",
+                       CURLFORM_COPYCONTENTS, password.c_str(),
+                       CURLFORM_END);
+
+       struct curl_slist *headerlist=NULL;
+       headerlist = curl_slist_append(headerlist, "Expect:");
+       headerlist = curl_slist_append(headerlist, "Accept: application/xml");
+       curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headerlist);
+
+       /* what URL that receives this POST */ 
+       std::string url = "https://api.soundcloud.com/oauth2/token";
+       curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
+       curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost);
+
+       // curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
+
+       // perform online request
+       CURLcode res = curl_easy_perform(curl_handle);
+       if( res != 0 ) {
+               std::cerr << "curl error " << res << " (" << curl_easy_strerror(res) << ")" << std::endl;
+               return "";
+       }
+
+       if(xml_page.memory){
+               //cheesy way to parse the json return value.  find access_token, then advance 3 quotes
+
+               if ( strstr ( xml_page.memory , "access_token" ) == NULL) {
+                       error << _("Upload to Soundcloud failed.  Perhaps your email or password are incorrect?\n") << endmsg;
+                       return "";
+               }
+
+               std::string token = strtok( xml_page.memory, "access_token" );
+               token = strtok( NULL, "\"" );
+               token = strtok( NULL, "\"" );
+               token = strtok( NULL, "\"" );
+
+               free( xml_page.memory );
+               return token;
+       }
+
+       return "";
+}
+
+int
+SoundcloudUploader::progress_callback(void *caller, double dltotal, double dlnow, double ultotal, double ulnow)
+{
+       SoundcloudUploader *scu = (SoundcloudUploader *) caller;
+       std::cerr << scu->title << ": uploaded " << ulnow << " of " << ultotal << std::endl;
+       scu->caller->SoundcloudProgress(ultotal, ulnow, scu->title); /* EMIT SIGNAL */
+       return 0;
+}
+
+
+std::string
+SoundcloudUploader::Upload(std::string file_path, std::string title, std::string token, bool ispublic, ARDOUR::ExportHandler *caller)
+{
+       int still_running;
+
+       struct MemoryStruct xml_page;
+       xml_page.memory = NULL;
+       xml_page.size = 0;
+
+       setcUrlOptions();
+
+       curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+       curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &xml_page);
+
+       struct curl_httppost *formpost=NULL;
+       struct curl_httppost *lastptr=NULL;
+
+       /* Fill in the file upload field. This makes libcurl load data from
+          the given file name when curl_easy_perform() is called. */ 
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "track[asset_data]",
+                       CURLFORM_FILE, file_path.c_str(),
+                       CURLFORM_END);
+
+       /* Fill in the filename field */ 
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "oauth_token",
+                       CURLFORM_COPYCONTENTS, token.c_str(),
+                       CURLFORM_END);
+
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "track[title]",
+                       CURLFORM_COPYCONTENTS, title.c_str(),
+                       CURLFORM_END);
+
+       curl_formadd(&formpost,
+                       &lastptr,
+                       CURLFORM_COPYNAME, "track[sharing]",
+                       CURLFORM_COPYCONTENTS, ispublic ? "public" : "private",
+                       CURLFORM_END);
+
+       /* initalize custom header list (stating that Expect: 100-continue is not
+          wanted */ 
+       struct curl_slist *headerlist=NULL;
+       static const char buf[] = "Expect:";
+       headerlist = curl_slist_append(headerlist, buf);
+
+
+       if (curl_handle && multi_handle) {
+
+               /* what URL that receives this POST */ 
+               std::string url = "https://api.soundcloud.com/tracks";
+               curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
+               // curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
+
+               curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headerlist);
+               curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, formpost);
+
+               this->title = title; // save title to show in progress bar
+               this->caller = caller;
+
+               curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 0); // turn on the progress bar
+               curl_easy_setopt (curl_handle, CURLOPT_PROGRESSFUNCTION, &SoundcloudUploader::progress_callback);
+               curl_easy_setopt (curl_handle, CURLOPT_PROGRESSDATA, this);
+
+               curl_multi_add_handle(multi_handle, curl_handle);
+
+               curl_multi_perform(multi_handle, &still_running);
+
+
+               while(still_running) {
+                       struct timeval timeout;
+                       int rc; /* select() return code */ 
+
+                       fd_set fdread;
+                       fd_set fdwrite;
+                       fd_set fdexcep;
+                       int maxfd = -1;
+
+                       long curl_timeo = -1;
+
+                       FD_ZERO(&fdread);
+                       FD_ZERO(&fdwrite);
+                       FD_ZERO(&fdexcep);
+
+                       /* set a suitable timeout to play around with */ 
+                       timeout.tv_sec = 1;
+                       timeout.tv_usec = 0;
+
+                       curl_multi_timeout(multi_handle, &curl_timeo);
+                       if(curl_timeo >= 0) {
+                               timeout.tv_sec = curl_timeo / 1000;
+                               if(timeout.tv_sec > 1)
+                                       timeout.tv_sec = 1;
+                               else
+                                       timeout.tv_usec = (curl_timeo % 1000) * 1000;
+                       }
+
+                       /* get file descriptors from the transfers */ 
+                       curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+
+                       /* In a real-world program you OF COURSE check the return code of the
+                          function calls.  On success, the value of maxfd is guaranteed to be
+                          greater or equal than -1.  We call select(maxfd + 1, ...), specially in
+                          case of (maxfd == -1), we call select(0, ...), which is basically equal
+                          to sleep. */ 
+
+                       rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+
+                       switch(rc) {
+                               case -1:
+                                       /* select error */ 
+                                       break;
+                               case 0:
+                               default:
+                                       /* timeout or readable/writable sockets */ 
+                                       curl_multi_perform(multi_handle, &still_running);
+                                       break;
+                       }
+               } 
+
+               /* then cleanup the formpost chain */ 
+               curl_formfree(formpost);
+
+               /* free slist */ 
+               curl_slist_free_all (headerlist);
+       }
+
+       curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 1); // turn off the progress bar
+
+       if(xml_page.memory){
+
+               std::cout << xml_page.memory << std::endl;
+
+               XMLTree doc;
+               doc.read_buffer( xml_page.memory );
+               XMLNode *root = doc.root();
+
+               if (!root) {
+                       std::cout << "no root XML node!" << std::endl;
+                       return "";
+               }
+
+               XMLNode *url_node = root->child("permalink-url");
+               if (!url_node) {
+                       std::cout << "no child node \"permalink-url\" found!" << std::endl;
+                       return "";
+               }
+
+               XMLNode *text_node = url_node->child("text");
+               if (!text_node) {
+                       std::cout << "no text node found!" << std::endl;
+                       return "";
+               }
+
+               free( xml_page.memory );
+               return text_node->content();
+       }
+
+       return "";
+};
+
+
+SoundcloudUploader:: ~SoundcloudUploader()
+{
+       curl_easy_cleanup(curl_handle);
+       curl_multi_cleanup(multi_handle);
+}
+
+
+void
+SoundcloudUploader::setcUrlOptions()
+{
+       // basic init for curl
+       curl_global_init(CURL_GLOBAL_ALL);
+       // some servers don't like requests that are made without a user-agent field, so we provide one
+       curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+       // setup curl error buffer
+       curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorBuffer);
+       // Allow redirection
+       curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
+       
+       // Allow connections to time out (without using signals)
+       curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
+       curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 30);
+
+       curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+       curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
+}
+
index 90e729a7f683d51df0f761fb3947ebf942afd6f1..760a9b787805f31c6db223b65540a6503c9afc8e 100644 (file)
@@ -65,4 +65,14 @@ SystemExec::SystemExec (std::string c, std::string a)
 #endif
 }
 
+SystemExec::SystemExec (std::string c, const std::map<char, std::string> subs)
+       : PBD::SystemExec(c, subs)
+{
+#ifndef PLATFORM_WINDOWS
+       if (!_vfork_exec_wrapper) {
+               _vfork_exec_wrapper = vfork_exec_wrapper_path();
+       }
+#endif
+}
+
 SystemExec::~SystemExec() { }
index 0bb2fea0cf3e0c6a22a1f25a07a916bdbab49045..621d1e2c747d0d30bfe4322184cee1db044b8b54 100644 (file)
@@ -884,6 +884,7 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
        TempoSection* ts;
        MeterSection* ms;
        double beat_frames;
+       double current_frame_exact;
        framepos_t bar_start_frame;
 
        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Extend map to %1 from %2 = %3\n", end, current, current_frame));
@@ -895,11 +896,13 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
        }
 
        beat_frames = meter->frames_per_grid (*tempo,_frame_rate);
+       current_frame_exact = current_frame;
 
        while (current_frame < end) {
 
                current.beats++;
-               current_frame += beat_frames;
+               current_frame_exact += beat_frames;
+               current_frame = llrint(current_frame_exact);
 
                if (current.beats > meter->divisions_per_bar()) {
                        current.bars++;
@@ -942,7 +945,8 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
                                                                                               tempo->start(), current_frame, tempo->bar_offset()));
                                                
                                                /* back up to previous beat */
-                                               current_frame -= beat_frames;
+                                               current_frame_exact -= beat_frames;
+                                               current_frame = llrint(current_frame_exact);
 
                                                /* set tempo section location
                                                 * based on offset from last
@@ -963,7 +967,8 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
 
                                                double offset_within_old_beat = (tempo->frame() - current_frame) / beat_frames;
 
-                                               current_frame += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
+                                               current_frame_exact += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
+                                               current_frame = llrint(current_frame_exact);
 
                                                /* next metric doesn't have to
                                                 * match this precisely to
@@ -1012,11 +1017,11 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
 
                if (current.beats == 1) {
                        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
-                       _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), current.bars, 1));
+                       _map.push_back (BBTPoint (*meter, *tempo, current_frame, current.bars, 1));
                        bar_start_frame = current_frame;
                } else {
                        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
-                       _map.push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), current.bars, current.beats));
+                       _map.push_back (BBTPoint (*meter, *tempo, current_frame, current.bars, current.beats));
                }
 
                if (next_metric == metrics.end()) {
index e469187ce9497709d8a54240a05aef9a3ed8757e..94490ca912487420c4fdf956ee60b555fb93e7cc 100644 (file)
@@ -60,7 +60,9 @@ ThreadBuffers::ensure_buffers (ChanCount howmany)
 
        for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                size_t count = std::max (scratch_buffers->available().get(*t), howmany.get(*t));
-               size_t size = _engine->raw_buffer_size (*t) / sizeof (Sample);
+               size_t size = (*t == DataType::MIDI)
+                       ? _engine->raw_buffer_size (*t)
+                       : _engine->raw_buffer_size (*t) / sizeof (Sample);
 
                scratch_buffers->ensure_buffers (*t, count, size);
                mix_buffers->ensure_buffers (*t, count, size);
index bf9d196e61dedaf830644cedf29fdb63e16254d6..f74bdca771fbedccc0442324849a0d0bf92c3cc4 100644 (file)
 #include <glib/gstdio.h>
 #include <glibmm.h>
 
+#include "pbd/error.h"
 
-#ifdef VST_SCANNER_APP
-#define errormsg cerr
-#define warningmsg cerr
-#define endmsg endl
-#else
+#ifndef VST_SCANNER_APP
 #include "ardour/plugin_manager.h" // scanner_bin_path
 #include "ardour/rc_configuration.h"
 #include "ardour/system_exec.h"
-#include "pbd/error.h"
-#define errormsg PBD::error
-#define warningmsg PBD::warning
 #endif
 
 #include "ardour/filesystem_paths.h"
@@ -330,7 +324,7 @@ vstfx_write_info_file (FILE* fp, vector<VSTInfo *> *infos)
        } else if (infos->size() == 1) {
                vstfx_write_info_block(fp, infos->front());
        } else {
-               errormsg << "Zero plugins in VST." << endmsg; // XXX here? rather make this impossible before if it ain't already.
+               PBD::error << "Zero plugins in VST." << endmsg; // XXX here? rather make this impossible before if it ain't already.
        }
 }
 
@@ -406,7 +400,6 @@ vstfx_un_blacklist (const char *dllpath)
        ::g_unlink(vstfx_blacklist_path (dllpath, 1).c_str());
 }
 
-#ifndef VST_SCANNER_APP
 /** remove info file from cache */
 static void
 vstfx_remove_infofile (const char *dllpath)
@@ -414,7 +407,6 @@ vstfx_remove_infofile (const char *dllpath)
        ::g_unlink(vstfx_infofile_path (dllpath, 0).c_str());
        ::g_unlink(vstfx_infofile_path (dllpath, 1).c_str());
 }
-#endif
 
 /** helper function, check if cache is newer than plugin
  * @return path to cache file */
@@ -516,7 +508,7 @@ vstfx_get_info_from_file(const char* dllpath, vector<VSTInfo*> *infos)
                rv = vstfx_load_info_file(infofile, infos);
                fclose (infofile);
                if (!rv) {
-                       warningmsg << "Cannot get VST information form " << dllpath << ": info file load failed." << endmsg;
+                       PBD::warning << "Cannot get VST information form " << dllpath << ": info file load failed." << endmsg;
                }
        }
        return rv;
@@ -782,7 +774,7 @@ vstfx_instantiate_and_get_info_lx (
        VSTHandle* h;
        VSTState* vstfx;
        if (!(h = vstfx_load(dllpath))) {
-               warningmsg << "Cannot get LinuxVST information from " << dllpath << ": load failed." << endmsg;
+               PBD::warning << "Cannot get LinuxVST information from " << dllpath << ": load failed." << endmsg;
                return false;
        }
 
@@ -790,7 +782,7 @@ vstfx_instantiate_and_get_info_lx (
 
        if (!(vstfx = vstfx_instantiate(h, simple_master_callback, 0))) {
                vstfx_unload(h);
-               warningmsg << "Cannot get LinuxVST information from " << dllpath << ": instantiation failed." << endmsg;
+               PBD::warning << "Cannot get LinuxVST information from " << dllpath << ": instantiation failed." << endmsg;
                return false;
        }
 
@@ -811,7 +803,7 @@ vstfx_instantiate_and_get_info_fst (
        VSTHandle* h;
        VSTState* vstfx;
        if(!(h = fst_load(dllpath))) {
-               warningmsg << "Cannot get Windows VST information from " << dllpath << ": load failed." << endmsg;
+               PBD::warning << "Cannot get Windows VST information from " << dllpath << ": load failed." << endmsg;
                return false;
        }
 
@@ -820,7 +812,7 @@ vstfx_instantiate_and_get_info_fst (
        if(!(vstfx = fst_instantiate(h, simple_master_callback, 0))) {
                fst_unload(&h);
                vstfx_current_loading_id = 0;
-               warningmsg << "Cannot get Windows VST information from " << dllpath << ": instantiation failed." << endmsg;
+               PBD::warning << "Cannot get Windows VST information from " << dllpath << ": instantiation failed." << endmsg;
                return false;
        }
        vstfx_current_loading_id = 0;
@@ -842,14 +834,14 @@ static char * _errorlog_dll = 0;
 static void parse_scanner_output (std::string msg, size_t /*len*/)
 {
        if (!_errorlog_fd && !_errorlog_dll) {
-               errormsg << "VST scanner: " << msg;
+               PBD::error << "VST scanner: " << msg;
                return;
        }
 
        if (!_errorlog_fd) {
                if (!(_errorlog_fd = fopen(vstfx_errorfile_path(_errorlog_dll, 0).c_str(), "w"))) {
                        if (!(_errorlog_fd = fopen(vstfx_errorfile_path(_errorlog_dll, 1).c_str(), "w"))) {
-                               errormsg << "Cannot create plugin error-log for plugin " << _errorlog_dll;
+                               PBD::error << "Cannot create plugin error-log for plugin " << _errorlog_dll;
                                free(_errorlog_dll);
                                _errorlog_dll = NULL;
                        }
@@ -859,7 +851,7 @@ static void parse_scanner_output (std::string msg, size_t /*len*/)
        if (_errorlog_fd) {
                fprintf (_errorlog_fd, "%s\n", msg.c_str());
        } else {
-               errormsg << "VST scanner: " << msg;
+               PBD::error << "VST scanner: " << msg;
        }
 }
 
@@ -919,7 +911,7 @@ vstfx_get_info (const char* dllpath, enum ARDOUR::PluginType type, enum VSTScanM
                PBD::ScopedConnectionList cons;
                scanner.ReadStdout.connect_same_thread (cons, boost::bind (&parse_scanner_output, _1 ,_2));
                if (scanner.start (2 /* send stderr&stdout via signal */)) {
-                       errormsg << "Cannot launch VST scanner app '" << scanner_bin_path << "': "<< strerror(errno) << endmsg;
+                       PBD::error << "Cannot launch VST scanner app '" << scanner_bin_path << "': "<< strerror(errno) << endmsg;
                        close_error_log();
                        return infos;
                } else {
@@ -985,7 +977,7 @@ vstfx_get_info (const char* dllpath, enum ARDOUR::PluginType type, enum VSTScanM
        /* crate cache/whitelist */
        infofile = vstfx_infofile_for_write (dllpath);
        if (!infofile) {
-               warningmsg << "Cannot cache VST information for " << dllpath << ": cannot create new FST info file." << endmsg;
+               PBD::warning << "Cannot cache VST information for " << dllpath << ": cannot create new FST info file." << endmsg;
                return infos;
        } else {
                vstfx_write_info_file (infofile, infos);
@@ -1013,7 +1005,7 @@ get_personal_vst_blacklist_dir() {
        /* if the directory doesn't exist, try to create it */
        if (!Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
                if (g_mkdir (dir.c_str (), 0700)) {
-                       errormsg << "Cannot create VST blacklist folder '" << dir << "'" << endmsg;
+                       PBD::error << "Cannot create VST blacklist folder '" << dir << "'" << endmsg;
                        //exit(1);
                }
        }
@@ -1026,7 +1018,7 @@ get_personal_vst_info_cache_dir() {
        /* if the directory doesn't exist, try to create it */
        if (!Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
                if (g_mkdir (dir.c_str (), 0700)) {
-                       errormsg << "Cannot create VST info folder '" << dir << "'" << endmsg;
+                       PBD::error << "Cannot create VST info folder '" << dir << "'" << endmsg;
                        //exit(1);
                }
        }
index 52e139db84fab0bcc7ab722006271cac9b4e2931..a18cc07356106c1f4045dde35699005811ad4b47 100644 (file)
@@ -250,6 +250,7 @@ VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
 {
        VstParameterProperties prop;
 
+       memset (&prop, 0, sizeof (VstParameterProperties));
        desc.min_unbound = false;
        desc.max_unbound = false;
        prop.flags = 0;
@@ -257,6 +258,7 @@ VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
        if (_plugin->dispatcher (_plugin, effGetParameterProperties, which, 0, &prop, 0)) {
 
                /* i have yet to find or hear of a VST plugin that uses this */
+               /* RG: faust2vsti does use this :) */
 
                if (prop.flags & kVstParameterUsesIntegerMinMax) {
                        desc.lower = prop.minInteger;
@@ -287,6 +289,10 @@ VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
                        desc.largestep = desc.step * 10.0f;
                }
 
+               if (strlen(prop.label) == 0) {
+                       _plugin->dispatcher (_plugin, effGetParamName, which, 0, prop.label, 0);
+               }
+
                desc.toggled = prop.flags & kVstParameterIsSwitch;
                desc.logarithmic = false;
                desc.sr_dependent = false;
index 4a500645452f046d68c7855799d602e579539dcc..85326e98f8cf2cef164dba85b4e98501df13bc38 100644 (file)
@@ -194,6 +194,7 @@ libardour_sources = [
         'sndfile_helpers.cc',
         'sndfileimportable.cc',
         'sndfilesource.cc',
+        'soundcloud_upload.cc',
         'source.cc',
         'source_factory.cc',
         'speakers.cc',
index 136e5b865546d22b4c87cda0809928f0258926d0..01e8085e04614e9dc4f24441fabff47a11bc4f38 100644 (file)
@@ -40,6 +40,8 @@ DummyAudioBackend::DummyAudioBackend (AudioEngine& e, AudioBackendInfo& info)
        , _dsp_load (0)
        , _n_inputs (0)
        , _n_outputs (0)
+       , _n_midi_inputs (0)
+       , _n_midi_outputs (0)
        , _systemic_input_latency (0)
        , _systemic_output_latency (0)
        , _processed_samples (0)
@@ -247,13 +249,27 @@ std::vector<std::string>
 DummyAudioBackend::enumerate_midi_options () const
 {
        std::vector<std::string> m;
-       m.push_back (_("None"));
+       m.push_back (_("1 in, 1 out"));
+       m.push_back (_("2 in, 2 out"));
+       m.push_back (_("8 in, 8 out"));
        return m;
 }
 
 int
-DummyAudioBackend::set_midi_option (const std::string&)
+DummyAudioBackend::set_midi_option (const std::string& opt)
 {
+       if (opt == _("1 in, 1 out")) {
+               _n_midi_inputs = _n_midi_outputs = 1;
+       }
+       else if (opt == _("2 in, 2 out")) {
+               _n_midi_inputs = _n_midi_outputs = 2;
+       }
+       else if (opt == _("8 in, 8 out")) {
+               _n_midi_inputs = _n_midi_outputs = 8;
+       }
+       else {
+               _n_midi_inputs = _n_midi_outputs = 0;
+       }
        return -1;
 }
 
@@ -606,8 +622,8 @@ DummyAudioBackend::register_system_ports()
 
        const int a_ins = _n_inputs > 0 ? _n_inputs : 8;
        const int a_out = _n_outputs > 0 ? _n_outputs : 8;
-       const int m_ins = 2; // TODO
-       const int m_out = 2;
+       const int m_ins = _n_midi_inputs > 0 ? _n_midi_inputs : 2;
+       const int m_out = _n_midi_outputs > 0 ? _n_midi_outputs : 2;
 
        /* audio ports */
        lr.min = lr.max = _samples_per_period + _systemic_input_latency;
@@ -981,17 +997,17 @@ DummyAudioBackend::main_process_thread ()
        _running = true;
        _processed_samples = 0;
 
-       struct timeval clock1, clock2;
-       ::gettimeofday (&clock1, NULL);
+       uint64_t clock1, clock2;
+       clock1 = g_get_monotonic_time();
        while (_running) {
                if (engine.process_callback (_samples_per_period)) {
                        return 0;
                }
                _processed_samples += _samples_per_period;
                if (!_freewheeling) {
-                       ::gettimeofday (&clock2, NULL);
-                       const int elapsed_time = (clock2.tv_sec - clock1.tv_sec) * 1000000 + (clock2.tv_usec - clock1.tv_usec);
-                       const int nomial_time = 1000000 * _samples_per_period / _samplerate;
+                       clock2 = g_get_monotonic_time();
+                       const int64_t elapsed_time = clock2 - clock1;
+                       const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate;
                        _dsp_load = elapsed_time / (float) nomial_time;
                        if (elapsed_time < nomial_time) {
                                Glib::usleep (nomial_time - elapsed_time);
@@ -1002,7 +1018,7 @@ DummyAudioBackend::main_process_thread ()
                        _dsp_load = 1.0;
                        Glib::usleep (100); // don't hog cpu
                }
-               ::gettimeofday (&clock1, NULL);
+               clock1 = g_get_monotonic_time();
        }
        _running = false;
        return 0;
index 7f97dd17f910213d226f383aeec07c7df018060e..28143ff7ba9d4254f53267fe283b81d4948624cc 100644 (file)
@@ -282,6 +282,9 @@ class DummyAudioBackend : public AudioBackend {
                uint32_t _n_inputs;
                uint32_t _n_outputs;
 
+               uint32_t _n_midi_inputs;
+               uint32_t _n_midi_outputs;
+
                uint32_t _systemic_input_latency;
                uint32_t _systemic_output_latency;
 
index c98aa571da5f1d617cfb2b828ed2e58cdd76e740..5e3d2b4da8be1e5bcf09e9b1742310bbfa76f010 100644 (file)
 namespace wvNS { 
 UMicroseconds& UMicroseconds::ReadTime()
 {
+       // Note: g_get_monotonic_time() may be a viable alternative
+       // (it is on Linux and OSX); if not, this code should really go into libpbd
 #ifdef PLATFORM_WINDOWS
        LARGE_INTEGER Frequency, Count ;
 
        QueryPerformanceFrequency(&Frequency) ;
        QueryPerformanceCounter(&Count);
        theTime = uint64_t((Count.QuadPart * 1000000.0 / Frequency.QuadPart));
-#endif
 
-#if defined(__linux__) || defined(__APPLE__)
-//     Mac code replaced by posix calls, to reduce Carbon dependency. 
-       timeval buf;
+#elif defined __MACH__ // OSX, BSD..
+
+       clock_serv_t cclock;
+       mach_timespec_t mts;
+       host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+       clock_get_time(cclock, &mts);
+       mach_port_deallocate(mach_task_self(), cclock);
+       theTime = (uint64_t)mts.tv_sec * 1e6 + (uint64_t)mts.tv_nsec / 1000;
+
+#else // Linux, POSIX
 
-       gettimeofday(&buf,NULL);
+       struct timespec *ts
+       clock_gettime(CLOCK_MONOTONIC, ts);
+       theTime = (uint64_t)ts.tv_sec * 1e6 + (uint64_t)buf.tv_nsec / 1000;
 
-       // micro sec
-       theTime = uint64_t(buf.tv_sec) * 1000*1000 + buf.tv_usec;
 #endif
 
        return *this;
index 12a20080b6d8fc4851d373a2fa5c2fb79c8df929..b2041d60310f3eea3132c6ee288807a85e323f23 100644 (file)
@@ -3,6 +3,10 @@
 #include <string.h>
 #include <vector>
 
+#include "pbd/pbd.h"
+#include "pbd/transmitter.h"
+#include "pbd/receiver.h"
+
 #include "ardour/filesystem_paths.h"
 #ifdef LXVST_SUPPORT
 #include "ardour/linux_vst_support.h"
 #endif
 #include "../ardour/filesystem_paths.cc"
 #include "../ardour/directory_names.cc"
-#include "../pbd/error.cc"
-#include "../pbd/basename.cc"
-#include "../pbd/search_path.cc"
-#include "../pbd/transmitter.cc"
-#include "../pbd/whitespace.cc"
+
 
 #ifdef LXVST_SUPPORT
 void
 vstfx_destroy_editor (VSTState* /*vstfx*/) { }
 #endif
 
+using namespace PBD;
+
+class DummyReceiver : public Receiver {
+       protected:
+               void receive (Transmitter::Channel chn, const char * str) {
+                       const char *prefix = "";
+                       switch (chn) {
+                               case Transmitter::Error:
+                                       prefix = "[ERROR]: ";
+                                       break;
+                               case Transmitter::Info:
+                                       /* ignore */
+                                       return;
+                               case Transmitter::Warning:
+                                       prefix = "[WARNING]: ";
+                                       break;
+                               case Transmitter::Fatal:
+                                       prefix = "[FATAL]: ";
+                                       break;
+                               case Transmitter::Throw:
+                                       abort ();
+                       }
+
+                       std::cerr << prefix << str << std::endl;
+
+                       if (chn == Transmitter::Fatal) {
+                               ::exit (1);
+                       }
+               }
+};
+
+DummyReceiver dummy_receiver;
+
 int main (int argc, char **argv) {
-       if (argc != 2) {
-               fprintf(stderr, "usage: %s <vst>\n", argv[0]);
+       char *dllpath = NULL;
+       if (argc == 3 && !strcmp("-f", argv[1])) {
+               dllpath = argv[2];
+               if (strstr (dllpath, ".so" ) || strstr(dllpath, ".dll")) {
+                       vstfx_remove_infofile(dllpath);
+                       vstfx_un_blacklist(dllpath);
+               }
+
+       }
+       else if (argc != 2) {
+               fprintf(stderr, "usage: %s [-f] <vst>\n", argv[0]);
                return EXIT_FAILURE;
+       } else {
+               dllpath = argv[1];
        }
 
-       char *dllpath = argv[1];
+       PBD::init();
+
+       dummy_receiver.listen_to (error);
+       dummy_receiver.listen_to (info);
+       dummy_receiver.listen_to (fatal);
+       dummy_receiver.listen_to (warning);
+
        std::vector<VSTInfo *> *infos = 0;
+
+       if (0) { }
 #ifdef LXVST_SUPPORT
-       if (strstr (dllpath, ".so")) {
+       else if (strstr (dllpath, ".so")) {
                infos = vstfx_get_info_lx(dllpath);
        }
 #endif
 
 #ifdef WINDOWS_VST_SUPPORT
-       if (strstr (dllpath, ".dll")) {
+       else if (strstr (dllpath, ".dll")) {
                infos = vstfx_get_info_fst(dllpath);
        }
 #endif
+       else {
+               fprintf(stderr, "'%s' is not a supported VST plugin.\n", dllpath);
+       }
+
+       PBD::cleanup();
 
        if (!infos || infos->empty()) {
                return EXIT_FAILURE;
@@ -60,4 +117,3 @@ int main (int argc, char **argv) {
                return EXIT_SUCCESS;
        }
 }
-
index 58e2f8f5bd066ff2415b3da1842e7f9e7ef528d3..00b65f21d866af0786c4b2cfbbee51e6c456e339 100644 (file)
@@ -37,7 +37,7 @@ class LIBGTKMM2EXT_API IdleAdjustment : public sigc::trackable
 
   private:
        void underlying_adjustment_value_changed();
-       struct timeval last_vc;
+       int64_t last_vc;
        gint timeout_handler();
        bool timeout_queued;
 };
index edf5517fffc6807b49810594a09cf17c08a0bae2..030d717133b52d8f4eadaa9804366f1045dee075 100644 (file)
@@ -33,7 +33,7 @@ IdleAdjustment::IdleAdjustment (Gtk::Adjustment& adj)
 {
        adj.signal_value_changed().connect (mem_fun (*this, &IdleAdjustment::underlying_adjustment_value_changed));
        timeout_queued = 0;
-       gettimeofday (&last_vc, 0);
+       last_vc = g_get_monotonic_time();
 }
 
 IdleAdjustment::~IdleAdjustment ()
@@ -43,7 +43,7 @@ IdleAdjustment::~IdleAdjustment ()
 void
 IdleAdjustment::underlying_adjustment_value_changed ()
 {
-       gettimeofday (&last_vc, 0);
+       last_vc = g_get_monotonic_time();
        
        if (timeout_queued) {
                return;
@@ -56,16 +56,13 @@ IdleAdjustment::underlying_adjustment_value_changed ()
 gint
 IdleAdjustment::timeout_handler ()
 {
-       struct timeval now;
-       struct timeval tdiff;
+       int64_t now, tdiff;
+       now = g_get_monotonic_time();
+       tdiff = now - last_vc;
 
-       gettimeofday (&now, 0);
+       std::cerr << "timer elapsed, diff = " << tdiff << " usec" << std::endl;
 
-       timersub (&now, &last_vc, &tdiff);
-
-       std::cerr << "timer elapsed, diff = " << tdiff.tv_sec << " + " << tdiff.tv_usec << std::endl;
-
-       if (tdiff.tv_sec > 0 || tdiff.tv_usec > 250000) {
+       if (tdiff > 250000) {
                std::cerr << "send signal\n";
                value_changed ();
                timeout_queued = false;
index 1232175fecc8192643c4bc2db22c3b5afbe56bc7..ce6e5a9c4f9367664107aa47b40340d8d39a89f0 100644 (file)
@@ -42,6 +42,8 @@
 #include <string>
 #include <pthread.h>
 #include <signal.h>
+#include <map>
+
 #ifdef NOPBD  /* unit-test outside ardour */
 #include <sigc++/bind.h>
 #include <sigc++/signal.h>
@@ -94,6 +96,23 @@ class LIBPBD_API SystemExec
                 *
                 */
                SystemExec (std::string c, char ** a);
+
+               /** similar to \ref SystemExec but expects a whole command line, and
+                * handles some simple escape sequences.
+                *
+                * @param command complete command-line to be executed
+                * @param subs a map of <char, std::string> listing the % substitutions to
+                *             be made.
+                *
+                * creates an argv array from the given command string, splitting into
+                * parameters at spaces.
+                * "\ " is non-splitting space, "\\" (and "\" at end of command) as "\",
+                * for "%<char>", <char> is looked up in subs and the corresponding string
+                * substituted. "%%" (and "%" at end of command)
+                * returns an argv array suitable for creating a new SystemExec with
+                */
+               SystemExec (std::string command, const std::map<char, std::string> subs);
+
                virtual ~SystemExec ();
 
                /** fork and execute the given program
@@ -182,6 +201,7 @@ class LIBPBD_API SystemExec
                int nicelevel; ///< process nice level - defaults to 0
 
                void make_argp(std::string);
+               void make_argp_escaped(std::string command, const std::map<char, std::string> subs);
                void make_envp();
 
                char **argp;
@@ -198,6 +218,7 @@ class LIBPBD_API SystemExec
 #else
                pid_t pid;
 #endif
+               void init ();
                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.
index 0102323505cf651336b2900987ef09e3868fc9f3..82398af0c84c7854fbd640901dab2a441ce89d73 100644 (file)
@@ -151,9 +151,8 @@ static int close_allv(const int except_fds[]) {
 }
 #endif /* not on windows, nor vfork */
 
-
-SystemExec::SystemExec (std::string c, std::string a)
-       : cmd(c)
+void
+SystemExec::init ()
 {
        pthread_mutex_init(&write_lock, NULL);
        thread_active=false;
@@ -161,12 +160,19 @@ SystemExec::SystemExec (std::string c, std::string a)
        pin[1] = -1;
        nicelevel = 0;
        envp = NULL;
-       argp = NULL;
 #ifdef PLATFORM_WINDOWS
        stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
        stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
        stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
 #endif
+}
+
+SystemExec::SystemExec (std::string c, std::string a)
+       : cmd(c)
+{
+       init ();
+
+       argp = NULL;
        make_envp();
        make_argp(a);
 }
@@ -174,21 +180,101 @@ SystemExec::SystemExec (std::string c, std::string 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;
+       init ();
+
 #ifdef PLATFORM_WINDOWS
-       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 (std::string command, const std::map<char, std::string> subs)
+{
+       init ();
+       make_argp_escaped(command, subs);
+       cmd = argp[0];
+       // cmd = strdup(argp[0]);
+       make_envp();
+}
+
+void
+SystemExec::make_argp_escaped(std::string command, const std::map<char, std::string> subs)
+{
+
+       int inquotes = 0;
+       int n = 0;
+       size_t i = 0;
+       std::string arg = "";
+
+       argp = (char **) malloc(sizeof(char *));
+
+       for (i = 0; i <= command.length(); i++) { // include terminating '\0'
+               char c = command.c_str()[i];
+               if (inquotes) {
+                       if (c == '"') {
+                               inquotes = 0;
+                       } else {
+                               // still in quotes - just copy
+                               arg += c;
+                       }
+               } else switch (c) {
+                       case '%' :
+                               c = command.c_str()[++i];
+                               if (c == '%' || c == '\0') {
+                                       // "%%", "%" at end-of-string => "%"
+                                       arg += '%';
+                               } else {
+                                       // search subs for string to substitute for char
+                                       std::map<char, std::string>::const_iterator s = subs.find(c);
+                                       if (s != subs.end()) {
+                                               // found substitution
+                                               arg += s->second;
+                                       } else {
+                                               // not a valid substitution, just copy
+                                               arg += '%';
+                                               arg += c;
+                                       }
+                               }
+                               break;
+                       case '\\':
+                               c = command.c_str()[++i];
+                               switch (c) {
+                                       case ' ' :
+                                       case '"' : arg += c; break; // "\\", "\" at end-of-string => "\"
+                                       case '\0': 
+                                       case '\\': arg += '\\'; break;
+                                       default  : arg += '\\'; arg += c; break;
+                               }
+                               break;
+                       case '"' :
+                               inquotes = 1;
+                               break;
+                       case ' ' :
+                       case '\t':
+                       case '\0':
+                               if (arg.length() > 0) {
+                                       // if there wasn't already a space or tab, start a new parameter
+                                       argp = (char **) realloc(argp, (n + 2) * sizeof(char *));
+                                       argp[n++] = strdup (arg.c_str());
+                                       arg = "";
+                               }
+                               break;
+                       default :
+                               arg += c;
+                               break;
+               }
+       }
+       argp[n] = NULL;
+
+       char *p = argp[0];
+       n = 0;
+       do {
+               std::cerr << "argv[" << n << "] == \"" << p << "\"" << std::endl;
+               p = argp[n++];
+       } while (p);
+
+}
+
 SystemExec::~SystemExec ()
 {
        terminate ();
@@ -522,7 +608,7 @@ SystemExec::make_argp(std::string args) {
                        *cp2 = '\0';
                        argp[argn++] = strdup(cp1);
                        cp1 = cp2 + 1;
-           argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
+                       argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
                }
        }
        if (cp2 != cp1) {
index da7340182e2f663bd65c557ac4fb1a87a6820290..63e6ad4201daf5c11a59e705d07fabda3eb47200 100644 (file)
@@ -154,7 +154,7 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
        framepos_t     last_where;
        ARDOUR::gain_t last_track_gain;
        uint32_t       last_meter_fill;
-       struct timeval last_wheel_motion;
+       uint64_t       last_wheel_motion;
        int            last_wheel_dir;
 
        Glib::Mutex io_lock;
index 96d7210ff6ad0250ad89778aae70a3eb551fbb9c..0e19062911a48ed7c9c42d8d87c18e7c3fbe94c3 100644 (file)
@@ -50,17 +50,8 @@ public:
        */
        unsigned long start()
        {
-#ifdef _WIN32
-               _start = (unsigned long)::GetTickCount();
-#else
-               gettimeofday ( &_start, 0 );
-#endif
-               running = true;
-#ifdef _WIN32
-               return _start;
-#else
-               return ( _start.tv_sec * 1000000 + _start.tv_usec ) / 1000;
-#endif
+               _start = g_get_monotonic_time();
+               return _start / 1000;
        }
 
        /**
@@ -69,12 +60,7 @@ public:
        */
        unsigned long stop()
        {
-#ifdef _WIN32
-               _stop = (unsigned long)::GetTickCount();
-#else
-               gettimeofday ( &_stop, 0 );
-#endif
-               running = false;
+               _stop = g_get_monotonic_time();
                return elapsed();
        }
 
@@ -85,28 +71,12 @@ public:
        {
                if ( running )
                {
-#ifdef _WIN32
-                       DWORD current = ::GetTickCount();
-                       return current - _start;
-#else
-                       struct timeval current;
-                       gettimeofday ( &current, 0 );
-                       return (
-                               ( current.tv_sec * 1000000 + current.tv_usec ) - ( _start.tv_sec * 1000000 + _start.tv_usec )
-                       ) / 1000
-                       ;
-#endif
+                       uint64_t now = g_get_monotonic_time();
+                       return (now - _start) / 1000;
                }
                else
                {
-#ifdef _WIN32
-                       return _stop - _start;
-#else
-                       return (
-                               ( _stop.tv_sec * 1000000 + _stop.tv_usec ) - ( _start.tv_sec * 1000000 + _start.tv_usec )
-                       ) / 1000
-                       ;
-#endif
+                       return (_stop - _start) / 1000;
                }
        }
        
@@ -121,13 +91,8 @@ public:
        }
 
 private:
-#ifdef _WIN32
-       unsigned long _start;
-       unsigned long _stop;
-#else
-       struct timeval _start;
-       struct timeval _stop;
-#endif
+       uint64_t _start;
+       uint64_t _stop;
        bool running;
 };
 
index baa4ba079b90ab2753dd66658de6a211a3652093..3f15e060a2d64ee8ba1443bd07b5192d7c6cb040 100644 (file)
@@ -62,7 +62,7 @@ TranzportControlProtocol::datawheel ()
                        prev_track ();
                }
 
-               timerclear (&last_wheel_motion);
+               last_wheel_motion = 0;
                
        } else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
 
@@ -72,7 +72,7 @@ TranzportControlProtocol::datawheel ()
                        prev_marker ();
                }
                
-               timerclear (&last_wheel_motion);
+               last_wheel_motion = 0;
                
        } else if (buttonmask & ButtonShift) {
                
@@ -104,7 +104,7 @@ TranzportControlProtocol::datawheel ()
                        }
                }
                
-               timerclear (&last_wheel_motion);
+               last_wheel_motion = 0;
                
        } else {
                
@@ -149,11 +149,10 @@ void
 TranzportControlProtocol::scrub ()
 {
        float speed;
-       struct timeval now;
-       struct timeval delta;
+       uint64_t now;
        int dir;
        
-       gettimeofday (&now, 0);
+       now = g_get_monotonic_time();
        
        if (_datawheel < WheelDirectionThreshold) {
                dir = 1;
@@ -165,13 +164,10 @@ TranzportControlProtocol::scrub ()
                /* changed direction, start over */
                speed = 0.1f;
        } else {
-               if (timerisset (&last_wheel_motion)) {
-
-                       timersub (&now, &last_wheel_motion, &delta);
-                       
+               if (last_wheel_motion != 0) {
                        /* 10 clicks per second => speed == 1.0 */
                        
-                       speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
+                       speed = 100000.0f / (float) (now - last_wheel_motion)
                        
                } else {