[ardour-dev] new feature: export all ranges

Andre Raue dawng at raue.info
Tue Jan 3 02:46:20 PST 2006


Hello,

during the last few weaks I have been implementing a new feature in 
ardour. This makes it possible to export all ranges marked with range 
markers to separate files in a row. Below you will find the following 
information:

1) How is it expected to work / what should it do?
2) limitations / requirements
3) Status of developement
4) Next steps
5) cvs diff against 0.99 for requirements mentioned in 2)
6) cvs diff against 0.99 for the current alpha-version (new files 
excluded, 5) included)
7) diff of new file session_export_dialog.cc against export_dialog.cc
8) diff of new file session_export_dialog.h against export_dialog.h

I would be happy about some constructive criticisim. So - if you have 
some comments or ideas concerning this feature/code, please don't 
hesitate to utter them. In addition it would be great if you could 
implement the changes explained in 2) and 5) in ardour 2.0, as I need 
those for this feature.

If somebody would like to have a complete version of the changed/new 
files, please let me know.  In this case I will provide them for download.

Last but not least I would like to thank Tommi Sakari Uimonen and Taybin 
Rutkin for helping me getting started.


1) How is it expected to work / what should it do?
-------------------------------------------------------
a) mark ranges within ardour as usual
b) select menu item  "Session - Export - Export all ranges..."
c) a dialog similar to the usual export-dialog appears
d) define a destination directory and some export-attributes like 
sampling-rate etc.
e) push start-button
f) all ranges marked by range markers get exported to the destination 
directory. Each range results in a separate file. File names are the 
same as range names.
g) export-dialog gets closed


2) limitations / requirements
-------------------------------
Using the current code, I found no safe way, to decide wether a Location 
object is a range or not. What I found is "enum Flags" in location.h. 
Using these flags you can for example decide if a Location object 
IsMark, IsAutoPunch, ... But there is no flag IsRange. Thus I decided to 
add this flag. This led to changes in the files editor_mouse.cc, 
location_ui.cc and location.h. You can find these changes in 5). These 
changes are the requirements I need for the implemented feature.
The disadvantage of this solution is: Ranges defined with prior versions 
of ardour won't be exported using this feature, as they are not flagged 
as ranges. An idea for solving this problem is to add this flag for all 
Location objects with different start- and end-frame when opening a 
session that has been saved with a prior ardour-version. Is this 
possible? Does the ardour-version get stored in the session file? Are 
ranges the only locations with different start- and end-frame in 0.99?


3) Status of developement
-----------------------------
As I based my development on ardour 0.99, I decided to halt development 
when reaching a proof of concept status until ardour 2.0 will be 
released. This is the point where I am. Thus I concider the current 
version as an alpha-version.
It works but you have to know what you do and it still has some bugs. E.g.:
- the name, that you fill in for the destination-directory must not have 
a '/' at the end
- the destination-directory get's not checked for existence
- all files get the ending '.wav' even if you chose a different file-format
- the progress bar starts at 0% and ends at 100% for each single range 
instead of starting by 0% for the first range and ending at 100% for the 
last one

So, if you find some more bugs, please let me know.


4) Next steps
---------------
After getting access to the 2.0-version of the ExportDialog class I will 
go on with development. My idea is to do some refactoring so that there 
is one base class and three derived classes for export-dialogs. One for 
exporting a region, one for exporting a single range and one for 
exporting all ranges. The bugs mentioned in 3) will be removed. I hope 
to be able to provide a complete version with ardour 2.0 or the version 
that follows 2.0.

Please let me know, when the 2.0-version of the ExportDialog class is ready.


5) cvs diff against 0.99 for requirements mentioned in 2)
--------------------------------------------------------------

Index: gtk_ardour/editor_mouse.cc
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/gtk_ardour/editor_mouse.cc,v
retrieving revision 1.1
retrieving revision 1.3
diff -r1.1 -r1.3
4205c4205
<             newloc = new Location(temp_location->start(), 
temp_location->end(), "unnamed");
---
 >             newloc = new Location(temp_location->start(), 
temp_location->end(), "unnamed", Location::IsRange);
Index: gtk_ardour/location_ui.cc
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/gtk_ardour/location_ui.cc,v
retrieving revision 1.1
retrieving revision 1.4
diff -r1.1 -r1.4
813c813
<         Location *location = new Location (where, where, "unnamed");
---
 >         Location *location = new Location (where, where, "unnamed", 
Location::IsRange);
886d885
<
Index: libs/ardour/ardour/location.h
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/libs/ardour/ardour/location.h,v
retrieving revision 1.1
retrieving revision 1.3
diff -r1.1 -r1.3
53c53,54
<         IsEnd = 0x20
---
 >         IsEnd = 0x20,
 >         IsRange = 0x40
97a99
 >     bool is_range() { return _flags & IsRange; }



6) cvs diff against 0.99 for the current alpha-version (new files excluded)
--------------------------------------------------------------------------------

Index: gtk_ardour/SConscript
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/gtk_ardour/SConscript,v
retrieving revision 1.1
retrieving revision 1.2
diff -r1.1 -r1.2
94a95
 > session_export_dialog.cc
Index: gtk_ardour/ardour_ui_ed.cc
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/gtk_ardour/ardour_ui_ed.cc,v
retrieving revision 1.1
retrieving revision 1.3
diff -r1.1 -r1.3
134a135
 >     export_items.push_back (MenuElem (_("Export all ranges..."), slot 
(*editor, &PublicEditor::export_ranges)));
315d315
<
Index: gtk_ardour/editor.h
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/gtk_ardour/editor.h,v
retrieving revision 1.1
retrieving revision 1.3
diff -r1.1 -r1.3
93a94
 > class SessionExportDialog;
230a232
 >     void export_ranges();
1596a1599
 >     SessionExportDialog *session_export_dialog;
Index: gtk_ardour/editor_export_audio.cc
===================================================================
RCS file: 
/home/andre/cvs_repository/Ardour/gtk_ardour/editor_export_audio.cc,v
retrieving revision 1.1
retrieving revision 1.4
diff -r1.1 -r1.4
23a24
 > #include "session_export_dialog.h"
69a71,84
 > Editor::export_ranges()
 > {
 >     if (session) {
 >         if (session_export_dialog == 0) {
 >             session_export_dialog = new SessionExportDialog(*this);
 >         }
 >        
 >         session_export_dialog->connect_to_session (session);
 >         session_export_dialog->set_range (0, 
session->current_end_frame());
 >         session_export_dialog->start_export();
 >     }
 > }
 >
 > void
Index: gtk_ardour/editor_mouse.cc
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/gtk_ardour/editor_mouse.cc,v
retrieving revision 1.1
retrieving revision 1.3
diff -r1.1 -r1.3
4205c4205
<             newloc = new Location(temp_location->start(), 
temp_location->end(), "unnamed");
---
 >             newloc = new Location(temp_location->start(), 
temp_location->end(), "unnamed", Location::IsRange);
Index: gtk_ardour/location_ui.cc
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/gtk_ardour/location_ui.cc,v
retrieving revision 1.1
retrieving revision 1.4
diff -r1.1 -r1.4
813c813
<         Location *location = new Location (where, where, "unnamed");
---
 >         Location *location = new Location (where, where, "unnamed", 
Location::IsRange);
886d885
<
Index: gtk_ardour/public_editor.h
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/gtk_ardour/public_editor.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -r1.1 -r1.2
82a83
 >     virtual void export_ranges() = 0;
Index: libs/ardour/ardour/location.h
===================================================================
RCS file: /home/andre/cvs_repository/Ardour/libs/ardour/ardour/location.h,v
retrieving revision 1.1
retrieving revision 1.3
diff -r1.1 -r1.3
53c53,54
<         IsEnd = 0x20
---
 >         IsEnd = 0x20,
 >         IsRange = 0x40
97a99
 >     bool is_range() { return _flags & IsRange; }



7) diff of new file session_export_dialog.cc against export_dialog.cc
---------------------------------------------------------------------------

40c40
< #include "export_dialog.h"
---
 > #include "session_export_dialog.h"
51,54c51,56
< GdkPixmap* ExportDialog::check_pixmap = 0;
< GdkPixmap* ExportDialog::check_mask = 0;
< GdkPixmap* ExportDialog::empty_pixmap = 0;
< GdkPixmap* ExportDialog::empty_mask = 0;
---
 > void frames_to_cd_frames_string (char*, jack_nframes_t, jack_nframes_t);
 >
 > GdkPixmap* SessionExportDialog::check_pixmap = 0;
 > GdkPixmap* SessionExportDialog::check_mask = 0;
 > GdkPixmap* SessionExportDialog::empty_pixmap = 0;
 > GdkPixmap* SessionExportDialog::empty_mask = 0;
102c104
< ExportDialog::ExportDialog(PublicEditor& e, AudioRegion* r)
---
 > SessionExportDialog::SessionExportDialog(PublicEditor& e, AudioRegion* r)
159c161
<     master_selector.button_press_event.connect (slot (*this, 
&ExportDialog::master_selector_button_press_event));
---
 >     master_selector.button_press_event.connect (slot (*this, 
&SessionExportDialog::master_selector_button_press_event));
171c173
<     track_selector.button_press_event.connect (slot (*this, 
&ExportDialog::track_selector_button_press_event));
---
 >     track_selector.button_press_event.connect (slot (*this, 
&SessionExportDialog::track_selector_button_press_event));
217c219
<     track_selector_button.clicked.connect (slot (*this, 
&ExportDialog::track_selector_button_click));
---
 >     track_selector_button.clicked.connect (slot (*this, 
&SessionExportDialog::track_selector_button_click));
381,383c383,385
<     delete_event.connect (slot (*this, &ExportDialog::window_closed));
<     ok_button.clicked.connect (slot (*this, &ExportDialog::do_export));
<     cancel_button.clicked.connect (slot (*this, 
&ExportDialog::end_dialog));
---
 >     delete_event.connect (slot (*this, 
&SessionExportDialog::window_closed));
 >     ok_button.clicked.connect (slot (*this, 
&SessionExportDialog::do_export));
 >     cancel_button.clicked.connect (slot (*this, 
&SessionExportDialog::end_dialog));
386c388
<     file_browse_button.clicked.connect (slot (*this, 
&ExportDialog::initiate_browse));
---
 >     file_browse_button.clicked.connect (slot (*this, 
&SessionExportDialog::initiate_browse));
388,392c390,394
<     channel_count_combo.get_popwin()->unmap_event.connect (slot 
(*this, &ExportDialog::channels_chosen));
<     bitdepth_format_combo.get_popwin()->unmap_event.connect (slot 
(*this, &ExportDialog::bitdepth_chosen));
<     header_format_combo.get_popwin()->unmap_event.connect (slot 
(*this, &ExportDialog::header_chosen));
<     sample_rate_combo.get_popwin()->unmap_event.connect (slot (*this, 
&ExportDialog::sample_rate_chosen));
<     cue_file_combo.get_popwin()->unmap_event.connect (slot (*this, 
&ExportDialog::cue_file_type_chosen));
---
 >     channel_count_combo.get_popwin()->unmap_event.connect (slot 
(*this, &SessionExportDialog::channels_chosen));
 >     bitdepth_format_combo.get_popwin()->unmap_event.connect (slot 
(*this, &SessionExportDialog::bitdepth_chosen));
 >     header_format_combo.get_popwin()->unmap_event.connect (slot 
(*this, &SessionExportDialog::header_chosen));
 >     sample_rate_combo.get_popwin()->unmap_event.connect (slot (*this, 
&SessionExportDialog::sample_rate_chosen));
 >     cue_file_combo.get_popwin()->unmap_event.connect (slot (*this, 
&SessionExportDialog::cue_file_type_chosen));
395c397
< ExportDialog::~ExportDialog()
---
 > SessionExportDialog::~SessionExportDialog()
403c405
< ExportDialog::connect_to_session (Session *s)
---
 > SessionExportDialog::connect_to_session (Session *s)
438c440
< ExportDialog::set_state()
---
 > SessionExportDialog::set_state()
554c556
< ExportDialog::save_state()
---
 > SessionExportDialog::save_state()
592c594
< ExportDialog::set_range (jack_nframes_t start, jack_nframes_t end)
---
 > SessionExportDialog::set_range (jack_nframes_t start, jack_nframes_t end)
604c606
< ExportDialog::progress_timeout ()
---
 > SessionExportDialog::progress_timeout ()
611c613
< ExportDialog::_export_region_thread (void *arg)
---
 > SessionExportDialog::_export_region_thread (void *arg)
615c617
<     static_cast<ExportDialog*>(arg)->export_region ();
---
 >     static_cast<SessionExportDialog*>(arg)->export_region ();
620c622
< ExportDialog::export_region ()
---
 > SessionExportDialog::export_region ()
625,639d626
< void
< frames_to_cd_frames_string (char* buf, jack_nframes_t when, 
jack_nframes_t fr)
< {
<
<   long unsigned int remainder;
<   int mins, secs, frames;
<
<     mins = when / (60 * fr);
<     remainder = when - (mins * 60 * fr);
<     secs = remainder / fr;
<     remainder -= secs * fr;
<     frames = remainder / (fr / 75);
<     sprintf (buf, " %02d:%02d:%02d", mins, secs, frames);
<
< }
648c635
< ExportDialog::export_toc_file (Locations::LocationList& locations, 
const string& path)
---
 > SessionExportDialog::export_toc_file (Locations::LocationList& 
locations, const string& path)
771c758
< ExportDialog::export_cue_file (Locations::LocationList& locations, 
const string& path)
---
 > SessionExportDialog::export_cue_file (Locations::LocationList& 
locations, const string& path)
894c881
< ExportDialog::do_export_cd_markers (const string& path,const string& 
cuefile_type)
---
 > SessionExportDialog::do_export_cd_markers (const string& path,const 
string& cuefile_type)
897c884
<         session->locations()->apply (*this, 
&ExportDialog::export_toc_file, path);   
---
 >         session->locations()->apply (*this, 
&SessionExportDialog::export_toc_file, path);   
899c886
<         session->locations()->apply (*this, 
&ExportDialog::export_cue_file, path);
---
 >         session->locations()->apply (*this, 
&SessionExportDialog::export_cue_file, path);
904,906c891,894
< void
< ExportDialog::do_export ()
< {
---
 > /*
 >     initializes spec, so that the export of a range can start
 > */
 > void SessionExportDialog::initSpec(AudioExportSpecification &spec){
908,921d895
<
<     ok_button.set_sensitive(false);
<     save_state();
<
<     if (cue_file_combo.get_entry()->get_text () != _("None")) {
<         do_export_cd_markers (file_entry.get_text(), 
cue_file_combo.get_entry()->get_text ());
<     }
<
<     if (cuefile_only_checkbox.get_active()) {
<         end_dialog ();
<         return;
<     }
<
<     set_modal (true);
923d896
<     spec.path = file_entry.get_text();
1048a1022
 > }
1050,1051c1024,1028
<     progress_connection = Main::timeout.connect (slot (*this, 
&ExportDialog::progress_timeout), 100);
<     cancel_label.set_text (_("Stop Export"));
---
 > void
 > SessionExportDialog::do_export ()
 > {
 >     ok_button.set_sensitive(false);
 >     save_state();
1053,1059c1030,1031
<     if (!audio_region) {
<         if (session->start_audio_export (spec)) {
<             goto out;
<         }
<     } else {
<         pthread_t thr;
<         pthread_create_and_store ("region export", &thr, 0, 
ExportDialog::_export_region_thread, this);
---
 >     if (cue_file_combo.get_entry()->get_text () != _("None")) {
 >         do_export_cd_markers (file_entry.get_text(), 
cue_file_combo.get_entry()->get_text ());
1062,1067c1034,1054
<     gtk_main_iteration ();
<     while (spec.running) {
<         if (gtk_events_pending()) {
<             gtk_main_iteration ();
<         } else {
<             usleep (10000);
---
 >     if (cuefile_only_checkbox.get_active()) {
 >         end_dialog ();
 >         return;
 >     }
 >
 >     set_modal (true);
 >    
 >     progress_connection = Main::timeout.connect (slot (*this, 
&SessionExportDialog::progress_timeout), 100);
 >     cancel_label.set_text (_("Stop Export"));
 >
 >     session->locations()->apply(*this, 
&SessionExportDialog::process_audioranges_export, spec);
 > #if 0
 >     goto out;
 > #endif   
 >    
 >     gtk_main_iteration();
 >     while(spec.running){
 >         if(gtk_events_pending()){
 >             gtk_main_iteration();
 >         }else {
 >             usleep(10000);
1077,1078c1064,1065
< void
< ExportDialog::end_dialog ()
---
 > void
 > 
SessionExportDialog::process_audioranges_export(Locations::LocationList& 
locations, ARDOUR::AudioExportSpecification& spec)
1079a1067,1101
 >     Locations::LocationList::iterator locationIter;
 >
 >     //XXX: ToDo: check somewhere if the given destination path is 
existing
 >     // and if it is a path
 >    
 >     for (locationIter = locations.begin(); locationIter != 
locations.end(); ++locationIter) {
 >         Location *currentLocation = (*locationIter);
 >        
 >         if(currentLocation->is_range()){
 >             //XXX: ToDo: check if file_entry has "/" at the end
 >             initSpec(spec);
 >             spec.path = file_entry.get_text() + '/' + 
currentLocation->name() + ".wav";
 >             spec.start_frame = currentLocation->start();
 >             spec.end_frame = currentLocation->end();
 >
 >             session->request_locate(spec.start_frame, false);
 >
 >             //XXX: ToDo: what to do when start_audio_export fails? 
before it was
 >             // goto out; in method do_export
 >             session->start_audio_export(spec);
 >
 >             // wait until export of this range finished
 >             gtk_main_iteration();
 >             while(spec.running){
 >                 if(gtk_events_pending()){
 >                     gtk_main_iteration();
 >                 }else {
 >                     usleep(10000);
 >                 }
 >             }
 >            
 >             session->engine().freewheel (false);
 >         }
 >     }
 > }
1080a1103,1106
 >
 > void
 > SessionExportDialog::end_dialog ()
 > {
1106c1132
< ExportDialog::start_export ()
---
 > SessionExportDialog::start_export ()
1142c1168
< ExportDialog::header_chosen (GdkEventAny* ignored)
---
 > SessionExportDialog::header_chosen (GdkEventAny* ignored)
1153c1179
< ExportDialog::bitdepth_chosen (GdkEventAny* ignored)
---
 > SessionExportDialog::bitdepth_chosen (GdkEventAny* ignored)
1172c1198
< ExportDialog::cue_file_type_chosen (GdkEventAny* ignored)
---
 > SessionExportDialog::cue_file_type_chosen (GdkEventAny* ignored)
1184c1210
< ExportDialog::sample_rate_chosen (GdkEventAny* ignored)
---
 > SessionExportDialog::sample_rate_chosen (GdkEventAny* ignored)
1215c1241
< ExportDialog::channels_chosen (GdkEventAny* ignored)
---
 > SessionExportDialog::channels_chosen (GdkEventAny* ignored)
1293c1319
< ExportDialog::track_selector_button_press_event (GdkEventButton* ev)
---
 > SessionExportDialog::track_selector_button_press_event 
(GdkEventButton* ev)
1317c1343
< ExportDialog::master_selector_button_press_event (GdkEventButton* ev)
---
 > SessionExportDialog::master_selector_button_press_event 
(GdkEventButton* ev)
1341c1367
< ExportDialog::window_closed (GdkEventAny *ignored)
---
 > SessionExportDialog::window_closed (GdkEventAny *ignored)
1347c1373
< ExportDialog::initiate_browse ()
---
 > SessionExportDialog::initiate_browse ()
1353,1356c1379,1382
<         file_selector->get_cancel_button()->clicked.connect (bind 
(slot (*this, &ExportDialog::finish_browse), -1));
<         file_selector->get_ok_button()->clicked.connect (bind (slot 
(*this, &ExportDialog::finish_browse), 1));
<         file_selector->map_event.connect (bind (slot (*this, 
&ExportDialog::change_focus_policy), true));
<         file_selector->unmap_event.connect (bind (slot (*this, 
&ExportDialog::change_focus_policy), false));
---
 >         file_selector->get_cancel_button()->clicked.connect (bind 
(slot (*this, &SessionExportDialog::finish_browse), -1));
 >         file_selector->get_ok_button()->clicked.connect (bind (slot 
(*this, &SessionExportDialog::finish_browse), 1));
 >         file_selector->map_event.connect (bind (slot (*this, 
&SessionExportDialog::change_focus_policy), true));
 >         file_selector->unmap_event.connect (bind (slot (*this, 
&SessionExportDialog::change_focus_policy), false));
1362c1388
< ExportDialog::change_focus_policy (GdkEventAny *ev, bool yn)
---
 > SessionExportDialog::change_focus_policy (GdkEventAny *ev, bool yn)
1369c1395
< ExportDialog::finish_browse (int status)
---
 > SessionExportDialog::finish_browse (int status)
1384c1410
< ExportDialog::track_selector_button_click ()
---
 > SessionExportDialog::track_selector_button_click ()


8) diff of new file session_export_dialog.h against export_dialog.h
--------------------------------------------------------------------------

20,21c20,21
< #ifndef __ardour_export_dialog_h__
< #define __ardour_export_dialog_h__
---
 > #ifndef __ardour_session_export_dialog_h__
 > #define __ardour_session_export_dialog_h__
37c37
< class ExportDialog : public ArdourDialog
---
 > class SessionExportDialog : public ArdourDialog
40,41c40,41
<     ExportDialog (PublicEditor&, ARDOUR::AudioRegion* r = 0);
<     ~ExportDialog ();
---
 >     SessionExportDialog (PublicEditor&, ARDOUR::AudioRegion* r = 0);
 >     ~SessionExportDialog ();
112c112,113
<           void do_export_cd_markers (const string& path, const string& 
cuefile_type);
---
 >     void do_export_cd_markers (const string& path, const string& 
cuefile_type);
 >     void initSpec(ARDOUR::AudioExportSpecification &spec);
115a117,118
 >     void process_audioranges_export(ARDOUR::Locations::LocationList& 
locations, ARDOUR::AudioExportSpecification& spec);
 >
131c134
< #endif // __ardour_export_dialog_h__
---
 > #endif // __ardour_session_export_dialog_h__


Greetings

Andre



More information about the Ardour-Dev mailing list