summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-09-19 03:29:16 +0000
committerDavid Robillard <d@drobilla.net>2006-09-19 03:29:16 +0000
commit7bd41538d951c3e476655df741adfbebbb990bde (patch)
treef9988f959571c75535341ab1de463b7cfc5209e3
parentc7307c09b8584b15610f0b29a40f839d9183419a (diff)
Merged with trunk R920.
git-svn-id: svn://localhost/ardour2/branches/midi@921 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--SConstruct11
-rw-r--r--gtk2_ardour/actions.cc8
-rwxr-xr-xgtk2_ardour/ardev2
-rw-r--r--gtk2_ardour/ardour.menus24
-rw-r--r--gtk2_ardour/ardour_ui.cc144
-rw-r--r--gtk2_ardour/ardour_ui_dependents.cc4
-rw-r--r--gtk2_ardour/ardour_ui_dialogs.cc4
-rw-r--r--gtk2_ardour/ardour_ui_options.cc2
-rw-r--r--gtk2_ardour/audio_streamview.cc23
-rw-r--r--gtk2_ardour/automation_line.h3
-rw-r--r--gtk2_ardour/canvas-simplerect.c54
-rw-r--r--gtk2_ardour/editing_syms.h9
-rw-r--r--gtk2_ardour/editor.cc129
-rw-r--r--gtk2_ardour/editor.h23
-rw-r--r--gtk2_ardour/editor_actions.cc171
-rw-r--r--gtk2_ardour/editor_audio_import.cc2
-rw-r--r--gtk2_ardour/editor_canvas.cc56
-rw-r--r--gtk2_ardour/editor_export_audio.cc4
-rw-r--r--gtk2_ardour/editor_ops.cc16
-rw-r--r--gtk2_ardour/editor_rulers.cc166
-rw-r--r--gtk2_ardour/editor_tempodisplay.cc126
-rw-r--r--gtk2_ardour/midi_streamview.cc13
-rw-r--r--gtk2_ardour/new_session_dialog.cc8
-rw-r--r--gtk2_ardour/option_editor.cc57
-rw-r--r--gtk2_ardour/option_editor.h2
-rw-r--r--gtk2_ardour/region_gain_line.h4
-rw-r--r--gtk2_ardour/route_time_axis.cc51
-rw-r--r--gtk2_ardour/route_time_axis.h3
-rw-r--r--gtk2_ardour/route_ui.cc14
-rw-r--r--gtk2_ardour/route_ui.h10
-rw-r--r--gtk2_ardour/sfdb_ui.cc19
-rw-r--r--gtk2_ardour/streamview.cc3
-rw-r--r--gtk2_ardour/streamview.h2
-rw-r--r--libs/appleutility/CAAudioFile.cpp1241
-rw-r--r--libs/appleutility/CAAudioFile.h439
-rw-r--r--libs/appleutility/CABufferList.cpp179
-rw-r--r--libs/appleutility/CABufferList.h300
-rw-r--r--libs/appleutility/CAXException.cpp45
-rw-r--r--libs/appleutility/CAXException.h158
-rw-r--r--libs/ardour/SConscript28
-rw-r--r--libs/ardour/ardour/audio_diskstream.h2
-rw-r--r--libs/ardour/ardour/audiofilesource.h9
-rw-r--r--libs/ardour/ardour/audioplaylist.h2
-rw-r--r--libs/ardour/ardour/audioregion.h1
-rw-r--r--libs/ardour/ardour/audiosource.h4
-rw-r--r--libs/ardour/ardour/automation_event.h4
-rw-r--r--libs/ardour/ardour/coreaudiosource.h9
-rw-r--r--libs/ardour/ardour/destructive_filesource.h6
-rw-r--r--libs/ardour/ardour/diskstream.h2
-rw-r--r--libs/ardour/ardour/io.h3
-rw-r--r--libs/ardour/ardour/location.h6
-rw-r--r--libs/ardour/ardour/midi_source.h4
-rw-r--r--libs/ardour/ardour/playlist.h3
-rw-r--r--libs/ardour/ardour/port.h2
-rw-r--r--libs/ardour/ardour/region.h3
-rw-r--r--libs/ardour/ardour/session.h9
-rw-r--r--libs/ardour/ardour/smf_source.h4
-rw-r--r--libs/ardour/ardour/sndfilesource.h6
-rw-r--r--libs/ardour/ardour/source.h11
-rw-r--r--libs/ardour/ardour/source_factory.h9
-rw-r--r--libs/ardour/ardour/tempo.h3
-rw-r--r--libs/ardour/audio_diskstream.cc7
-rw-r--r--libs/ardour/audio_playlist.cc1
-rw-r--r--libs/ardour/audioengine.cc5
-rw-r--r--libs/ardour/audiofilesource.cc24
-rw-r--r--libs/ardour/audiofilter.cc2
-rw-r--r--libs/ardour/audioregion.cc23
-rw-r--r--libs/ardour/audiosource.cc8
-rw-r--r--libs/ardour/coreaudiosource.cc157
-rw-r--r--libs/ardour/destructive_filesource.cc12
-rw-r--r--libs/ardour/globals.cc4
-rw-r--r--libs/ardour/import.cc2
-rw-r--r--libs/ardour/io.cc5
-rw-r--r--libs/ardour/location.cc5
-rw-r--r--libs/ardour/midi_source.cc8
-rw-r--r--libs/ardour/panner.cc2
-rw-r--r--libs/ardour/plugin.cc4
-rw-r--r--libs/ardour/route.cc14
-rw-r--r--libs/ardour/session.cc74
-rw-r--r--libs/ardour/session_state.cc175
-rw-r--r--libs/ardour/session_time.cc4
-rw-r--r--libs/ardour/session_timefx.cc3
-rw-r--r--libs/ardour/smf_source.cc8
-rw-r--r--libs/ardour/sndfilesource.cc16
-rw-r--r--libs/ardour/source.cc13
-rw-r--r--libs/ardour/source_factory.cc81
-rw-r--r--libs/ardour/tempo.cc30
-rw-r--r--libs/ardour/utils.cc2
-rw-r--r--libs/ardour/vst_plugin.cc4
-rw-r--r--libs/gtkmm2ext/dndtreeview.cc7
-rw-r--r--libs/pbd/pbd/stateful.h2
91 files changed, 3495 insertions, 866 deletions
diff --git a/SConstruct b/SConstruct
index be4b6ce0b8..73aca5a4d9 100644
--- a/SConstruct
+++ b/SConstruct
@@ -468,17 +468,6 @@ if conf.CheckHeader ('boost/shared_ptr.hpp', language='CXX') == 0:
libraries['boost'] = conf.Finish ()
-conf = env.Configure ()
-
-# jack_port_ensure_monitor available
-
-if conf.CheckFunc('jack_port_ensure_monitor'):
- env.Append(CCFLAGS='-DWITH_JACK_PORT_ENSURE_MONITOR')
-else:
- print '\nWARNING: You need at least svn revision 985 of jack for hardware monitoring to work correctly.\n'
-
-env = conf.Finish()
-
#
# Check for liblo
diff --git a/gtk2_ardour/actions.cc b/gtk2_ardour/actions.cc
index 2197d4dc00..b2408620a5 100644
--- a/gtk2_ardour/actions.cc
+++ b/gtk2_ardour/actions.cc
@@ -73,13 +73,13 @@ ActionManager::init ()
ui_manager->add_ui_from_file (ui_file);
loaded = true;
} catch (Glib::MarkupError& err) {
- error << "badly formatted UI definition file" << endmsg;
+ error << _("badly formatted UI definition file") << endmsg;
} catch (...) {
- error << "Ardour menu definition file not found" << endmsg;
+ error << _("Ardour menu definition file not found") << endmsg;
}
if (!loaded) {
- error << "ardour will not work without a valid ardour.menus file" << endmsg;
+ error << _("ardour will not work without a valid ardour.menus file") << endmsg;
exit(1);
}
}
@@ -277,7 +277,7 @@ ActionManager::uncheck_toggleaction (const char * name)
RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
tact->set_active (false);
} else {
- error << "Unknown action name: " << name << endmsg;
+ error << string_compose (_("Unknown action name: %1"), name) << endmsg;
}
delete [] group_name;
diff --git a/gtk2_ardour/ardev b/gtk2_ardour/ardev
index 751557d634..d3d44e55fe 100755
--- a/gtk2_ardour/ardev
+++ b/gtk2_ardour/ardev
@@ -1,3 +1,3 @@
#!/bin/sh
source `dirname "$0"`/ardev_common.sh
-exec gtk2_ardour/ardour.bin --novst "$*"
+exec gtk2_ardour/ardour.bin --novst $*
diff --git a/gtk2_ardour/ardour.menus b/gtk2_ardour/ardour.menus
index 0f1f741c30..d213b4a53c 100644
--- a/gtk2_ardour/ardour.menus
+++ b/gtk2_ardour/ardour.menus
@@ -214,6 +214,30 @@
<menuitem action='FileHeaderFormatCAF'/>
</menu>
</menu>
+ <menu action='SMPTE'>
+ <menuitem action='Smpte23976'/>
+ <menuitem action='Smpte24'/>
+ <menuitem action='Smpte24976'/>
+ <menuitem action='Smpte25'/>
+ <menuitem action='Smpte2997drop'/>
+ <menuitem action='Smpte2997'/>
+ <menuitem action='Smpte30drop'/>
+ <menuitem action='Smpte30'/>
+ <menuitem action='Smpte5994'/>
+ <menuitem action='Smpte60'/>
+ </menu>
+ <menu action='Pullup'>
+ <menuitem action='PullupPlus4Plus1'/>
+ <menuitem action='PullupPlus4'/>
+ <menuitem action='PullupPlus4Minus1'/>
+ <menuitem action='PullupPlus1'/>
+ <menuitem action='PullupNone'/>
+ <menuitem action='PullupMinus1'/>
+ <menuitem action='PullupMinus4Plus1'/>
+ <menuitem action='PullupMinus4'/>
+ <menuitem action='PullupMinus4Minus1'/>
+ </menu>
+ <separator/>
<menu action='Autoconnect'>
<menuitem action='AutoConnectNewTrackInputsToHardware'/>
<separator/>
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index dae6c9f751..f0848e6f89 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -1651,6 +1651,9 @@ ARDOUR_UI::save_template ()
void
ARDOUR_UI::new_session (bool startup, std::string predetermined_path)
{
+ string session_name;
+ string session_path;
+
int response = Gtk::RESPONSE_NONE;
new_session_dialog->set_modal(true);
@@ -1672,14 +1675,28 @@ ARDOUR_UI::new_session (bool startup, std::string predetermined_path)
new_session_dialog->reset();
} else if (response == Gtk::RESPONSE_YES) {
- /* YES == OPEN, but there's no enum for that */
- std::string session_name = new_session_dialog->session_name();
- std::string session_path = new_session_dialog->session_folder();
- load_session (session_path, session_name);
+ /* YES == OPEN, but there's no enum for that */
+ session_name = new_session_dialog->session_name();
+
+ if (session_name.empty()) {
+ response = Gtk::RESPONSE_NONE;
+ cerr << "session name is empty\n";
+ continue;
+ }
+
+ if (session_name[0] == '/' ||
+ (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
+ (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
+ load_session (Glib::path_get_dirname (session_name), session_name);
+ } else {
+ session_path = new_session_dialog->session_folder();
+ load_session (session_path, session_name);
+ }
} else if (response == Gtk::RESPONSE_OK) {
+
if (new_session_dialog->get_current_page() == 1) {
/* XXX this is a bit of a hack..
@@ -1687,93 +1704,121 @@ ARDOUR_UI::new_session (bool startup, std::string predetermined_path)
if we're on page 1 (the load page)
Unfortunately i can't see how atm..
*/
-
- std::string session_name = new_session_dialog->session_name();
- std::string session_path = new_session_dialog->session_folder();
- load_session (session_path, session_name);
-
+
+ if (session_name.empty()) {
+ response = Gtk::RESPONSE_NONE;
+ cerr << "session name is empty 2\n";
+ continue;
+ }
+
+ if (session_name[0] == '/' ||
+ (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
+ (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
+ load_session (Glib::path_get_dirname (session_name), session_name);
+ } else {
+ session_path = new_session_dialog->session_folder();
+ load_session (session_path, session_name);
+ }
+
} else {
_session_is_new = true;
- std::string session_name = new_session_dialog->session_name();
- std::string session_path = new_session_dialog->session_folder();
+ session_name = new_session_dialog->session_name();
+ if (session_name.empty()) {
+ response = Gtk::RESPONSE_NONE;
+ cerr << "session name is empty 3\n";
+ continue;
+ }
+
+ if (session_name[0] == '/' ||
+ (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
+ (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
+
+ session_path = Glib::path_get_dirname (session_name);
+ session_name = Glib::path_get_basename (session_name);
+
+ } else {
+
+ std::string session_path = new_session_dialog->session_folder();
+
+ }
//XXX This is needed because session constructor wants a
//non-existant path. hopefully this will be fixed at some point.
-
- session_path = Glib::build_filename(session_path, session_name);
-
+
+ session_path = Glib::build_filename (session_path, session_name);
+
std::string template_name = new_session_dialog->session_template_name();
-
+
if (new_session_dialog->use_session_template()) {
-
- load_session (session_path, session_name, &template_name);
+
+ load_session (session_path, session_name, &template_name);
} else {
-
- uint32_t cchns;
+
+ uint32_t cchns;
uint32_t mchns;
Session::AutoConnectOption iconnect;
Session::AutoConnectOption oconnect;
-
+
if (new_session_dialog->create_control_bus()) {
- cchns = (uint32_t) new_session_dialog->control_channel_count();
+ cchns = (uint32_t) new_session_dialog->control_channel_count();
} else {
- cchns = 0;
+ cchns = 0;
}
-
+
if (new_session_dialog->create_master_bus()) {
- mchns = (uint32_t) new_session_dialog->master_channel_count();
+ mchns = (uint32_t) new_session_dialog->master_channel_count();
} else {
- mchns = 0;
+ mchns = 0;
}
-
+
if (new_session_dialog->connect_inputs()) {
- iconnect = Session::AutoConnectPhysical;
+ iconnect = Session::AutoConnectPhysical;
} else {
- iconnect = Session::AutoConnectOption (0);
+ iconnect = Session::AutoConnectOption (0);
}
-
+
/// @todo some minor tweaks.
-
+
if (new_session_dialog->connect_outs_to_master()) {
- oconnect = Session::AutoConnectMaster;
+ oconnect = Session::AutoConnectMaster;
} else if (new_session_dialog->connect_outs_to_physical()) {
- oconnect = Session::AutoConnectPhysical;
+ oconnect = Session::AutoConnectPhysical;
} else {
- oconnect = Session::AutoConnectOption (0);
+ oconnect = Session::AutoConnectOption (0);
}
-
+
uint32_t nphysin = (uint32_t) new_session_dialog->input_limit_count();
uint32_t nphysout = (uint32_t) new_session_dialog->output_limit_count();
-
+
build_session (session_path,
- session_name,
- cchns,
- mchns,
- iconnect,
- oconnect,
- nphysin,
- nphysout,
- engine->frame_rate() * 60 * 5);
+ session_name,
+ cchns,
+ mchns,
+ iconnect,
+ oconnect,
+ nphysin,
+ nphysout,
+ engine->frame_rate() * 60 * 5);
}
- }
+ }
}
} while (response == Gtk::RESPONSE_NONE);
+
show();
new_session_dialog->get_window()->set_cursor();
-
new_session_dialog->hide();
}
void
ARDOUR_UI::close_session()
{
- unload_session();
- new_session ();
+ unload_session();
+ new_session ();
}
int
@@ -1873,6 +1918,11 @@ ARDOUR_UI::show ()
{
if (editor) {
editor->show_window ();
+
+ if (!shown_flag) {
+ editor->present ();
+ }
+
shown_flag = true;
}
diff --git a/gtk2_ardour/ardour_ui_dependents.cc b/gtk2_ardour/ardour_ui_dependents.cc
index 0603fc6baa..bf096f86c1 100644
--- a/gtk2_ardour/ardour_ui_dependents.cc
+++ b/gtk2_ardour/ardour_ui_dependents.cc
@@ -79,6 +79,10 @@ ARDOUR_UI::connect_dependents_to_session (ARDOUR::Session *s)
{
editor->connect_to_session (s);
mixer->connect_to_session (s);
+
+ /* its safe to do this now */
+
+ s->restore_history (s->snap_name());
}
void
diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc
index c90480c1dd..fe5963c535 100644
--- a/gtk2_ardour/ardour_ui_dialogs.cc
+++ b/gtk2_ardour/ardour_ui_dialogs.cc
@@ -131,10 +131,6 @@ ARDOUR_UI::connect_to_session (Session *s)
start_clocking ();
start_blinking ();
- if (editor) {
- editor->present();
- }
-
transport_stopped ();
second_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::every_second), 1000);
diff --git a/gtk2_ardour/ardour_ui_options.cc b/gtk2_ardour/ardour_ui_options.cc
index 205180a344..21afbcde21 100644
--- a/gtk2_ardour/ardour_ui_options.cc
+++ b/gtk2_ardour/ardour_ui_options.cc
@@ -463,6 +463,7 @@ ARDOUR_UI::setup_session_options ()
session_control_changed (Session::AutoReturn);
session_control_changed (Session::AutoInput);
session_control_changed (Session::Clicking);
+ session_control_changed (Session::SmpteMode);
session->ControlChanged.connect (mem_fun (*this, &ARDOUR_UI::queue_session_control_changed));
}
@@ -555,7 +556,6 @@ ARDOUR_UI::session_control_changed (Session::ControlType t)
case Session::CrossfadingModel:
break;
-
case Session::AutoPlay:
map_some_session_state ("Transport", "ToggleAutoPlay", &Session::get_auto_play);
break;
diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc
index 2b9cd23567..85ba517f8e 100644
--- a/gtk2_ardour/audio_streamview.cc
+++ b/gtk2_ardour/audio_streamview.cc
@@ -68,6 +68,7 @@ AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
_amplitude_above_axis = 1.0;
use_rec_regions = tv.editor.show_waveforms_recording ();
+
}
AudioStreamView::~AudioStreamView ()
@@ -215,9 +216,7 @@ AudioStreamView::playlist_modified ()
StreamView::playlist_modified();
- /* if the playlist is modified, make sure xfades are on top and all the regionviews are stacked
- correctly.
- */
+ /* make sure xfades are on top and all the regionviews are stacked correctly. */
for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
(*i)->get_canvas_group()->raise_to_top();
@@ -419,10 +418,11 @@ AudioStreamView::setup_rec_box ()
boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion>
(RegionFactory::create (sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags | Region::DoNotSaveState), false)));
+ assert(region);
region->set_position (_trackview.session().transport_frame(), this);
rec_regions.push_back (region);
- /* catch it if it goes away */
- region->GoingAway.connect (bind (mem_fun (*this, &AudioStreamView::remove_rec_region), region));
+
+ // rec regions are destroyed in setup_rec_box
/* we add the region later */
}
@@ -504,6 +504,14 @@ AudioStreamView::setup_rec_box ()
/* remove temp regions */
+ for (list<boost::shared_ptr<Region> >::iterator iter = rec_regions.begin(); iter != rec_regions.end();) {
+ list<boost::shared_ptr<Region> >::iterator tmp;
+ tmp = iter;
+ ++tmp;
+ (*iter)->drop_references ();
+ iter = tmp;
+ }
+
rec_regions.clear();
// cerr << "\tclear " << rec_rects.size() << " rec rects\n";
@@ -567,9 +575,10 @@ AudioStreamView::update_rec_regions ()
continue;
}
- // FIXME
boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(*iter);
- assert(region);
+ if (!region) {
+ continue;
+ }
jack_nframes_t origlen = region->length();
diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h
index f8262d2a2d..8311025b02 100644
--- a/gtk2_ardour/automation_line.h
+++ b/gtk2_ardour/automation_line.h
@@ -163,9 +163,8 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
XMLNode& get_state (void);
int set_state (const XMLNode&);
- PBD::ID id() { return _id; }
protected:
- PBD::ID _id;
+
string _name;
guint32 _height;
uint32_t _line_color;
diff --git a/gtk2_ardour/canvas-simplerect.c b/gtk2_ardour/canvas-simplerect.c
index abddf5756b..d59096e68b 100644
--- a/gtk2_ardour/canvas-simplerect.c
+++ b/gtk2_ardour/canvas-simplerect.c
@@ -263,7 +263,7 @@ gnome_canvas_simplerect_reset_bounds (GnomeCanvasItem *item)
GnomeCanvasSimpleRect* simplerect;
double x1, x2, y1, y2;
double old_x1, old_x2, old_y1, old_y2;
- double a, b;
+ double a, b, c, d;
old_x1 = item->x1;
old_y1 = item->y1;
@@ -287,42 +287,24 @@ gnome_canvas_simplerect_reset_bounds (GnomeCanvasItem *item)
gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x2, y2, &simplerect->bbox_lrx, &simplerect->bbox_lry);
/* now queue redraws for changed areas */
-
- if (item->x1 != old_x1) {
-
- /* left edge changed. redraw the area that altered */
a = MIN(item->x1, old_x1);
b = MAX(item->x1, old_x1);
- gnome_canvas_request_redraw (item->canvas, a - 1, item->y1, b + 1, item->y2);
- }
-
- if (item->x2 != old_x2) {
-
- /* right edge changed. redraw the area that altered */
-
- a = MIN(item->x2, old_x2);
- b = MAX(item->x2, old_x2);
- gnome_canvas_request_redraw (item->canvas, a - 1, item->y1, b + 1, item->y2);
- }
-
- if (item->y1 != old_y1) {
-
- /* top edge changed. redraw the area that altered */
-
- a = MIN(item->y1, old_y1);
- b = MAX(item->y1, old_y1);
- gnome_canvas_request_redraw (item->canvas, item->x1, a - 1, item->x2, b + 1);
- }
-
- if (item->y2 != old_y2) {
-
- /* lower edge changed. redraw the area that altered */
-
- a = MIN(item->y2, old_y2);
- b = MAX(item->y2, old_y2);
- gnome_canvas_request_redraw (item->canvas, item->x1, a - 1, item->x2, b + 1);
- }
+
+ a = MIN(a, item->x2);
+ a = MIN(a, old_x2);
+ b = MAX(b, item->x2);
+ b = MAX(b, old_x2);
+
+ c = MIN(item->y1, old_y1);
+ d = MAX(item->y1, old_y1);
+
+ c = MIN(c,item->y2);
+ c = MIN(c, old_y2);
+ d = MAX(d,item->y2);
+ d = MAX(d, old_y2);
+
+ gnome_canvas_request_redraw (item->canvas, a, c, b + 0.5, d + 0.5);
}
/*
@@ -494,8 +476,8 @@ gnome_canvas_simplerect_update (GnomeCanvasItem *item, double *affine, ArtSVP *c
gnome_canvas_request_redraw (item->canvas,
simplerect->bbox_ulx,
simplerect->bbox_uly,
- simplerect->bbox_lrx+1,
- simplerect->bbox_lry+1);
+ simplerect->bbox_lrx+0.5,
+ simplerect->bbox_lry+0.5);
simplerect->full_draw_on_update = FALSE;
}
diff --git a/gtk2_ardour/editing_syms.h b/gtk2_ardour/editing_syms.h
index 654ddc8852..3a503e2cb5 100644
--- a/gtk2_ardour/editing_syms.h
+++ b/gtk2_ardour/editing_syms.h
@@ -54,7 +54,8 @@ DISPLAYCONTROL(ShowMeasures)
DISPLAYCONTROL(ShowWaveforms)
DISPLAYCONTROL(ShowWaveformsRecording)
-IMPORTMODE(ImportAsRegion)
-IMPORTMODE(ImportAsTrack)
-IMPORTMODE(ImportAsTapeTrack)
-IMPORTMODE(ImportToTrack)
+// if this is changed, remember to update the string table in sfdb_ui.cc
+IMPORTMODE(ImportAsRegion=0)
+IMPORTMODE(ImportToTrack=1)
+IMPORTMODE(ImportAsTrack=2)
+IMPORTMODE(ImportAsTapeTrack=3)
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index 933db72bab..0fc9810c70 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -643,7 +643,7 @@ Editor::Editor (AudioEngine& eng)
edit_pane.pack1 (edit_packer, true, true);
edit_pane.pack2 (the_notebook, false, true);
- edit_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
+ edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
top_hbox.pack_start (toolbar_frame, true, true);
@@ -700,6 +700,7 @@ Editor::Editor (AudioEngine& eng)
ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
+
constructed = true;
instant_save ();
@@ -882,6 +883,9 @@ Editor::reposition_x_origin (jack_nframes_t frame)
}
horizontal_adjustment.set_value (frame/frames_per_unit);
+ } else {
+ update_fixed_rulers();
+ tempo_map_changed (Change (0));
}
}
@@ -965,20 +969,10 @@ void
Editor::canvas_horizontally_scrolled ()
{
- Glib::signal_idle().connect (mem_fun(*this, &Editor::lazy_canvas_horizontally_scrolled));
-
-}
-
-bool
-Editor::lazy_canvas_horizontally_scrolled ()
-{
-
- leftmost_frame = (jack_nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
-
+ leftmost_frame = (jack_nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
update_fixed_rulers ();
tempo_map_changed (Change (0));
- return false;
}
void
@@ -996,7 +990,6 @@ Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
set_frames_per_unit (nfpu);
reposition_x_origin (frame);
-
repos_zoom_queued = false;
return FALSE;
@@ -1033,6 +1026,10 @@ Editor::session_control_changed (Session::ControlType t)
update_layering_model ();
break;
+ case Session::SmpteMode:
+ update_smpte_mode ();
+ break;
+
default:
break;
}
@@ -1179,6 +1176,9 @@ Editor::connect_to_session (Session *t)
session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
+ session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_smpte_mode)));
+ session_connections.push_back (session->PullupChanged.connect (mem_fun(*this, &Editor::update_video_pullup)));
+
session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
edit_groups_changed ();
@@ -1266,9 +1266,12 @@ Editor::connect_to_session (Session *t)
}
/* xfade visibility state set from editor::set_state() */
-
- update_crossfade_model ();
- update_layering_model ();
+
+ update_crossfade_model();
+ update_layering_model();
+
+ update_smpte_mode();
+ update_video_pullup();
handle_new_duration ();
@@ -1292,7 +1295,7 @@ Editor::connect_to_session (Session *t)
horizontal_adjustment.set_value (0);
restore_ruler_visibility ();
- tempo_map_changed (Change (0));
+ //tempo_map_changed (Change (0));
session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
edit_cursor->set_position (0);
@@ -1328,6 +1331,7 @@ Editor::connect_to_session (Session *t)
}
/* register for undo history */
+
session->register_with_memento_command_factory(_id, this);
}
@@ -2110,6 +2114,9 @@ Editor::set_state (const XMLNode& node)
int x, y, xoff, yoff;
Gdk::Geometry g;
+ if ((prop = node.property ("id")) != 0) {
+ _id = prop->value ();
+ }
if ((geometry = find_named_node (node, "geometry")) == 0) {
@@ -2241,6 +2248,9 @@ Editor::get_state ()
XMLNode* node = new XMLNode ("Editor");
char buf[32];
+ _id.print (buf);
+ node->add_property ("id", buf);
+
if (is_realized()) {
Glib::RefPtr<Gdk::Window> win = get_window();
@@ -2250,7 +2260,7 @@ Editor::get_state ()
win->get_size(width, height);
XMLNode* geometry = new XMLNode ("geometry");
- char buf[32];
+
snprintf(buf, sizeof(buf), "%d", width);
geometry->add_property("x_size", string(buf));
snprintf(buf, sizeof(buf), "%d", height);
@@ -4085,6 +4095,7 @@ Editor::restore_editing_space ()
{
mouse_mode_tearoff->set_visible (true);
tools_tearoff->set_visible (true);
+
edit_pane.set_position (pre_maximal_pane_position);
unfullscreen();
@@ -4139,6 +4150,87 @@ Editor::on_key_press_event (GdkEventKey* ev)
}
void
+Editor::update_smpte_mode ()
+{
+ ENSURE_GUI_THREAD(mem_fun(*this, &Editor::update_smpte_mode));
+
+ RefPtr<Action> act;
+
+ float frames = session->smpte_frames_per_second;
+ bool drop = session->smpte_drop_frames;
+
+ if ((frames < 23.976 * 1.0005) && !drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte23976"));
+ else if ((frames < 24 * 1.0005) && !drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte24"));
+ else if ((frames < 24.976 * 1.0005) && !drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte24976"));
+ else if ((frames < 25 * 1.0005) && !drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte25"));
+ else if ((frames < 29.97 * 1.0005) && !drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte2997"));
+ else if ((frames < 29.97 * 1.0005) && drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte2997drop"));
+ else if ((frames < 30 * 1.0005) && !drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte30"));
+ else if ((frames < 30 * 1.0005) && drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte30drop"));
+ else if ((frames < 59.94 * 1.0005) && !drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte5994"));
+ else if ((frames < 60 * 1.0005) && !drop)
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte60"));
+ else
+ cerr << "Unexpected SMPTE value (" << frames << (drop ? "drop" : "") << ") in update_smpte_mode. Menu is probably wrong\n" << endl;
+
+
+ if (act) {
+ RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
+ if (ract && !ract->get_active()) {
+ ract->set_active (true);
+ }
+ }
+}
+
+void
+Editor::update_video_pullup ()
+{
+ ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_video_pullup));
+
+ RefPtr<Action> act;
+
+ float pullup = session->video_pullup;
+
+ if ( pullup < (-4.1667 - 0.1) * 0.99) {
+ act = ActionManager::get_action (X_("Editor"), X_("PullupMinus4Minus1"));
+ } else if ( pullup < (-4.1667) * 0.99 ) {
+ act = ActionManager::get_action (X_("Editor"), X_("PullupMinus4"));
+ } else if ( pullup < (-4.1667 + 0.1) * 0.99 ) {
+ act = ActionManager::get_action (X_("Editor"), X_("PullupMinus4Plus1"));
+ } else if ( pullup < (-0.1) * 0.99 ) {
+ act = ActionManager::get_action (X_("Editor"), X_("PullupMinus1"));
+ } else if (pullup > (4.1667 + 0.1) * 0.99 ) {
+ act = ActionManager::get_action (X_("Editor"), X_("PullupPlus4Plus1"));
+ } else if ( pullup > (4.1667) * 0.99 ) {
+ act = ActionManager::get_action (X_("Editor"), X_("PullupPlus4"));
+ } else if ( pullup > (4.1667 - 0.1) * 0.99) {
+ act = ActionManager::get_action (X_("Editor"), X_("PullupPlus4Minus1"));
+ } else if ( pullup > (0.1) * 0.99 ) {
+ act = ActionManager::get_action (X_("Editor"), X_("PullupPlus1"));
+ } else
+ act = ActionManager::get_action (X_("Editor"), X_("PullupNone"));
+
+
+ if (act) {
+ RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
+ if (ract && !ract->get_active()) {
+ ract->set_active (true);
+ }
+ }
+
+}
+
+
+void
Editor::update_layering_model ()
{
RefPtr<Action> act;
@@ -4163,7 +4255,6 @@ Editor::update_layering_model ()
}
}
-
void
Editor::update_crossfade_model ()
{
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 239bd6307d..fe5d47df0c 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -143,8 +143,6 @@ class Editor : public PublicEditor
XMLNode& get_state ();
int set_state (const XMLNode& );
- PBD::ID id() { return _id; }
-
void set_mouse_mode (Editing::MouseMode, bool force=true);
void step_mouse_mode (bool next);
Editing::MouseMode current_mouse_mode () { return mouse_mode; }
@@ -231,6 +229,7 @@ class Editor : public PublicEditor
void set_show_measures (bool yn);
bool show_measures () const { return _show_measures; }
+ bool initial_ruler_update_required;
#ifdef FFT_ANALYSIS
/* analysis window */
@@ -302,6 +301,14 @@ class Editor : public PublicEditor
void set_meter_falloff (int);
void set_meter_hold (int32_t);
+ /* SMPTE timecode & video sync */
+
+ void smpte_fps_chosen (ARDOUR::Session::SmpteFormat format);
+ void video_pullup_chosen (ARDOUR::Session::PullupFormat pullup);
+
+ void update_smpte_mode();
+ void update_video_pullup();
+
/* xfades */
void toggle_auto_xfade ();
@@ -311,8 +318,8 @@ class Editor : public PublicEditor
void update_crossfade_model ();
void set_crossfade_model (ARDOUR::CrossfadeModel);
- /* layers */
+ /* layers */
void set_layer_model (ARDOUR::Session::LayerModel);
void update_layering_model ();
@@ -349,8 +356,6 @@ class Editor : public PublicEditor
ARDOUR::AudioEngine& engine;
bool constructed;
- PBD::ID _id;
-
PlaylistSelector* _playlist_selector;
void set_frames_per_unit (double);
@@ -683,7 +688,7 @@ class Editor : public PublicEditor
void tie_vertical_scrolling ();
void canvas_horizontally_scrolled ();
- bool lazy_canvas_horizontally_scrolled ();
+
void reposition_and_zoom (jack_nframes_t sample, double fpu);
gint deferred_reposition_and_zoom (jack_nframes_t sample, double fpu);
void end_location_changed (ARDOUR::Location*);
@@ -1185,8 +1190,6 @@ class Editor : public PublicEditor
bool _follow_playhead;
bool _show_waveforms_recording;
- void add_bbt_marks (ARDOUR::TempoMap::BBTPointList&);
-
ARDOUR::TempoMap::BBTPointList *current_bbt_points;
typedef vector<ArdourCanvas::SimpleLine*> TimeLineList;
@@ -1197,7 +1200,7 @@ class Editor : public PublicEditor
ArdourCanvas::SimpleLine* get_time_line ();
void hide_measures ();
void draw_measures ();
- void draw_time_bars ();
+ bool lazy_hide_and_draw_measures ();
void new_tempo_section ();
@@ -1506,7 +1509,7 @@ class Editor : public PublicEditor
jack_nframes_t autoscroll_distance;
static gint _autoscroll_canvas (void *);
- gint autoscroll_canvas ();
+ bool autoscroll_canvas ();
void start_canvas_autoscroll (int direction);
void stop_canvas_autoscroll ();
void maybe_autoscroll (GdkEvent*);
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index 65195ca822..f1b9ef4b83 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -39,6 +39,8 @@ Editor::register_actions ()
ActionManager::register_action (editor_actions, X_("Monitoring"), _("Monitoring"));
ActionManager::register_action (editor_actions, X_("Autoconnect"), _("Autoconnect"));
ActionManager::register_action (editor_actions, X_("Layering"), _("Layering"));
+ ActionManager::register_action (editor_actions, X_("SMPTE"), _("SMPTE fps"));
+ ActionManager::register_action (editor_actions, X_("Pullup"), _("Pullup / Pulldown"));
ActionManager::register_action (editor_actions, X_("Metering"), _("Metering"));
ActionManager::register_action (editor_actions, X_("MeteringFallOffRate"), _("Fall off rate"));
ActionManager::register_action (editor_actions, X_("MeteringHoldTime"), _("Hold Time"));
@@ -393,6 +395,31 @@ Editor::register_actions ()
ActionManager::register_radio_action (editor_actions, layer_model_group, X_("LayerMoveAddHigher"), _("Most Recently Moved/Added is Higher"), bind (mem_fun (*this, &Editor::set_layer_model), Session::MoveAddHigher));
ActionManager::register_radio_action (editor_actions, layer_model_group, X_("LayerAddHigher"), _("Most Recently Added is Higher"), bind (mem_fun (*this, &Editor::set_layer_model), Session::AddHigher));
+ RadioAction::Group smpte_group;
+
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte23976"), _("23.976"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_23976));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte24"), _("24"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_24));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte24976"), _("24.976"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_24976));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte25"), _("25"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_25));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte2997"), _("29.97"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_2997));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte2997drop"), _("29.97 drop"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_2997drop));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte30"), _("30"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_30));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte30drop"), _("30 drop"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_30drop));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte5994"), _("59.94"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_5994));
+ ActionManager::register_radio_action (editor_actions, smpte_group, X_("Smpte60"), _("60"), bind (mem_fun (*this, &Editor::smpte_fps_chosen), Session::smpte_60));
+
+ RadioAction::Group pullup_group;
+
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupPlus4Plus1"), _("+4.1667% + 0.1%"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_Plus4Plus1));
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupPlus4"), _("+4.1667%"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_Plus4));
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupPlus4Minus1"), _("+4.1667% - 0.1%"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_Plus4Minus1));
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupPlus1"), _("+ 0.1%"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_Plus1));
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupNone"), _("None"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_None));
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupMinus1"), _("- 0.1%"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_Minus1));
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupMinus4Plus1"), _("-4.1667% + 0.1%"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_Minus4Plus1));
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupMinus4"), _("-4.1667%"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_Minus4));
+ ActionManager::register_radio_action (editor_actions, pullup_group, X_("PullupMinus4Minus1"), _("-4.1667% - 0.1%"), bind (mem_fun (*this, &Editor::video_pullup_chosen), Session::pullup_Minus4Minus1));
+
ActionManager::add_action_group (rl_actions);
ActionManager::add_action_group (zoom_actions);
ActionManager::add_action_group (mouse_mode_actions);
@@ -493,6 +520,150 @@ Editor::set_layer_model (Session::LayerModel model)
}
void
+Editor::smpte_fps_chosen (Session::SmpteFormat format)
+{
+ /* this is driven by a toggle on a radio group, and so is invoked twice,
+ once for the item that became inactive and once for the one that became
+ active.
+ */
+
+ if (session) {
+
+ float fps = 10;
+ bool drop = false;
+
+ RefPtr<Action> act;
+
+ switch (format) {
+ case Session::smpte_23976: {
+ fps=23.976;
+ drop = false;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte23976"));
+ } break;
+ case Session::smpte_24: {
+ fps=24;
+ drop = false;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte24"));
+ } break;
+ case Session::smpte_24976: {
+ fps=24.976;
+ drop = false;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte24976"));
+ } break;
+ case Session::smpte_25: {
+ fps=25;
+ drop = false;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte25"));
+ } break;
+ case Session::smpte_2997: {
+ fps=29.97;
+ drop = false;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte2997"));
+ } break;
+ case Session::smpte_2997drop: {
+ fps=29.97;
+ drop = true;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte2997drop"));
+ } break;
+ case Session::smpte_30: {
+ fps=30;
+ drop = false;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte30"));
+ } break;
+ case Session::smpte_30drop: {
+ fps=30;
+ drop = true;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte30drop"));
+ } break;
+ case Session::smpte_5994: {
+ fps=59.94;
+ drop = false;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte5994"));
+ } break;
+ case Session::smpte_60: {
+ fps=60;
+ drop = false;
+ act = ActionManager::get_action (X_("Editor"), X_("Smpte60"));
+ } break;
+ default:
+ cerr << "Editor received unexpected smpte type" << endl;
+ }
+
+ if (act) {
+ RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
+ if (ract && ract->get_active()) {
+ session->set_smpte_type (fps, drop);
+ }
+ }
+ }
+}
+
+void
+Editor::video_pullup_chosen (Session::PullupFormat pullup)
+{
+ /* this is driven by a toggle on a radio group, and so is invoked twice,
+ once for the item that became inactive and once for the one that became
+ active.
+ */
+
+ if (session) {
+
+ RefPtr<Action> act;
+
+ float pull = 0.0;
+
+ switch (pullup) {
+ case Session::pullup_Plus4Plus1:{
+ pull = 4.1667 + 0.1;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupPlus4Plus1"));
+ } break;
+ case Session::pullup_Plus4:{
+ pull = 4.1667;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupPlus4"));
+ } break;
+ case Session::pullup_Plus4Minus1:{
+ pull = 4.1667 - 0.1;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupPlus4Minus1"));
+ } break;
+ case Session::pullup_Plus1:{
+ pull = 0.1;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupPlus1"));
+ } break;
+ case Session::pullup_None:{
+ pull = 0.0;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupNone"));
+ } break;
+ case Session::pullup_Minus1:{
+ pull = -0.1;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupMinus1"));
+ } break;
+ case Session::pullup_Minus4Plus1:{
+ pull = -4.1667 + 0.1;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupMinus4Plus1"));
+ } break;
+ case Session::pullup_Minus4:{
+ pull = -4.1667;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupMinus4"));
+ } break;
+ case Session::pullup_Minus4Minus1:{
+ pull = -4.1667 - 0.1;
+ act = ActionManager::get_action (X_("Editor"), X_("PullupMinus4Minus1"));
+ } break;
+ default:
+ cerr << "Session received unexpected pullup type" << endl;
+ }
+
+ if (act) {
+ RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
+ if (ract && ract->get_active()) {
+ session->set_video_pullup ( pull );
+ }
+ } else cerr << "Editor::video_pullup_chosen could not find action to match pullup." << endl;
+ }
+}
+
+
+void
Editor::set_crossfade_model (CrossfadeModel model)
{
RefPtr<Action> act;
diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc
index fdd680beb2..e38dee5953 100644
--- a/gtk2_ardour/editor_audio_import.cc
+++ b/gtk2_ardour/editor_audio_import.cc
@@ -270,7 +270,7 @@ Editor::embed_sndfile (Glib::ustring path, bool split, bool multiple_files, bool
idspec += string_compose(":%1", n);
try {
- source = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, idspec, (mode == ImportAsTrack ? AudioFileSource::Destructive : AudioFileSource::Flag (0))));
+ source = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, *session, idspec, (mode == ImportAsTrack ? AudioFileSource::Destructive : AudioFileSource::Flag (0))));
sources.push_back(source);
}
diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc
index d8eebf1c4b..e2e04326ca 100644
--- a/gtk2_ardour/editor_canvas.cc
+++ b/gtk2_ardour/editor_canvas.cc
@@ -266,14 +266,15 @@ Editor::initialize_canvas ()
edit_cursor = new Cursor (*this, "blue", &Editor::canvas_edit_cursor_event);
playhead_cursor = new Cursor (*this, "red", &Editor::canvas_playhead_cursor_event);
-
+
+ initial_ruler_update_required = true;
track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate));
+
}
void
Editor::track_canvas_allocate (Gtk::Allocation alloc)
{
- static bool first_time = true;
canvas_width = alloc.get_width();
canvas_height = alloc.get_height();
@@ -318,14 +319,16 @@ Editor::track_canvas_allocate (Gtk::Allocation alloc)
transport_punchout_line->property_y2() = canvas_height;
}
- update_fixed_rulers ();
-
- if (is_visible() && first_time) {
+ if (is_visible() && initial_ruler_update_required) {
+ /*
+ this is really dumb, but signal_size_allocate() gets emitted intermittently
+ depending on whether the canvas contents are visible or not.
+ we only want to do this once
+ */
+ update_fixed_rulers();
tempo_map_changed (Change (0));
- first_time = false;
- } else {
- redisplay_tempo ();
- }
+ initial_ruler_update_required = false;
+ }
Resized (); /* EMIT_SIGNAL */
}
@@ -414,6 +417,8 @@ Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context
const SelectionData& data,
guint info, guint time)
{
+ cerr << "dropping, target = " << data.get_target() << endl;
+
if (data.get_target() == "regions") {
drop_regions (context, x, y, data, info, time);
} else {
@@ -528,7 +533,7 @@ Editor::maybe_autoscroll (GdkEvent* event)
}
- if (autoscroll_direction != last_autoscroll_direction) {
+ if ((autoscroll_direction != last_autoscroll_direction) || (leftmost_frame < frame < rightmost_frame)) {
stop_canvas_autoscroll ();
}
@@ -542,14 +547,13 @@ Editor::maybe_autoscroll (GdkEvent* event)
gint
Editor::_autoscroll_canvas (void *arg)
{
- return ((Editor *) arg)->autoscroll_canvas ();
+ return ((Editor *) arg)->autoscroll_canvas ();
}
-gint
+bool
Editor::autoscroll_canvas ()
{
jack_nframes_t new_frame;
- bool keep_calling = true;
jack_nframes_t limit = max_frames - current_page_frames();
GdkEventMotion ev;
jack_nframes_t target_frame;
@@ -570,10 +574,6 @@ Editor::autoscroll_canvas ()
target_frame = drag_info.current_pointer_frame + autoscroll_distance;
}
- if (new_frame != leftmost_frame) {
- reposition_x_origin (new_frame);
- }
-
/* now fake a motion event to get the object that is being dragged to move too */
ev.type = GDK_MOTION_NOTIFY;
@@ -593,20 +593,26 @@ Editor::autoscroll_canvas ()
/* connect the timeout so that we get called repeatedly */
- autoscroll_timeout_tag = g_timeout_add (20, _autoscroll_canvas, this);
- keep_calling = false;
+ autoscroll_timeout_tag = g_idle_add ( _autoscroll_canvas, this);
+ return false;
+
+ }
- } else if (autoscroll_cnt == 50) { /* 0.5 seconds */
+ if (new_frame != leftmost_frame) {
+ reposition_x_origin (new_frame);
+ }
+
+ if (autoscroll_cnt == 50) { /* 0.5 seconds */
/* after about a while, speed up a bit by changing the timeout interval */
- autoscroll_distance = (jack_nframes_t) floor (current_page_frames()/50.0f);
+ autoscroll_distance = (jack_nframes_t) floor (current_page_frames()/30.0f);
- } else if (autoscroll_cnt == 75) { /* 1.0 seconds */
+ } else if (autoscroll_cnt == 150) { /* 1.0 seconds */
autoscroll_distance = (jack_nframes_t) floor (current_page_frames()/20.0f);
- } else if (autoscroll_cnt == 100) { /* 1.5 seconds */
+ } else if (autoscroll_cnt == 300) { /* 1.5 seconds */
/* after about another while, speed up by increasing the shift per callback */
@@ -614,7 +620,7 @@ Editor::autoscroll_canvas ()
}
- return keep_calling;
+ return true;
}
void
@@ -631,7 +637,7 @@ Editor::start_canvas_autoscroll (int dir)
autoscroll_cnt = 0;
/* do it right now, which will start the repeated callbacks */
-
+
autoscroll_canvas ();
}
diff --git a/gtk2_ardour/editor_export_audio.cc b/gtk2_ardour/editor_export_audio.cc
index 6c67a8fb0e..1b0308b080 100644
--- a/gtk2_ardour/editor_export_audio.cc
+++ b/gtk2_ardour/editor_export_audio.cc
@@ -210,7 +210,7 @@ Editor::write_region (string path, boost::shared_ptr<AudioRegion> region)
try {
- fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, path, AudioFileSource::Flag (0)));
+ fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, *session, path, AudioFileSource::Flag (0)));
}
catch (failed_constructor& err) {
@@ -343,7 +343,7 @@ Editor::write_audio_range (AudioPlaylist& playlist, const ChanCount& count, list
path = s;
try {
- fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, path, AudioFileSource::Flag (0)));
+ fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, *session, path, AudioFileSource::Flag (0)));
}
catch (failed_constructor& err) {
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index 7d262503f8..f44b433caa 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -1110,9 +1110,9 @@ Editor::temporal_zoom_step (bool coarser)
nfpu = frames_per_unit;
if (coarser) {
- nfpu *= 2.0;
+ nfpu *= 1.61803399;
} else {
- nfpu = max(1.0,(nfpu/2.0));
+ nfpu = max(1.0,(nfpu/1.61803399));
}
temporal_zoom (nfpu);
@@ -1251,22 +1251,22 @@ Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame)
{
if (!session) return;
- jack_nframes_t range_before = frame - leftmost_frame;
+ double range_before = frame - leftmost_frame;
double new_fpu;
new_fpu = frames_per_unit;
if (coarser) {
- new_fpu *= 2.0;
- range_before *= 2;
+ new_fpu *= 1.61803399;
+ range_before *= 1.61803399;
} else {
- new_fpu = max(1.0,(new_fpu/2.0));
- range_before /= 2;
+ new_fpu = max(1.0,(new_fpu/1.61803399));
+ range_before /= 1.61803399;
}
if (new_fpu == frames_per_unit) return;
- jack_nframes_t new_leftmost = frame - range_before;
+ jack_nframes_t new_leftmost = frame - (jack_nframes_t)range_before;
if (new_leftmost > frame) new_leftmost = 0;
diff --git a/gtk2_ardour/editor_rulers.cc b/gtk2_ardour/editor_rulers.cc
index 47641655e7..224e779bf9 100644
--- a/gtk2_ardour/editor_rulers.cc
+++ b/gtk2_ardour/editor_rulers.cc
@@ -819,9 +819,9 @@ Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upp
if (lower > (spacer = (jack_nframes_t)(128 * Editor::get_current_zoom ()))) {
lower = lower - spacer;
} else {
- upper = upper + spacer - lower;
lower = 0;
}
+ upper = upper + spacer;
range = (jack_nframes_t) floor (upper - lower);
if (range < (2 * session->frames_per_smpte_frame())) { /* 0 - 2 frames */
@@ -1035,114 +1035,87 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
return 0;
}
- TempoMap::BBTPointList::iterator i;
- TempoMap::BBTPointList *zoomed_bbt_points;
+ TempoMap::BBTPointList::iterator i;
+
uint32_t beats = 0;
uint32_t bars = 0;
- uint32_t tick = 0;
- uint32_t skip;
- uint32_t t;
- uint32_t zoomed_beats = 0;
- uint32_t zoomed_bars = 0;
uint32_t desirable_marks;
uint32_t magic_accent_number = 1;
gint nmarks;
char buf[64];
gint n;
jack_nframes_t pos;
- jack_nframes_t frame_one_beats_worth;
- jack_nframes_t frame_skip;
- double frame_skip_error;
- double accumulated_error;
- bool bar_helper_on = true;
-
+ bool bar_helper_on = true;
- BBT_Time previous_beat;
BBT_Time next_beat;
jack_nframes_t next_beat_pos;
jack_nframes_t ilower = (jack_nframes_t) floor (lower);
- jack_nframes_t iupper = (jack_nframes_t) floor (upper);
- if ((desirable_marks = maxchars / 6) == 0) {
+ if ((desirable_marks = maxchars / 7) == 0) {
return 0;
}
/* align the tick marks to whatever we're snapping to... */
-
- if (snap_type == SnapToAThirdBeat) {
+
+ switch (snap_type) {
+ case SnapToAThirdBeat:
bbt_beat_subdivision = 3;
- } else if (snap_type == SnapToAQuarterBeat) {
+ break;
+ case SnapToAQuarterBeat:
bbt_beat_subdivision = 4;
- } else if (snap_type == SnapToAEighthBeat) {
+ break;
+ case SnapToAEighthBeat:
bbt_beat_subdivision = 8;
magic_accent_number = 2;
- } else if (snap_type == SnapToASixteenthBeat) {
+ break;
+ case SnapToASixteenthBeat:
bbt_beat_subdivision = 16;
magic_accent_number = 4;
- } else if (snap_type == SnapToAThirtysecondBeat) {
+ break;
+ case SnapToAThirtysecondBeat:
bbt_beat_subdivision = 32;
magic_accent_number = 8;
- } else {
+ break;
+ default:
bbt_beat_subdivision = 4;
+ break;
}
- /* First find what a beat's distance is, so we can start plotting stuff before the beginning of the ruler */
-
- session->bbt_time(ilower,previous_beat);
- previous_beat.ticks = 0;
- next_beat = previous_beat;
-
- if (session->tempo_map().meter_at(ilower).beats_per_bar() < (next_beat.beats + 1)) {
- next_beat.bars += 1;
- next_beat.beats = 1;
- } else {
- next_beat.beats += 1;
- }
-
- frame_one_beats_worth = session->tempo_map().frame_time(next_beat) - session->tempo_map().frame_time(previous_beat);
-
-
- zoomed_bbt_points = session->tempo_map().get_points((ilower >= frame_one_beats_worth) ? ilower - frame_one_beats_worth : 0, iupper);
-
- if (current_bbt_points == 0 || zoomed_bbt_points == 0 || zoomed_bbt_points->empty()) {
+ if (current_bbt_points == 0 || current_bbt_points->empty()) {
return 0;
}
- for (i = current_bbt_points->begin(); i != current_bbt_points->end(); i++) {
- if ((*i).type == TempoMap::Beat) {
- beats++;
- } else if ((*i).type == TempoMap::Bar) {
- bars++;
- }
- }
+ i = current_bbt_points->end();
+ i--;
+ bars = (*i).bar - (*current_bbt_points->begin()).bar;
+ beats = current_bbt_points->size() - bars;
+
/*Only show the bar helper if there aren't many bars on the screen */
- if (bars > 1) {
+ if (bars > 2) {
bar_helper_on = false;
}
- for (i = zoomed_bbt_points->begin(); i != zoomed_bbt_points->end(); i++) {
- if ((*i).type == TempoMap::Beat) {
- zoomed_beats++;
- } else if ((*i).type == TempoMap::Bar) {
- zoomed_bars++;
- }
- }
-
if (desirable_marks > (beats / 4)) {
/* we're in beat land...*/
+ uint32_t tick = 0;
+ uint32_t skip;
+ uint32_t t;
+ jack_nframes_t frame_skip;
+ double frame_skip_error;
+ double accumulated_error;
double position_of_helper;
bool i_am_accented = false;
bool we_need_ticks = false;
position_of_helper = ilower + (30 * Editor::get_current_zoom ());
- if (desirable_marks >= (beats * 2)) {
- nmarks = (zoomed_beats * bbt_beat_subdivision) + 1;
+ if (desirable_marks >= (beats)) {
+ nmarks = ((beats + 1) * bbt_beat_subdivision) + 1;
we_need_ticks = true;
} else {
- nmarks = zoomed_beats + 1;
+ nmarks = beats + 1;
}
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
@@ -1151,17 +1124,14 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
(*marks)[0].position = ilower;
(*marks)[0].style = GtkCustomRulerMarkMicro;
- for (n = 1, i = zoomed_bbt_points->begin(); i != zoomed_bbt_points->end() && n < nmarks; ++i) {
-
- if ((*i).frame <= ilower && (bar_helper_on)) {
-
+ for (n = 1, i = current_bbt_points->begin(); n < nmarks && i != current_bbt_points->end(); i++) {
+
+ if ((*i).frame < ilower && (bar_helper_on)) {
snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
(*marks)[0].label = g_strdup (buf);
} else {
-
if ((*i).type == TempoMap::Bar) {
- tick = 0;
(((*i).frame < position_of_helper) && bar_helper_on) ?
snprintf (buf, sizeof(buf), " ") : snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
(*marks)[n].label = g_strdup (buf);
@@ -1170,7 +1140,6 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
n++;
} else if (((*i).type == TempoMap::Beat) && ((*i).beat > 1)) {
- tick = 0;
((((*i).frame < position_of_helper) && bar_helper_on) || !we_need_ticks) ?
snprintf (buf, sizeof(buf), " ") : snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat);
if (((*i).beat % 2 == 1) || we_need_ticks) {
@@ -1184,33 +1153,36 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
}
}
- /* Find the next beat */
-
- session->bbt_time((*i).frame, next_beat);
- if (session->tempo_map().meter_at((*i).frame).beats_per_bar() > (next_beat.beats + 1)) {
- next_beat.beats += 1;
- } else {
- next_beat.bars += 1;
- next_beat.beats = 1;
- }
-
- next_beat_pos = session->tempo_map().frame_time(next_beat);
/* Add the tick marks */
- if (we_need_ticks) {
+ if (we_need_ticks && (*i).type != TempoMap::Bar) {
+
+ /* Find the next beat */
+
+ next_beat.beats = (*i).beat;
+ next_beat.bars = (*i).bar;
+
+ if ((*i).meter->beats_per_bar() > (next_beat.beats + 1)) {
+ next_beat.beats += 1;
+ } else {
+ next_beat.bars += 1;
+ next_beat.beats = 1;
+ }
+
+ next_beat_pos = session->tempo_map().frame_time(next_beat);
- frame_skip = (jack_nframes_t) floor ((session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
- frame_skip_error = ((session->frame_rate() * 60.0f) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute())) - frame_skip;
+ frame_skip = (jack_nframes_t) floor (frame_skip_error = (session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
+ frame_skip_error -= frame_skip;
skip = (uint32_t) (Meter::ticks_per_beat / bbt_beat_subdivision);
pos = (*i).frame + frame_skip;
accumulated_error = frame_skip_error;
- tick += skip;
+ tick = skip;
- for (t = 0; tick < Meter::ticks_per_beat && pos <= next_beat_pos ; pos += frame_skip, tick += skip, ++t) {
+ for (t = 0; (tick < Meter::ticks_per_beat) && (n < nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) {
if (t % magic_accent_number == (magic_accent_number - 1)) {
i_am_accented = true;
@@ -1247,23 +1219,22 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
}
}
}
- delete zoomed_bbt_points;
return n; //return the actual number of marks made, since we might have skipped some fro fractional time signatures
} else {
/* we're in bar land */
- if (desirable_marks < (uint32_t) (zoomed_bars / 256)) {
+ if (desirable_marks < (uint32_t) (bars / 256)) {
nmarks = 1;
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
- snprintf (buf, sizeof(buf), "too many bars... (currently %" PRIu32 ")", zoomed_bars );
+ snprintf (buf, sizeof(buf), "too many bars... (currently %" PRIu32 ")", bars );
(*marks)[0].style = GtkCustomRulerMarkMajor;
(*marks)[0].label = g_strdup (buf);
(*marks)[0].position = ilower;
- } else if (desirable_marks < (uint32_t) (nmarks = (gint) (zoomed_bars / 64))) {
+ } else if (desirable_marks < (uint32_t) (nmarks = (gint) (bars / 64))) {
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
- for (n = 0, i = zoomed_bbt_points->begin(); i != zoomed_bbt_points->end() && n < nmarks; i++) {
+ for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) {
if ((*i).type == TempoMap::Bar) {
if ((*i).bar % 64 == 1) {
if ((*i).bar % 256 == 1) {
@@ -1283,9 +1254,9 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
}
}
}
- } else if (desirable_marks < (uint32_t) (nmarks = (gint)(zoomed_bars / 16))) {
+ } else if (desirable_marks < (uint32_t) (nmarks = (gint)(bars / 16))) {
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
- for (n = 0, i = zoomed_bbt_points->begin(); i != zoomed_bbt_points->end() && n < nmarks; i++) {
+ for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) {
if ((*i).type == TempoMap::Bar) {
if ((*i).bar % 16 == 1) {
if ((*i).bar % 64 == 1) {
@@ -1305,9 +1276,9 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
}
}
}
- } else if (desirable_marks < (uint32_t) (nmarks = (gint)(zoomed_bars / 4))){
+ } else if (desirable_marks < (uint32_t) (nmarks = (gint)(bars / 4))){
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
- for (n = 0, i = zoomed_bbt_points->begin(); i != zoomed_bbt_points->end() && n < nmarks; ++i) {
+ for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; ++i) {
if ((*i).type == TempoMap::Bar) {
if ((*i).bar % 4 == 1) {
if ((*i).bar % 16 == 1) {
@@ -1328,9 +1299,9 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
}
}
} else {
- nmarks = zoomed_bars;
+ nmarks = bars;
*marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
- for (n = 0, i = zoomed_bbt_points->begin(); i != zoomed_bbt_points->end() && n < nmarks; i++) {
+ for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) {
if ((*i).type == TempoMap::Bar) {
if ((*i).bar % 4 == 1) {
snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
@@ -1349,7 +1320,6 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper
}
}
}
- delete zoomed_bbt_points;
return nmarks;
}
}
@@ -1448,9 +1418,9 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble up
if (lower > (spacer = (jack_nframes_t)(128 * Editor::get_current_zoom ()))) {
lower = lower - spacer;
} else {
- upper = upper + spacer;
lower = 0;
}
+ upper = upper + spacer;
range = iupper - ilower;
if (range < (fr / 50)) {
diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc
index db1ee5e34e..e101da196f 100644
--- a/gtk2_ardour/editor_tempodisplay.cc
+++ b/gtk2_ardour/editor_tempodisplay.cc
@@ -96,14 +96,36 @@ void
Editor::tempo_map_changed (Change ignored)
{
ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::tempo_map_changed), ignored));
-
+
+ BBT_Time previous_beat, next_beat; // the beats previous to the leftmost frame and after the rightmost frame
+
+ session->bbt_time(leftmost_frame, previous_beat);
+ session->bbt_time(leftmost_frame + current_page_frames(), next_beat);
+
+ if (previous_beat.beats > 1) {
+ previous_beat.beats -= 1;
+ } else if (previous_beat.bars > 1) {
+ previous_beat.bars--;
+ previous_beat.beats += 1;
+ }
+ previous_beat.ticks = 0;
+
+ if (session->tempo_map().meter_at(leftmost_frame + current_page_frames()).beats_per_bar () > next_beat.beats + 1) {
+ next_beat.beats += 1;
+ } else {
+ next_beat.bars += 1;
+ next_beat.beats = 1;
+ }
+ next_beat.ticks = 0;
+
if (current_bbt_points) {
- delete current_bbt_points;
+ delete current_bbt_points;
current_bbt_points = 0;
}
if (session) {
- current_bbt_points = session->tempo_map().get_points (leftmost_frame, leftmost_frame + current_page_frames());
+ current_bbt_points = session->tempo_map().get_points (session->tempo_map().frame_time (previous_beat), session->tempo_map().frame_time (next_beat));
+ update_tempo_based_rulers ();
} else {
current_bbt_points = 0;
}
@@ -114,11 +136,11 @@ Editor::tempo_map_changed (Change ignored)
void
Editor::redisplay_tempo ()
{
- hide_measures ();
if (session && current_bbt_points) {
- draw_measures ();
- update_tempo_based_rulers ();
+ Glib::signal_idle().connect (mem_fun (*this, &Editor::lazy_hide_and_draw_measures));
+ } else {
+ hide_measures ();
}
}
@@ -126,7 +148,7 @@ void
Editor::hide_measures ()
{
for (TimeLineList::iterator i = used_measure_lines.begin(); i != used_measure_lines.end(); ++i) {
- (*i)->hide();
+ (*i)->hide();
free_measure_lines.push_back (*i);
}
used_measure_lines.clear ();
@@ -149,6 +171,14 @@ Editor::get_time_line ()
return line;
}
+bool
+Editor::lazy_hide_and_draw_measures ()
+{
+ hide_measures ();
+ draw_measures ();
+ return false;
+}
+
void
Editor::draw_measures ()
{
@@ -156,86 +186,63 @@ Editor::draw_measures ()
return;
}
- TempoMap::BBTPointList::iterator i = current_bbt_points->begin();
- TempoMap::BBTPoint& p = (*i);
+ TempoMap::BBTPointList::iterator i;
ArdourCanvas::SimpleLine *line;
- gdouble xpos, last_xpos;
- uint32_t cnt;
+ gdouble xpos;
+ double x1, x2, y1, y2, beat_density;
+
+ uint32_t beats = 0;
+ uint32_t bars = 0;
uint32_t color;
if (current_bbt_points == 0 || current_bbt_points->empty()) {
return;
}
- cnt = 0;
- last_xpos = 0;
+ track_canvas.get_scroll_region (x1, y1, x2, y2);
/* get the first bar spacing */
- gdouble last_beat = DBL_MAX;
- gdouble beat_spacing = 0;
-
- for (i = current_bbt_points->begin(); i != current_bbt_points->end() && beat_spacing == 0; ++i) {
- TempoMap::BBTPoint& p = (*i);
+ i = current_bbt_points->end();
+ i--;
+ bars = (*i).bar - (*current_bbt_points->begin()).bar;
+ beats = current_bbt_points->size() - bars;
- switch (p.type) {
- case TempoMap::Bar:
- break;
+ beat_density = (beats * 10.0f) / track_canvas.get_width ();
- case TempoMap::Beat:
- xpos = frame_to_unit (p.frame);
- if (last_beat < xpos) {
- beat_spacing = xpos - last_beat;
- }
- last_beat = xpos;
- }
- }
-
- if (beat_spacing < 3.0) {
- /* if the lines are too close together, they become useless */
+ if (beat_density > 2.0f) {
+ /* if the lines are too close together, they become useless */
return;
}
-
- double x1, x2, y1, y2;
- track_canvas.get_scroll_region (x1, y1, x2, y2);
- y2 = 1000000000.0f;
-
+
for (i = current_bbt_points->begin(); i != current_bbt_points->end(); ++i) {
- p = (*i);
-
- switch (p.type) {
+ switch ((*i).type) {
case TempoMap::Bar:
break;
case TempoMap::Beat:
- xpos = frame_to_unit (p.frame);
- if (p.beat == 1) {
+ if ((*i).beat == 1) {
color = color_map[cMeasureLineBeat];
} else {
color = color_map[cMeasureLineBar];
- /* only draw beat lines if the gaps between beats
- are large.
- */
+ /* only draw beat lines if the gaps between beats are large. */
- if (beat_spacing < 4.0) {
- break;
+ if (beat_density > 0.25) {
+ break;
}
}
-
- if (cnt == 0 || xpos - last_xpos > 4.0) {
- line = get_time_line ();
- line->property_x1() = xpos;
- line->property_x2() = xpos;
- line->property_y2() = y2;
- line->property_color_rgba() = color;
- line->raise_to_top();
- line->show();
- last_xpos = xpos;
- ++cnt;
- }
+
+ xpos = frame_to_unit ((*i).frame);
+ line = get_time_line ();
+ line->property_x1() = xpos;
+ line->property_x2() = xpos;
+ line->property_y2() = y2;
+ line->property_color_rgba() = color;
+ //line->raise_to_top();
+ line->show();
break;
}
}
@@ -244,6 +251,7 @@ Editor::draw_measures ()
cursor_group->raise_to_top();
time_line_group->lower_to_bottom();
+ return;
}
void
diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc
index 94d2a397cf..d718cc9802 100644
--- a/gtk2_ardour/midi_streamview.cc
+++ b/gtk2_ardour/midi_streamview.cc
@@ -183,8 +183,8 @@ MidiStreamView::setup_rec_box ()
assert(region);
region->set_position (_trackview.session().transport_frame(), this);
rec_regions.push_back (region);
- /* catch it if it goes away */
- region->GoingAway.connect (bind (mem_fun (*this, &MidiStreamView::remove_rec_region), region));
+
+ // rec regions are destroyed in setup_rec_box
/* we add the region later */
}
@@ -252,6 +252,15 @@ MidiStreamView::setup_rec_box ()
last_rec_data_frame = 0;
/* remove temp regions */
+
+ for (list<boost::shared_ptr<Region> >::iterator iter = rec_regions.begin(); iter != rec_regions.end();) {
+ list<boost::shared_ptr<Region> >::iterator tmp;
+ tmp = iter;
+ ++tmp;
+ (*iter)->drop_references ();
+ iter = tmp;
+ }
+
rec_regions.clear();
// cerr << "\tclear " << rec_rects.size() << " rec rects\n";
diff --git a/gtk2_ardour/new_session_dialog.cc b/gtk2_ardour/new_session_dialog.cc
index 462fb57711..4a533137a6 100644
--- a/gtk2_ardour/new_session_dialog.cc
+++ b/gtk2_ardour/new_session_dialog.cc
@@ -657,8 +657,8 @@ NewSessionDialog::reset_template()
void
NewSessionDialog::reset_recent()
{
- /* Shamelessly ripped from ardour_ui.cc */
- std::vector<string *> *sessions;
+ /* Shamelessly ripped from ardour_ui.cc */
+ std::vector<string *> *sessions;
std::vector<string *>::iterator i;
RecentSessionsSorter cmp;
@@ -677,7 +677,7 @@ NewSessionDialog::reset_recent()
for (i = sessions->begin(); i != sessions->end(); ++i) {
- std::vector<std::string*>* states;
+ std::vector<std::string*>* states;
std::vector<const gchar*> item;
std::string fullpath = *(*i);
@@ -699,7 +699,7 @@ NewSessionDialog::reset_recent()
row[recent_columns.visible_name] = Glib::path_get_basename (fullpath);
row[recent_columns.fullpath] = fullpath;
- if (states->size() > 1) {
+ if (states->size()) {
/* add the children */
diff --git a/gtk2_ardour/option_editor.cc b/gtk2_ardour/option_editor.cc
index b7fc7e746e..013761a86a 100644
--- a/gtk2_ardour/option_editor.cc
+++ b/gtk2_ardour/option_editor.cc
@@ -152,7 +152,6 @@ OptionEditor::set_session (Session *s)
click_emphasis_path_entry.set_sensitive (false);
session_raid_entry.set_sensitive (false);
- smpte_fps_combo.set_sensitive (false);
short_xfade_slider.set_sensitive (false);
smpte_offset_negative_button.set_sensitive (false);
@@ -165,28 +164,9 @@ OptionEditor::set_session (Session *s)
click_path_entry.set_sensitive (true);
click_emphasis_path_entry.set_sensitive (true);
session_raid_entry.set_sensitive (true);
- smpte_fps_combo.set_sensitive (true);
short_xfade_slider.set_sensitive (true);
smpte_offset_negative_button.set_sensitive (true);
- if (!s->smpte_drop_frames) {
- // non-drop frames
- if (s->smpte_frames_per_second == 24.0)
- smpte_fps_combo.set_active_text (_("24 FPS"));
- else if (s->smpte_frames_per_second == 25.0)
- smpte_fps_combo.set_active_text (_("25 FPS"));
- else if (s->smpte_frames_per_second == 30.0)
- smpte_fps_combo.set_active_text (_("30 FPS"));
- else
- smpte_fps_combo.set_active_text (_("???"));
- } else {
- // drop frames
- if (floor(s->smpte_frames_per_second) == 29.0)
- smpte_fps_combo.set_active_text (_("30 FPS drop"));
- else
- smpte_fps_combo.set_active_text (_("???"));
- }
-
smpte_offset_clock.set_session (s);
smpte_offset_clock.set (s->smpte_offset (), true);
@@ -352,15 +332,6 @@ OptionEditor::setup_sync_options ()
HBox* hbox;
vector<string> dumb;
- dumb.clear ();
- dumb.push_back (X_("24 FPS"));
- dumb.push_back (X_("25 FPS"));
- dumb.push_back (X_("30 FPS drop"));
- dumb.push_back (X_("30 FPS non-drop"));
-
- set_popdown_strings (smpte_fps_combo, dumb);
- smpte_fps_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::smpte_fps_chosen));
-
smpte_offset_clock.set_mode (AudioClock::SMPTE);
smpte_offset_clock.ValueChanged.connect (mem_fun(*this, &OptionEditor::smpte_offset_chosen));
@@ -368,22 +339,12 @@ OptionEditor::setup_sync_options ()
smpte_offset_negative_button.unset_flags (Gtk::CAN_FOCUS);
- Label *smpte_fps_label = manage (new Label (_("SMPTE Frames/second")));
Label *smpte_offset_label = manage (new Label (_("SMPTE Offset")));
- smpte_fps_label->set_name("OptionsLabel");
smpte_offset_label->set_name("OptionsLabel");
hbox = manage (new HBox);
hbox->set_border_width (5);
hbox->set_spacing (10);
- hbox->pack_start (*smpte_fps_label, false, false);
- hbox->pack_start (smpte_fps_combo, false, false);
-
- sync_packer.pack_start (*hbox, false, false);
-
- hbox = manage (new HBox);
- hbox->set_border_width (5);
- hbox->set_spacing (10);
hbox->pack_start (*smpte_offset_label, false, false);
hbox->pack_start (smpte_offset_clock, false, false);
hbox->pack_start (smpte_offset_negative_button, false, false);
@@ -402,24 +363,6 @@ OptionEditor::smpte_offset_negative_clicked ()
}
void
-OptionEditor::smpte_fps_chosen ()
-{
- if (session) {
- string str = smpte_fps_combo.get_active_text();
-
- if (str == X_("24 FPS")) {
- session->set_smpte_type (24.0, false);
- } else if (str == X_("25 FPS")) {
- session->set_smpte_type (25.0, false);
- } else if (str == X_("30 FPS drop")) {
- session->set_smpte_type (29.97, true);
- } else if (str == X_("30 FPS non-drop")) {
- session->set_smpte_type (30.0, false);
- }
- }
-}
-
-void
OptionEditor::smpte_offset_chosen()
{
if (session) {
diff --git a/gtk2_ardour/option_editor.h b/gtk2_ardour/option_editor.h
index 1331d3126e..d3235164a6 100644
--- a/gtk2_ardour/option_editor.h
+++ b/gtk2_ardour/option_editor.h
@@ -100,13 +100,11 @@ class OptionEditor : public Gtk::Dialog
Gtk::VBox sync_packer;
Gtk::ComboBoxText slave_type_combo;
- Gtk::ComboBoxText smpte_fps_combo;
AudioClock smpte_offset_clock;
Gtk::CheckButton smpte_offset_negative_button;
void setup_sync_options ();
- void smpte_fps_chosen ();
void smpte_offset_chosen ();
void smpte_offset_negative_clicked ();
diff --git a/gtk2_ardour/region_gain_line.h b/gtk2_ardour/region_gain_line.h
index 02340c8bae..3781fe60bb 100644
--- a/gtk2_ardour/region_gain_line.h
+++ b/gtk2_ardour/region_gain_line.h
@@ -26,16 +26,12 @@ class AudioRegionGainLine : public AutomationLine
void remove_point (ControlPoint&);
- PBD::ID id() { return _id; }
-
private:
ARDOUR::Session& session;
AudioRegionView& rv;
UndoAction get_memento();
-
- PBD::ID _id;
};
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 27d1739fd4..470a6d0b88 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -118,18 +118,6 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
hide_button.add (*(manage (new Image (get_xpm("small_x.xpm")))));
- solo_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false);
- mute_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false);
- playlist_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false);
- automation_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false);
- size_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false);
- visual_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false);
- hide_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false);
-
- solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false);
- solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false);
- mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
- mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
edit_group_button.signal_button_release_event().connect (mem_fun(*this, &RouteTimeAxisView::edit_click), false);
playlist_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::playlist_click));
automation_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::automation_click));
@@ -137,10 +125,14 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
visual_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::visual_click));
hide_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::hide_click));
+ solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false);
+ solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false);
+ mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
+ mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
+
if (is_track()) {
rec_enable_button->set_active (false);
rec_enable_button->set_name ("TrackRecordEnableButton");
- rec_enable_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false);
rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press));
controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record"));
@@ -197,6 +189,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
_route->name_changed.connect (mem_fun(*this, &RouteTimeAxisView::route_name_changed));
_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
+
if (is_track()) {
track()->FreezeChange.connect (mem_fun(*this, &RouteTimeAxisView::map_frozen));
@@ -215,6 +208,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
editor.ZoomChanged.connect (mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit));
ColorChanged.connect (mem_fun (*this, &RouteTimeAxisView::color_handler));
+
}
RouteTimeAxisView::~RouteTimeAxisView ()
@@ -605,19 +599,19 @@ RouteTimeAxisView::set_height (TrackHeight h)
show_name_entry ();
hide_name_label ();
- mute_button->show_all();
- solo_button->show_all();
+ mute_button->show();
+ solo_button->show();
if (rec_enable_button)
- rec_enable_button->show_all();
+ rec_enable_button->show();
- edit_group_button.show_all();
- hide_button.show_all();
- visual_button.show_all();
- size_button.show_all();
- automation_button.show_all();
+ edit_group_button.show();
+ hide_button.show();
+ visual_button.show();
+ size_button.show();
+ automation_button.show();
if (is_track() && track()->mode() == ARDOUR::Normal) {
- playlist_button.show_all();
+ playlist_button.show();
}
break;
@@ -625,10 +619,10 @@ RouteTimeAxisView::set_height (TrackHeight h)
show_name_entry ();
hide_name_label ();
- mute_button->show_all();
- solo_button->show_all();
+ mute_button->show();
+ solo_button->show();
if (rec_enable_button)
- rec_enable_button->show_all();
+ rec_enable_button->show();
edit_group_button.hide ();
hide_button.hide ();
@@ -1193,13 +1187,6 @@ RouteTimeAxisView::color_handler (ColorID id, uint32_t val)
}
}
-bool
-RouteTimeAxisView::select_me (GdkEventButton* ev)
-{
- editor.get_selection().add (this);
- return false;
-}
-
void
RouteTimeAxisView::show_all_automation ()
{
diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h
index f3643de68b..7489dc84fe 100644
--- a/gtk2_ardour/route_time_axis.h
+++ b/gtk2_ardour/route_time_axis.h
@@ -214,8 +214,7 @@ protected:
void map_frozen ();
void color_handler (ColorID, uint32_t);
- bool select_me (GdkEventButton*);
-
+
void region_view_added (RegionView*);
void add_ghost_to_redirect (RegionView*, AutomationTimeAxisView*);
diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc
index 3ede0bc1c7..040dac6e0e 100644
--- a/gtk2_ardour/route_ui.cc
+++ b/gtk2_ardour/route_ui.cc
@@ -86,10 +86,10 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
update_rec_display ();
}
-
+
mute_button->unset_flags (Gtk::CAN_FOCUS);
solo_button->unset_flags (Gtk::CAN_FOCUS);
-
+
/* map the current state */
map_frozen ();
@@ -100,7 +100,7 @@ RouteUI::~RouteUI()
delete mute_menu;
}
-gint
+bool
RouteUI::mute_press(GdkEventButton* ev)
{
if (!ignore_toggle) {
@@ -161,7 +161,7 @@ RouteUI::mute_press(GdkEventButton* ev)
return true;
}
-gint
+bool
RouteUI::mute_release(GdkEventButton* ev)
{
if (!ignore_toggle) {
@@ -175,7 +175,7 @@ RouteUI::mute_release(GdkEventButton* ev)
return true;
}
-gint
+bool
RouteUI::solo_press(GdkEventButton* ev)
{
if (!ignore_toggle) {
@@ -255,7 +255,7 @@ RouteUI::solo_press(GdkEventButton* ev)
return true;
}
-gint
+bool
RouteUI::solo_release(GdkEventButton* ev)
{
if (!ignore_toggle) {
@@ -271,7 +271,7 @@ RouteUI::solo_release(GdkEventButton* ev)
return true;
}
-gint
+bool
RouteUI::rec_enable_press(GdkEventButton* ev)
{
if (!ignore_toggle && is_track() && rec_enable_button) {
diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h
index b01d7d41cb..00b3e0a313 100644
--- a/gtk2_ardour/route_ui.h
+++ b/gtk2_ardour/route_ui.h
@@ -90,11 +90,11 @@ class RouteUI : public virtual AxisView
XMLNode* get_child_xml_node (const string & childname);
- gint mute_press(GdkEventButton*);
- gint mute_release(GdkEventButton*);
- gint solo_press(GdkEventButton*);
- gint solo_release(GdkEventButton*);
- gint rec_enable_press(GdkEventButton*);
+ bool mute_press(GdkEventButton*);
+ bool mute_release(GdkEventButton*);
+ bool solo_press(GdkEventButton*);
+ bool solo_release(GdkEventButton*);
+ bool rec_enable_press(GdkEventButton*);
void solo_changed(void*);
void mute_changed(void*);
diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc
index b0601704c8..f434463500 100644
--- a/gtk2_ardour/sfdb_ui.cc
+++ b/gtk2_ardour/sfdb_ui.cc
@@ -36,6 +36,7 @@
#include <ardour/source_factory.h>
#include "ardour_ui.h"
+#include "editing.h"
#include "gui_thread.h"
#include "prompter.h"
#include "sfdb_ui.h"
@@ -197,7 +198,7 @@ SoundFileBox::play_btn_clicked ()
for (int n = 0; n < sf_info.channels; ++n) {
try {
- afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, path+":"+string_compose("%1", n), AudioFileSource::Flag (0)));
+ afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, *_session, path+":"+string_compose("%1", n), AudioFileSource::Flag (0)));
srclist.push_back(afs);
} catch (failed_constructor& err) {
@@ -305,6 +306,15 @@ SoundFileBox::field_selected ()
}
}
+// this needs to be kept in sync with the ImportMode enum defined in editing.h and editing_syms.h.
+static const char *import_mode_strings[] = {
+ X_("Add to Region list"),
+ X_("Add to selected Track(s)"),
+ X_("Add as new Track(s)"),
+ X_("Add as new Tape Track(s)"),
+ 0
+};
+
SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s)
: ArdourDialog (title, false),
chooser (Gtk::FILE_CHOOSER_ACTION_OPEN)
@@ -339,13 +349,6 @@ SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
show_all ();
}
-static const char *import_mode_strings[] = {
- X_("Add to Region list"),
- X_("Add as new Track(s)"),
- X_("Add to selected Track(s)"),
- 0
-};
-
vector<string> SoundFileOmega::mode_strings;
SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s)
diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc
index 3a1237f882..3a15d84982 100644
--- a/gtk2_ardour/streamview.cc
+++ b/gtk2_ardour/streamview.cc
@@ -178,6 +178,8 @@ StreamView::remove_region_view (boost::shared_ptr<Region> r)
}
}
+#if 0
+(unused)
void
StreamView::remove_rec_region (boost::shared_ptr<Region> r)
{
@@ -195,6 +197,7 @@ StreamView::remove_rec_region (boost::shared_ptr<Region> r)
}
}
}
+#endif
void
StreamView::undisplay_diskstream ()
diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h
index 6f5e37869a..e965fc7c94 100644
--- a/gtk2_ardour/streamview.h
+++ b/gtk2_ardour/streamview.h
@@ -109,7 +109,7 @@ protected:
virtual void add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_waves) = 0;
virtual void remove_region_view (boost::shared_ptr<ARDOUR::Region> );
- void remove_rec_region (boost::shared_ptr<ARDOUR::Region>);
+ //void remove_rec_region (boost::shared_ptr<ARDOUR::Region>); (unused)
void display_diskstream (boost::shared_ptr<ARDOUR::Diskstream>);
virtual void undisplay_diskstream ();
diff --git a/libs/appleutility/CAAudioFile.cpp b/libs/appleutility/CAAudioFile.cpp
new file mode 100644
index 0000000000..e1e39b0ec9
--- /dev/null
+++ b/libs/appleutility/CAAudioFile.cpp
@@ -0,0 +1,1241 @@
+/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+ CAAudioFile.cpp
+
+=============================================================================*/
+
+#include "CAAudioFile.h"
+
+#if !CAAF_USE_EXTAUDIOFILE
+
+#include "CAXException.h"
+#include <algorithm>
+#include "CAHostTimeBase.h"
+#include "CADebugMacros.h"
+
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+ #include <AudioToolbox/AudioToolbox.h>
+#else
+ #include <AudioFormat.h>
+#endif
+
+#if DEBUG
+ //#define VERBOSE_IO 1
+ //#define VERBOSE_CONVERTER 1
+ //#define VERBOSE_CHANNELMAP 1
+ //#define LOG_FUNCTION_ENTRIES 1
+
+ #if VERBOSE_CHANNELMAP
+ #include "CAChannelLayouts.h" // this is in Source/Tests/AudioFileTools/Utility
+ #endif
+#endif
+
+#if LOG_FUNCTION_ENTRIES
+ class FunctionLogger {
+ public:
+ FunctionLogger(const char *name, const char *fmt=NULL, ...) : mName(name) {
+ Indent();
+ printf("-> %s ", name);
+ if (fmt) {
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ }
+ printf("\n");
+ ++sIndent;
+ }
+ ~FunctionLogger() {
+ --sIndent;
+ Indent();
+ printf("<- %s\n", mName);
+ if (sIndent == 0)
+ printf("\n");
+ }
+
+ static void Indent() {
+ for (int i = sIndent; --i >= 0; ) {
+ putchar(' '); putchar(' ');
+ }
+ }
+
+ const char *mName;
+ static int sIndent;
+ };
+ int FunctionLogger::sIndent = 0;
+
+ #define LOG_FUNCTION(name, format, ...) FunctionLogger _flog(name, format, ## __VA_ARGS__);
+#else
+ #define LOG_FUNCTION(name, format, foo)
+#endif
+
+static const UInt32 kDefaultIOBufferSizeBytes = 0x10000;
+
+#if CAAUDIOFILE_PROFILE
+ #define StartTiming(af, starttime) UInt64 starttime = af->mProfiling ? CAHostTimeBase::GetTheCurrentTime() : 0
+ #define ElapsedTime(af, starttime, counter) if (af->mProfiling) counter += (CAHostTimeBase::GetTheCurrentTime() - starttime)
+#else
+ #define StartTiming(af, starttime)
+ #define ElapsedTime(af, starttime, counter)
+#endif
+
+#define kNoMoreInputRightNow 'nein'
+
+// _______________________________________________________________________________________
+//
+CAAudioFile::CAAudioFile() :
+ mAudioFile(0),
+ mUseCache(false),
+ mFinishingEncoding(false),
+ mMode(kClosed),
+ mFileDataOffset(-1),
+ mFramesToSkipFollowingSeek(0),
+
+ mClientOwnsIOBuffer(false),
+ mPacketDescs(NULL),
+ mNumPacketDescs(0),
+ mConverter(NULL),
+ mMagicCookie(NULL),
+ mWriteBufferList(NULL)
+#if CAAUDIOFILE_PROFILE
+ ,
+ mProfiling(false),
+ mTicksInConverter(0),
+ mTicksInReadInConverter(0),
+ mTicksInIO(0),
+ mInConverter(false)
+#endif
+{
+ mIOBufferList.mBuffers[0].mData = NULL;
+ mIOBufferList.mBuffers[0].mDataByteSize = 0;
+ mClientMaxPacketSize = 0;
+ mIOBufferSizeBytes = kDefaultIOBufferSizeBytes;
+}
+
+// _______________________________________________________________________________________
+//
+CAAudioFile::~CAAudioFile()
+{
+ Close();
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::Close()
+{
+ LOG_FUNCTION("CAAudioFile::Close", NULL, NULL);
+ if (mMode == kClosed)
+ return;
+ if (mMode == kWriting)
+ FlushEncoder();
+ CloseConverter();
+ if (mAudioFile != 0 && mOwnOpenFile) {
+ AudioFileClose(mAudioFile);
+ mAudioFile = 0;
+ }
+ if (!mClientOwnsIOBuffer) {
+ delete[] (Byte *)mIOBufferList.mBuffers[0].mData;
+ mIOBufferList.mBuffers[0].mData = NULL;
+ mIOBufferList.mBuffers[0].mDataByteSize = 0;
+ }
+ delete[] mPacketDescs; mPacketDescs = NULL; mNumPacketDescs = 0;
+ delete[] mMagicCookie; mMagicCookie = NULL;
+ delete mWriteBufferList; mWriteBufferList = NULL;
+ mMode = kClosed;
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::CloseConverter()
+{
+ if (mConverter) {
+#if VERBOSE_CONVERTER
+ printf("CAAudioFile %p : CloseConverter\n", this);
+#endif
+ AudioConverterDispose(mConverter);
+ mConverter = NULL;
+ }
+}
+
+// =======================================================================================
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::Open(const FSRef &fsref)
+{
+ LOG_FUNCTION("CAAudioFile::Open", "%p", this);
+ XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open");
+ mFSRef = fsref;
+ XThrowIfError(AudioFileOpen(&mFSRef, fsRdPerm, 0, &mAudioFile), "open audio file");
+ mOwnOpenFile = true;
+ mMode = kReading;
+ GetExistingFileInfo();
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::Wrap(AudioFileID fileID, bool forWriting)
+{
+ LOG_FUNCTION("CAAudioFile::Wrap", "%p", this);
+ XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open");
+
+ mAudioFile = fileID;
+ mOwnOpenFile = false;
+ mMode = forWriting ? kPreparingToWrite : kReading;
+ GetExistingFileInfo();
+ if (forWriting)
+ FileFormatChanged();
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::CreateNew(const FSRef &parentDir, CFStringRef filename, AudioFileTypeID filetype, const AudioStreamBasicDescription &dataFormat, const AudioChannelLayout *layout)
+{
+ LOG_FUNCTION("CAAudioFile::CreateNew", "%p", this);
+ XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open");
+
+ mFileDataFormat = dataFormat;
+ if (layout) {
+ mFileChannelLayout = layout;
+#if VERBOSE_CHANNELMAP
+ printf("PrepareNew passed channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+ }
+ mMode = kPreparingToCreate;
+ FileFormatChanged(&parentDir, filename, filetype);
+}
+
+// _______________________________________________________________________________________
+//
+// called to create the file -- or update its format/channel layout/properties based on an encoder
+// setting change
+void CAAudioFile::FileFormatChanged(const FSRef *parentDir, CFStringRef filename, AudioFileTypeID filetype)
+{
+ LOG_FUNCTION("CAAudioFile::FileFormatChanged", "%p", this);
+ XThrowIf(mMode != kPreparingToCreate && mMode != kPreparingToWrite, kExtAudioFileError_InvalidOperationOrder, "new file not prepared");
+
+ UInt32 propertySize;
+ OSStatus err;
+ AudioStreamBasicDescription saveFileDataFormat = mFileDataFormat;
+
+#if VERBOSE_CONVERTER
+ mFileDataFormat.PrintFormat(stdout, "", "Specified file data format");
+#endif
+
+ // Find out the actual format the converter will produce. This is necessary in
+ // case the bitrate has forced a lower sample rate, which needs to be set correctly
+ // in the stream description passed to AudioFileCreate.
+ if (mConverter != NULL) {
+ propertySize = sizeof(AudioStreamBasicDescription);
+ Float64 origSampleRate = mFileDataFormat.mSampleRate;
+ XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterCurrentOutputStreamDescription, &propertySize, &mFileDataFormat), "get audio converter's output stream description");
+ // do the same for the channel layout being output by the converter
+#if VERBOSE_CONVERTER
+ mFileDataFormat.PrintFormat(stdout, "", "Converter output");
+#endif
+ if (fiszero(mFileDataFormat.mSampleRate))
+ mFileDataFormat.mSampleRate = origSampleRate;
+ err = AudioConverterGetPropertyInfo(mConverter, kAudioConverterOutputChannelLayout, &propertySize, NULL);
+ if (err == noErr && propertySize > 0) {
+ AudioChannelLayout *layout = static_cast<AudioChannelLayout *>(malloc(propertySize));
+ err = AudioConverterGetProperty(mConverter, kAudioConverterOutputChannelLayout, &propertySize, layout);
+ if (err) {
+ free(layout);
+ XThrow(err, "couldn't get audio converter's output channel layout");
+ }
+ mFileChannelLayout = layout;
+#if VERBOSE_CHANNELMAP
+ printf("got new file's channel layout from converter: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+ free(layout);
+ }
+ }
+
+ // create the output file
+ if (mMode == kPreparingToCreate) {
+ CAStreamBasicDescription newFileDataFormat = mFileDataFormat;
+ if (fiszero(newFileDataFormat.mSampleRate))
+ newFileDataFormat.mSampleRate = 44100; // just make something up for now
+#if VERBOSE_CONVERTER
+ newFileDataFormat.PrintFormat(stdout, "", "Applied to new file");
+#endif
+ XThrowIfError(AudioFileCreate(parentDir, filename, filetype, &newFileDataFormat, 0, &mFSRef, &mAudioFile), "create audio file");
+ mMode = kPreparingToWrite;
+ mOwnOpenFile = true;
+ } else if (saveFileDataFormat != mFileDataFormat || fnotequal(saveFileDataFormat.mSampleRate, mFileDataFormat.mSampleRate)) {
+ // second check must be explicit since operator== on ASBD treats SR of zero as "don't care"
+ if (fiszero(mFileDataFormat.mSampleRate))
+ mFileDataFormat.mSampleRate = mClientDataFormat.mSampleRate;
+#if VERBOSE_CONVERTER
+ mFileDataFormat.PrintFormat(stdout, "", "Applied to new file");
+#endif
+ XThrowIf(fiszero(mFileDataFormat.mSampleRate), kExtAudioFileError_InvalidDataFormat, "file's sample rate is 0");
+ XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyDataFormat, sizeof(AudioStreamBasicDescription), &mFileDataFormat), "couldn't update file's data format");
+ }
+
+ UInt32 deferSizeUpdates = 1;
+ err = AudioFileSetProperty(mAudioFile, kAudioFilePropertyDeferSizeUpdates, sizeof(UInt32), &deferSizeUpdates);
+
+ if (mConverter != NULL) {
+ // encoder
+ // get the magic cookie, if any, from the converter
+ delete[] mMagicCookie; mMagicCookie = NULL;
+ mMagicCookieSize = 0;
+
+ err = AudioConverterGetPropertyInfo(mConverter, kAudioConverterCompressionMagicCookie, &propertySize, NULL);
+
+ // we can get a noErr result and also a propertySize == 0
+ // -- if the file format does support magic cookies, but this file doesn't have one.
+ if (err == noErr && propertySize > 0) {
+ mMagicCookie = new Byte[propertySize];
+ XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterCompressionMagicCookie, &propertySize, mMagicCookie), "get audio converter's magic cookie");
+ mMagicCookieSize = propertySize; // the converter lies and tell us the wrong size
+ // now set the magic cookie on the output file
+ UInt32 willEatTheCookie = false;
+ // the converter wants to give us one; will the file take it?
+ err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyMagicCookieData,
+ NULL, &willEatTheCookie);
+ if (err == noErr && willEatTheCookie) {
+#if VERBOSE_CONVERTER
+ printf("Setting cookie on encoded file\n");
+#endif
+ XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyMagicCookieData, mMagicCookieSize, mMagicCookie), "set audio file's magic cookie");
+ }
+ }
+
+ // get maximum packet size
+ propertySize = sizeof(UInt32);
+ XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterPropertyMaximumOutputPacketSize, &propertySize, &mFileMaxPacketSize), "get audio converter's maximum output packet size");
+
+ AllocateBuffers(true /* okToFail */);
+ } else {
+ InitFileMaxPacketSize();
+ }
+
+ if (mFileChannelLayout.IsValid() && mFileChannelLayout.NumberChannels() > 2) {
+ // don't bother tagging mono/stereo files
+ UInt32 isWritable;
+ err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyChannelLayout, NULL, &isWritable);
+ if (!err && isWritable) {
+#if VERBOSE_CHANNELMAP
+ printf("writing file's channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+ err = AudioFileSetProperty(mAudioFile, kAudioFilePropertyChannelLayout,
+ mFileChannelLayout.Size(), &mFileChannelLayout.Layout());
+ if (err)
+ CAXException::Warning("could not set the file's channel layout", err);
+ } else {
+#if VERBOSE_CHANNELMAP
+ printf("file won't accept a channel layout (write)\n");
+#endif
+ }
+ }
+
+ UpdateClientMaxPacketSize(); // also sets mFrame0Offset
+ mPacketMark = 0;
+ mFrameMark = 0;
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::InitFileMaxPacketSize()
+{
+ LOG_FUNCTION("CAAudioFile::InitFileMaxPacketSize", "%p", this);
+ UInt32 propertySize = sizeof(UInt32);
+ OSStatus err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyMaximumPacketSize,
+ &propertySize, &mFileMaxPacketSize);
+ if (err) {
+ // workaround for 3361377: not all file formats' maximum packet sizes are supported
+ if (!mFileDataFormat.IsPCM())
+ XThrowIfError(err, "get audio file's maximum packet size");
+ mFileMaxPacketSize = mFileDataFormat.mBytesPerFrame;
+ }
+ AllocateBuffers(true /* okToFail */);
+}
+
+
+// _______________________________________________________________________________________
+//
+SInt64 CAAudioFile::FileDataOffset()
+{
+ if (mFileDataOffset < 0) {
+ UInt32 propertySize = sizeof(SInt64);
+ XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyDataOffset, &propertySize, &mFileDataOffset), "couldn't get file's data offset");
+ }
+ return mFileDataOffset;
+}
+
+// _______________________________________________________________________________________
+//
+SInt64 CAAudioFile::GetNumberFrames() const
+{
+ AudioFilePacketTableInfo pti;
+ UInt32 propertySize = sizeof(pti);
+ OSStatus err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti);
+ if (err == noErr)
+ return pti.mNumberValidFrames;
+ return mFileDataFormat.mFramesPerPacket * GetNumberPackets() - mFrame0Offset;
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::SetNumberFrames(SInt64 nFrames)
+{
+ XThrowIf(mFileDataFormat.mFramesPerPacket != 1, kExtAudioFileError_InvalidDataFormat, "SetNumberFrames only supported for PCM");
+ XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, sizeof(SInt64), &nFrames), "Couldn't set number of packets on audio file");
+}
+
+// _______________________________________________________________________________________
+//
+// call for existing file, NOT new one - from Open() or Wrap()
+void CAAudioFile::GetExistingFileInfo()
+{
+ LOG_FUNCTION("CAAudioFile::GetExistingFileInfo", "%p", this);
+ UInt32 propertySize;
+ OSStatus err;
+
+ // get mFileDataFormat
+ propertySize = sizeof(AudioStreamBasicDescription);
+ XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyDataFormat, &propertySize, &mFileDataFormat), "get audio file's data format");
+
+ // get mFileChannelLayout
+ err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyChannelLayout, &propertySize, NULL);
+ if (err == noErr && propertySize > 0) {
+ AudioChannelLayout *layout = static_cast<AudioChannelLayout *>(malloc(propertySize));
+ err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyChannelLayout, &propertySize, layout);
+ if (err == noErr) {
+ mFileChannelLayout = layout;
+#if VERBOSE_CHANNELMAP
+ printf("existing file's channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+ }
+ free(layout);
+ XThrowIfError(err, "get audio file's channel layout");
+ }
+ if (mMode != kReading)
+ return;
+
+#if 0
+ // get mNumberPackets
+ propertySize = sizeof(mNumberPackets);
+ XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, &propertySize, &mNumberPackets), "get audio file's packet count");
+#if VERBOSE_IO
+ printf("CAAudioFile::GetExistingFileInfo: %qd packets\n", mNumberPackets);
+#endif
+#endif
+
+ // get mMagicCookie
+ err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyMagicCookieData, &propertySize, NULL);
+ if (err == noErr && propertySize > 0) {
+ mMagicCookie = new Byte[propertySize];
+ mMagicCookieSize = propertySize;
+ XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyMagicCookieData, &propertySize, mMagicCookie), "get audio file's magic cookie");
+ }
+ InitFileMaxPacketSize();
+ mPacketMark = 0;
+ mFrameMark = 0;
+
+ UpdateClientMaxPacketSize();
+}
+
+// =======================================================================================
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::SetFileChannelLayout(const CAAudioChannelLayout &layout)
+{
+ LOG_FUNCTION("CAAudioFile::SetFileChannelLayout", "%p", this);
+ mFileChannelLayout = layout;
+#if VERBOSE_CHANNELMAP
+ printf("file channel layout set explicitly (%s): %s\n", mMode == kReading ? "read" : "write", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+ if (mMode != kReading)
+ FileFormatChanged();
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout)
+{
+ LOG_FUNCTION("CAAudioFile::SetClientFormat", "%p", this);
+ XThrowIf(!dataFormat.IsPCM(), kExtAudioFileError_NonPCMClientFormat, "non-PCM client format on audio file");
+
+ bool dataFormatChanging = (mClientDataFormat.mFormatID == 0 || mClientDataFormat != dataFormat);
+
+ if (dataFormatChanging) {
+ CloseConverter();
+ if (mWriteBufferList) {
+ delete mWriteBufferList;
+ mWriteBufferList = NULL;
+ }
+ mClientDataFormat = dataFormat;
+ }
+
+ if (layout && layout->IsValid()) {
+ XThrowIf(layout->NumberChannels() != mClientDataFormat.NumberChannels(), kExtAudioFileError_InvalidChannelMap, "inappropriate channel map");
+ mClientChannelLayout = *layout;
+ }
+
+ bool differentLayouts;
+ if (mClientChannelLayout.IsValid()) {
+ if (mFileChannelLayout.IsValid()) {
+ differentLayouts = mClientChannelLayout.Tag() != mFileChannelLayout.Tag();
+#if VERBOSE_CHANNELMAP
+ printf("two valid layouts, %s\n", differentLayouts ? "different" : "same");
+#endif
+ } else {
+ differentLayouts = false;
+#if VERBOSE_CHANNELMAP
+ printf("valid client layout, unknown file layout\n");
+#endif
+ }
+ } else {
+ differentLayouts = false;
+#if VERBOSE_CHANNELMAP
+ if (mFileChannelLayout.IsValid())
+ printf("valid file layout, unknown client layout\n");
+ else
+ printf("two invalid layouts\n");
+#endif
+ }
+
+ if (mClientDataFormat != mFileDataFormat || differentLayouts) {
+ // We need an AudioConverter.
+ if (mMode == kReading) {
+ // file -> client (decode)
+//mFileDataFormat.PrintFormat( stdout, "", "File: ");
+//mClientDataFormat.PrintFormat(stdout, "", "Client: ");
+
+ if (mConverter == NULL)
+ XThrowIfError(AudioConverterNew(&mFileDataFormat, &mClientDataFormat, &mConverter),
+ "create audio converter");
+
+#if VERBOSE_CONVERTER
+ printf("CAAudioFile %p -- created converter\n", this);
+ CAShow(mConverter);
+#endif
+ // set the magic cookie, if any (for decode)
+ if (mMagicCookie)
+ SetConverterProperty(kAudioConverterDecompressionMagicCookie, mMagicCookieSize, mMagicCookie, mFileDataFormat.IsPCM());
+ // we get cookies from some AIFF's but the converter barfs on them,
+ // so we set canFail to true for PCM
+
+ SetConverterChannelLayout(false, mFileChannelLayout);
+ SetConverterChannelLayout(true, mClientChannelLayout);
+
+ // propagate leading/trailing frame counts
+ if (mFileDataFormat.mBitsPerChannel == 0) {
+ UInt32 propertySize;
+ OSStatus err;
+ AudioFilePacketTableInfo pti;
+ propertySize = sizeof(pti);
+ err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti);
+ if (err == noErr && (pti.mPrimingFrames > 0 || pti.mRemainderFrames > 0)) {
+ AudioConverterPrimeInfo primeInfo;
+ primeInfo.leadingFrames = pti.mPrimingFrames;
+ primeInfo.trailingFrames = pti.mRemainderFrames;
+ /* ignore any error. better to play it at all than not. */
+ /*err = */AudioConverterSetProperty(mConverter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo);
+ //XThrowIfError(err, "couldn't set prime info on converter");
+ }
+ }
+ } else if (mMode == kPreparingToCreate || mMode == kPreparingToWrite) {
+ // client -> file (encode)
+ if (mConverter == NULL)
+ XThrowIfError(AudioConverterNew(&mClientDataFormat, &mFileDataFormat, &mConverter), "create audio converter");
+ mWriteBufferList = CABufferList::New("", mClientDataFormat);
+ SetConverterChannelLayout(false, mClientChannelLayout);
+ SetConverterChannelLayout(true, mFileChannelLayout);
+ if (mMode == kPreparingToWrite)
+ FileFormatChanged();
+ } else
+ XThrowIfError(kExtAudioFileError_InvalidOperationOrder, "audio file format not yet known");
+ }
+ UpdateClientMaxPacketSize();
+}
+
+// _______________________________________________________________________________________
+//
+OSStatus CAAudioFile::SetConverterProperty(
+ AudioConverterPropertyID inPropertyID,
+ UInt32 inPropertyDataSize,
+ const void* inPropertyData,
+ bool inCanFail)
+{
+ OSStatus err = noErr;
+ //LOG_FUNCTION("ExtAudioFile::SetConverterProperty", "%p %-4.4s", this, (char *)&inPropertyID);
+ if (inPropertyID == kAudioConverterPropertySettings && *(CFPropertyListRef *)inPropertyData == NULL)
+ ;
+ else {
+ err = AudioConverterSetProperty(mConverter, inPropertyID, inPropertyDataSize, inPropertyData);
+ if (!inCanFail) {
+ XThrowIfError(err, "set audio converter property");
+ }
+ }
+ UpdateClientMaxPacketSize();
+ if (mMode == kPreparingToWrite)
+ FileFormatChanged();
+ return err;
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::SetConverterChannelLayout(bool output, const CAAudioChannelLayout &layout)
+{
+ LOG_FUNCTION("CAAudioFile::SetConverterChannelLayout", "%p", this);
+ OSStatus err;
+
+ if (layout.IsValid()) {
+#if VERBOSE_CHANNELMAP
+ printf("Setting converter's %s channel layout: %s\n", output ? "output" : "input",
+ CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag()));
+#endif
+ if (output) {
+ err = AudioConverterSetProperty(mConverter, kAudioConverterOutputChannelLayout,
+ layout.Size(), &layout.Layout());
+ XThrowIf(err && err != kAudioConverterErr_OperationNotSupported, err, "couldn't set converter's output channel layout");
+ } else {
+ err = AudioConverterSetProperty(mConverter, kAudioConverterInputChannelLayout,
+ layout.Size(), &layout.Layout());
+ XThrowIf(err && err != kAudioConverterErr_OperationNotSupported, err, "couldn't set converter's input channel layout");
+ }
+ if (mMode == kPreparingToWrite)
+ FileFormatChanged();
+ }
+}
+
+// _______________________________________________________________________________________
+//
+CFArrayRef CAAudioFile::GetConverterConfig()
+{
+ CFArrayRef plist;
+ UInt32 propertySize = sizeof(plist);
+ XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterPropertySettings, &propertySize, &plist), "get converter property settings");
+ return plist;
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::UpdateClientMaxPacketSize()
+{
+ LOG_FUNCTION("CAAudioFile::UpdateClientMaxPacketSize", "%p", this);
+ mFrame0Offset = 0;
+ if (mConverter != NULL) {
+ AudioConverterPropertyID property = (mMode == kReading) ?
+ kAudioConverterPropertyMaximumOutputPacketSize :
+ kAudioConverterPropertyMaximumInputPacketSize;
+
+ UInt32 propertySize = sizeof(UInt32);
+ XThrowIfError(AudioConverterGetProperty(mConverter, property, &propertySize, &mClientMaxPacketSize),
+ "get audio converter's maximum packet size");
+
+ if (mFileDataFormat.mBitsPerChannel == 0) {
+ AudioConverterPrimeInfo primeInfo;
+ propertySize = sizeof(primeInfo);
+ OSStatus err = AudioConverterGetProperty(mConverter, kAudioConverterPrimeInfo, &propertySize, &primeInfo);
+ if (err == noErr)
+ mFrame0Offset = primeInfo.leadingFrames;
+#if VERBOSE_CONVERTER
+ printf("kAudioConverterPrimeInfo: err = %ld, leadingFrames = %ld\n", err, mFrame0Offset);
+#endif
+ }
+ } else {
+ mClientMaxPacketSize = mFileMaxPacketSize;
+ }
+}
+
+// _______________________________________________________________________________________
+// Allocates: mIOBufferList, mIOBufferSizePackets, mPacketDescs
+// Dependent on: mFileMaxPacketSize, mIOBufferSizeBytes
+void CAAudioFile::AllocateBuffers(bool okToFail)
+{
+ LOG_FUNCTION("CAAudioFile::AllocateBuffers", "%p", this);
+ if (mFileMaxPacketSize == 0) {
+ if (okToFail)
+ return;
+ XThrowIf(true, kExtAudioFileError_MaxPacketSizeUnknown, "file's maximum packet size is 0");
+ }
+ UInt32 bufferSizeBytes = mIOBufferSizeBytes = std::max(mIOBufferSizeBytes, mFileMaxPacketSize);
+ // must be big enough for at least one maximum size packet
+
+ if (mIOBufferList.mBuffers[0].mDataByteSize != bufferSizeBytes) {
+ mIOBufferList.mNumberBuffers = 1;
+ mIOBufferList.mBuffers[0].mNumberChannels = mFileDataFormat.mChannelsPerFrame;
+ if (!mClientOwnsIOBuffer) {
+ //printf("reallocating I/O buffer\n");
+ delete[] (Byte *)mIOBufferList.mBuffers[0].mData;
+ mIOBufferList.mBuffers[0].mData = new Byte[bufferSizeBytes];
+ }
+ mIOBufferList.mBuffers[0].mDataByteSize = bufferSizeBytes;
+ mIOBufferSizePackets = bufferSizeBytes / mFileMaxPacketSize;
+ }
+
+ UInt32 propertySize = sizeof(UInt32);
+ UInt32 externallyFramed;
+ XThrowIfError(AudioFormatGetProperty(kAudioFormatProperty_FormatIsExternallyFramed,
+ sizeof(AudioStreamBasicDescription), &mFileDataFormat, &propertySize, &externallyFramed),
+ "is format externally framed");
+ if (mNumPacketDescs != (externallyFramed ? mIOBufferSizePackets : 0)) {
+ delete[] mPacketDescs;
+ mPacketDescs = NULL;
+ mNumPacketDescs = 0;
+
+ if (externallyFramed) {
+ //printf("reallocating packet descs\n");
+ mPacketDescs = new AudioStreamPacketDescription[mIOBufferSizePackets];
+ mNumPacketDescs = mIOBufferSizePackets;
+ }
+ }
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::SetIOBuffer(void *buf)
+{
+ if (!mClientOwnsIOBuffer)
+ delete[] (Byte *)mIOBufferList.mBuffers[0].mData;
+ mIOBufferList.mBuffers[0].mData = buf;
+
+ if (buf == NULL) {
+ mClientOwnsIOBuffer = false;
+ SetIOBufferSizeBytes(mIOBufferSizeBytes);
+ } else {
+ mClientOwnsIOBuffer = true;
+ AllocateBuffers();
+ }
+// printf("CAAudioFile::SetIOBuffer %p: %p, 0x%lx bytes, mClientOwns = %d\n", this, mIOBufferList.mBuffers[0].mData, mIOBufferSizeBytes, mClientOwnsIOBuffer);
+}
+
+// ===============================================================================
+
+/*
+For Tiger:
+added kAudioFilePropertyPacketToFrame and kAudioFilePropertyFrameToPacket.
+You pass in an AudioFramePacketTranslation struct, with the appropriate field filled in, to AudioFileGetProperty.
+
+ kAudioFilePropertyPacketToFrame = 'pkfr',
+ // pass a AudioFramePacketTranslation with mPacket filled out and get mFrame back. mFrameOffsetInPacket is ignored.
+ kAudioFilePropertyFrameToPacket = 'frpk',
+ // pass a AudioFramePacketTranslation with mFrame filled out and get mPacket and mFrameOffsetInPacket back.
+
+struct AudioFramePacketTranslation
+{
+ SInt64 mFrame;
+ SInt64 mPacket;
+ UInt32 mFrameOffsetInPacket;
+};
+*/
+
+SInt64 CAAudioFile::PacketToFrame(SInt64 packet) const
+{
+ AudioFramePacketTranslation trans;
+ UInt32 propertySize;
+
+ switch (mFileDataFormat.mFramesPerPacket) {
+ case 1:
+ return packet;
+ case 0:
+ trans.mPacket = packet;
+ propertySize = sizeof(trans);
+ XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketToFrame, &propertySize, &trans),
+ "packet <-> frame translation unimplemented for format with variable frames/packet");
+ return trans.mFrame;
+ }
+ return packet * mFileDataFormat.mFramesPerPacket;
+}
+
+SInt64 CAAudioFile::FrameToPacket(SInt64 inFrame) const
+{
+ AudioFramePacketTranslation trans;
+ UInt32 propertySize;
+
+ switch (mFileDataFormat.mFramesPerPacket) {
+ case 1:
+ return inFrame;
+ case 0:
+ trans.mFrame = inFrame;
+ propertySize = sizeof(trans);
+ XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyFrameToPacket, &propertySize, &trans),
+ "packet <-> frame translation unimplemented for format with variable frames/packet");
+ return trans.mPacket;
+ }
+ return inFrame / mFileDataFormat.mFramesPerPacket;
+}
+
+// _______________________________________________________________________________________
+//
+
+SInt64 CAAudioFile::Tell() const // frameNumber
+{
+ return mFrameMark - mFrame0Offset;
+}
+
+void CAAudioFile::SeekToPacket(SInt64 packetNumber)
+{
+#if VERBOSE_IO
+ printf("CAAudioFile::SeekToPacket: %qd\n", packetNumber);
+#endif
+ XThrowIf(mMode != kReading || packetNumber < 0 /*|| packetNumber >= mNumberPackets*/ , kExtAudioFileError_InvalidSeek, "seek to packet in audio file");
+ if (mPacketMark == packetNumber)
+ return; // already there! don't reset converter
+ mPacketMark = packetNumber;
+
+ mFrameMark = PacketToFrame(packetNumber) - mFrame0Offset;
+ mFramesToSkipFollowingSeek = 0;
+ if (mConverter)
+ // must reset -- if we reached end of stream. converter will no longer work otherwise
+ AudioConverterReset(mConverter);
+}
+
+/*
+ Example: AAC, 1024 frames/packet, 2112 frame offset
+
+ 2112
+ |
+ Absolute frames: 0 1024 2048 | 3072
+ +---------+---------+--|------+---------+---------+
+ Packets: | 0 | 1 | | 2 | 3 | 4 |
+ +---------+---------+--|------+---------+---------+
+ Client frames: -2112 -1088 -64 | 960 SeekToFrame, TellFrame
+ |
+ 0
+
+ * Offset between absolute and client frames is mFrame0Offset.
+ *** mFrameMark is in client frames ***
+
+ Examples:
+ clientFrame 0 960 1000 1024
+ absoluteFrame 2112 3072 3112 3136
+ packet 0 0 0 1
+ tempFrameMark* -2112 -2112 -2112 -1088
+ mFramesToSkipFollowingSeek 2112 3072 3112 2112
+*/
+void CAAudioFile::Seek(SInt64 clientFrame)
+{
+ if (clientFrame == mFrameMark)
+ return; // already there! don't reset converter
+
+ //SInt64 absoluteFrame = clientFrame + mFrame0Offset;
+ XThrowIf(mMode != kReading || clientFrame < 0 || !mClientDataFormat.IsPCM(), kExtAudioFileError_InvalidSeek, "seek to frame in audio file");
+
+#if VERBOSE_IO
+ SInt64 prevFrameMark = mFrameMark;
+#endif
+
+ SInt64 packet;
+ packet = FrameToPacket(clientFrame);
+ if (packet < 0)
+ packet = 0;
+ SeekToPacket(packet);
+ // this will have backed up mFrameMark to match the beginning of the packet
+ mFramesToSkipFollowingSeek = std::max(UInt32(clientFrame - mFrameMark), UInt32(0));
+ mFrameMark = clientFrame;
+
+#if VERBOSE_IO
+ printf("CAAudioFile::SeekToFrame: frame %qd (from %qd), packet %qd, skip %ld frames\n", mFrameMark, prevFrameMark, packet, mFramesToSkipFollowingSeek);
+#endif
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::Read(UInt32 &ioNumPackets, AudioBufferList *ioData)
+ // May read fewer packets than requested if:
+ // buffer is not big enough
+ // file does not contain that many more packets
+ // Note that eofErr is not fatal, just results in 0 packets returned
+ // ioData's buffer sizes may be shortened
+{
+ XThrowIf(mClientMaxPacketSize == 0, kExtAudioFileError_MaxPacketSizeUnknown, "client maximum packet size is 0");
+ if (mIOBufferList.mBuffers[0].mData == NULL) {
+#if DEBUG
+ printf("warning: CAAudioFile::AllocateBuffers called from ReadPackets\n");
+#endif
+ AllocateBuffers();
+ }
+ UInt32 bufferSizeBytes = ioData->mBuffers[0].mDataByteSize;
+ UInt32 maxNumPackets = bufferSizeBytes / mClientMaxPacketSize;
+ // older versions of AudioConverterFillComplexBuffer don't do this, so do our own sanity check
+ UInt32 nPackets = std::min(ioNumPackets, maxNumPackets);
+
+ mMaxPacketsToRead = ~0UL;
+
+ if (mClientDataFormat.mFramesPerPacket == 1) { // PCM or equivalent
+ while (mFramesToSkipFollowingSeek > 0) {
+ UInt32 skipFrames = std::min(mFramesToSkipFollowingSeek, maxNumPackets);
+ UInt32 framesPerPacket;
+ if ((framesPerPacket=mFileDataFormat.mFramesPerPacket) > 0)
+ mMaxPacketsToRead = (skipFrames + framesPerPacket - 1) / framesPerPacket;
+
+ if (mConverter == NULL) {
+ XThrowIfError(ReadInputProc(NULL, &skipFrames, ioData, NULL, this), "read audio file");
+ } else {
+#if CAAUDIOFILE_PROFILE
+ mInConverter = true;
+#endif
+ StartTiming(this, fill);
+ XThrowIfError(AudioConverterFillComplexBuffer(mConverter, ReadInputProc, this, &skipFrames, ioData, NULL), "convert audio packets (pcm read)");
+ ElapsedTime(this, fill, mTicksInConverter);
+#if CAAUDIOFILE_PROFILE
+ mInConverter = false;
+#endif
+ }
+ if (skipFrames == 0) { // hit EOF
+ ioNumPackets = 0;
+ return;
+ }
+ mFrameMark += skipFrames;
+#if VERBOSE_IO
+ printf("CAAudioFile::ReadPackets: skipped %ld frames\n", skipFrames);
+#endif
+
+ mFramesToSkipFollowingSeek -= skipFrames;
+
+ // restore mDataByteSize
+ for (int i = ioData->mNumberBuffers; --i >= 0 ; )
+ ioData->mBuffers[i].mDataByteSize = bufferSizeBytes;
+ }
+ }
+
+ if (mFileDataFormat.mFramesPerPacket > 0)
+ // don't read more packets than we are being asked to produce
+ mMaxPacketsToRead = nPackets / mFileDataFormat.mFramesPerPacket + 1;
+ if (mConverter == NULL) {
+ XThrowIfError(ReadInputProc(NULL, &nPackets, ioData, NULL, this), "read audio file");
+ } else {
+#if CAAUDIOFILE_PROFILE
+ mInConverter = true;
+#endif
+ StartTiming(this, fill);
+ XThrowIfError(AudioConverterFillComplexBuffer(mConverter, ReadInputProc, this, &nPackets, ioData, NULL), "convert audio packets (read)");
+ ElapsedTime(this, fill, mTicksInConverter);
+#if CAAUDIOFILE_PROFILE
+ mInConverter = false;
+#endif
+ }
+ if (mClientDataFormat.mFramesPerPacket == 1)
+ mFrameMark += nPackets;
+
+ ioNumPackets = nPackets;
+}
+
+// _______________________________________________________________________________________
+//
+OSStatus CAAudioFile::ReadInputProc( AudioConverterRef inAudioConverter,
+ UInt32* ioNumberDataPackets,
+ AudioBufferList* ioData,
+ AudioStreamPacketDescription** outDataPacketDescription,
+ void* inUserData)
+{
+ CAAudioFile *This = static_cast<CAAudioFile *>(inUserData);
+
+#if 0
+ SInt64 remainingPacketsInFile = This->mNumberPackets - This->mPacketMark;
+ if (remainingPacketsInFile <= 0) {
+ *ioNumberDataPackets = 0;
+ ioData->mBuffers[0].mDataByteSize = 0;
+ if (outDataPacketDescription)
+ *outDataPacketDescription = This->mPacketDescs;
+#if VERBOSE_IO
+ printf("CAAudioFile::ReadInputProc: EOF\n");
+#endif
+ return noErr; // not eofErr; EOF is signified by 0 packets/0 bytes
+ }
+#endif
+
+ // determine how much to read
+ AudioBufferList *readBuffer;
+ UInt32 readPackets;
+ if (inAudioConverter != NULL) {
+ // getting called from converter, need to use our I/O buffer
+ readBuffer = &This->mIOBufferList;
+ readPackets = This->mIOBufferSizePackets;
+ } else {
+ // getting called directly from ReadPackets, use supplied buffer
+ if (This->mFileMaxPacketSize == 0)
+ return kExtAudioFileError_MaxPacketSizeUnknown;
+ readBuffer = ioData;
+ readPackets = std::min(*ioNumberDataPackets, readBuffer->mBuffers[0].mDataByteSize / This->mFileMaxPacketSize);
+ // don't attempt to read more packets than will fit in the buffer
+ }
+ // don't try to read past EOF
+// if (readPackets > remainingPacketsInFile)
+// readPackets = remainingPacketsInFile;
+ // don't read more packets than necessary to produce the requested amount of converted data
+ if (readPackets > This->mMaxPacketsToRead) {
+#if VERBOSE_IO
+ printf("CAAudioFile::ReadInputProc: limiting read to %ld packets (from %ld)\n", This->mMaxPacketsToRead, readPackets);
+#endif
+ readPackets = This->mMaxPacketsToRead;
+ }
+
+ // read
+ UInt32 bytesRead;
+ OSStatus err;
+
+ StartTiming(This, read);
+ StartTiming(This, readinconv);
+ err = AudioFileReadPackets(This->mAudioFile, This->mUseCache, &bytesRead, This->mPacketDescs, This->mPacketMark, &readPackets, readBuffer->mBuffers[0].mData);
+#if CAAUDIOFILE_PROFILE
+ if (This->mInConverter) ElapsedTime(This, readinconv, This->mTicksInReadInConverter);
+#endif
+ ElapsedTime(This, read, This->mTicksInIO);
+
+ if (err) {
+ DebugMessageN1("Error %ld from AudioFileReadPackets!!!\n", err);
+ return err;
+ }
+
+#if VERBOSE_IO
+ printf("CAAudioFile::ReadInputProc: read %ld packets (%qd-%qd), %ld bytes, err %ld\n", readPackets, This->mPacketMark, This->mPacketMark + readPackets, bytesRead, err);
+#if VERBOSE_IO >= 2
+ if (This->mPacketDescs) {
+ for (UInt32 i = 0; i < readPackets; ++i) {
+ printf(" read packet %qd : offset %qd, length %ld\n", This->mPacketMark + i, This->mPacketDescs[i].mStartOffset, This->mPacketDescs[i].mDataByteSize);
+ }
+ }
+ printf(" read buffer:"); CAShowAudioBufferList(readBuffer, 0, 4);
+#endif
+#endif
+ if (readPackets == 0) {
+ *ioNumberDataPackets = 0;
+ ioData->mBuffers[0].mDataByteSize = 0;
+ return noErr;
+ }
+
+ if (outDataPacketDescription)
+ *outDataPacketDescription = This->mPacketDescs;
+ ioData->mBuffers[0].mDataByteSize = bytesRead;
+ ioData->mBuffers[0].mData = readBuffer->mBuffers[0].mData;
+
+ This->mPacketMark += readPackets;
+ if (This->mClientDataFormat.mFramesPerPacket != 1) { // for PCM client formats we update in Read
+ // but for non-PCM client format (weird case) we must update here/now
+ if (This->mFileDataFormat.mFramesPerPacket > 0)
+ This->mFrameMark += readPackets * This->mFileDataFormat.mFramesPerPacket;
+ else {
+ for (UInt32 i = 0; i < readPackets; ++i)
+ This->mFrameMark += This->mPacketDescs[i].mVariableFramesInPacket;
+ }
+ }
+ *ioNumberDataPackets = readPackets;
+ return noErr;
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::Write(UInt32 numPackets, const AudioBufferList *data)
+{
+ if (mIOBufferList.mBuffers[0].mData == NULL) {
+#if DEBUG
+ printf("warning: CAAudioFile::AllocateBuffers called from WritePackets\n");
+#endif
+ AllocateBuffers();
+ }
+
+ if (mMode == kPreparingToWrite)
+ mMode = kWriting;
+ else
+ XThrowIf(mMode != kWriting, kExtAudioFileError_InvalidOperationOrder, "can't write to this file");
+ if (mConverter != NULL) {
+ mWritePackets = numPackets;
+ mWriteBufferList->SetFrom(data);
+ WritePacketsFromCallback(WriteInputProc, this);
+ } else {
+ StartTiming(this, write);
+ XThrowIfError(AudioFileWritePackets(mAudioFile, mUseCache, data->mBuffers[0].mDataByteSize,
+ NULL, mPacketMark, &numPackets, data->mBuffers[0].mData),
+ "write audio file");
+ ElapsedTime(this, write, mTicksInIO);
+#if VERBOSE_IO
+ printf("CAAudioFile::WritePackets: wrote %ld packets at %qd, %ld bytes\n", numPackets, mPacketMark, data->mBuffers[0].mDataByteSize);
+#endif
+ //mNumberPackets =
+ mPacketMark += numPackets;
+ if (mFileDataFormat.mFramesPerPacket > 0)
+ mFrameMark += numPackets * mFileDataFormat.mFramesPerPacket;
+ // else: shouldn't happen since we're only called when there's no converter
+ }
+}
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::FlushEncoder()
+{
+ if (mConverter != NULL) {
+ mFinishingEncoding = true;
+ WritePacketsFromCallback(WriteInputProc, this);
+ mFinishingEncoding = false;
+
+ // get priming info from converter, set it on the file
+ if (mFileDataFormat.mBitsPerChannel == 0) {
+ UInt32 propertySize;
+ OSStatus err;
+ AudioConverterPrimeInfo primeInfo;
+ propertySize = sizeof(primeInfo);
+
+ err = AudioConverterGetProperty(mConverter, kAudioConverterPrimeInfo, &propertySize, &primeInfo);
+ if (err == noErr) {
+ AudioFilePacketTableInfo pti;
+ propertySize = sizeof(pti);
+ err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti);
+ if (err == noErr) {
+//printf("old packet table info: %qd valid, %ld priming, %ld remainder\n", pti.mNumberValidFrames, pti.mPrimingFrames, pti.mRemainderFrames);
+ UInt64 totalFrames = pti.mNumberValidFrames + pti.mPrimingFrames + pti.mRemainderFrames;
+ pti.mPrimingFrames = primeInfo.leadingFrames;
+ pti.mRemainderFrames = primeInfo.trailingFrames;
+ pti.mNumberValidFrames = totalFrames - pti.mPrimingFrames - pti.mRemainderFrames;
+//printf("new packet table info: %qd valid, %ld priming, %ld remainder\n", pti.mNumberValidFrames, pti.mPrimingFrames, pti.mRemainderFrames);
+ XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, sizeof(pti), &pti), "couldn't set packet table info on audio file");
+ }
+ }
+ }
+ }
+}
+
+// _______________________________________________________________________________________
+//
+OSStatus CAAudioFile::WriteInputProc( AudioConverterRef /*inAudioConverter*/,
+ UInt32 * ioNumberDataPackets,
+ AudioBufferList* ioData,
+ AudioStreamPacketDescription ** outDataPacketDescription,
+ void* inUserData)
+{
+ CAAudioFile *This = static_cast<CAAudioFile *>(inUserData);
+ if (This->mFinishingEncoding) {
+ *ioNumberDataPackets = 0;
+ ioData->mBuffers[0].mDataByteSize = 0;
+ ioData->mBuffers[0].mData = NULL;
+ if (outDataPacketDescription)
+ *outDataPacketDescription = NULL;
+ return noErr;
+ }
+ UInt32 numPackets = This->mWritePackets;
+ if (numPackets == 0) {
+ return kNoMoreInputRightNow;
+ }
+ This->mWriteBufferList->ToAudioBufferList(ioData);
+ This->mWriteBufferList->BytesConsumed(numPackets * This->mClientDataFormat.mBytesPerFrame);
+ *ioNumberDataPackets = numPackets;
+ if (outDataPacketDescription)
+ *outDataPacketDescription = NULL;
+ This->mWritePackets -= numPackets;
+ return noErr;
+}
+
+// _______________________________________________________________________________________
+//
+#if VERBOSE_IO
+static void hexdump(const void *addr, long len)
+{
+ const Byte *p = (Byte *)addr;
+ UInt32 offset = 0;
+
+ if (len > 0x400) len = 0x400;
+
+ while (len > 0) {
+ int n = len > 16 ? 16 : len;
+ printf("%08lX: ", offset);
+ for (int i = 0; i < 16; ++i)
+ if (i < n)
+ printf("%02X ", p[i]);
+ else printf(" ");
+ for (int i = 0; i < 16; ++i)
+ if (i < n)
+ putchar(p[i] >= ' ' && p[i] < 127 ? p[i] : '.');
+ else putchar(' ');
+ putchar('\n');
+ p += 16;
+ len -= 16;
+ offset += 16;
+ }
+}
+#endif
+
+// _______________________________________________________________________________________
+//
+void CAAudioFile::WritePacketsFromCallback(
+ AudioConverterComplexInputDataProc inInputDataProc,
+ void * inInputDataProcUserData)
+{
+ while (true) {
+ // keep writing until we exhaust the input (temporary stop), or produce no output (EOF)
+ UInt32 numEncodedPackets = mIOBufferSizePackets;
+ mIOBufferList.mBuffers[0].mDataByteSize = mIOBufferSizeBytes;
+#if CAAUDIOFILE_PROFILE
+ mInConverter = true;
+#endif
+ StartTiming(this, fill);
+ OSStatus err = AudioConverterFillComplexBuffer(mConverter, inInputDataProc, inInputDataProcUserData,
+ &numEncodedPackets, &mIOBufferList, mPacketDescs);
+ ElapsedTime(this, fill, mTicksInConverter);
+#if CAAUDIOFILE_PROFILE
+ mInConverter = false;
+#endif
+ XThrowIf(err != 0 && err != kNoMoreInputRightNow, err, "convert audio packets (write)");
+ if (numEncodedPackets == 0)
+ break;
+ Byte *buf = (Byte *)mIOBufferList.mBuffers[0].mData;
+#if VERBOSE_IO
+ printf("CAAudioFile::WritePacketsFromCallback: wrote %ld packets, %ld bytes\n", numEncodedPackets, mIOBufferList.mBuffers[0].mDataByteSize);
+ if (mPacketDescs) {
+ for (UInt32 i = 0; i < numEncodedPackets; ++i) {
+ printf(" write packet %qd : offset %qd, length %ld\n", mPacketMark + i, mPacketDescs[i].mStartOffset, mPacketDescs[i].mDataByteSize);
+#if VERBOSE_IO >= 2
+ hexdump(buf + mPacketDescs[i].mStartOffset, mPacketDescs[i].mDataByteSize);
+#endif
+ }
+ }
+#endif
+ StartTiming(this, write);
+ XThrowIfError(AudioFileWritePackets(mAudioFile, mUseCache, mIOBufferList.mBuffers[0].mDataByteSize, mPacketDescs, mPacketMark, &numEncodedPackets, buf), "write audio file");
+ ElapsedTime(this, write, mTicksInIO);
+ mPacketMark += numEncodedPackets;
+ //mNumberPackets += numEncodedPackets;
+ if (mFileDataFormat.mFramesPerPacket > 0)
+ mFrameMark += numEncodedPackets * mFileDataFormat.mFramesPerPacket;
+ else {
+ for (UInt32 i = 0; i < numEncodedPackets; ++i)
+ mFrameMark += mPacketDescs[i].mVariableFramesInPacket;
+ }
+ if (err == kNoMoreInputRightNow)
+ break;
+ }
+}
+
+#endif // !CAAF_USE_EXTAUDIOFILE
diff --git a/libs/appleutility/CAAudioFile.h b/libs/appleutility/CAAudioFile.h
new file mode 100644
index 0000000000..2cfb4f3031
--- /dev/null
+++ b/libs/appleutility/CAAudioFile.h
@@ -0,0 +1,439 @@
+/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+ CAAudioFile.h
+
+=============================================================================*/
+
+#ifndef __CAAudioFile_h__
+#define __CAAudioFile_h__
+
+#include <AvailabilityMacros.h>
+
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+ #include <AudioToolbox/AudioToolbox.h>
+#else
+ #include <AudioToolbox.h>
+#endif
+
+#include "CAStreamBasicDescription.h"
+#include "CABufferList.h"
+#include "CAAudioChannelLayout.h"
+#include "CAXException.h"
+#include "CAMath.h"
+
+#ifndef CAAF_USE_EXTAUDIOFILE
+// option: use AudioToolbox/ExtAudioFile.h? Only available on Tiger.
+ #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_3
+ // we are building software that must be deployable on Panther or earlier
+ #define CAAF_USE_EXTAUDIOFILE 0
+ #else
+ // else we require Tiger and can use the API
+ #define CAAF_USE_EXTAUDIOFILE 1
+ #endif
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_4
+ // we have pre-Tiger headers; add our own declarations
+ typedef UInt32 AudioFileTypeID;
+ enum {
+ kExtAudioFileError_InvalidProperty = -66561,
+ kExtAudioFileError_InvalidPropertySize = -66562,
+ kExtAudioFileError_NonPCMClientFormat = -66563,
+ kExtAudioFileError_InvalidChannelMap = -66564, // number of channels doesn't match format
+ kExtAudioFileError_InvalidOperationOrder = -66565,
+ kExtAudioFileError_InvalidDataFormat = -66566,
+ kExtAudioFileError_MaxPacketSizeUnknown = -66567,
+ kExtAudioFileError_InvalidSeek = -66568, // writing, or offset out of bounds
+ kExtAudioFileError_AsyncWriteTooLarge = -66569,
+ kExtAudioFileError_AsyncWriteBufferOverflow = -66570 // an async write could not be completed in time
+ };
+#else
+ #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+ #include <AudioToolbox/ExtendedAudioFile.h>
+ #else
+ #include "ExtendedAudioFile.h"
+ #endif
+#endif
+
+// _______________________________________________________________________________________
+// Wrapper class for an AudioFile, supporting encode/decode to/from a PCM client format
+class CAAudioFile {
+public:
+ // implementation-independent helpers
+ void Open(const char *filePath) {
+ FSRef fsref;
+ XThrowIfError(FSPathMakeRef((UInt8 *)filePath, &fsref, NULL), "locate audio file");
+ Open(fsref);
+ }
+
+ bool HasConverter() const { return GetConverter() != NULL; }
+
+ double GetDurationSeconds() {
+ double sr = GetFileDataFormat().mSampleRate;
+ return fnonzero(sr) ? GetNumberFrames() / sr : 0.;
+ }
+ // will be 0 if the file's frames/packet is 0 (variable)
+ // or the file's sample rate is 0 (unknown)
+
+#if CAAF_USE_EXTAUDIOFILE
+public:
+ CAAudioFile() : mExtAF(NULL) { }
+ virtual ~CAAudioFile() { if (mExtAF) Close(); }
+
+ void Open(const FSRef &fsref) {
+ // open an existing file
+ XThrowIfError(ExtAudioFileOpen(&fsref, &mExtAF), "ExtAudioFileOpen failed");
+ }
+
+ void CreateNew(const FSRef &inParentDir, CFStringRef inFileName, AudioFileTypeID inFileType, const AudioStreamBasicDescription &inStreamDesc, const AudioChannelLayout *inChannelLayout=NULL) {
+ XThrowIfError(ExtAudioFileCreateNew(&inParentDir, inFileName, inFileType, &inStreamDesc, inChannelLayout, &mExtAF), "ExtAudioFileCreateNew failed");
+ }
+
+ void Wrap(AudioFileID fileID, bool forWriting) {
+ // use this to wrap an AudioFileID opened externally
+ XThrowIfError(ExtAudioFileWrapAudioFileID(fileID, forWriting, &mExtAF), "ExtAudioFileWrapAudioFileID failed");
+ }
+
+ void Close() {
+ XThrowIfError(ExtAudioFileDispose(mExtAF), "ExtAudioFileClose failed");
+ mExtAF = NULL;
+ }
+
+ const CAStreamBasicDescription &GetFileDataFormat() {
+ UInt32 size = sizeof(mFileDataFormat);
+ XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_FileDataFormat, &size, &mFileDataFormat), "Couldn't get file's data format");
+ return mFileDataFormat;
+ }
+
+ const CAAudioChannelLayout & GetFileChannelLayout() {
+ return FetchChannelLayout(mFileChannelLayout, kExtAudioFileProperty_FileChannelLayout);
+ }
+
+ void SetFileChannelLayout(const CAAudioChannelLayout &layout) {
+ XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_FileChannelLayout, layout.Size(), &layout.Layout()), "Couldn't set file's channel layout");
+ mFileChannelLayout = layout;
+ }
+
+ const CAStreamBasicDescription &GetClientDataFormat() {
+ UInt32 size = sizeof(mClientDataFormat);
+ XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_ClientDataFormat, &size, &mClientDataFormat), "Couldn't get client data format");
+ return mClientDataFormat;
+ }
+
+ const CAAudioChannelLayout & GetClientChannelLayout() {
+ return FetchChannelLayout(mClientChannelLayout, kExtAudioFileProperty_ClientChannelLayout);
+ }
+
+ void SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL) {
+ XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ClientDataFormat, sizeof(dataFormat), &dataFormat), "Couldn't set client format");
+ if (layout)
+ SetClientChannelLayout(*layout);
+ }
+
+ void SetClientChannelLayout(const CAAudioChannelLayout &layout) {
+ XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ClientChannelLayout, layout.Size(), &layout.Layout()), "Couldn't set client channel layout");
+ }
+
+ AudioConverterRef GetConverter() const {
+ UInt32 size = sizeof(AudioConverterRef);
+ AudioConverterRef converter;
+ XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_AudioConverter, &size, &converter), "Couldn't get file's AudioConverter");
+ return converter;
+ }
+
+ OSStatus SetConverterProperty(AudioConverterPropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData, bool inCanFail=false)
+ {
+ OSStatus err = AudioConverterSetProperty(GetConverter(), inPropertyID, inPropertyDataSize, inPropertyData);
+ if (!inCanFail)
+ XThrowIfError(err, "Couldn't set audio converter property");
+ if (!err) {
+ // must tell the file that we have changed the converter; a NULL converter config is sufficient
+ CFPropertyListRef config = NULL;
+ XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ConverterConfig, sizeof(CFPropertyListRef), &config), "couldn't signal the file that the converter has changed");
+ }
+ return err;
+ }
+
+ SInt64 GetNumberFrames() {
+ SInt64 length;
+ UInt32 size = sizeof(SInt64);
+ XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_FileLengthFrames, &size, &length), "Couldn't get file's length");
+ return length;
+ }
+
+ void SetNumberFrames(SInt64 length) {
+ XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_FileLengthFrames, sizeof(SInt64), &length), "Couldn't set file's length");
+ }
+
+ void Seek(SInt64 pos) {
+ XThrowIfError(ExtAudioFileSeek(mExtAF, pos), "Couldn't seek in audio file");
+ }
+
+ SInt64 Tell() {
+ SInt64 pos;
+ XThrowIfError(ExtAudioFileTell(mExtAF, &pos), "Couldn't get file's mark");
+ return pos;
+ }
+
+ void Read(UInt32 &ioFrames, AudioBufferList *ioData) {
+ XThrowIfError(ExtAudioFileRead(mExtAF, &ioFrames, ioData), "Couldn't read audio file");
+ }
+
+ void Write(UInt32 inFrames, const AudioBufferList *inData) {
+ XThrowIfError(ExtAudioFileWrite(mExtAF, inFrames, inData), "Couldn't write audio file");
+ }
+
+ void SetIOBufferSizeBytes(UInt32 bufferSizeBytes) {
+ XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_IOBufferSizeBytes, sizeof(UInt32), &bufferSizeBytes), "Couldn't set audio file's I/O buffer size");
+ }
+
+private:
+ const CAAudioChannelLayout & FetchChannelLayout(CAAudioChannelLayout &layoutObj, ExtAudioFilePropertyID propID) {
+ UInt32 size;
+ XThrowIfError(ExtAudioFileGetPropertyInfo(mExtAF, propID, &size, NULL), "Couldn't get info about channel layout");
+ AudioChannelLayout *layout = (AudioChannelLayout *)malloc(size);
+ OSStatus err = ExtAudioFileGetProperty(mExtAF, propID, &size, layout);
+ if (err) {
+ free(layout);
+ XThrowIfError(err, "Couldn't get channel layout");
+ }
+ layoutObj = layout;
+ free(layout);
+ return layoutObj;
+ }
+
+
+private:
+ ExtAudioFileRef mExtAF;
+
+ CAStreamBasicDescription mFileDataFormat;
+ CAAudioChannelLayout mFileChannelLayout;
+
+ CAStreamBasicDescription mClientDataFormat;
+ CAAudioChannelLayout mClientChannelLayout;
+#endif
+
+#if !CAAF_USE_EXTAUDIOFILE
+ CAAudioFile();
+ virtual ~CAAudioFile();
+
+ // --- second-stage initializers ---
+ // Use exactly one of the following:
+ // - Open
+ // - PrepareNew followed by Create
+ // - Wrap
+
+ void Open(const FSRef &fsref);
+ // open an existing file
+
+ void CreateNew(const FSRef &inParentDir, CFStringRef inFileName, AudioFileTypeID inFileType, const AudioStreamBasicDescription &inStreamDesc, const AudioChannelLayout *inChannelLayout=NULL);
+
+ void Wrap(AudioFileID fileID, bool forWriting);
+ // use this to wrap an AudioFileID opened externally
+
+ // ---
+
+ void Close();
+ // In case you want to close the file before the destructor executes
+
+ // --- Data formats ---
+
+ // Allow specifying the file's channel layout. Must be called before SetClientFormat.
+ // When writing, the specified channel layout is written to the file (if the file format supports
+ // the channel layout). When reading, the specified layout overrides the one read from the file,
+ // if any.
+ void SetFileChannelLayout(const CAAudioChannelLayout &layout);
+
+ // This specifies the data format which the client will use for reading/writing the file,
+ // which may be different from the file's format. An AudioConverter is created if necessary.
+ // The client format must be linear PCM.
+ void SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL);
+ void SetClientDataFormat(const CAStreamBasicDescription &dataFormat) { SetClientFormat(dataFormat, NULL); }
+ void SetClientChannelLayout(const CAAudioChannelLayout &layout) { SetClientFormat(mClientDataFormat, &layout); }
+
+ // Wrapping the underlying converter, if there is one
+ OSStatus SetConverterProperty(AudioConverterPropertyID inPropertyID,
+ UInt32 inPropertyDataSize,
+ const void * inPropertyData,
+ bool inCanFail = false);
+ void SetConverterConfig(CFArrayRef config) {
+ SetConverterProperty(kAudioConverterPropertySettings, sizeof(config), &config); }
+ CFArrayRef GetConverterConfig();
+
+ // --- I/O ---
+ // All I/O is sequential, but you can seek to an arbitrary position when reading.
+ // SeekToPacket and TellPacket's packet numbers are in the file's data format, not the client's.
+ // However, ReadPackets/WritePackets use packet counts in the client data format.
+
+ void Read(UInt32 &ioNumFrames, AudioBufferList *ioData);
+ void Write(UInt32 numFrames, const AudioBufferList *data);
+
+ // These can fail for files without a constant mFramesPerPacket
+ void Seek(SInt64 frameNumber);
+ SInt64 Tell() const; // frameNumber
+
+ // --- Accessors ---
+ // note: client parameters only valid if SetClientFormat has been called
+ AudioFileID GetAudioFileID() const { return mAudioFile; }
+ const CAStreamBasicDescription &GetFileDataFormat() const { return mFileDataFormat; }
+ const CAStreamBasicDescription &GetClientDataFormat() const { return mClientDataFormat; }
+ const CAAudioChannelLayout & GetFileChannelLayout() const { return mFileChannelLayout; }
+ const CAAudioChannelLayout & GetClientChannelLayout() const { return mClientChannelLayout; }
+ AudioConverterRef GetConverter() const { return mConverter; }
+
+ UInt32 GetFileMaxPacketSize() const { return mFileMaxPacketSize; }
+ UInt32 GetClientMaxPacketSize() const { return mClientMaxPacketSize; }
+ SInt64 GetNumberPackets() const {
+ SInt64 npackets;
+ UInt32 propertySize = sizeof(npackets);
+ XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, &propertySize, &npackets), "get audio file's packet count");
+ return npackets;
+ }
+ SInt64 GetNumberFrames() const;
+ // will be 0 if the file's frames/packet is 0 (variable)
+ void SetNumberFrames(SInt64 length); // should only be set on a PCM file
+
+ // --- Tunable performance parameters ---
+ void SetUseCache(bool b) { mUseCache = b; }
+ void SetIOBufferSizeBytes(UInt32 bufferSizeBytes) { mIOBufferSizeBytes = bufferSizeBytes; }
+ UInt32 GetIOBufferSizeBytes() { return mIOBufferSizeBytes; }
+ void * GetIOBuffer() { return mIOBufferList.mBuffers[0].mData; }
+ void SetIOBuffer(void *buf);
+
+ // -- Profiling ---
+#if CAAUDIOFILE_PROFILE
+ void EnableProfiling(bool b) { mProfiling = b; }
+ UInt64 TicksInConverter() const { return (mTicksInConverter > 0) ? (mTicksInConverter - mTicksInReadInConverter) : 0; }
+ UInt64 TicksInIO() const { return mTicksInIO; }
+#endif
+
+// _______________________________________________________________________________________
+private:
+ SInt64 FileDataOffset();
+ void SeekToPacket(SInt64 packetNumber);
+ SInt64 TellPacket() const { return mPacketMark; } // will be imprecise if SeekToFrame was called
+
+ void SetConverterChannelLayout(bool output, const CAAudioChannelLayout &layout);
+ void WritePacketsFromCallback(
+ AudioConverterComplexInputDataProc inInputDataProc,
+ void * inInputDataProcUserData);
+ // will use I/O buffer size
+ void InitFileMaxPacketSize();
+ void FileFormatChanged(const FSRef *parentDir=0, CFStringRef filename=0, AudioFileTypeID filetype=0);
+
+ void GetExistingFileInfo();
+ void FlushEncoder();
+ void CloseConverter();
+ void UpdateClientMaxPacketSize();
+ void AllocateBuffers(bool okToFail=false);
+ SInt64 PacketToFrame(SInt64 packet) const;
+ SInt64 FrameToPacket(SInt64 inFrame) const;
+
+ static OSStatus ReadInputProc( AudioConverterRef inAudioConverter,
+ UInt32* ioNumberDataPackets,
+ AudioBufferList* ioData,
+ AudioStreamPacketDescription** outDataPacketDescription,
+ void* inUserData);
+
+ static OSStatus WriteInputProc( AudioConverterRef inAudioConverter,
+ UInt32* ioNumberDataPackets,
+ AudioBufferList* ioData,
+ AudioStreamPacketDescription** outDataPacketDescription,
+ void* inUserData);
+// _______________________________________________________________________________________
+private:
+
+ // the file
+ FSRef mFSRef;
+ AudioFileID mAudioFile;
+ bool mOwnOpenFile;
+ bool mUseCache;
+ bool mFinishingEncoding;
+ enum { kClosed, kReading, kPreparingToCreate, kPreparingToWrite, kWriting } mMode;
+
+// SInt64 mNumberPackets; // in file's format
+ SInt64 mFileDataOffset;
+ SInt64 mPacketMark; // in file's format
+ SInt64 mFrameMark; // this may be offset from the start of the file
+ // by the codec's latency; i.e. our frame 0 could
+ // lie at frame 2112 of a decoded AAC file
+ SInt32 mFrame0Offset;
+ UInt32 mFramesToSkipFollowingSeek;
+
+ // buffers
+ UInt32 mIOBufferSizeBytes;
+ UInt32 mIOBufferSizePackets;
+ AudioBufferList mIOBufferList; // only one buffer -- USE ACCESSOR so it can be lazily initialized
+ bool mClientOwnsIOBuffer;
+ AudioStreamPacketDescription *mPacketDescs;
+ UInt32 mNumPacketDescs;
+
+ // formats/conversion
+ AudioConverterRef mConverter;
+ CAStreamBasicDescription mFileDataFormat;
+ CAStreamBasicDescription mClientDataFormat;
+ CAAudioChannelLayout mFileChannelLayout;
+ CAAudioChannelLayout mClientChannelLayout;
+ UInt32 mFileMaxPacketSize;
+ UInt32 mClientMaxPacketSize;
+
+ // cookie
+ Byte * mMagicCookie;
+ UInt32 mMagicCookieSize;
+
+ // for ReadPackets
+ UInt32 mMaxPacketsToRead;
+
+ // for WritePackets
+ UInt32 mWritePackets;
+ CABufferList * mWriteBufferList;
+
+#if CAAUDIOFILE_PROFILE
+ // performance
+ bool mProfiling;
+ UInt64 mTicksInConverter;
+ UInt64 mTicksInReadInConverter;
+ UInt64 mTicksInIO;
+ bool mInConverter;
+#endif
+
+#endif // CAAF_USE_EXTAUDIOFILE
+};
+
+#endif // __CAAudioFile_h__
diff --git a/libs/appleutility/CABufferList.cpp b/libs/appleutility/CABufferList.cpp
new file mode 100644
index 0000000000..81298f918a
--- /dev/null
+++ b/libs/appleutility/CABufferList.cpp
@@ -0,0 +1,179 @@
+/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+ CABufferList.cpp
+
+=============================================================================*/
+
+#include "CABufferList.h"
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+ #include <CoreServices/CoreServices.h>
+#else
+ #include <Endian.h>
+#endif
+
+void CABufferList::AllocateBuffers(UInt32 nBytes)
+{
+ if (nBytes <= GetNumBytes()) return;
+
+ if (mNumberBuffers > 1)
+ // align successive buffers for Altivec and to take alternating
+ // cache line hits by spacing them by odd multiples of 16
+ nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10;
+ UInt32 memorySize = nBytes * mNumberBuffers;
+ Byte *newMemory = new Byte[memorySize], *p = newMemory;
+ memset(newMemory, 0, memorySize); // get page faults now, not later
+
+ AudioBuffer *buf = mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf) {
+ if (buf->mData != NULL && buf->mDataByteSize > 0)
+ // preserve existing buffer contents
+ memcpy(p, buf->mData, buf->mDataByteSize);
+ buf->mDataByteSize = nBytes;
+ buf->mData = p;
+ p += nBytes;
+ }
+ Byte *oldMemory = mBufferMemory;
+ mBufferMemory = newMemory;
+ delete[] oldMemory;
+}
+
+void CABufferList::AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inSrcList, CABufferList *inSetPtrList)
+{
+ if (mNumberBuffers != inSrcList->mNumberBuffers) return;
+ if (mNumberBuffers != inSetPtrList->mNumberBuffers) return;
+ if (nBytes <= GetNumBytes()) {
+ CopyAllFrom(inSrcList, inSetPtrList);
+ return;
+ }
+ inSetPtrList->VerifyNotTrashingOwnedBuffer();
+ UInt32 fromByteSize = inSrcList->GetNumBytes();
+
+ if (mNumberBuffers > 1)
+ // align successive buffers for Altivec and to take alternating
+ // cache line hits by spacing them by odd multiples of 16
+ nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10;
+ UInt32 memorySize = nBytes * mNumberBuffers;
+ Byte *newMemory = new Byte[memorySize], *p = newMemory;
+ memset(newMemory, 0, memorySize); // make buffer "hot"
+
+ AudioBuffer *buf = mBuffers;
+ AudioBuffer *ptrBuf = inSetPtrList->mBuffers;
+ AudioBuffer *srcBuf = inSrcList->mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf, ++ptrBuf, ++srcBuf) {
+ if (srcBuf->mData != NULL && srcBuf->mDataByteSize > 0)
+ // preserve existing buffer contents
+ memmove(p, srcBuf->mData, srcBuf->mDataByteSize);
+ buf->mDataByteSize = nBytes;
+ buf->mData = p;
+ ptrBuf->mDataByteSize = srcBuf->mDataByteSize;
+ ptrBuf->mData = p;
+ p += nBytes;
+ }
+ Byte *oldMemory = mBufferMemory;
+ mBufferMemory = newMemory;
+ if (inSrcList != inSetPtrList)
+ inSrcList->BytesConsumed(fromByteSize);
+ delete[] oldMemory;
+}
+
+void CABufferList::DeallocateBuffers()
+{
+ AudioBuffer *buf = mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf) {
+ buf->mData = NULL;
+ buf->mDataByteSize = 0;
+ }
+ if (mBufferMemory != NULL) {
+ delete[] mBufferMemory;
+ mBufferMemory = NULL;
+ }
+
+}
+
+extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize)
+{
+ printf("AudioBufferList @ %p:\n", abl);
+ const AudioBuffer *buf = abl->mBuffers;
+ for (UInt32 i = 0; i < abl->mNumberBuffers; ++i, ++buf) {
+ printf(" [%2ld]: %2ldch, %5ld bytes @ %8p",
+ i, buf->mNumberChannels, buf->mDataByteSize, buf->mData);
+ if (framesToPrint) {
+ printf(":");
+ Byte *p = (Byte *)buf->mData;
+ for (int j = framesToPrint * buf->mNumberChannels; --j >= 0; )
+ switch (wordSize) {
+ case 0:
+ printf(" %6.3f", *(Float32 *)p);
+ p += sizeof(Float32);
+ break;
+ case 1:
+ case -1:
+ printf(" %02X", *p);
+ p += 1;
+ break;
+ case 2:
+ printf(" %04X", EndianU16_BtoN(*(UInt16 *)p));
+ p += 2;
+ break;
+ case 3:
+ printf(" %06X", (p[0] << 16) | (p[1] << 8) | p[2]);
+ p += 3;
+ break;
+ case 4:
+ printf(" %08lX", EndianU32_BtoN(*(UInt32 *)p));
+ p += 4;
+ break;
+ case -2:
+ printf(" %04X", EndianU16_LtoN(*(UInt16 *)p));
+ p += 2;
+ break;
+ case -3:
+ printf(" %06X", (p[2] << 16) | (p[1] << 8) | p[0]);
+ p += 3;
+ break;
+ case -4:
+ printf(" %08lX", EndianU32_LtoN(*(UInt32 *)p));
+ p += 4;
+ break;
+ }
+ }
+ printf("\n");
+ }
+}
+
diff --git a/libs/appleutility/CABufferList.h b/libs/appleutility/CABufferList.h
new file mode 100644
index 0000000000..3b0cef9a52
--- /dev/null
+++ b/libs/appleutility/CABufferList.h
@@ -0,0 +1,300 @@
+/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+ CABufferList.h
+
+=============================================================================*/
+
+#ifndef __CABufferList_h__
+#define __CABufferList_h__
+
+#include <stddef.h>
+#include "CAStreamBasicDescription.h"
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+ #include <CoreServices/CoreServices.h>
+#else
+ #include <AssertMacros.h>
+#endif
+
+extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize);
+ // wordSize: 0 = float32, else integer word size, negative if little-endian
+
+/* ____________________________________________________________________________
+// CABufferList - variable length buffer list
+
+ This class is designed for use in non-simplistic cases. For AudioUnits, AUBufferList
+ is preferred.
+
+ CABufferList can be used in one of two ways:
+ - as mutable pointers into non-owned memory
+ - as an immutable array of buffers (owns its own memory).
+
+ All buffers are assumed to have the same format (number of channels, word size), so that
+ we can assume their mDataByteSizes are all the same.
+____________________________________________________________________________ */
+class CABufferList {
+public:
+ void * operator new(size_t /*size*/, int nBuffers) {
+ return ::operator new(sizeof(CABufferList) + (nBuffers-1) * sizeof(AudioBuffer));
+ }
+ static CABufferList * New(const char *name, const CAStreamBasicDescription &format)
+ {
+ UInt32 numBuffers = format.NumberChannelStreams(), channelsPerBuffer = format.NumberInterleavedChannels();
+ return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer);
+ }
+
+protected:
+ CABufferList(const char *name, UInt32 numBuffers, UInt32 channelsPerBuffer) :
+ mName(name),
+ mBufferMemory(NULL)
+ {
+ check(numBuffers > 0 /*&& channelsPerBuffer > 0*/);
+ mNumberBuffers = numBuffers;
+ AudioBuffer *buf = mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf) {
+ buf->mNumberChannels = channelsPerBuffer;
+ buf->mDataByteSize = 0;
+ buf->mData = NULL;
+ }
+ }
+
+public:
+ ~CABufferList()
+ {
+ if (mBufferMemory)
+ delete[] mBufferMemory;
+ }
+
+ const char * Name() { return mName; }
+
+ const AudioBufferList & GetBufferList() const { return *(AudioBufferList *)&mNumberBuffers; }
+
+ AudioBufferList & GetModifiableBufferList()
+ {
+ VerifyNotTrashingOwnedBuffer();
+ return _GetBufferList();
+ }
+
+ UInt32 GetNumBytes() const
+ {
+ return mBuffers[0].mDataByteSize;
+ }
+
+ void SetBytes(UInt32 nBytes, void *data)
+ {
+ VerifyNotTrashingOwnedBuffer();
+ check(mNumberBuffers == 1);
+ mBuffers[0].mDataByteSize = nBytes;
+ mBuffers[0].mData = data;
+ }
+
+ void CopyAllFrom(CABufferList *srcbl, CABufferList *ptrbl)
+ // copies bytes from srcbl
+ // make ptrbl reflect the length copied
+ // note that srcbl may be same as ptrbl!
+ {
+ // Note that this buffer *can* own memory and its pointers/lengths are not
+ // altered; only its buffer contents, which are copied from srcbl.
+ // The pointers/lengths in ptrbl are updated to reflect the addresses/lengths
+ // of the copied data, and srcbl's contents are consumed.
+ ptrbl->VerifyNotTrashingOwnedBuffer();
+ UInt32 nBytes = srcbl->GetNumBytes();
+ AudioBuffer *mybuf = mBuffers, *srcbuf = srcbl->mBuffers,
+ *ptrbuf = ptrbl->mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf, ++ptrbuf) {
+ memmove(mybuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
+ ptrbuf->mData = mybuf->mData;
+ ptrbuf->mDataByteSize = srcbuf->mDataByteSize;
+ }
+ if (srcbl != ptrbl)
+ srcbl->BytesConsumed(nBytes);
+ }
+
+ void AppendFrom(CABufferList *blp, UInt32 nBytes)
+ {
+ VerifyNotTrashingOwnedBuffer();
+ AudioBuffer *mybuf = mBuffers, *srcbuf = blp->mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf) {
+ check(nBytes <= srcbuf->mDataByteSize);
+ memcpy((Byte *)mybuf->mData + mybuf->mDataByteSize, srcbuf->mData, nBytes);
+ mybuf->mDataByteSize += nBytes;
+ }
+ blp->BytesConsumed(nBytes);
+ }
+
+ void PadWithZeroes(UInt32 desiredBufferSize)
+ // for cases where an algorithm (e.g. SRC) requires some
+ // padding to create silence following end-of-file
+ {
+ VerifyNotTrashingOwnedBuffer();
+ if (GetNumBytes() > desiredBufferSize) return;
+ AudioBuffer *buf = mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf) {
+ memset((Byte *)buf->mData + buf->mDataByteSize, 0, desiredBufferSize - buf->mDataByteSize);
+ buf->mDataByteSize = desiredBufferSize;
+ }
+ }
+
+ void SetToZeroes(UInt32 nBytes)
+ {
+ VerifyNotTrashingOwnedBuffer();
+ AudioBuffer *buf = mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf) {
+ memset((Byte *)buf->mData, 0, nBytes);
+ buf->mDataByteSize = nBytes;
+ }
+ }
+
+ void Reset()
+ {
+ DeallocateBuffers();
+ }
+
+ Boolean SameDataAs(const CABufferList* anotherBufferList)
+ {
+ // check to see if two buffer lists point to the same memory.
+ if (mNumberBuffers != anotherBufferList->mNumberBuffers) return false;
+
+ for (UInt32 i = 0; i < mNumberBuffers; ++i) {
+ if (mBuffers[i].mData != anotherBufferList->mBuffers[i].mData) return false;
+ }
+ return true;
+ }
+
+ void BytesConsumed(UInt32 nBytes)
+ // advance buffer pointers, decrease buffer sizes
+ {
+ VerifyNotTrashingOwnedBuffer();
+ AudioBuffer *buf = mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf) {
+ check(nBytes <= buf->mDataByteSize);
+ buf->mData = (Byte *)buf->mData + nBytes;
+ buf->mDataByteSize -= nBytes;
+ }
+ }
+
+ void SetFrom(const AudioBufferList *abl)
+ {
+ VerifyNotTrashingOwnedBuffer();
+ memcpy(&_GetBufferList(), abl, (char *)&abl->mBuffers[abl->mNumberBuffers] - (char *)abl);
+ }
+
+ void SetFrom(const CABufferList *blp)
+ {
+ SetFrom(&blp->GetBufferList());
+ }
+
+ void SetFrom(const AudioBufferList *abl, UInt32 nBytes)
+ {
+ VerifyNotTrashingOwnedBuffer();
+ AudioBuffer *mybuf = mBuffers;
+ const AudioBuffer *srcbuf = abl->mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf) {
+ mybuf->mNumberChannels = srcbuf->mNumberChannels;
+ mybuf->mDataByteSize = nBytes;
+ mybuf->mData = srcbuf->mData;
+ }
+ }
+
+ void SetFrom(const CABufferList *blp, UInt32 nBytes)
+ {
+ SetFrom(&blp->GetBufferList(), nBytes);
+ }
+
+ AudioBufferList * ToAudioBufferList(AudioBufferList *abl) const
+ {
+ memcpy(abl, &GetBufferList(), (char *)&abl->mBuffers[mNumberBuffers] - (char *)abl);
+ return abl;
+ }
+
+ void AllocateBuffers(UInt32 nBytes);
+ void AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inCopyFromList, CABufferList *inSetPtrList);
+
+ void DeallocateBuffers();
+
+ void UseExternalBuffer(Byte *ptr, UInt32 nBytes);
+
+ void AdvanceBufferPointers(UInt32 nBytes)
+ // this is for bufferlists that function simply as
+ // an array of pointers into another bufferlist, being advanced,
+ // as in RenderOutput implementations
+ {
+ VerifyNotTrashingOwnedBuffer();
+ AudioBuffer *buf = mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf) {
+ buf->mData = (Byte *)buf->mData + nBytes;
+ buf->mDataByteSize -= nBytes;
+ }
+ }
+
+ void SetNumBytes(UInt32 nBytes)
+ {
+ VerifyNotTrashingOwnedBuffer();
+ AudioBuffer *buf = mBuffers;
+ for (UInt32 i = mNumberBuffers; i--; ++buf)
+ buf->mDataByteSize = nBytes;
+ }
+
+ void Print(const char *label=NULL, int nframes=0, int wordSize=0) const
+ {
+ if (label == NULL)
+ label = mName;
+ printf("%s - ", label);
+ CAShowAudioBufferList(&GetBufferList(), nframes, wordSize);
+ if (mBufferMemory)
+ printf(" owned memory @ 0x%p:\n", mBufferMemory);
+ }
+
+protected:
+ AudioBufferList & _GetBufferList() { return *(AudioBufferList *)&mNumberBuffers; } // use with care
+ // if we make this public, then we lose ability to call VerifyNotTrashingOwnedBuffer
+ void VerifyNotTrashingOwnedBuffer()
+ {
+ // This needs to be called from places where we are modifying the buffer list.
+ // It's an error to modify the buffer pointers or lengths if we own the buffer memory.
+ check(mBufferMemory == NULL);
+ }
+
+ const char * mName; // for debugging
+ Byte * mBufferMemory;
+ // the rest must exactly mirror the structure of AudioBufferList
+ UInt32 mNumberBuffers;
+ AudioBuffer mBuffers[1];
+};
+
+#endif // __CABufferList_h__
diff --git a/libs/appleutility/CAXException.cpp b/libs/appleutility/CAXException.cpp
new file mode 100644
index 0000000000..088575f041
--- /dev/null
+++ b/libs/appleutility/CAXException.cpp
@@ -0,0 +1,45 @@
+/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+ CAXException.cpp
+
+=============================================================================*/
+
+#include "CAXException.h"
+
+CAXException::WarningHandler CAXException::sWarningHandler = NULL;
diff --git a/libs/appleutility/CAXException.h b/libs/appleutility/CAXException.h
new file mode 100644
index 0000000000..796119763d
--- /dev/null
+++ b/libs/appleutility/CAXException.h
@@ -0,0 +1,158 @@
+/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+ CAXException.h
+
+=============================================================================*/
+
+#ifndef __CAXException_h__
+#define __CAXException_h__
+
+#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
+ #include <CoreServices/CoreServices.h>
+#else
+ #include <ConditionalMacros.h>
+ #include <CoreServices.h>
+#endif
+#include "CADebugMacros.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+// An extended exception class that includes the name of the failed operation
+class CAXException {
+public:
+ CAXException(const char *operation, OSStatus err) :
+ mError(err)
+ {
+ if (operation == NULL)
+ mOperation[0] = '\0';
+ else if (strlen(operation) >= sizeof(mOperation)) {
+ memcpy(mOperation, operation, sizeof(mOperation) - 1);
+ mOperation[sizeof(mOperation) - 1] = '\0';
+ } else
+ strcpy(mOperation, operation);
+ }
+
+ char *FormatError(char *str) const
+ {
+ return FormatError(str, mError);
+ }
+
+ char mOperation[256];
+ const OSStatus mError;
+
+ // -------------------------------------------------
+
+ typedef void (*WarningHandler)(const char *msg, OSStatus err);
+
+ /*static void Throw(const char *operation, OSStatus err)
+ {
+ throw CAXException(operation, err);
+ }*/
+
+ static char *FormatError(char *str, OSStatus error)
+ {
+ // see if it appears to be a 4-char-code
+ *(UInt32 *)(str + 1) = EndianU32_NtoB(error);
+ if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
+ str[0] = str[5] = '\'';
+ str[6] = '\0';
+ } else
+ // no, format it as an integer
+ sprintf(str, "%ld", error);
+ return str;
+ }
+
+ static void Warning(const char *s, OSStatus error)
+ {
+ if (sWarningHandler)
+ (*sWarningHandler)(s, error);
+ }
+
+ static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; }
+private:
+ static WarningHandler sWarningHandler;
+};
+
+#if DEBUG || CoreAudio_Debug
+ #define XThrowIfError(error, operation) \
+ do { \
+ OSStatus __err = error; \
+ if (__err) { \
+ char __buf[12]; \
+ DebugMessageN2("error %s: %4s\n", CAXException::FormatError(__buf, __err), operation);\
+ STOP; \
+ throw CAXException(operation, __err); \
+ } \
+ } while (0)
+
+ #define XThrowIf(condition, error, operation) \
+ do { \
+ if (condition) { \
+ OSStatus __err = error; \
+ char __buf[12]; \
+ DebugMessageN2("error %s: %4s\n", CAXException::FormatError(__buf, __err), operation);\
+ STOP; \
+ throw CAXException(operation, __err); \
+ } \
+ } while (0)
+
+#else
+ #define XThrowIfError(error, operation) \
+ do { \
+ OSStatus __err = error; \
+ if (__err) { \
+ throw CAXException(operation, __err); \
+ } \
+ } while (0)
+
+ #define XThrowIf(condition, error, operation) \
+ do { \
+ if (condition) { \
+ OSStatus __err = error; \
+ throw CAXException(operation, __err); \
+ } \
+ } while (0)
+
+#endif
+
+#define XThrow(error, operation) XThrowIf(true, error, operation)
+#define XThrowIfErr(error) XThrowIfError(error, #error)
+
+#endif // __CAXException_h__
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index c15897d8be..2e5253ec25 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -171,9 +171,27 @@ def CheckJackRecomputeLatencies(context):
context.Result(result)
return result
+jack_video_frame_offset_test = """
+#include <jack/transport.h>
+int main(int argc, char** argv)
+{
+ jack_position_t pos;
+
+ pos.valid & JackVideoFrameOffset;
+ return 0;
+}
+"""
+
+def CheckJackVideoFrameOffset(context):
+ context.Message('Checking for JackVideoFrameOffset in jack_position_bits_t enum...')
+ result = context.TryLink(jack_video_frame_offset_test, '.c')
+ context.Result(result)
+ return result
+
conf = Configure(ardour, custom_tests = {
'CheckJackClientOpen' : CheckJackClientOpen,
- 'CheckJackRecomputeLatencies' : CheckJackRecomputeLatencies
+ 'CheckJackRecomputeLatencies' : CheckJackRecomputeLatencies,
+ 'CheckJackVideoFrameOffset' : CheckJackVideoFrameOffset
})
if conf.CheckJackClientOpen():
@@ -182,6 +200,14 @@ if conf.CheckJackClientOpen():
if conf.CheckJackRecomputeLatencies():
ardour.Append(CXXFLAGS="-DHAVE_JACK_RECOMPUTE_LATENCIES")
+if conf.CheckJackVideoFrameOffset():
+ ardour.Append(CXXFLAGS="-DHAVE_JACK_VIDEO_SUPPORT")
+
+if conf.CheckFunc('jack_port_ensure_monitor'):
+ env.Append(CCFLAGS='-DHAVE_JACK_PORT_ENSURE_MONITOR')
+else:
+ print '\nWARNING: You need at least svn revision 985 of jack for hardware monitoring to work correctly.\n'
+
#
# Optional header files
#
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index 8588c9660d..81206f2bb0 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -61,8 +61,6 @@ class AudioDiskstream : public Diskstream
AudioDiskstream (Session &, const XMLNode&);
~AudioDiskstream();
- const PBD::ID& id() const { return _id; }
-
float playback_buffer_load() const;
float capture_buffer_load() const;
diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h
index b1ffab0944..0cab328fba 100644
--- a/libs/ardour/ardour/audiofilesource.h
+++ b/libs/ardour/ardour/audiofilesource.h
@@ -75,7 +75,7 @@ class AudioFileSource : public AudioSource {
int move_to_trash (const string trash_dir_name);
- static bool is_empty (string path);
+ static bool is_empty (Session&, string path);
void mark_streaming_write_completed ();
void mark_take (string);
@@ -104,16 +104,16 @@ class AudioFileSource : public AudioSource {
/* constructor to be called for existing external-to-session files */
- AudioFileSource (std::string path, Flag flags);
+ AudioFileSource (Session&, std::string path, Flag flags);
/* constructor to be called for new in-session files */
- AudioFileSource (std::string path, Flag flags,
+ AudioFileSource (Session&, std::string path, Flag flags,
SampleFormat samp_format, HeaderFormat hdr_format);
/* constructor to be called for existing in-session files */
- AudioFileSource (const XMLNode&);
+ AudioFileSource (Session&, const XMLNode&);
int init (string idstr, bool must_exist);
@@ -121,7 +121,6 @@ class AudioFileSource : public AudioSource {
string _path;
Flag _flags;
string _take_id;
- bool allow_remove_if_empty;
uint64_t timeline_position;
static string peak_dir;
diff --git a/libs/ardour/ardour/audioplaylist.h b/libs/ardour/ardour/audioplaylist.h
index 0426208ba1..6a52f1c16f 100644
--- a/libs/ardour/ardour/audioplaylist.h
+++ b/libs/ardour/ardour/audioplaylist.h
@@ -111,6 +111,8 @@ class AudioPlaylist : public ARDOUR::Playlist
bool region_changed (Change, boost::shared_ptr<Region>);
void crossfade_changed (Change);
void add_crossfade (Crossfade&);
+
+ void source_offset_changed (boost::shared_ptr<AudioRegion> region);
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index 9b97a88bc0..71a66e52a0 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -174,6 +174,7 @@ class AudioRegion : public Region
void recompute_at_end ();
void envelope_changed (Change);
+ void source_offset_changed ();
mutable Curve _fade_in;
FadeShape _fade_in_shape;
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 751213ee8e..6a0a20d4b8 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -47,8 +47,8 @@ const jack_nframes_t frames_per_peak = 256;
class AudioSource : public Source
{
public:
- AudioSource (string name);
- AudioSource (const XMLNode&);
+ AudioSource (Session&, string name);
+ AudioSource (Session&, const XMLNode&);
virtual ~AudioSource ();
virtual jack_nframes_t available_peaks (double zoom) const;
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index a3b84289c1..22ab706f82 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -159,8 +159,6 @@ struct ControlEvent {
XMLNode &get_state(void);
int set_state (const XMLNode &s);
- PBD::ID id() { return _id; }
-
void set_max_xval (double);
double get_max_xval() const { return max_xval; }
@@ -189,7 +187,7 @@ struct ControlEvent {
static sigc::signal<void, AutomationList*> AutomationListCreated;
protected:
- PBD::ID _id;
+
struct State : public ARDOUR::StateManager::State {
AutomationEventList events;
diff --git a/libs/ardour/ardour/coreaudiosource.h b/libs/ardour/ardour/coreaudiosource.h
index cf25c466ee..49009caf53 100644
--- a/libs/ardour/ardour/coreaudiosource.h
+++ b/libs/ardour/ardour/coreaudiosource.h
@@ -20,15 +20,16 @@
#ifndef __coreaudio_source_h__
#define __coreaudio_source_h__
+#include <appleutility/CAAudioFile.h>
+
#include <ardour/audiofilesource.h>
-#include <AudioToolbox/ExtendedAudioFile.h>
namespace ARDOUR {
class CoreAudioSource : public AudioFileSource {
public:
- CoreAudioSource (const XMLNode&);
- CoreAudioSource (const string& path_plus_channel, Flag);
+ CoreAudioSource (ARDOUR::Session&, const XMLNode&);
+ CoreAudioSource (ARDOUR::Session&, const string& path_plus_channel, Flag);
~CoreAudioSource ();
float sample_rate() const;
@@ -45,7 +46,7 @@ class CoreAudioSource : public AudioFileSource {
private:
- ExtAudioFileRef af;
+ mutable CAAudioFile af;
uint16_t n_channels;
mutable float *tmpbuf;
diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h
index fb2a3be47b..fed84217e7 100644
--- a/libs/ardour/ardour/destructive_filesource.h
+++ b/libs/ardour/ardour/destructive_filesource.h
@@ -31,12 +31,12 @@ namespace ARDOUR {
class DestructiveFileSource : public SndFileSource {
public:
- DestructiveFileSource (std::string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate,
+ DestructiveFileSource (Session&, std::string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate,
Flag flags = AudioFileSource::Flag (AudioFileSource::Writable));
- DestructiveFileSource (std::string path, Flag flags);
+ DestructiveFileSource (Session&, std::string path, Flag flags);
- DestructiveFileSource (const XMLNode&);
+ DestructiveFileSource (Session&, const XMLNode&);
~DestructiveFileSource ();
jack_nframes_t last_capture_start_frame() const;
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index 2bce6a424f..048e9df90f 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -92,7 +92,6 @@ class IO;
bool destructive() const { return _flags & Destructive; }
virtual void set_destructive (bool yn);
- const PBD::ID& id() const { return _id; }
bool hidden() const { return _flags & Hidden; }
bool recordable() const { return _flags & Recordable; }
bool reversed() const { return _actual_speed < 0.0f; }
@@ -243,7 +242,6 @@ class IO;
ARDOUR::Session& _session;
ARDOUR::IO* _io;
ChanCount _n_channels;
- PBD::ID _id;
Playlist* _playlist;
mutable gint _record_enabled;
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index ef0ab6c465..6074376291 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -263,8 +263,6 @@ public:
void start_pan_touch (uint32_t which);
void end_pan_touch (uint32_t which);
- const PBD::ID& id() const { return _id; }
-
void defer_pan_reset ();
void allow_pan_reset ();
@@ -292,7 +290,6 @@ public:
string _name;
Connection* _input_connection;
Connection* _output_connection;
- PBD::ID _id;
bool no_panner_reset;
bool _phase_invert;
XMLNode* deferred_state;
diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h
index 1052b74bd4..96fb1b1bcf 100644
--- a/libs/ardour/ardour/location.h
+++ b/libs/ardour/ardour/location.h
@@ -121,10 +121,7 @@ class Location : public sigc::trackable, public PBD::StatefulDestructible
XMLNode& get_state (void);
int set_state (const XMLNode&);
- PBD::ID id() { return _id; }
-
private:
- PBD::ID _id;
string _name;
jack_nframes_t _start;
jack_nframes_t _end;
@@ -150,7 +147,6 @@ class Locations : public StateManager, public PBD::StatefulDestructible
XMLNode& get_state (void);
int set_state (const XMLNode&);
- PBD::ID id() { return _id; }
Location *get_location_by_id(PBD::ID);
Location* auto_loop_location () const;
@@ -204,8 +200,6 @@ class Locations : public StateManager, public PBD::StatefulDestructible
Change restore_state (StateManager::State&);
StateManager::State* state_factory (std::string why) const;
-
- PBD::ID _id;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h
index 757e33f70e..a035bf683e 100644
--- a/libs/ardour/ardour/midi_source.h
+++ b/libs/ardour/ardour/midi_source.h
@@ -43,8 +43,8 @@ class MidiRingBuffer;
class MidiSource : public Source
{
public:
- MidiSource (string name);
- MidiSource (const XMLNode&);
+ MidiSource (Session& session, string name);
+ MidiSource (Session& session, const XMLNode&);
virtual ~MidiSource ();
virtual jack_nframes_t read (MidiRingBuffer& dst, jack_nframes_t start, jack_nframes_t cnt, jack_nframes_t stamp_offset) const;
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index c04b59286f..4249007fff 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -81,7 +81,6 @@ class Playlist : public StateManager, public PBD::StatefulDestructible {
EditMode get_edit_mode() const { return _edit_mode; }
void set_edit_mode (EditMode);
- PBD::ID id() { return _id; }
/* Editing operations */
void add_region (boost::shared_ptr<Region>, jack_nframes_t position, float times = 1, bool with_save = true);
@@ -279,8 +278,6 @@ class Playlist : public StateManager, public PBD::StatefulDestructible {
void unset_freeze_child (Playlist*);
void timestamp_layer_op (boost::shared_ptr<Region>);
-
- PBD::ID _id;
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h
index 2a99bdcc16..d6dcd55645 100644
--- a/libs/ardour/ardour/port.h
+++ b/libs/ardour/ardour/port.h
@@ -103,7 +103,7 @@ class Port : public sigc::trackable {
void ensure_monitor_input (bool yn) {
-#ifdef WITH_JACK_PORT_ENSURE_MONITOR
+#ifdef HAVE_JACK_PORT_ENSURE_MONITOR
jack_port_ensure_monitor (_port, yn);
#else
jack_port_request_monitor(_port, yn);
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index c3e93fc7ae..821927f8c2 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -37,7 +37,6 @@ class XMLNode;
namespace ARDOUR {
class Playlist;
-class Source;
enum RegionEditState {
EditChangesNothing = 0,
@@ -99,8 +98,6 @@ class Region : public PBD::StatefulDestructible, public StateManager, public boo
virtual ~Region();
- const PBD::ID& id() const { return _id; }
-
/* Note: changing the name of a Region does not constitute an edit */
string name() const { return _name; }
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 09fd01baec..99616f9729 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -267,8 +267,7 @@ class Session : public sigc::trackable, public PBD::StatefulDestructible
bool dirty() const { return _state_of_the_state & Dirty; }
sigc::signal<void> DirtyChanged;
- std::string sound_dir () const;
- std::string tape_dir () const;
+ std::string sound_dir (bool with_path = true) const;
std::string peak_dir () const;
std::string dead_sound_dir () const;
std::string automation_dir () const;
@@ -281,7 +280,8 @@ class Session : public sigc::trackable, public PBD::StatefulDestructible
static string change_audio_path_by_name (string oldpath, string oldname, string newname, bool destructive);
static string change_midi_path_by_name (string oldpath, string oldname, string newname, bool destructive);
- static string peak_path_from_audio_path (string);
+
+ string peak_path_from_audio_path (string) const;
string audio_path_from_name (string, uint32_t nchans, uint32_t chan, bool destructive);
string midi_path_from_name (string);
@@ -1713,9 +1713,10 @@ class Session : public sigc::trackable, public PBD::StatefulDestructible
uint32_t _total_free_4k_blocks;
Glib::Mutex space_lock;
+ static const char* old_sound_dir_name;
static const char* sound_dir_name;
- static const char* tape_dir_name;
static const char* dead_sound_dir_name;
+ static const char* interchange_dir_name;
static const char* peak_dir_name;
string discover_best_sound_dir (bool destructive = false);
diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h
index 5c3fdcfec9..98e78e3802 100644
--- a/libs/ardour/ardour/smf_source.h
+++ b/libs/ardour/ardour/smf_source.h
@@ -44,10 +44,10 @@ class SMFSource : public MidiSource {
};
/** Constructor for existing external-to-session files */
- SMFSource (std::string path, Flag flags = Flag(0));
+ SMFSource (Session& session, std::string path, Flag flags = Flag(0));
/* Constructor for existing in-session files */
- SMFSource (const XMLNode&);
+ SMFSource (Session& session, const XMLNode&);
virtual ~SMFSource ();
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index ab3e61eb29..cb6bd2e920 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -31,11 +31,11 @@ class SndFileSource : public AudioFileSource {
public:
/* constructor to be called for existing external-to-session files */
- SndFileSource (std::string path, Flag flags);
+ SndFileSource (Session&, std::string path, Flag flags);
/* constructor to be called for new in-session files */
- SndFileSource (std::string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate,
+ SndFileSource (Session&, std::string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate,
Flag flags = AudioFileSource::Flag (AudioFileSource::Writable|
AudioFileSource::Removable|
AudioFileSource::RemovableIfEmpty|
@@ -43,7 +43,7 @@ class SndFileSource : public AudioFileSource {
/* constructor to be called for existing in-session files */
- SndFileSource (const XMLNode&);
+ SndFileSource (Session&, const XMLNode&);
~SndFileSource ();
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index a18250fff2..591e7181a1 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -32,11 +32,14 @@
namespace ARDOUR {
+class Session;
+
class Source : public PBD::StatefulDestructible, public sigc::trackable
{
public:
- Source (std::string name, DataType type);
- Source (const XMLNode&);
+ Source (Session&, std::string name, DataType type);
+ Source (Session&, const XMLNode&);
+
virtual ~Source ();
std::string name() const { return _name; }
@@ -44,8 +47,6 @@ class Source : public PBD::StatefulDestructible, public sigc::trackable
DataType type() { return _type; }
- const PBD::ID& id() const { return _id; }
-
time_t timestamp() const { return _timestamp; }
void stamp (time_t when) { _timestamp = when; }
@@ -65,13 +66,13 @@ class Source : public PBD::StatefulDestructible, public sigc::trackable
protected:
void update_length (jack_nframes_t pos, jack_nframes_t cnt);
+ Session& _session;
string _name;
DataType _type;
time_t _timestamp;
jack_nframes_t _length;
private:
- PBD::ID _id;
};
}
diff --git a/libs/ardour/ardour/source_factory.h b/libs/ardour/ardour/source_factory.h
index 2b25752a0d..073532c6ab 100644
--- a/libs/ardour/ardour/source_factory.h
+++ b/libs/ardour/ardour/source_factory.h
@@ -13,14 +13,17 @@ class XMLNode;
namespace ARDOUR {
+class Session;
+
class SourceFactory {
public:
static sigc::signal<void,boost::shared_ptr<Source> > SourceCreated;
- static boost::shared_ptr<Source> create (const XMLNode& node);
+ static boost::shared_ptr<Source> create (Session&, const XMLNode& node);
- static boost::shared_ptr<Source> createReadable (DataType type, std::string idstr, AudioFileSource::Flag flags, bool announce = true);
- static boost::shared_ptr<Source> createWritable (DataType type, std::string name, bool destructive, jack_nframes_t rate, bool announce = true);
+ // MIDI sources will have to be hacked in here somehow
+ static boost::shared_ptr<Source> createReadable (DataType type, Session&, std::string idstr, AudioFileSource::Flag flags, bool announce = true);
+ static boost::shared_ptr<Source> createWritable (DataType type, Session&, std::string name, bool destructive, jack_nframes_t rate, bool announce = true);
};
}
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index 9111aeba68..0b37579ecb 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -242,7 +242,6 @@ class TempoMap : public StateManager, public PBD::StatefulDestructible
XMLNode& get_state (void);
int set_state (const XMLNode&);
- PBD::ID id() { return _id; }
void dump (std::ostream&) const;
void clear ();
@@ -320,8 +319,6 @@ class TempoMap : public StateManager, public PBD::StatefulDestructible
void save_state (std::string why);
- PBD::ID _id;
-
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 7b77aad8f5..9572297ac5 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -1590,7 +1590,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
string region_name;
_session.region_name (region_name, channels[0].write_source->name(), false);
- cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl;
+ // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl;
try {
boost::shared_ptr<Region> rx (RegionFactory::create (srcs, buffer_position, (*ci)->frames, region_name));
@@ -1948,7 +1948,7 @@ AudioDiskstream::use_new_write_source (uint32_t n)
if (chan.write_source) {
- if (AudioFileSource::is_empty (chan.write_source->path())) {
+ if (AudioFileSource::is_empty (_session, chan.write_source->path())) {
chan.write_source->mark_for_remove ();
chan.write_source.reset ();
} else {
@@ -2185,7 +2185,8 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
}
try {
- fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, prop->value(), false, _session.frame_rate()));
+ fs = boost::dynamic_pointer_cast<AudioFileSource> (
+ SourceFactory::createWritable (DataType::AUDIO, _session, prop->value(), false, _session.frame_rate()));
}
catch (failed_constructor& err) {
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index 7fc29f84b8..bd09b1e6b3 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -899,3 +899,4 @@ AudioPlaylist::crossfades_at (jack_nframes_t frame, Crossfades& clist)
}
}
}
+
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index ddb835c78f..b2a1fb6a0f 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -167,6 +167,9 @@ AudioEngine::stop ()
bool
AudioEngine::get_sync_offset (jack_nframes_t& offset) const
{
+
+#ifdef HAVE_JACK_VIDEO_SUPPORT
+
jack_position_t pos;
(void) jack_transport_query (_jack, &pos);
@@ -176,6 +179,8 @@ AudioEngine::get_sync_offset (jack_nframes_t& offset) const
return true;
}
+#endif
+
return false;
}
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 963a2274df..adfd352d12 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -63,8 +63,8 @@ char AudioFileSource::bwf_country_code[3] = "US";
char AudioFileSource::bwf_organization_code[4] = "LAS";
char AudioFileSource::bwf_serial_number[13] = "000000000000";
-AudioFileSource::AudioFileSource (string idstr, Flag flags)
- : AudioSource (idstr), _flags (flags)
+AudioFileSource::AudioFileSource (Session& s, string idstr, Flag flags)
+ : AudioSource (s, idstr), _flags (flags)
{
/* constructor used for existing external to session files. file must exist already */
@@ -74,8 +74,8 @@ AudioFileSource::AudioFileSource (string idstr, Flag flags)
}
-AudioFileSource::AudioFileSource (std::string path, Flag flags, SampleFormat samp_format, HeaderFormat hdr_format)
- : AudioSource (path), _flags (flags)
+AudioFileSource::AudioFileSource (Session& s, std::string path, Flag flags, SampleFormat samp_format, HeaderFormat hdr_format)
+ : AudioSource (s, path), _flags (flags)
{
/* constructor used for new internal-to-session files. file cannot exist */
@@ -84,8 +84,8 @@ AudioFileSource::AudioFileSource (std::string path, Flag flags, SampleFormat sam
}
}
-AudioFileSource::AudioFileSource (const XMLNode& node)
- : AudioSource (node), _flags (Flag (Writable|CanRename))
+AudioFileSource::AudioFileSource (Session& s, const XMLNode& node)
+ : AudioSource (s, node), _flags (Flag (Writable|CanRename))
{
/* constructor used for existing internal-to-session files. file must exist */
@@ -101,6 +101,7 @@ AudioFileSource::AudioFileSource (const XMLNode& node)
AudioFileSource::~AudioFileSource ()
{
if (removable()) {
+ cerr << "Removing file " << _path << " because its removable\n";
unlink (_path.c_str());
unlink (peakpath.c_str());
}
@@ -109,7 +110,7 @@ AudioFileSource::~AudioFileSource ()
bool
AudioFileSource::removable () const
{
- return (_flags & Removable) && ((_flags & RemoveAtDestroy) || ((_flags & RemovableIfEmpty) && is_empty (_path)));
+ return (_flags & Removable) && ((_flags & RemoveAtDestroy) || ((_flags & RemovableIfEmpty) && length() == 0));
}
int
@@ -135,7 +136,7 @@ AudioFileSource::init (string pathstr, bool must_exist)
string
AudioFileSource::peak_path (string audio_path)
{
- return Session::peak_path_from_audio_path (audio_path);
+ return _session.peak_path_from_audio_path (audio_path);
}
string
@@ -527,7 +528,7 @@ void
AudioFileSource::set_allow_remove_if_empty (bool yn)
{
if (writable()) {
- allow_remove_if_empty = yn;
+ _flags = Flag (_flags | RemovableIfEmpty);
}
}
@@ -561,11 +562,12 @@ AudioFileSource::set_name (string newname, bool destructive)
}
bool
-AudioFileSource::is_empty (string path)
+AudioFileSource::is_empty (Session& s, string path)
{
bool ret = false;
+
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (
- SourceFactory::createReadable (DataType::AUDIO, path, NoPeakFile, false));
+ SourceFactory::createReadable (DataType::AUDIO, s, path, NoPeakFile, false));
if (afs) {
ret = (afs->length() == 0);
diff --git a/libs/ardour/audiofilter.cc b/libs/ardour/audiofilter.cc
index 0a630f1e25..4c38ecec20 100644
--- a/libs/ardour/audiofilter.cc
+++ b/libs/ardour/audiofilter.cc
@@ -51,7 +51,7 @@ AudioFilter::make_new_sources (boost::shared_ptr<AudioRegion> region, SourceList
try {
nsrcs.push_back (boost::dynamic_pointer_cast<AudioSource> (
- SourceFactory::createWritable (DataType::AUDIO, path, false, session.frame_rate())));
+ SourceFactory::createWritable (DataType::AUDIO, session, path, false, session.frame_rate())));
}
catch (failed_constructor& err) {
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 362ab305db..959177d0cf 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -38,7 +38,7 @@
#include <ardour/dB.h>
#include <ardour/playlist.h>
#include <ardour/audiofilter.h>
-#include <ardour/audiosource.h>
+#include <ardour/audiofilesource.h>
#include "i18n.h"
#include <locale.h>
@@ -71,6 +71,11 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t sta
_fade_out (0.0, 2.0, 1.0, false),
_envelope (0.0, 2.0, 1.0, false)
{
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
+ if (afs) {
+ afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
+ }
+
_scale_amplitude = 1.0;
set_default_fades ();
@@ -88,6 +93,11 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t sta
, _fade_out (0.0, 2.0, 1.0, false)
, _envelope (0.0, 2.0, 1.0, false)
{
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
+ if (afs) {
+ afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
+ }
+
_scale_amplitude = 1.0;
set_default_fades ();
@@ -180,6 +190,11 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
, _fade_out (0.0, 2.0, 1.0, false)
, _envelope (0.0, 2.0, 1.0, false)
{
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
+ if (afs) {
+ afs->HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioRegion::source_offset_changed));
+ }
+
set_default_fades ();
if (set_state (node)) {
@@ -1165,6 +1180,12 @@ AudioRegion::speed_mismatch (float sr) const
return fsr != sr;
}
+void
+AudioRegion::source_offset_changed ()
+{
+ set_position (source()->natural_position() + start(), this);
+}
+
boost::shared_ptr<AudioSource>
AudioRegion::audio_source (uint32_t n) const
{
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index d74a38097c..a8fe2a7c73 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -50,8 +50,8 @@ int AudioSource::peak_request_pipe[2];
bool AudioSource::_build_missing_peakfiles = false;
bool AudioSource::_build_peakfiles = false;
-AudioSource::AudioSource (string name)
- : Source (name, DataType::AUDIO)
+AudioSource::AudioSource (Session& s, string name)
+ : Source (s, name, DataType::AUDIO)
{
if (pending_peak_sources_lock == 0) {
pending_peak_sources_lock = new Glib::Mutex;
@@ -63,8 +63,8 @@ AudioSource::AudioSource (string name)
_write_data_count = 0;
}
-AudioSource::AudioSource (const XMLNode& node)
- : Source (node)
+AudioSource::AudioSource (Session& s, const XMLNode& node)
+ : Source (s, node)
{
if (pending_peak_sources_lock == 0) {
pending_peak_sources_lock = new Glib::Mutex;
diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc
index 0d7e690a25..049b5aabbe 100644
--- a/libs/ardour/coreaudiosource.cc
+++ b/libs/ardour/coreaudiosource.cc
@@ -20,6 +20,9 @@
#include <pbd/error.h>
#include <ardour/coreaudiosource.h>
+#include <appleutility/CAAudioFile.h>
+#include <appleutility/CAStreamBasicDescription.h>
+
#include "i18n.h"
#include <AudioToolbox/AudioFormat.h>
@@ -27,14 +30,14 @@
using namespace ARDOUR;
using namespace PBD;
-CoreAudioSource::CoreAudioSource (const XMLNode& node)
- : AudioFileSource (node)
+CoreAudioSource::CoreAudioSource (Session& s, const XMLNode& node)
+ : AudioFileSource (s, node)
{
init (_name);
}
-CoreAudioSource::CoreAudioSource (const string& idstr, Flag flags)
- : AudioFileSource(idstr, flags)
+CoreAudioSource::CoreAudioSource (Session& s, const string& idstr, Flag flags)
+ : AudioFileSource(s, idstr, flags)
{
init (idstr);
}
@@ -43,93 +46,48 @@ void
CoreAudioSource::init (const string& idstr)
{
string::size_type pos;
- string file;
tmpbuf = 0;
tmpbufsize = 0;
- af = 0;
- OSStatus err = noErr;
_name = idstr;
if ((pos = idstr.find_last_of (':')) == string::npos) {
channel = 0;
- file = idstr;
+ _path = idstr;
} else {
channel = atoi (idstr.substr (pos+1).c_str());
- file = idstr.substr (0, pos);
- }
-
- /* note that we temporarily truncated _id at the colon */
- FSRef fsr;
- err = FSPathMakeRef ((UInt8*)file.c_str(), &fsr, 0);
- if (err != noErr) {
- error << string_compose (_("Could not make reference to file: %1"), name()) << endmsg;
- throw failed_constructor();
- }
-
- err = ExtAudioFileOpen (&fsr, &af);
- if (err != noErr) {
- error << string_compose (_("Could not open file: %1"), name()) << endmsg;
- ExtAudioFileDispose (af);
- throw failed_constructor();
+ _path = idstr.substr (0, pos);
}
- AudioStreamBasicDescription file_asbd;
- memset(&file_asbd, 0, sizeof(AudioStreamBasicDescription));
- size_t asbd_size = sizeof(AudioStreamBasicDescription);
- err = ExtAudioFileGetProperty(af,
- kExtAudioFileProperty_FileDataFormat, &asbd_size, &file_asbd);
- if (err != noErr) {
- error << string_compose (_("Could not get file data format for file: %1"), name()) << endmsg;
- ExtAudioFileDispose (af);
- throw failed_constructor();
- }
- n_channels = file_asbd.mChannelsPerFrame;
-
- cerr << "number of channels: " << n_channels << endl;
+ cerr << "CoreAudioSource::init() " << name() << endl;
- if (channel >= n_channels) {
- error << string_compose(_("CoreAudioSource: file only contains %1 channels; %2 is invalid as a channel number"), n_channels, channel) << endmsg;
- ExtAudioFileDispose (af);
- throw failed_constructor();
- }
+ /* note that we temporarily truncated _id at the colon */
+ try {
+ af.Open(_path.c_str());
- int64_t ca_frames;
- size_t prop_size = sizeof(int64_t);
+ CAStreamBasicDescription file_asbd (af.GetFileDataFormat());
+ n_channels = file_asbd.NumberChannels();
+ cerr << "number of channels: " << n_channels << endl;
+
+ if (channel >= n_channels) {
+ error << string_compose("CoreAudioSource: file only contains %1 channels; %2 is invalid as a channel number (%3)", n_channels, channel, name()) << endmsg;
+ throw failed_constructor();
+ }
- err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &prop_size, &ca_frames);
- if (err != noErr) {
- error << string_compose (_("Could not get file length for file: %1"), name()) << endmsg;
- ExtAudioFileDispose (af);
- throw failed_constructor();
- }
+ _length = af.GetNumberFrames();
- _length = ca_frames;
- _path = file;
-
- AudioStreamBasicDescription client_asbd;
- memset(&client_asbd, 0, sizeof(AudioStreamBasicDescription));
- client_asbd.mSampleRate = file_asbd.mSampleRate;
- client_asbd.mFormatID = kAudioFormatLinearPCM;
- client_asbd.mFormatFlags = kLinearPCMFormatFlagIsFloat;
- client_asbd.mBytesPerPacket = file_asbd.mChannelsPerFrame * 4;
- client_asbd.mFramesPerPacket = 1;
- client_asbd.mBytesPerFrame = client_asbd.mBytesPerPacket;
- client_asbd.mChannelsPerFrame = file_asbd.mChannelsPerFrame;
- client_asbd.mBitsPerChannel = 32;
-
- err = ExtAudioFileSetProperty (af, kExtAudioFileProperty_ClientDataFormat, asbd_size, &client_asbd);
- if (err != noErr) {
- error << string_compose (_("Could not set client data format for file: %1"), name()) << endmsg;
- ExtAudioFileDispose (af);
+ CAStreamBasicDescription client_asbd(file_asbd);
+ client_asbd.SetCanonical(client_asbd.NumberChannels(), false);
+ af.SetClientFormat (client_asbd);
+ } catch (CAXException& cax) {
+ error << string_compose ("CoreAudioSource: %1 (%2)", cax.mOperation, name()) << endmsg;
throw failed_constructor ();
}
if (_build_peakfiles) {
- if (initialize_peakfile (false, file)) {
- error << string_compose(_("initialize peakfile failed for file %1"), name()) << endmsg;
- ExtAudioFileDispose (af);
+ if (initialize_peakfile (false, _path)) {
+ error << string_compose("CoreAudioSource: initialize peakfile failed (%1)", name()) << endmsg;
throw failed_constructor ();
}
}
@@ -137,41 +95,44 @@ CoreAudioSource::init (const string& idstr)
CoreAudioSource::~CoreAudioSource ()
{
+ cerr << "CoreAudioSource::~CoreAudioSource() " << name() << endl;
GoingAway (); /* EMIT SIGNAL */
- if (af) {
- ExtAudioFileDispose (af);
- }
-
if (tmpbuf) {
delete [] tmpbuf;
}
+
+ cerr << "deletion done" << endl;
}
jack_nframes_t
CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const
{
- OSStatus err = noErr;
-
- err = ExtAudioFileSeek(af, start);
- if (err != noErr) {
- error << string_compose(_("CoreAudioSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), err) << endmsg;
+ try {
+ af.Seek (start);
+ } catch (CAXException& cax) {
+ error << string_compose("CoreAudioSource: %1 to %2 (%3)", cax.mOperation, start, _name.substr (1)) << endmsg;
return 0;
}
AudioBufferList abl;
abl.mNumberBuffers = 1;
abl.mBuffers[0].mNumberChannels = n_channels;
- abl.mBuffers[0].mDataByteSize = cnt * sizeof(Sample);
- abl.mBuffers[0].mData = dst;
+ UInt32 new_cnt = cnt;
if (n_channels == 1) {
- err = ExtAudioFileRead(af, (UInt32*) &cnt, &abl);
- _read_data_count = cnt * sizeof(float);
- return cnt;
+ abl.mBuffers[0].mDataByteSize = cnt * sizeof(Sample);
+ abl.mBuffers[0].mData = dst;
+ try {
+ af.Read (new_cnt, &abl);
+ } catch (CAXException& cax) {
+ error << string_compose("CoreAudioSource: %1 (%2)", cax.mOperation, _name);
+ }
+ _read_data_count = new_cnt * sizeof(float);
+ return new_cnt;
}
- uint32_t real_cnt = cnt * n_channels;
+ UInt32 real_cnt = cnt * n_channels;
{
Glib::Mutex::Lock lm (_tmpbuf_lock);
@@ -185,10 +146,16 @@ CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_
tmpbuf = new float[tmpbufsize];
}
- abl.mBuffers[0].mDataByteSize = real_cnt * sizeof(Sample);
+ abl.mBuffers[0].mDataByteSize = tmpbufsize * sizeof(Sample);
abl.mBuffers[0].mData = tmpbuf;
+
+ cerr << "channel: " << channel << endl;
- err = ExtAudioFileRead(af, (UInt32*) &real_cnt, &abl);
+ try {
+ af.Read (real_cnt, &abl);
+ } catch (CAXException& cax) {
+ error << string_compose("CoreAudioSource: %1 (%2)", cax.mOperation, _name);
+ }
float *ptr = tmpbuf + channel;
real_cnt /= n_channels;
@@ -208,15 +175,12 @@ CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_
float
CoreAudioSource::sample_rate() const
{
- AudioStreamBasicDescription client_asbd;
- memset(&client_asbd, 0, sizeof(AudioStreamBasicDescription));
+ CAStreamBasicDescription client_asbd;
- OSStatus err = noErr;
- size_t asbd_size = sizeof(AudioStreamBasicDescription);
-
- err = ExtAudioFileSetProperty (af, kExtAudioFileProperty_ClientDataFormat, asbd_size, &client_asbd);
- if (err != noErr) {
- error << string_compose(_("Could not detect samplerate for: %1"), name()) << endmsg;
+ try {
+ client_asbd = af.GetClientDataFormat ();
+ } catch (CAXException& cax) {
+ error << string_compose("CoreAudioSource: %1 (%2)", cax.mOperation, _name);
return 0.0;
}
@@ -228,4 +192,3 @@ CoreAudioSource::update_header (jack_nframes_t when, struct tm&, time_t)
{
return 0;
}
-
diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc
index bf16b40005..1e57d88d70 100644
--- a/libs/ardour/destructive_filesource.cc
+++ b/libs/ardour/destructive_filesource.cc
@@ -68,21 +68,21 @@ gain_t* DestructiveFileSource::out_coefficient = 0;
gain_t* DestructiveFileSource::in_coefficient = 0;
jack_nframes_t DestructiveFileSource::xfade_frames = 64;
-DestructiveFileSource::DestructiveFileSource (string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, Flag flags)
- : SndFileSource (path, samp_format, hdr_format, rate, flags)
+DestructiveFileSource::DestructiveFileSource (Session& s, string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, Flag flags)
+ : SndFileSource (s, path, samp_format, hdr_format, rate, flags)
{
init ();
}
-DestructiveFileSource::DestructiveFileSource (string path, Flag flags)
- : SndFileSource (path, flags)
+DestructiveFileSource::DestructiveFileSource (Session& s, string path, Flag flags)
+ : SndFileSource (s, path, flags)
{
init ();
}
-DestructiveFileSource::DestructiveFileSource (const XMLNode& node)
- : SndFileSource (node)
+DestructiveFileSource::DestructiveFileSource (Session& s, const XMLNode& node)
+ : SndFileSource (s, node)
{
init ();
}
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 6f3b772ece..cc92529d88 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -375,7 +375,9 @@ ARDOUR::get_user_ardour_path ()
/* create it if necessary */
- mkdir (path.c_str (), 0755);
+ if (g_mkdir_with_parents (path.c_str (), 0755)) {
+ throw exception ();
+ }
return path;
}
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index 01c7182e14..b10f76424b 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -140,7 +140,7 @@ Session::import_audiofile (import_status& status)
try {
newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> (
- SourceFactory::createWritable (DataType::AUDIO, buf, false, frame_rate()));
+ SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
}
catch (failed_constructor& err) {
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index a30881b4da..57a89b2310 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -20,6 +20,7 @@
#include <algorithm>
#include <unistd.h>
#include <locale.h>
+#include <errno.h>
#include <sigc++/bind.h>
@@ -2143,8 +2144,8 @@ IO::load_automation (const string& path)
fullpath += path;
in.open (fullpath.c_str());
if (!in) {
- error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
- return -1;
+ error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg;
+ return -1;
}
}
diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc
index 30b28c6abe..6b3ea6f220 100644
--- a/libs/ardour/location.cc
+++ b/libs/ardour/location.cc
@@ -81,13 +81,18 @@ Location::set_start (jack_nframes_t s)
{
if (is_mark()) {
if (_start != s) {
+
_start = s;
_end = s;
+
start_changed(this); /* EMIT SIGNAL */
+
if ( is_start() ) {
+
Session::StartTimeChanged (); /* EMIT SIGNAL */
AudioFileSource::set_header_position_offset ( s );
}
+
if ( is_end() ) {
Session::EndTimeChanged (); /* EMIT SIGNAL */
}
diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc
index c4cfe3c71d..de2f6b1c5d 100644
--- a/libs/ardour/midi_source.cc
+++ b/libs/ardour/midi_source.cc
@@ -42,15 +42,15 @@ using namespace PBD;
sigc::signal<void,MidiSource *> MidiSource::MidiSourceCreated;
-MidiSource::MidiSource (string name)
- : Source (name, DataType::MIDI)
+MidiSource::MidiSource (Session& s, string name)
+ : Source (s, name, DataType::MIDI)
{
_read_data_count = 0;
_write_data_count = 0;
}
-MidiSource::MidiSource (const XMLNode& node)
- : Source (node)
+MidiSource::MidiSource (Session& s, const XMLNode& node)
+ : Source (s, node)
{
_read_data_count = 0;
_write_data_count = 0;
diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc
index 1ced0faf89..0c3b0a291f 100644
--- a/libs/ardour/panner.cc
+++ b/libs/ardour/panner.cc
@@ -1090,7 +1090,7 @@ Panner::save () const
ofstream out (automation_path.c_str());
if (!out) {
- error << string_compose (_("cannot open pan automation file \"%1\" for saving (%s)"), automation_path, strerror (errno))
+ error << string_compose (_("cannot open pan automation file \"%1\" for saving (%2)"), automation_path, strerror (errno))
<< endmsg;
return -1;
}
diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc
index 8d200b0ee4..9a82c3bbab 100644
--- a/libs/ardour/plugin.cc
+++ b/libs/ardour/plugin.cc
@@ -224,13 +224,13 @@ Plugin::save_preset (string name, string domain)
free(lrdf_add_preset(source.c_str(), name.c_str(), unique_id(), &defaults));
string path = string_compose("%1/.%2", envvar, domain);
- if (mkdir(path.c_str(), 0775) && errno != EEXIST) {
+ if (g_mkdir_with_parents (path.c_str(), 0775)) {
warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
return false;
}
path += "/rdf";
- if (mkdir(path.c_str(), 0775) && errno != EEXIST) {
+ if (g_mkdir_with_parents (path.c_str(), 0775)) {
warning << string_compose(_("Could not create %1. Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
return false;
}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 672e0692cb..398df02179 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -277,17 +277,17 @@ Route::process_output_buffers (BufferSet& bufs,
-------------------------------------------------------------------------------------------------- */
if (declick > 0) {
- Amp::run (bufs, nframes, 0.0, 1.0, _phase_invert);
+ Amp::run (bufs, nframes, 0.0, 1.0, false);
_pending_declick = 0;
} else if (declick < 0) {
- Amp::run (bufs, nframes, 1.0, 0.0, _phase_invert);
+ Amp::run (bufs, nframes, 1.0, 0.0, false);
_pending_declick = 0;
} else {
/* no global declick */
if (solo_gain != dsg) {
- Amp::run (bufs, nframes, solo_gain, dsg, _phase_invert);
+ Amp::run (bufs, nframes, solo_gain, dsg, false);
solo_gain = dsg;
}
}
@@ -302,7 +302,7 @@ Route::process_output_buffers (BufferSet& bufs,
}
if (!_soloed && _mute_affects_pre_fader && (mute_gain != dmg)) {
- Amp::run (bufs, nframes, mute_gain, dmg, _phase_invert);
+ Amp::run (bufs, nframes, mute_gain, dmg, false);
mute_gain = dmg;
mute_declick_applied = true;
}
@@ -379,7 +379,7 @@ Route::process_output_buffers (BufferSet& bufs,
if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader) {
- Amp::run (bufs, nframes, mute_gain, dmg, _phase_invert);
+ Amp::run (bufs, nframes, mute_gain, dmg, false);
mute_gain = dmg;
mute_declick_applied = true;
}
@@ -543,7 +543,7 @@ Route::process_output_buffers (BufferSet& bufs,
}
if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_control_outs) {
- Amp::run (bufs, nframes, mute_gain, dmg, _phase_invert);
+ Amp::run (bufs, nframes, mute_gain, dmg, false);
mute_gain = dmg;
mute_declick_applied = true;
}
@@ -588,7 +588,7 @@ Route::process_output_buffers (BufferSet& bufs,
----------------------------------------------------------------------*/
if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_main_outs) {
- Amp::run (bufs, nframes, mute_gain, dmg, _phase_invert);
+ Amp::run (bufs, nframes, mute_gain, dmg, false);
mute_gain = dmg;
mute_declick_applied = true;
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index ebdbea1fc4..b670afb1ba 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -87,10 +87,11 @@ using boost::shared_ptr;
const char* Session::_template_suffix = X_(".template");
const char* Session::_statefile_suffix = X_(".ardour");
const char* Session::_pending_suffix = X_(".pending");
-const char* Session::sound_dir_name = X_("sounds");
-const char* Session::tape_dir_name = X_("tapes");
+const char* Session::old_sound_dir_name = X_("sounds");
+const char* Session::sound_dir_name = X_("audiofiles");
const char* Session::peak_dir_name = X_("peaks");
const char* Session::dead_sound_dir_name = X_("dead_sounds");
+const char* Session::interchange_dir_name = X_("interchange");
Session::compute_peak_t Session::compute_peak = 0;
Session::apply_gain_to_buffer_t Session::apply_gain_to_buffer = 0;
@@ -2836,17 +2837,11 @@ Session::source_by_id (const PBD::ID& id)
}
string
-Session::peak_path_from_audio_path (string audio_path)
+Session::peak_path_from_audio_path (string audio_path) const
{
- /* XXX hardly bombproof! fix me */
-
string res;
- res = Glib::path_get_dirname (audio_path);
- res = Glib::path_get_dirname (res);
- res += '/';
- res += peak_dir_name;
- res += '/';
+ res = peak_dir ();
res += PBD::basename_nosuffix (audio_path);
res += ".peak";
@@ -2992,11 +2987,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
spath = (*i).path;
- if (destructive) {
- spath += tape_dir_name;
- } else {
- spath += sound_dir_name;
- }
+ spath += sound_dir (false);
if (destructive) {
if (nchan < 2) {
@@ -3032,9 +3023,10 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
}
}
- if (access (buf, F_OK) == 0) {
+ if (g_file_test (buf, G_FILE_TEST_EXISTS)) {
existing++;
- }
+ }
+
}
if (existing == 0) {
@@ -3053,11 +3045,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
string foo = buf;
- if (destructive) {
- spath = tape_dir ();
- } else {
- spath = discover_best_sound_dir ();
- }
+ spath = discover_best_sound_dir ();
string::size_type pos = foo.find_last_of ('/');
@@ -3074,7 +3062,8 @@ boost::shared_ptr<AudioFileSource>
Session::create_audio_source_for_session (AudioDiskstream& ds, uint32_t chan, bool destructive)
{
string spath = audio_path_from_name (ds.name(), ds.n_channels().get(DataType::AUDIO), chan, destructive);
- return boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, spath, destructive, frame_rate()));
+ return boost::dynamic_pointer_cast<AudioFileSource> (
+ SourceFactory::createWritable (DataType::AUDIO, *this, spath, destructive, frame_rate()));
}
// FIXME: _terrible_ code duplication
@@ -3260,7 +3249,7 @@ Session::create_midi_source_for_session (MidiDiskstream& ds)
{
string spath = midi_path_from_name (ds.name());
- return boost::dynamic_pointer_cast<SMFSource> (SourceFactory::createWritable (DataType::MIDI, spath, false, frame_rate()));
+ return boost::dynamic_pointer_cast<SMFSource> (SourceFactory::createWritable (DataType::MIDI, *this, spath, false, frame_rate()));
}
@@ -3420,17 +3409,35 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::
void
Session::remove_empty_sounds ()
{
-
PathScanner scanner;
- string dir;
-
- dir = sound_dir ();
- vector<string *>* possible_audiofiles = scanner (dir, "\\.wav$", false, true);
+ vector<string *>* possible_audiofiles = scanner (sound_dir(), "\\.(wav|aiff|caf|w64)$", false, true);
+ Glib::Mutex::Lock lm (source_lock);
+
+ regex_t compiled_tape_track_pattern;
+ int err;
+
+ if ((err = regcomp (&compiled_tape_track_pattern, "/T[0-9][0-9][0-9][0-9]-", REG_EXTENDED|REG_NOSUB))) {
+
+ char msg[256];
+
+ regerror (err, &compiled_tape_track_pattern, msg, sizeof (msg));
+
+ error << string_compose (_("Cannot compile tape track regexp for use (%1)"), msg) << endmsg;
+ return;
+ }
+
for (vector<string *>::iterator i = possible_audiofiles->begin(); i != possible_audiofiles->end(); ++i) {
+
+ /* never remove files that appear to be a tape track */
- if (AudioFileSource::is_empty (*(*i))) {
+ if (regexec (&compiled_tape_track_pattern, (*i)->c_str(), 0, 0, 0) == 0) {
+ delete *i;
+ continue;
+ }
+
+ if (AudioFileSource::is_empty (*this, *(*i))) {
unlink ((*i)->c_str());
@@ -3610,7 +3617,7 @@ jack_nframes_t
Session::available_capture_duration ()
{
const double scale = 4096.0 / sizeof (Sample);
-
+
if (_total_free_4k_blocks * scale > (double) max_frames) {
return max_frames;
}
@@ -3914,7 +3921,8 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf
}
try {
- fsource = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, buf, false, frame_rate()));
+ fsource = boost::dynamic_pointer_cast<AudioFileSource> (
+ SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
}
catch (failed_constructor& err) {
@@ -3931,7 +3939,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf
to_do = len;
/* create a set of reasonably-sized buffers */
- buffers.ensure_buffers(nchans, chunk_size);
+buffers.ensure_buffers(nchans, chunk_size);
buffers.set_count(nchans);
while (to_do && !itt.cancel) {
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index eaaa723a0c..a8b2804ff0 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -309,7 +309,6 @@ Session::second_stage_init (bool new_session)
if (!new_session) {
if (load_state (_current_snapshot_name)) {
- cerr << "load state failed\n";
return -1;
}
remove_empty_sounds ();
@@ -371,7 +370,6 @@ Session::second_stage_init (bool new_session)
_end_location_is_free = false;
}
- restore_history(_current_snapshot_name);
return 0;
}
@@ -436,16 +434,7 @@ Session::setup_raid_path (string path)
if (fspath[fspath.length()-1] != '/') {
fspath += '/';
}
- fspath += sound_dir_name;
- fspath += ':';
-
- /* tape dir */
-
- fspath += sp.path;
- if (fspath[fspath.length()-1] != '/') {
- fspath += '/';
- }
- fspath += tape_dir_name;
+ fspath += sound_dir (false);
AudioFileSource::set_search_path (fspath);
SMFSource::set_search_path (fspath); // FIXME: should be different
@@ -467,16 +456,7 @@ Session::setup_raid_path (string path)
if (fspath[fspath.length()-1] != '/') {
fspath += '/';
}
- fspath += sound_dir_name;
- fspath += ':';
-
- /* add tape dir to file search path */
-
- fspath += sp.path;
- if (fspath[fspath.length()-1] != '/') {
- fspath += '/';
- }
- fspath += tape_dir_name;
+ fspath += sound_dir (false);
fspath += ':';
remaining = remaining.substr (colon+1);
@@ -492,15 +472,9 @@ Session::setup_raid_path (string path)
if (fspath[fspath.length()-1] != '/') {
fspath += '/';
}
- fspath += sound_dir_name;
+ fspath += sound_dir (false);
fspath += ':';
- fspath += sp.path;
- if (fspath[fspath.length()-1] != '/') {
- fspath += '/';
- }
- fspath += tape_dir_name;
-
session_dirs.push_back (sp);
}
@@ -518,61 +492,40 @@ int
Session::create (bool& new_session, string* mix_template, jack_nframes_t initial_length)
{
string dir;
+
+ new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
- if (mkdir (_path.c_str(), 0755) < 0) {
- if (errno == EEXIST) {
- new_session = false;
- } else {
- error << string_compose(_("Session: cannot create session dir \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
- return -1;
- }
- } else {
- new_session = true;
+ if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session dir \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
+ return -1;
}
dir = peak_dir ();
- if (mkdir (dir.c_str(), 0755) < 0) {
- if (errno != EEXIST) {
- error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
- return -1;
- }
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
}
dir = sound_dir ();
- if (mkdir (dir.c_str(), 0755) < 0) {
- if (errno != EEXIST) {
- error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
- return -1;
- }
- }
-
- dir = tape_dir ();
-
- if (mkdir (dir.c_str(), 0755) < 0) {
- if (errno != EEXIST) {
- error << string_compose(_("Session: cannot create session tape dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
- return -1;
- }
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
}
dir = dead_sound_dir ();
- if (mkdir (dir.c_str(), 0755) < 0) {
- if (errno != EEXIST) {
- error << string_compose(_("Session: cannot create session dead sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
- return -1;
- }
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session dead sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
}
dir = automation_dir ();
- if (mkdir (dir.c_str(), 0755) < 0) {
- if (errno != EEXIST) {
- error << string_compose(_("Session: cannot create session automation dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
- return -1;
- }
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session automation dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
}
@@ -725,6 +678,8 @@ Session::save_state (string snapshot_name, bool pending)
}
+ cerr << "actually writing state\n";
+
if (!tree.write (xml_path)) {
error << string_compose (_("state could not be saved to %1"), xml_path) << endmsg;
@@ -2031,13 +1986,12 @@ Session::load_sources (const XMLNode& node)
boost::shared_ptr<Source>
Session::XMLSourceFactory (const XMLNode& node)
{
-
if (node.name() != "Source") {
return boost::shared_ptr<Source>();
}
try {
- return SourceFactory::create (node);
+ return SourceFactory::create (*this, node);
}
catch (failed_constructor& err) {
@@ -2062,7 +2016,7 @@ Session::save_template (string template_name)
if ((dp = opendir (dir.c_str()))) {
closedir (dp);
} else {
- if (mkdir (dir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)<0) {
+ if (g_mkdir_with_parents (dir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
error << string_compose(_("Could not create mix templates directory \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
return -1;
}
@@ -2142,11 +2096,9 @@ Session::ensure_sound_dir (string path, string& result)
/* Ensure that the parent directory exists */
- if (mkdir (path.c_str(), 0775)) {
- if (errno != EEXIST) {
- error << string_compose(_("cannot create session directory \"%1\"; ignored"), path) << endmsg;
- return -1;
- }
+ if (g_mkdir_with_parents (path.c_str(), 0775)) {
+ error << string_compose(_("cannot create session directory \"%1\"; ignored"), path) << endmsg;
+ return -1;
}
/* Ensure that the sounds directory exists */
@@ -2155,33 +2107,27 @@ Session::ensure_sound_dir (string path, string& result)
result += '/';
result += sound_dir_name;
- if (mkdir (result.c_str(), 0775)) {
- if (errno != EEXIST) {
- error << string_compose(_("cannot create sounds directory \"%1\"; ignored"), result) << endmsg;
- return -1;
- }
+ if (g_mkdir_with_parents (result.c_str(), 0775)) {
+ error << string_compose(_("cannot create sounds directory \"%1\"; ignored"), result) << endmsg;
+ return -1;
}
dead = path;
dead += '/';
dead += dead_sound_dir_name;
- if (mkdir (dead.c_str(), 0775)) {
- if (errno != EEXIST) {
- error << string_compose(_("cannot create dead sounds directory \"%1\"; ignored"), dead) << endmsg;
- return -1;
- }
+ if (g_mkdir_with_parents (dead.c_str(), 0775)) {
+ error << string_compose(_("cannot create dead sounds directory \"%1\"; ignored"), dead) << endmsg;
+ return -1;
}
peak = path;
peak += '/';
peak += peak_dir_name;
- if (mkdir (peak.c_str(), 0775)) {
- if (errno != EEXIST) {
- error << string_compose(_("cannot create peak file directory \"%1\"; ignored"), peak) << endmsg;
- return -1;
- }
+ if (g_mkdir_with_parents (peak.c_str(), 0775)) {
+ error << string_compose(_("cannot create peak file directory \"%1\"; ignored"), peak) << endmsg;
+ return -1;
}
/* callers expect this to be terminated ... */
@@ -2196,12 +2142,6 @@ Session::discover_best_sound_dir (bool destructive)
vector<space_and_path>::iterator i;
string result;
- /* destructive files all go into the same place */
-
- if (destructive) {
- return tape_dir();
- }
-
/* handle common case without system calls */
if (session_dirs.size() == 1) {
@@ -2418,20 +2358,37 @@ Session::dead_sound_dir () const
}
string
-Session::sound_dir () const
+Session::sound_dir (bool with_path) const
{
- string res = _path;
+ /* support old session structure */
+
+ struct stat statbuf;
+ string old;
+
+ if (with_path) {
+ old = _path;
+ }
+
+ old += sound_dir_name;
+ old += '/';
+
+ if (stat (old.c_str(), &statbuf) == 0) {
+ return old;
+ }
+
+ string res;
+
+ if (with_path) {
+ res = _path;
+ }
+
+ res += interchange_dir_name;
+ res += '/';
+ res += legalize_for_path (_name);
+ res += '/';
res += sound_dir_name;
res += '/';
- return res;
-}
-string
-Session::tape_dir () const
-{
- string res = _path;
- res += tape_dir_name;
- res += '/';
return res;
}
@@ -3427,8 +3384,7 @@ Session::save_history (string snapshot_name)
XMLTree tree;
string xml_path;
string bak_path;
-
-
+
tree.set_root (&history.get_state());
if (snapshot_name.empty()) {
@@ -3436,7 +3392,6 @@ Session::save_history (string snapshot_name)
}
xml_path = _path + snapshot_name + ".history";
- cerr << "Saving history to " << xml_path << endmsg;
bak_path = xml_path + ".bak";
@@ -3447,6 +3402,8 @@ Session::save_history (string snapshot_name)
return -1;
}
+ cerr << "actually writing history\n";
+
if (!tree.write (xml_path))
{
error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
diff --git a/libs/ardour/session_time.cc b/libs/ardour/session_time.cc
index c74d3021cb..887a9fa6c4 100644
--- a/libs/ardour/session_time.cc
+++ b/libs/ardour/session_time.cc
@@ -51,7 +51,7 @@ Session::bbt_time (jack_nframes_t when, BBT_Time& bbt)
void
Session::sync_time_vars ()
{
- _current_frame_rate = _base_frame_rate * (1.0 + (video_pullup/100.0) );
+ _current_frame_rate = (jack_nframes_t) round (_base_frame_rate * (1.0 + (video_pullup/100.0)));
_frames_per_hour = _current_frame_rate * 3600;
_frames_per_smpte_frame = (double) _current_frame_rate / (double) smpte_frames_per_second;
_smpte_frames_per_hour = (unsigned long) (smpte_frames_per_second * 3600.0);
@@ -432,9 +432,11 @@ Session::jack_timebase_callback (jack_transport_state_t state,
pos->valid = jack_position_bits_t (pos->valid | JackPositionBBT);
}
+#ifdef HAVE_JACK_VIDEO_SUPPORT
//poke audio video ratio so Ardour can track Video Sync
pos->audio_frames_per_video_frame = frame_rate() / smpte_frames_per_second;
pos->valid = jack_position_bits_t (pos->valid | JackAudioVideoRatio);
+#endif
#if 0
/* SMPTE info */
diff --git a/libs/ardour/session_timefx.cc b/libs/ardour/session_timefx.cc
index 4ba8d42d9e..b5b143514c 100644
--- a/libs/ardour/session_timefx.cc
+++ b/libs/ardour/session_timefx.cc
@@ -82,8 +82,7 @@ Session::tempoize_region (TimeStretchRequest& tsr)
}
try {
- sources.push_back (boost::dynamic_pointer_cast<AudioFileSource> (
- SourceFactory::createWritable (DataType::AUDIO, path, false, frame_rate())));
+ sources.push_back (boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *this, path, false, frame_rate())));
} catch (failed_constructor& err) {
error << string_compose (_("tempoize: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg;
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index e1845a009f..0e3064503a 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -48,8 +48,8 @@ bool SMFSource::header_position_negative;
uint64_t SMFSource::header_position_offset;
*/
-SMFSource::SMFSource (std::string path, Flag flags)
- : MidiSource (region_name_from_path(path))
+SMFSource::SMFSource (Session& s, std::string path, Flag flags)
+ : MidiSource (s, region_name_from_path(path))
, _channel(0)
, _flags (Flag(flags | Writable)) // FIXME: this needs to be writable for now
, _allow_remove_if_empty(true)
@@ -72,8 +72,8 @@ SMFSource::SMFSource (std::string path, Flag flags)
assert(_name.find("/") == string::npos);
}
-SMFSource::SMFSource (const XMLNode& node)
- : MidiSource (node)
+SMFSource::SMFSource (Session& s, const XMLNode& node)
+ : MidiSource (s, node)
, _channel(0)
, _flags (Flag (Writable|CanRename))
, _allow_remove_if_empty(true)
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index b6ded6d617..0e80dee714 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -34,8 +34,8 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-SndFileSource::SndFileSource (const XMLNode& node)
- : AudioFileSource (node)
+SndFileSource::SndFileSource (Session& s, const XMLNode& node)
+ : AudioFileSource (s, node)
{
init (_name);
@@ -52,9 +52,9 @@ SndFileSource::SndFileSource (const XMLNode& node)
}
}
-SndFileSource::SndFileSource (string idstr, Flag flags)
+SndFileSource::SndFileSource (Session& s, string idstr, Flag flags)
/* files created this way are never writable or removable */
- : AudioFileSource (idstr, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
+ : AudioFileSource (s, idstr, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
{
init (idstr);
@@ -71,8 +71,8 @@ SndFileSource::SndFileSource (string idstr, Flag flags)
}
}
-SndFileSource::SndFileSource (string idstr, SampleFormat sfmt, HeaderFormat hf, jack_nframes_t rate, Flag flags)
- : AudioFileSource(idstr, flags, sfmt, hf)
+SndFileSource::SndFileSource (Session& s, string idstr, SampleFormat sfmt, HeaderFormat hf, jack_nframes_t rate, Flag flags)
+ : AudioFileSource (s, idstr, flags, sfmt, hf)
{
int fmt = 0;
@@ -226,7 +226,6 @@ SndFileSource::open ()
_length = _info.frames;
-
_broadcast_info = new SF_BROADCAST_INFO;
memset (_broadcast_info, 0, sizeof (*_broadcast_info));
@@ -507,6 +506,9 @@ SndFileSource::set_header_timeline_position ()
delete _broadcast_info;
_broadcast_info = 0;
}
+
+
+
}
jack_nframes_t
diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc
index d218e2cf94..977aea6efd 100644
--- a/libs/ardour/source.cc
+++ b/libs/ardour/source.cc
@@ -42,11 +42,9 @@ using std::max;
using namespace ARDOUR;
-sigc::signal<void,Source*> Source::SourceCreated;
-
-
-Source::Source (string name, DataType type)
- : _type(type)
+Source::Source (Session& s, string name, DataType type)
+ : _session (s)
+ , _type(type)
{
assert(_name.find("/") == string::npos);
@@ -55,8 +53,9 @@ Source::Source (string name, DataType type)
_length = 0;
}
-Source::Source (const XMLNode& node)
- : _type(DataType::AUDIO)
+Source::Source (Session& s, const XMLNode& node)
+ : _session (s)
+ , _type(DataType::AUDIO)
{
_timestamp = 0;
_length = 0;
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 61a7659a5e..29cd5166ff 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -37,7 +37,7 @@ sigc::signal<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated;
#ifdef HAVE_COREAUDIO
boost::shared_ptr<Source>
-SourceFactory::create (const XMLNode& node)
+SourceFactory::create (Session& s, const XMLNode& node)
{
DataType type = DataType::AUDIO;
const XMLProperty* prop = node.property("type");
@@ -49,11 +49,18 @@ SourceFactory::create (const XMLNode& node)
if (node.property (X_("destructive")) != 0) {
- boost::shared_ptr<Source> ret (new DestructiveFileSource (node));
+ boost::shared_ptr<Source> ret (new DestructiveFileSource (s, node));
SourceCreated (ret);
return ret;
} else {
+
+ try {
+ boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
+ SourceCreated (ret);
+ return ret;
+
+ } catch (failed_constructor& err) {
try {
boost::shared_ptr<Source> ret (new CoreAudioSource (node));
@@ -83,7 +90,7 @@ SourceFactory::create (const XMLNode& node)
#else
boost::shared_ptr<Source>
-SourceFactory::create (const XMLNode& node)
+SourceFactory::create (Session& s, const XMLNode& node)
{
DataType type = DataType::AUDIO;
const XMLProperty* prop = node.property("type");
@@ -95,20 +102,20 @@ SourceFactory::create (const XMLNode& node)
if (node.property (X_("destructive")) != 0) {
- boost::shared_ptr<Source> ret (new DestructiveFileSource (node));
+ boost::shared_ptr<Source> ret (new DestructiveFileSource (s, node));
SourceCreated (ret);
return ret;
} else {
- boost::shared_ptr<Source> ret (new SndFileSource (node));
+ boost::shared_ptr<Source> ret (new SndFileSource (s, node));
SourceCreated (ret);
return ret;
}
} else if (type == DataType::MIDI) {
-
- boost::shared_ptr<Source> ret (new SMFSource (node));
+
+ boost::shared_ptr<Source> ret (new SMFSource (s, node));
SourceCreated (ret);
return ret;
@@ -121,35 +128,34 @@ SourceFactory::create (const XMLNode& node)
#ifdef HAVE_COREAUDIO
boost::shared_ptr<Source>
-SourceFactory::createReadable (string idstr, AudioFileSource::Flag flags, bool announce)
+SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFileSource::Flag flags, bool announce)
{
if (type == DataType::AUDIO) {
if (flags & Destructive) {
- boost::shared_ptr<Source> ret (new DestructiveFileSource (idstr, flags));
+ boost::shared_ptr<Source> ret (new DestructiveFileSource (s, idstr, flags));
if (announce) {
SourceCreated (ret);
}
return ret;
- }
-
- try {
- boost::shared_ptr<Source> ret (new CoreAudioSource (idstr, flags));
- if (announce) {
- SourceCreated (ret);
+
+ try {
+ boost::shared_ptr<Source> ret (new CoreAudioSource (s, idstr, flags));
+ if (announce) {
+ SourceCreated (ret);
+ }
+ return ret;
+
+ } catch (failed_constructor& err) {
+ boost::shared_ptr<Source> ret (new SndFileSource (s, idstr, flags));
+ if (announce) {
+ SourceCreated (ret);
+ }
+ return ret;
}
- return ret;
- }
- catch (failed_constructor& err) {
- boost::shared_ptr<Source> ret (new SndFileSource (idstr, flags));
- if (announce) {
- SourceCreated (ret);
- }
- return ret;
- }
} else if (type == DataType::MIDI) {
- boost::shared_ptr<Source> ret (new SMFSource (node));
+ boost::shared_ptr<Source> ret (new SMFSource (s, node));
SourceCreated (ret);
return ret;
@@ -161,10 +167,11 @@ SourceFactory::createReadable (string idstr, AudioFileSource::Flag flags, bool a
#else
boost::shared_ptr<Source>
-SourceFactory::createReadable (DataType type, string idstr, AudioFileSource::Flag flags, bool announce)
+SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFileSource::Flag flags, bool announce)
{
if (type == DataType::AUDIO) {
- boost::shared_ptr<Source> ret (new SndFileSource (idstr, flags));
+
+ boost::shared_ptr<Source> ret (new SndFileSource (s, idstr, flags));
if (announce) {
SourceCreated (ret);
}
@@ -172,8 +179,10 @@ SourceFactory::createReadable (DataType type, string idstr, AudioFileSource::Fla
} else if (type == DataType::MIDI) {
- boost::shared_ptr<Source> ret (new SMFSource (idstr, SMFSource::Flag(0))); // FIXME: flags?
- SourceCreated (ret);
+ boost::shared_ptr<Source> ret (new SMFSource (s, idstr, SMFSource::Flag(0))); // FIXME: flags?
+ if (announce) {
+ SourceCreated (ret);
+ }
return ret;
}
@@ -184,13 +193,14 @@ SourceFactory::createReadable (DataType type, string idstr, AudioFileSource::Fla
#endif // HAVE_COREAUDIO
boost::shared_ptr<Source>
-SourceFactory::createWritable (DataType type, std::string path, bool destructive, jack_nframes_t rate, bool announce)
+SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, jack_nframes_t rate, bool announce)
{
/* this might throw failed_constructor(), which is OK */
if (type == DataType::AUDIO) {
if (destructive) {
- boost::shared_ptr<Source> ret (new DestructiveFileSource (path,
+
+ boost::shared_ptr<Source> ret (new DestructiveFileSource (s, path,
Config->get_native_file_data_format(),
Config->get_native_file_header_format(),
rate));
@@ -200,7 +210,8 @@ SourceFactory::createWritable (DataType type, std::string path, bool destructive
return ret;
} else {
- boost::shared_ptr<Source> ret (new SndFileSource (path,
+
+ boost::shared_ptr<Source> ret (new SndFileSource (s, path,
Config->get_native_file_data_format(),
Config->get_native_file_header_format(),
rate));
@@ -208,13 +219,15 @@ SourceFactory::createWritable (DataType type, std::string path, bool destructive
SourceCreated (ret);
}
return ret;
+
}
+
} else if (type == DataType::MIDI) {
- boost::shared_ptr<Source> ret (new SMFSource (path));
+ boost::shared_ptr<Source> ret (new SMFSource (s, path));
SourceCreated (ret);
return ret;
-
+
}
return boost::shared_ptr<Source> ();
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 02884f062b..c2ff4f9a3a 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -919,6 +919,33 @@ jack_nframes_t
TempoMap::round_to_beat_subdivision (jack_nframes_t fr, int sub_num)
{
+
+ BBT_Time the_beat;
+ uint32_t ticks_one_half_subdivisions_worth;
+ uint32_t ticks_one_subdivisions_worth;
+
+ bbt_time(fr, the_beat);
+
+ ticks_one_subdivisions_worth = (uint32_t)Meter::ticks_per_beat / sub_num;
+ ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
+
+ if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
+ uint32_t difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
+ if (the_beat.ticks + difference >= (uint32_t)Meter::ticks_per_beat) {
+ the_beat.beats++;
+ the_beat.ticks += difference;
+ the_beat.ticks -= (uint32_t)Meter::ticks_per_beat;
+ } else {
+ the_beat.ticks += difference;
+ }
+ } else {
+ the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
+ }
+
+ return frame_time (the_beat);
+
+ /* XXX just keeping this for reference
+
TempoMap::BBTPointList::iterator i;
TempoMap::BBTPointList *more_zoomed_bbt_points;
jack_nframes_t frame_one_beats_worth;
@@ -970,6 +997,9 @@ TempoMap::round_to_beat_subdivision (jack_nframes_t fr, int sub_num)
delete more_zoomed_bbt_points;
return fr ;
+
+ */
+
}
jack_nframes_t
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 8d9d799a44..ce4f4accd3 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -287,7 +287,7 @@ compute_equal_power_fades (jack_nframes_t nframes, float* in, float* out)
in[0] = 0.0f;
- for (int i = 1; i < nframes - 1; ++i) {
+ for (jack_nframes_t i = 1; i < nframes - 1; ++i) {
in[i] = in[i-1] + step;
}
diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc
index dbb7547052..5dd32f2d51 100644
--- a/libs/ardour/vst_plugin.cc
+++ b/libs/ardour/vst_plugin.cc
@@ -174,9 +174,9 @@ VSTPlugin::get_state()
if (stat (path.c_str(), &sbuf)) {
if (errno == ENOENT) {
- if (mkdir (path.c_str(), 0600)) {
+ if (g_mkdir_with_parents (path.c_str(), 0600)) {
error << string_compose (_("cannot create VST chunk directory: %1"),
- strerror (errno))
+ strerror (errno))
<< endmsg;
return *root;
}
diff --git a/libs/gtkmm2ext/dndtreeview.cc b/libs/gtkmm2ext/dndtreeview.cc
index d7ee5a7b27..83955861cf 100644
--- a/libs/gtkmm2ext/dndtreeview.cc
+++ b/libs/gtkmm2ext/dndtreeview.cc
@@ -48,6 +48,8 @@ DnDTreeView::serialize_pointers (RefPtr<TreeModel> model, TreeSelection::ListHan
uint32_t cnt = selection->size();
uint32_t sz = (sizeof (void*) * cnt) + sizeof (SerializedObjectPointers);
+ cerr << "lets plan to serialize " << cnt << " from selection\n";
+
char* buf = new char[sz];
SerializedObjectPointers* sr = new (buf) SerializedObjectPointers;
@@ -59,10 +61,12 @@ DnDTreeView::serialize_pointers (RefPtr<TreeModel> model, TreeSelection::ListHan
cnt = 0;
for (TreeSelection::ListHandle_Path::iterator x = selection->begin(); x != selection->end(); ++x, ++cnt) {
+ cerr << "getting next item\n";
TreeModel::Row row = *(model->get_iter (*x));
row.get_value (data_column, sr->ptr[cnt]);
}
-
+
+ cerr << "returning an SR with size = " << sr->size << endl;
return sr;
}
@@ -79,6 +83,7 @@ DnDTreeView::on_drag_data_get(const RefPtr<DragContext>& context, SelectionData&
SerializedObjectPointers* sr = serialize_pointers (get_model(), &selection, selection_data.get_target());
selection_data.set (8, (guchar*)sr, sr->size);
+ cerr << "selection data set to contain " << sr->size << endl;
}
}
diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h
index 5adddfc1c0..5fbac11e5c 100644
--- a/libs/pbd/pbd/stateful.h
+++ b/libs/pbd/pbd/stateful.h
@@ -42,7 +42,7 @@ class Stateful {
virtual void add_instant_xml (XMLNode&, const std::string& dir);
XMLNode *instant_xml (const std::string& str, const std::string& dir);
- PBD::ID id() { return _id; }
+ const PBD::ID& id() const { return _id; }
protected:
XMLNode *_extra_xml;