From ab6f1ed9bafa869648b6e94ee5186ff317b32c3e Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 10 Aug 2006 01:22:45 +0000 Subject: Merged with trunk R776 git-svn-id: svn://localhost/ardour2/branches/midi@777 d708f5d6-7413-0410-9779-e7cbd77b26cf --- SConstruct | 18 +- ardour.dox | 6 +- au_pluginui.cc | 45 + gtk2_ardour/SConscript | 1 + gtk2_ardour/ardev_common.sh | 2 +- gtk2_ardour/ardour2_ui.rc | 9 + gtk2_ardour/ardour_ui.cc | 2 + gtk2_ardour/ardour_ui_dialogs.cc | 1 + gtk2_ardour/audio_region_view.cc | 11 +- gtk2_ardour/audio_time_axis.cc | 1 + gtk2_ardour/automation_line.cc | 26 +- gtk2_ardour/automation_line.h | 7 +- gtk2_ardour/automation_time_axis.cc | 175 ++-- gtk2_ardour/automation_time_axis.h | 2 + gtk2_ardour/editor.cc | 8 +- gtk2_ardour/editor.h | 7 +- gtk2_ardour/editor_audio_import.cc | 5 +- gtk2_ardour/editor_keyboard.cc | 6 +- gtk2_ardour/editor_markers.cc | 36 +- gtk2_ardour/editor_mouse.cc | 102 +- gtk2_ardour/editor_ops.cc | 182 ++-- gtk2_ardour/editor_tempodisplay.cc | 30 +- gtk2_ardour/editor_timefx.cc | 6 +- gtk2_ardour/gain_automation_time_axis.cc | 6 +- gtk2_ardour/location_ui.cc | 16 +- gtk2_ardour/main.cc | 73 +- gtk2_ardour/new_session_dialog.cc | 73 +- gtk2_ardour/new_session_dialog.h | 2 + gtk2_ardour/opts.cc | 7 +- gtk2_ardour/pan_automation_time_axis.cc | 23 +- gtk2_ardour/plugin_selector.cc | 8 +- gtk2_ardour/plugin_selector.h | 7 - gtk2_ardour/plugin_ui.cc | 94 +- gtk2_ardour/plugin_ui.h | 25 +- gtk2_ardour/redirect_automation_time_axis.cc | 6 +- gtk2_ardour/redirect_box.cc | 12 +- gtk2_ardour/region_editor.h | 2 +- gtk2_ardour/region_gain_line.cc | 15 +- gtk2_ardour/region_gain_line.h | 3 + gtk2_ardour/route_params_ui.cc | 10 +- gtk2_ardour/route_time_axis.cc | 86 +- gtk2_ardour/route_ui.cc | 48 +- gtk2_ardour/time_axis_view.cc | 1 + gtk2_ardour/vst_pluginui.cc | 10 +- libs/appleutility/AUOutputBL.cpp | 160 +++ libs/appleutility/AUOutputBL.h | 115 +++ libs/appleutility/CAAudioChannelLayout.cpp | 138 +++ libs/appleutility/CAAudioChannelLayout.h | 162 +++ libs/appleutility/CAAudioChannelLayoutObject.cpp | 199 ++++ libs/appleutility/CAAudioUnit.cpp | 1202 ++++++++++++++++++++++ libs/appleutility/CAAudioUnit.h | 383 +++++++ libs/appleutility/CACFDictionary.cpp | 478 +++++++++ libs/appleutility/CACFDictionary.h | 141 +++ libs/appleutility/CACFNumber.cpp | 65 ++ libs/appleutility/CACFNumber.h | 102 ++ libs/appleutility/CACFString.cpp | 106 ++ libs/appleutility/CACFString.h | 156 +++ libs/appleutility/CAComponent.cpp | 257 +++++ libs/appleutility/CAComponent.h | 120 +++ libs/appleutility/CAComponentDescription.cpp | 123 +++ libs/appleutility/CAComponentDescription.h | 148 +++ libs/appleutility/CAConditionalMacros.h | 74 ++ libs/appleutility/CADebugMacros.cpp | 84 ++ libs/appleutility/CADebugMacros.h | 414 ++++++++ libs/appleutility/CAMath.h | 64 ++ libs/appleutility/CAReferenceCounted.h | 83 ++ libs/appleutility/CAStreamBasicDescription.cpp | 520 ++++++++++ libs/appleutility/CAStreamBasicDescription.h | 224 ++++ libs/appleutility/SConscript | 23 + libs/ardour/SConscript | 4 + libs/ardour/ardour/ardour.h | 2 +- libs/ardour/ardour/audio_unit.h | 76 +- libs/ardour/ardour/automation_event.h | 8 +- libs/ardour/ardour/ladspa_plugin.h | 15 +- libs/ardour/ardour/location.h | 6 + libs/ardour/ardour/playlist.h | 3 + libs/ardour/ardour/plugin.h | 30 +- libs/ardour/ardour/plugin_manager.h | 12 +- libs/ardour/ardour/route.h | 2 +- libs/ardour/ardour/session.h | 75 +- libs/ardour/ardour/state_manager.h | 2 + libs/ardour/ardour/tempo.h | 3 + libs/ardour/ardour/track.h | 2 +- libs/ardour/ardour/vst_plugin.h | 11 +- libs/ardour/audio_diskstream.cc | 6 +- libs/ardour/audio_unit.cc | 388 +++++-- libs/ardour/automation_event.cc | 14 + libs/ardour/globals.cc | 6 +- libs/ardour/insert.cc | 26 +- libs/ardour/io.cc | 2 +- libs/ardour/ladspa_plugin.cc | 25 +- libs/ardour/plugin.cc | 42 + libs/ardour/plugin_manager.cc | 96 +- libs/ardour/session.cc | 4 + libs/ardour/session_command.cc | 101 ++ libs/ardour/session_state.cc | 70 +- libs/ardour/session_transport.cc | 8 +- libs/ardour/state_manager.cc | 3 + libs/ardour/track.cc | 21 +- libs/ardour/vst_plugin.cc | 30 + libs/libsndfile/src/flac.c | 12 +- libs/pbd/SConscript | 1 + libs/pbd/command.cc | 10 + libs/pbd/id.cc | 8 + libs/pbd/pbd/command.h | 37 + libs/pbd/pbd/id.h | 1 + libs/pbd/pbd/memento_command.h | 99 ++ libs/pbd/pbd/undo.h | 29 +- libs/pbd/undo.cc | 88 +- libs/surfaces/control_protocol/basic_ui.cc | 1 + 110 files changed, 7355 insertions(+), 780 deletions(-) create mode 100644 au_pluginui.cc create mode 100644 libs/appleutility/AUOutputBL.cpp create mode 100644 libs/appleutility/AUOutputBL.h create mode 100644 libs/appleutility/CAAudioChannelLayout.cpp create mode 100644 libs/appleutility/CAAudioChannelLayout.h create mode 100644 libs/appleutility/CAAudioChannelLayoutObject.cpp create mode 100644 libs/appleutility/CAAudioUnit.cpp create mode 100644 libs/appleutility/CAAudioUnit.h create mode 100644 libs/appleutility/CACFDictionary.cpp create mode 100644 libs/appleutility/CACFDictionary.h create mode 100644 libs/appleutility/CACFNumber.cpp create mode 100644 libs/appleutility/CACFNumber.h create mode 100644 libs/appleutility/CACFString.cpp create mode 100644 libs/appleutility/CACFString.h create mode 100644 libs/appleutility/CAComponent.cpp create mode 100644 libs/appleutility/CAComponent.h create mode 100644 libs/appleutility/CAComponentDescription.cpp create mode 100644 libs/appleutility/CAComponentDescription.h create mode 100644 libs/appleutility/CAConditionalMacros.h create mode 100644 libs/appleutility/CADebugMacros.cpp create mode 100644 libs/appleutility/CADebugMacros.h create mode 100644 libs/appleutility/CAMath.h create mode 100644 libs/appleutility/CAReferenceCounted.h create mode 100644 libs/appleutility/CAStreamBasicDescription.cpp create mode 100644 libs/appleutility/CAStreamBasicDescription.h create mode 100644 libs/appleutility/SConscript create mode 100644 libs/ardour/session_command.cc create mode 100644 libs/pbd/command.cc create mode 100644 libs/pbd/pbd/command.h create mode 100644 libs/pbd/pbd/memento_command.h diff --git a/SConstruct b/SConstruct index 64aad2737f..e7e43a1405 100644 --- a/SConstruct +++ b/SConstruct @@ -454,6 +454,9 @@ conf = Configure (libraries['flac']) conf.CheckLib ('FLAC', 'FLAC__stream_decoder_new', language='CXX') libraries['flac'] = conf.Finish () +# or if that fails... +#libraries['flac'] = LibraryInfo (LIBS='FLAC') + # # Check for liblo @@ -547,6 +550,10 @@ if env['SYSLIBS']: # libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas') libraries['soundtouch'] = LibraryInfo() libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs libSoundTouch') + + libraries['appleutility'] = LibraryInfo(LIBS='libappleutility', + LIBPATH='#libs/appleutility', + CPPPATH='#libs/appleutility') coredirs = [ 'templates' @@ -561,6 +568,9 @@ if env['SYSLIBS']: if env['VST']: subdirs = ['libs/fst'] + subdirs + ['vst'] + + if env['COREAUDIO']: + subdirs = subdirs + ['libs/appleutility'] gtk_subdirs = [ # 'libs/flowcanvas', @@ -600,7 +610,10 @@ else: # libraries['libglademm'] = LibraryInfo(LIBS='libglademm', # LIBPATH='#libs/libglademm', # CPPPATH='#libs/libglademm') - + libraries['appleutility'] = LibraryInfo(LIBS='libappleutility', + LIBPATH='#libs/appleutility', + CPPPATH='#libs/appleutility') + coredirs = [ 'libs/soundtouch', 'templates' @@ -616,6 +629,9 @@ else: if env['VST']: subdirs = ['libs/fst'] + subdirs + ['vst'] + + if env['COREAUDIO']: + subdirs = subdirs + ['libs/appleutility'] gtk_subdirs = [ 'libs/glibmm2', diff --git a/ardour.dox b/ardour.dox index 2ad51340df..0ff7c85a41 100644 --- a/ardour.dox +++ b/ardour.dox @@ -972,13 +972,13 @@ ENABLE_PREPROCESSING = YES # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. @@ -1006,7 +1006,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = HAVE_COREAUDIO VST_SUPPORT HAVE_LIBLO FFT_ANALYSIS # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/au_pluginui.cc b/au_pluginui.cc new file mode 100644 index 0000000000..cbf493a629 --- /dev/null +++ b/au_pluginui.cc @@ -0,0 +1,45 @@ +/* + Copyright (C) 2006 Paul Davis + Written by Taybin Rutkin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "plugin_ui.h" + +using namespace ARDOUR; +using namespace PBD; + +AUPluginUI::AUPluginUI (boost::shared_ptr pi, boost::shared_ptr ap) + : PlugUIBase (pi), + au (ap) +{ + info << "AUPluginUI created" << endmsg; +} + +AUPluginUI::~AUPluginUI () +{ + // nothing to do here - plugin destructor destroys the GUI +} + +int +AUPluginUI::get_preferred_height () +{ + return -1; +} diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index 33f2d3471b..2d59be1b5e 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -59,6 +59,7 @@ if gtkardour['FFT_ANALYSIS']: if gtkardour['COREAUDIO']: gtkardour.Append(CCFLAGS='-DHAVE_COREAUDIO') + gtkardour.Merge([libraries['appleutility']]) skipped_files=Split(""" connection_editor.cc diff --git a/gtk2_ardour/ardev_common.sh b/gtk2_ardour/ardev_common.sh index ce3b1935c5..bf644f3e84 100755 --- a/gtk2_ardour/ardev_common.sh +++ b/gtk2_ardour/ardev_common.sh @@ -2,7 +2,7 @@ export ARDOUR_PATH=./glade:./pixmaps:. -export LD_LIBRARY_PATH=../libs/surfaces/control_protocol:../libs/ardour:../libs/midi++2:../libs/pbd:../libs/soundtouch:../libs/gtkmm2ext:../libs/sigc++2:../libs/glibmm2:../libs/gtkmm2/atk:../libs/gtkmm2/pango:../libs/gtkmm2/gdk:../libs/gtkmm2/gtk:../libs/libgnomecanvasmm:../libs/libsndfile:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH=../libs/surfaces/control_protocol:../libs/ardour:../libs/midi++2:../libs/pbd:../libs/soundtouch:../libs/gtkmm2ext:../libs/sigc++2:../libs/glibmm2:../libs/gtkmm2/atk:../libs/gtkmm2/pango:../libs/gtkmm2/gdk:../libs/gtkmm2/gtk:../libs/libgnomecanvasmm:../libs/libsndfile:../libs/appleutility:$LD_LIBRARY_PATH # DYLD_LIBRARY_PATH is for darwin. export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH diff --git a/gtk2_ardour/ardour2_ui.rc b/gtk2_ardour/ardour2_ui.rc index 6945ea1338..d589f6ce55 100644 --- a/gtk2_ardour/ardour2_ui.rc +++ b/gtk2_ardour/ardour2_ui.rc @@ -219,6 +219,14 @@ style "mute_button" = "small_button" fg[PRELIGHT] = { 0, 0, 0 } } + +style "multiline_combo" = "small_button" +{ + font_name = "sans 8" + xthickness = 0 + ythickness = 0 +} + style "mixer_mute_button" = "mute_button" { font_name = "sans 7" @@ -951,6 +959,7 @@ widget "*TrackRecordEnableButton" style "track_rec_enable_button" widget "*TrackRecordEnableButton*" style "track_rec_enable_button" widget "*TrackMuteButton*" style "mute_button" widget "*TrackLoopButton*" style "track_loop_button" +widget "*PanAutomationLineSelector*" style "multiline_combo" widget "*EditorTimeButton*" style "time_button" widget "*EditorMixerButton*" style "default_buttons_menus" widget "*SoloButton*" style "solo_button" diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 827a967361..203d64c3c3 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1326,6 +1326,7 @@ ARDOUR_UI::start_engine () settings for a new session */ session->save_state (""); + session->save_history (); } /* there is too much going on, in too many threads, for us to @@ -1499,6 +1500,7 @@ ARDOUR_UI::save_state_canfail (string name) } if ((ret = session->save_state (name)) != 0) { + session->save_history(); return ret; } } diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc index 25f3068a81..d2cc3e1e1c 100644 --- a/gtk2_ardour/ardour_ui_dialogs.cc +++ b/gtk2_ardour/ardour_ui_dialogs.cc @@ -156,6 +156,7 @@ ARDOUR_UI::unload_session () case 1: session->save_state (""); + session->save_history(); break; } } diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index b12713433b..dff2300529 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include "streamview.h" #include "audio_region_view.h" @@ -896,18 +897,20 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) gain_line->view_to_model_y (y); trackview.session().begin_reversible_command (_("add gain control point")); - trackview.session().add_undo (audio_region().envelope().get_memento()); + XMLNode &before = audio_region().envelope().get_state(); if (!audio_region().envelope_active()) { - trackview.session().add_undo( bind( mem_fun(audio_region(), &AudioRegion::set_envelope_active), false) ); + XMLNode &before = audio_region().get_state(); audio_region().set_envelope_active(true); - trackview.session().add_redo( bind( mem_fun(audio_region(), &AudioRegion::set_envelope_active), true) ); + XMLNode &after = audio_region().get_state(); + trackview.session().add_command (new MementoCommand(audio_region(), before, after)); } audio_region().envelope().add (fx, y); - trackview.session().add_redo_no_execute (audio_region().envelope().get_memento()); + XMLNode &after = audio_region().envelope().get_state(); + trackview.session().add_command (new MementoCommand(audio_region().envelope(), before, after)); trackview.session().commit_reversible_command (); } diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 376e05aa4c..9ae94d1fe0 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include #include diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index b87a71ca87..5c09ddd49b 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -887,7 +888,7 @@ AutomationLine::start_drag (ControlPoint* cp, float fraction) } trackview.editor.current_session()->begin_reversible_command (str); - trackview.editor.current_session()->add_undo (get_memento()); + trackview.editor.current_session()->add_command (new MementoUndoCommand(*this, get_state())); first_drag_fraction = fraction; last_drag_fraction = fraction; @@ -936,7 +937,7 @@ AutomationLine::end_drag (ControlPoint* cp) update_pending = false; - trackview.editor.current_session()->add_redo_no_execute (get_memento()); + trackview.editor.current_session()->add_command (new MementoRedoCommand(*this, get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -1013,11 +1014,11 @@ AutomationLine::remove_point (ControlPoint& cp) model_representation (cp, mr); trackview.editor.current_session()->begin_reversible_command (_("remove control point")); - trackview.editor.current_session()->add_undo (get_memento()); + XMLNode &before = get_state(); alist.erase (mr.start, mr.end); - trackview.editor.current_session()->add_redo_no_execute (get_memento()); + trackview.editor.current_session()->add_command(new MementoCommand(*this, before, get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -1225,9 +1226,9 @@ void AutomationLine::clear () { /* parent must create command */ - trackview.editor.current_session()->add_undo (get_memento()); + XMLNode &before = get_state(); alist.clear(); - trackview.editor.current_session()->add_redo_no_execute (get_memento()); + trackview.editor.current_session()->add_command (new MementoCommand(*this, before, get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -1266,3 +1267,16 @@ AutomationLine::hide_all_but_selected_control_points () } } } + +XMLNode &AutomationLine::get_state(void) +{ + // TODO + return alist.get_state(); +} + +int AutomationLine::set_state(const XMLNode &node) +{ + // TODO + alist.set_state(node); + return 0; +} diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index e922de6c80..ec86b7455f 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -94,7 +94,7 @@ class ControlPoint ShapeType _shape; }; -class AutomationLine : public sigc::trackable +class AutomationLine : public sigc::trackable, public Stateful { public: AutomationLine (const string & name, TimeAxisView&, ArdourCanvas::Group&, ARDOUR::AutomationList&); @@ -158,7 +158,12 @@ class AutomationLine : public sigc::trackable bool is_last_point (ControlPoint &); bool is_first_point (ControlPoint &); + 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/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index 02a88b578b..7025a11178 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -1,4 +1,5 @@ #include +#include #include "ardour_ui.h" #include "automation_time_axis.h" @@ -40,6 +41,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptrtooltips().set_tip(height_button, _("track height")); ARDOUR_UI::instance()->tooltips().set_tip(auto_button, _("automation state")); ARDOUR_UI::instance()->tooltips().set_tip(clear_button, _("clear track")); @@ -98,7 +102,7 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptrset_name (X_("TrackPlugName")); - plugname->set_alignment (1.0, 0.5); + plugname->show(); name_label.set_name (X_("TrackParameterName")); controls_table.remove (name_hbox); controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); @@ -138,8 +142,8 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptrget_child_xml_node (_state_name); - //controls_table.show_all (); - TimeAxisView::set_height (ht); base_rect->property_y2() = h; @@ -297,117 +301,88 @@ AutomationTimeAxisView::set_height (TrackHeight ht) (*i)->set_height (); } + switch (ht) { case Largest: xml_node->add_property ("track_height", "largest"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - controls_table.show_all (); - - hide_name_entry (); - show_name_label (); break; case Large: xml_node->add_property ("track_height", "large"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - controls_table.show_all (); - hide_name_entry (); - show_name_label (); break; case Larger: xml_node->add_property ("track_height", "larger"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - controls_table.show_all (); - hide_name_entry (); - show_name_label (); break; case Normal: xml_node->add_property ("track_height", "normal"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - plugname_packed = true; - controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } else { - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - controls_table.show_all (); - hide_name_entry (); - show_name_label (); break; case Smaller: xml_node->add_property ("track_height", "smaller"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - } - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.hide_all (); - hide_name_entry (); - show_name_label (); - name_hbox.show_all (); - controls_table.show (); break; case Small: xml_node->add_property ("track_height", "small"); - controls_table.remove (name_hbox); - if (plugname) { - if (plugname_packed) { - controls_table.remove (*plugname); - plugname_packed = false; - } - } - controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.hide_all (); - hide_name_entry (); - show_name_label (); - name_hbox.show_all (); - controls_table.show (); break; } + if (changed_between_small_and_normal || first_call_to_set_height) { + first_call_to_set_height = false; + switch (ht) { + case Largest: + case Large: + case Larger: + case Normal: + + controls_table.remove (name_hbox); + + if (plugname) { + if (plugname_packed) { + controls_table.remove (*plugname); + plugname_packed = false; + } + controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + plugname_packed = true; + controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + } else { + controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + } + hide_name_entry (); + show_name_label (); + name_hbox.show_all (); + + auto_button.show(); + height_button.show(); + clear_button.show(); + hide_button.show_all(); + break; + + case Smaller: + case Small: + + controls_table.remove (name_hbox); + if (plugname) { + if (plugname_packed) { + controls_table.remove (*plugname); + plugname_packed = false; + } + } + controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.hide_all (); + hide_name_entry (); + show_name_label (); + name_hbox.show_all (); + + auto_button.hide(); + height_button.hide(); + clear_button.hide(); + hide_button.hide(); + break; + } + } + if (changed) { /* only emit the signal if the height really changed */ route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ @@ -501,13 +476,13 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel AutomationList& alist (line.the_list()); bool ret = false; - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); switch (op) { case Cut: if ((what_we_got = alist.cut (selection.time.front().start, selection.time.front().end)) != 0) { editor.get_cut_buffer().add (what_we_got); - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command(new MementoCommand(alist, before, alist.get_state())); ret = true; } break; @@ -519,7 +494,7 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel case Clear: if ((what_we_got = alist.cut (selection.time.front().start, selection.time.front().end)) != 0) { - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command(new MementoCommand(alist, before, alist.get_state())); delete what_we_got; what_we_got = 0; ret = true; @@ -551,7 +526,7 @@ AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& { AutomationList& alist (line.the_list()); - _session.add_undo (alist.get_memento()); + _session.add_command (new MementoUndoCommand(alist, alist.get_state())); for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) { @@ -582,7 +557,7 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS AutomationList& alist (line.the_list()); bool ret = false; - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) { @@ -594,7 +569,7 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS case Cut: if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) { editor.get_cut_buffer().add (what_we_got); - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command (new MementoCommand(alist, before, alist.get_state())); ret = true; } break; @@ -606,7 +581,7 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS case Clear: if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) { - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command (new MementoCommand(alist, before, alist.get_state())); delete what_we_got; what_we_got = 0; ret = true; @@ -663,9 +638,9 @@ AutomationTimeAxisView::paste_one (AutomationLine& line, jack_nframes_t pos, flo (*x)->value = foo; } - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); alist.paste (copy, pos, times); - _session.add_redo_no_execute (alist.get_memento()); + _session.add_command (new MementoCommand(alist, before, alist.get_state())); return true; } diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index 6de11a7c6d..0cd9acc034 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -84,6 +84,8 @@ class AutomationTimeAxisView : public TimeAxisView { string _state_name; bool in_destructor; + bool first_call_to_set_height; + Gtk::Button hide_button; Gtk::Button height_button; Gtk::Button clear_button; diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 518ef7217a..513251085c 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -2878,8 +2879,8 @@ void Editor::begin_reversible_command (string name) { if (session) { - UndoAction ua = get_memento(); - session->begin_reversible_command (name, &ua); + before = &get_state(); + session->begin_reversible_command (name); } } @@ -2887,8 +2888,7 @@ void Editor::commit_reversible_command () { if (session) { - UndoAction ua = get_memento(); - session->commit_reversible_command (&ua); + session->commit_reversible_command (new MementoCommand(*this, *before, get_state())); } } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 05a134157e..3488c756ac 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -142,6 +142,8 @@ 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; } @@ -346,6 +348,8 @@ class Editor : public PublicEditor ARDOUR::AudioEngine& engine; bool constructed; + PBD::ID _id; + PlaylistSelector* _playlist_selector; void set_frames_per_unit (double); @@ -1595,13 +1599,14 @@ class Editor : public PublicEditor UndoAction get_memento() const; + XMLNode *before; /* used in *_reversible_command */ void begin_reversible_command (string cmd_name); void commit_reversible_command (); /* visual history */ UndoHistory visual_history; - UndoCommand current_visual_command; + UndoTransaction current_visual_command; void begin_reversible_visual_command (const string & cmd_name); void commit_reversible_visual_command (); diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc index f8c632f08a..7524f9605c 100644 --- a/gtk2_ardour/editor_audio_import.cc +++ b/gtk2_ardour/editor_audio_import.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include "ardour_ui.h" #include "editor.h" @@ -320,9 +321,9 @@ Editor::finish_bringing_in_audio (AudioRegion& region, uint32_t in_chans, uint32 AudioRegion* copy = new AudioRegion (region); begin_reversible_command (_("insert sndfile")); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*copy, pos); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command (new MementoCommand(*playlist, before, playlist->get_state())); commit_reversible_command (); pos += region.length(); diff --git a/gtk2_ardour/editor_keyboard.cc b/gtk2_ardour/editor_keyboard.cc index d2b7c1160e..f48d860d15 100644 --- a/gtk2_ardour/editor_keyboard.cc +++ b/gtk2_ardour/editor_keyboard.cc @@ -20,6 +20,7 @@ #include #include +#include #include "editor.h" #include "region_view.h" @@ -102,11 +103,12 @@ Editor::kbd_mute_unmute_region () { if (entered_regionview) { begin_reversible_command (_("mute region")); - session->add_undo (entered_regionview->region().playlist()->get_memento()); + XMLNode &before = entered_regionview->region().playlist()->get_state(); entered_regionview->region().set_muted (!entered_regionview->region().muted()); - session->add_redo_no_execute (entered_regionview->region().playlist()->get_memento()); + XMLNode &after = entered_regionview->region().playlist()->get_state(); + session->add_command (new MementoCommand(*(entered_regionview->region().playlist()), before, after)); commit_reversible_command(); } } diff --git a/gtk2_ardour/editor_markers.cc b/gtk2_ardour/editor_markers.cc index f34b8590a4..ccc1415888 100644 --- a/gtk2_ardour/editor_markers.cc +++ b/gtk2_ardour/editor_markers.cc @@ -26,6 +26,7 @@ #include #include +#include #include "editor.h" #include "marker.h" @@ -290,9 +291,10 @@ Editor::mouse_add_new_marker (jack_nframes_t where) if (session) { Location *location = new Location (where, where, "mark", Location::IsMark); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); } } @@ -329,9 +331,10 @@ gint Editor::really_remove_marker (Location* loc) { session->begin_reversible_command (_("remove marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->remove (loc); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); return FALSE; } @@ -838,12 +841,13 @@ Editor::marker_menu_rename () } begin_reversible_command ( _("rename marker") ); - session->add_undo( session->locations()->get_memento() ); + XMLNode &before = session->locations()->get_state(); dialog.get_result(txt); loc->set_name (txt); - session->add_redo_no_execute( session->locations()->get_memento() ); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), before, after)); commit_reversible_command (); } @@ -868,16 +872,18 @@ Editor::new_transport_marker_menu_set_loop () if ((tll = transport_loop_location()) == 0) { Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"), Location::IsAutoLoop); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (loc, true); session->set_auto_loop_location (loc); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), before, after)); } else { - session->add_undo (retype_return(bind (mem_fun (*tll, &Location::set), tll->start(), tll->end()))); - session->add_redo (retype_return(bind (mem_fun (*tll, &Location::set), temp_location->start(), temp_location->end()))); + XMLNode &before = tll->get_state(); tll->set_hidden (false, this); tll->set (temp_location->start(), temp_location->end()); + XMLNode &after = tll->get_state(); + session->add_command (new MementoCommand(*tll, before, after)); } commit_reversible_command (); @@ -894,15 +900,17 @@ Editor::new_transport_marker_menu_set_punch () if ((tpl = transport_punch_location()) == 0) { tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (tpl, true); session->set_auto_punch_location (tpl); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), before, after)); } else { - session->add_undo (retype_return(bind (mem_fun (*tpl, &Location::set), tpl->start(), tpl->end()))); - session->add_redo (retype_return(bind (mem_fun (*tpl, &Location::set), temp_location->start(), temp_location->end()))); + XMLNode &before = tpl->get_state(); tpl->set_hidden(false, this); tpl->set(temp_location->start(), temp_location->end()); + XMLNode &after = tpl->get_state(); + session->add_command (new MementoCommand(*tpl, before, after)); } commit_reversible_command (); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 9b7ad99acb..a05dcba9e3 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -28,6 +28,7 @@ #include #include +#include #include "ardour_ui.h" #include "editor.h" @@ -1818,9 +1819,14 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even } begin_reversible_command (_("change fade in length")); - session->add_undo (arv->region().get_memento()); + XMLNode &before = arv->audio_region().get_state(); + arv->audio_region().set_fade_in_length (fade_length); - session->add_redo_no_execute (arv->region().get_memento()); + + XMLNode &after = arv->audio_region().get_state(); + session->add_command(new MementoCommand(arv->audio_region(), + before, + after)); commit_reversible_command (); fade_in_drag_motion_callback (item, event); } @@ -1910,9 +1916,12 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve } begin_reversible_command (_("change fade out length")); - session->add_undo (arv->region().get_memento()); + XMLNode &before = arv->region().get_state(); + arv->audio_region().set_fade_out_length (fade_length); - session->add_redo_no_execute (arv->region().get_memento()); + + XMLNode &after = arv->region().get_state(); + session->add_command(new MementoCommand(arv->region(), before, after)); commit_reversible_command (); fade_out_drag_motion_callback (item, event); @@ -2154,7 +2163,7 @@ Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event begin_reversible_command ( _("move marker") ); - session->add_undo( session->locations()->get_memento() ); + XMLNode &before = session->locations()->get_state(); Location * location = find_location_from_marker (marker, is_start); @@ -2166,7 +2175,8 @@ Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event } } - session->add_redo_no_execute( session->locations()->get_memento() ); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); commit_reversible_command (); marker_drag_line->hide(); @@ -2280,9 +2290,10 @@ Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* if (drag_info.copy == true) { begin_reversible_command (_("copy meter mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.add_meter (marker->meter(), when); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command(new MementoCommand(map, before, after)); commit_reversible_command (); // delete the dummy marker we used for visual representation of copying. @@ -2290,9 +2301,10 @@ Editor::meter_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* delete marker; } else { begin_reversible_command (_("move meter mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.move_meter (marker->meter(), when); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command(new MementoCommand(map, before, after)); commit_reversible_command (); } } @@ -2407,12 +2419,13 @@ Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* TempoMap& map (session->tempo_map()); map.bbt_time (drag_info.last_pointer_frame, when); - + if (drag_info.copy == true) { begin_reversible_command (_("copy tempo mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.add_tempo (marker->tempo(), when); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command (new MementoCommand(map, before, after)); commit_reversible_command (); // delete the dummy marker we used for visual representation of copying. @@ -2420,9 +2433,10 @@ Editor::tempo_marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* delete marker; } else { begin_reversible_command (_("move tempo mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.move_tempo (marker->tempo(), when); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command (new MementoCommand(map, before, after)); commit_reversible_command (); } } @@ -2786,7 +2800,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) insert_result = affected_playlists.insert (to_playlist); if (insert_result.second) { - session->add_undo (to_playlist->get_memento ()); + session->add_command (new MementoUndoCommand(*to_playlist, to_playlist->get_state())); } latest_regionview = 0; @@ -3224,7 +3238,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) insert_result = motion_frozen_playlists.insert (pl); if (insert_result.second) { pl->freeze(); - session->add_undo(pl->get_memento()); + session->add_command(new MementoUndoCommand(*pl, pl->get_state())); } } } @@ -3352,7 +3366,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event insert_result = motion_frozen_playlists.insert(to_playlist); if (insert_result.second) { to_playlist->freeze(); - session->add_undo(to_playlist->get_memento()); + session->add_command(new MementoUndoCommand(*to_playlist, to_playlist->get_state())); } } @@ -3434,7 +3448,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event out: for (set::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) { (*p)->thaw (); - session->add_redo_no_execute ((*p)->get_memento()); + session->add_command (new MementoRedoCommand(*(*p), (*p)->get_state())); } motion_frozen_playlists.clear (); @@ -3629,9 +3643,10 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) Playlist* playlist = clicked_trackview->playlist(); - session->add_undo (playlist->get_memento ()); + before = &(playlist->get_state()); clicked_trackview->playlist()->add_region (*region, selection->time[clicked_selection].start); - session->add_redo_no_execute (playlist->get_memento ()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand(*playlist, *before, after)); commit_reversible_command (); @@ -3998,7 +4013,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) Playlist * pl = (*i)->region().playlist(); insert_result = motion_frozen_playlists.insert (pl); if (insert_result.second) { - session->add_undo (pl->get_memento()); + session->add_command(new MementoUndoCommand(*pl, pl->get_state())); } } } @@ -4188,8 +4203,8 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) for (set::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) { //(*p)->thaw (); - session->add_redo_no_execute ((*p)->get_memento()); - } + session->add_command (new MementoRedoCommand(*(*p), (*p)->get_state())); + } motion_frozen_playlists.clear (); @@ -4222,18 +4237,22 @@ Editor::point_trim (GdkEvent* event) i != selection->regions.by_layer().end(); ++i) { if (!(*i)->region().locked()) { - session->add_undo ((*i)->region().playlist()->get_memento()); + Playlist *pl = (*i)->region().playlist(); + XMLNode &before = pl->get_state(); (*i)->region().trim_front (new_bound, this); - session->add_redo_no_execute ((*i)->region().playlist()->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand(*pl, before, after)); } } } else { if (!rv->region().locked()) { - session->add_undo (rv->region().playlist()->get_memento()); + Playlist *pl = rv->region().playlist(); + XMLNode &before = pl->get_state(); rv->region().trim_front (new_bound, this); - session->add_redo_no_execute (rv->region().playlist()->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand(*pl, before, after)); } } @@ -4249,18 +4268,22 @@ Editor::point_trim (GdkEvent* event) for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { if (!(*i)->region().locked()) { - session->add_undo ((*i)->region().playlist()->get_memento()); + Playlist *pl = (*i)->region().playlist(); + XMLNode &before = pl->get_state(); (*i)->region().trim_end (new_bound, this); - session->add_redo_no_execute ((*i)->region().playlist()->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand(*pl, before, after)); } } } else { if (!rv->region().locked()) { - session->add_undo (rv->region().playlist()->get_memento()); + Playlist *pl = rv->region().playlist(); + XMLNode &before = pl->get_state(); rv->region().trim_end (new_bound, this); - session->add_redo_no_execute (rv->region().playlist()->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command (new MementoCommand(*pl, before, after)); } } @@ -4282,7 +4305,8 @@ Editor::thaw_region_after_trim (RegionView& rv) } region.thaw (_("trimmed region")); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command (new MementoRedoCommand(*(region.playlist()), after)); AudioRegionView* arv = dynamic_cast(&rv); if (arv) @@ -4421,16 +4445,19 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event) switch (range_marker_op) { case CreateRangeMarker: + { begin_reversible_command (_("new range marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker); session->locations()->add (newloc, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); commit_reversible_command (); range_bar_drag_rect->hide(); range_marker_drag_rect->hide(); break; + } case CreateTransportMarker: // popup menu to pick loop or punch @@ -4804,9 +4831,10 @@ Editor::mouse_brush_insert_region (RegionView* rv, jack_nframes_t pos) Playlist* playlist = atv->playlist(); double speed = atv->get_diskstream()->speed(); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*(new AudioRegion (arv->audio_region())), (jack_nframes_t) (pos * speed)); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand(*playlist, before, after)); // playlist is frozen, so we have to update manually diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index af366e18d0..9b69026a01 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -209,9 +210,10 @@ Editor::split_regions_at (jack_nframes_t where, RegionSelection& regions) _new_regionviews_show_envelope = arv->envelope_visible(); if (pl) { - session->add_undo (pl->get_memento()); + XMLNode &before = pl->get_state(); pl->split_region ((*a)->region(), where); - session->add_redo_no_execute (pl->get_memento()); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand(*pl, before, after)); } a = tmp; @@ -231,9 +233,10 @@ Editor::remove_clicked_region () Playlist* playlist = clicked_audio_trackview->playlist(); begin_reversible_command (_("remove region")); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->remove_region (&clicked_regionview->region()); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand(*playlist, before, after)); commit_reversible_command (); } @@ -406,9 +409,10 @@ Editor::nudge_forward (bool next) distance = next_distance; } - session->add_undo (r.playlist()->get_memento()); + XMLNode &before = r.playlist()->get_state(); r.set_position (r.position() + distance, this); - session->add_redo_no_execute (r.playlist()->get_memento()); + XMLNode &after = r.playlist()->get_state(); + session->add_command (new MementoCommand(*(r.playlist()), before, after)); } commit_reversible_command (); @@ -440,14 +444,15 @@ Editor::nudge_backward (bool next) distance = next_distance; } - session->add_undo (r.playlist()->get_memento()); + XMLNode &before = r.playlist()->get_state(); if (r.position() > distance) { r.set_position (r.position() - distance, this); } else { r.set_position (0, this); } - session->add_redo_no_execute (r.playlist()->get_memento()); + XMLNode &after = r.playlist()->get_state(); + session->add_command(new MementoCommand(*(r.playlist()), before, after)); } commit_reversible_command (); @@ -480,9 +485,10 @@ Editor::nudge_forward_capture_offset () for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { Region& r ((*i)->region()); - session->add_undo (r.playlist()->get_memento()); + XMLNode &before = r.playlist()->get_state(); r.set_position (r.position() + distance, this); - session->add_redo_no_execute (r.playlist()->get_memento()); + XMLNode &after = r.playlist()->get_state(); + session->add_command(new MementoCommand(*(r.playlist()), before, after)); } commit_reversible_command (); @@ -506,14 +512,15 @@ Editor::nudge_backward_capture_offset () for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { Region& r ((*i)->region()); - session->add_undo (r.playlist()->get_memento()); + XMLNode &before = r.playlist()->get_state(); if (r.position() > distance) { r.set_position (r.position() - distance, this); } else { r.set_position (0, this); } - session->add_redo_no_execute (r.playlist()->get_memento()); + XMLNode &after = r.playlist()->get_state(); + session->add_command(new MementoCommand(*(r.playlist()), before, after)); } commit_reversible_command (); @@ -1290,9 +1297,10 @@ Editor::add_location_from_selection () Location *location = new Location (start, end, "selection"); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); } @@ -1303,9 +1311,10 @@ Editor::add_location_from_playhead_cursor () Location *location = new Location (where, where, "mark", Location::IsMark); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); } @@ -1321,9 +1330,10 @@ Editor::add_location_from_audio_region () Location *location = new Location (region.position(), region.last_frame(), region.name()); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); } @@ -1739,9 +1749,10 @@ Editor::clear_markers () { if (session) { session->begin_reversible_command (_("clear markers")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->clear_markers (); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); } } @@ -1751,7 +1762,7 @@ Editor::clear_ranges () { if (session) { session->begin_reversible_command (_("clear ranges")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); Location * looploc = session->locations()->auto_loop_location(); Location * punchloc = session->locations()->auto_punch_location(); @@ -1761,7 +1772,8 @@ Editor::clear_ranges () if (looploc) session->locations()->add (looploc); if (punchloc) session->locations()->add (punchloc); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); } } @@ -1770,9 +1782,10 @@ void Editor::clear_locations () { session->begin_reversible_command (_("clear locations")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->clear (); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); session->locations()->clear (); } @@ -1820,9 +1833,9 @@ Editor::insert_region_list_drag (AudioRegion& region, int x, int y) snap_to (where); begin_reversible_command (_("insert dragged region")); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*(new AudioRegion (region)), where, 1.0); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command(new MementoCommand(*playlist, before, playlist->get_state())); commit_reversible_command (); } @@ -1856,9 +1869,9 @@ Editor::insert_region_list_selection (float times) Region* region = (*i)[region_list_columns.region]; begin_reversible_command (_("insert region")); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*(createRegion (*region)), edit_cursor->current_frame, times); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command(new MementoCommand(*playlist, before, playlist->get_state())); commit_reversible_command (); } @@ -2283,7 +2296,9 @@ Editor::separate_region_from_selection () begin_reversible_command (_("separate")); doing_undo = true; } - if (doing_undo) session->add_undo ((playlist)->get_memento()); + XMLNode *before; + if (doing_undo) + before = &(playlist->get_state()); /* XXX need to consider musical time selections here at some point */ @@ -2293,7 +2308,8 @@ Editor::separate_region_from_selection () playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true); } - if (doing_undo) session->add_redo_no_execute (playlist->get_memento()); + if (doing_undo) + session->add_command(new MementoCommand(*playlist, *before, playlist->get_state())); } } } @@ -2328,11 +2344,14 @@ Editor::separate_regions_using_location (Location& loc) if (atv->is_audio_track()) { if ((playlist = atv->playlist()) != 0) { + XMLNode *before; if (!doing_undo) { begin_reversible_command (_("separate")); doing_undo = true; } - if (doing_undo) session->add_undo ((playlist)->get_memento()); + if (doing_undo) + before = &(playlist->get_state()); + /* XXX need to consider musical time selections here at some point */ @@ -2340,7 +2359,8 @@ Editor::separate_regions_using_location (Location& loc) playlist->partition ((jack_nframes_t)(loc.start() * speed), (jack_nframes_t)(loc.end() * speed), true); - if (doing_undo) session->add_redo_no_execute (playlist->get_memento()); + if (doing_undo) + session->add_command(new MementoCommand(*playlist, *before, playlist->get_state())); } } } @@ -2411,9 +2431,10 @@ Editor::crop_region_to_selection () end = min (selection->time.end_frame(), start + region->length() - 1); cnt = end - start + 1; - session->add_undo ((*i)->get_memento()); + XMLNode &before = (*i)->get_state(); region->trim_to (start, cnt, this); - session->add_redo_no_execute ((*i)->get_memento()); + XMLNode &after = (*i)->get_state(); + session->add_command (new MementoCommand(*(*i), before, after)); } commit_reversible_command (); @@ -2454,9 +2475,9 @@ Editor::region_fill_track () return; } - session->add_undo (pl->get_memento()); + XMLNode &before = pl->get_state(); pl->add_region (*(new AudioRegion (*ar)), ar->last_frame(), times); - session->add_redo_no_execute (pl->get_memento()); + session->add_command (new MementoCommand(*pl, before, pl->get_state())); } commit_reversible_command (); @@ -2504,9 +2525,9 @@ Editor::region_fill_selection () continue; } - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->add_region (*(createRegion (*region)), start, times); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command (new MementoCommand(*playlist, before, playlist->get_state())); } commit_reversible_command (); @@ -2521,9 +2542,10 @@ Editor::set_a_regions_sync_position (Region& region, jack_nframes_t position) return; } begin_reversible_command (_("set region sync position")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.set_sync_position (position); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand(*(region.playlist()), before, after)); commit_reversible_command (); } @@ -2541,9 +2563,10 @@ Editor::set_region_sync_from_edit_cursor () Region& region (clicked_regionview->region()); begin_reversible_command (_("set sync from edit cursor")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.set_sync_position (edit_cursor->current_frame); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand(*(region.playlist()), before, after)); commit_reversible_command (); } @@ -2553,9 +2576,10 @@ Editor::remove_region_sync () if (clicked_regionview) { Region& region (clicked_regionview->region()); begin_reversible_command (_("remove sync")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.clear_sync_position (); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand(*(region.playlist()), before, after)); commit_reversible_command (); } } @@ -2568,9 +2592,10 @@ Editor::naturalize () } begin_reversible_command (_("naturalize")); for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { - session->add_undo ((*i)->region().get_memento()); + XMLNode &before = (*i)->region().get_state(); (*i)->region().move_to_natural_position (this); - session->add_redo_no_execute ((*i)->region().get_memento()); + XMLNode &after = (*i)->region().get_state(); + session->add_command (new MementoCommand((*i)->region(), before, after)); } commit_reversible_command (); } @@ -2636,7 +2661,7 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) Region& region ((*i)->region()); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); if (dir > 0) { region.set_position (region.position() + distance, this); @@ -2644,7 +2669,8 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) region.set_position (region.position() - distance, this); } - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand(*(region.playlist()), before, after)); } @@ -2678,7 +2704,7 @@ Editor::align_region (Region& region, RegionPoint point, jack_nframes_t position void Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t position) { - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); switch (point) { case SyncPoint: @@ -2696,7 +2722,8 @@ Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t break; } - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand(*(region.playlist()), before, after)); } void @@ -2718,9 +2745,10 @@ Editor::trim_region_to_edit_cursor () } begin_reversible_command (_("trim to edit")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand(*(region.playlist()), before, after)); commit_reversible_command (); } @@ -2743,9 +2771,10 @@ Editor::trim_region_from_edit_cursor () } begin_reversible_command (_("trim to edit")); - session->add_undo (region.playlist()->get_memento()); + XMLNode &before = region.playlist()->get_state(); region.trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this); - session->add_redo_no_execute (region.playlist()->get_memento()); + XMLNode &after = region.playlist()->get_state(); + session->add_command(new MementoCommand(*(region.playlist()), before, after)); commit_reversible_command (); } @@ -2857,9 +2886,10 @@ Editor::bounce_range_selection () itt.cancel = false; itt.progress = false; - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); atv->audio_track()->bounce_range (start, cnt, itt); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command (new MementoCommand (*playlist, before, after)); } commit_reversible_command (); @@ -2977,7 +3007,7 @@ Editor::cut_copy_regions (CutCopyOp op) insert_result = freezelist.insert (pl); if (insert_result.second) { pl->freeze (); - session->add_undo (pl->get_memento()); + session->add_command (new MementoUndoCommand(*pl, pl->get_state())); } } } @@ -3041,7 +3071,7 @@ Editor::cut_copy_regions (CutCopyOp op) for (set::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) { (*pl)->thaw (); - session->add_redo_no_execute ((*pl)->get_memento()); + session->add_command (new MementoRedoCommand(*(*pl), (*pl)->get_state())); } } @@ -3154,9 +3184,9 @@ Editor::paste_named_selection (float times) tmp = chunk; ++tmp; - session->add_undo (apl->get_memento()); + XMLNode &before = apl->get_state(); apl->paste (**chunk, edit_cursor->current_frame, times); - session->add_redo_no_execute (apl->get_memento()); + session->add_command(new MementoCommand(*apl, before, apl->get_state())); if (tmp != ns->playlists.end()) { chunk = tmp; @@ -3185,9 +3215,9 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times) sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); playlist = (*i)->region().playlist(); - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->duplicate (r, r.last_frame(), times); - session->add_redo_no_execute (playlist->get_memento()); + session->add_command(new MementoCommand(*playlist, before, playlist->get_state())); c.disconnect (); @@ -3225,9 +3255,10 @@ Editor::duplicate_selection (float times) if ((playlist = (*i)->playlist()) == 0) { continue; } - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->duplicate (**ri, selection->time[clicked_selection].end, times); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command (new MementoCommand(*playlist, before, after)); ++ri; if (ri == new_regions.end()) { @@ -3275,9 +3306,10 @@ void Editor::clear_playlist (Playlist& playlist) { begin_reversible_command (_("clear playlist")); - session->add_undo (playlist.get_memento()); + XMLNode &before = playlist.get_state(); playlist.clear (); - session->add_redo_no_execute (playlist.get_memento()); + XMLNode &after = playlist.get_state(); + session->add_command (new MementoCommand(playlist, before, after)); commit_reversible_command (); } @@ -3311,9 +3343,10 @@ Editor::nudge_track (bool use_edit_cursor, bool forwards) continue; } - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->nudge_after (start, distance, forwards); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command (new MementoCommand(*playlist, before, after)); } commit_reversible_command (); @@ -3367,9 +3400,9 @@ Editor::normalize_region () AudioRegionView* const arv = dynamic_cast(*r); if (!arv) continue; - session->add_undo (arv->region().get_memento()); + XMLNode &before = arv->region().get_state(); arv->audio_region().normalize_to (0.0f); - session->add_redo_no_execute (arv->region().get_memento()); + session->add_command (new MementoCommand(arv->region(), before, arv->region().get_state())); } commit_reversible_command (); @@ -3394,9 +3427,9 @@ Editor::denormalize_region () AudioRegionView* const arv = dynamic_cast(*r); if (!arv) continue; - session->add_undo (arv->region().get_memento()); + XMLNode &before = arv->region().get_state(); arv->audio_region().set_scale_amplitude (1.0f); - session->add_redo_no_execute (arv->region().get_memento()); + session->add_command (new MementoCommand(arv->region(), before, arv->region().get_state())); } commit_reversible_command (); @@ -3440,9 +3473,10 @@ Editor::apply_filter (AudioFilter& filter, string command) if (arv->audio_region().apply (filter) == 0) { - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->replace_region (arv->region(), *(filter.results.front()), arv->region().position()); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command(new MementoCommand(*playlist, before, after)); } else { goto out; } diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc index 5f998ada9f..9f7fe7cf09 100644 --- a/gtk2_ardour/editor_tempodisplay.cc +++ b/gtk2_ardour/editor_tempodisplay.cc @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -273,9 +274,10 @@ Editor::mouse_add_new_tempo_event (jack_nframes_t frame) tempo_dialog.get_bbt_time (requested); begin_reversible_command (_("add tempo mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.add_tempo (Tempo (bpm), requested); - session->add_redo_no_execute (map.get_memento()); + XMLNode &after = map.get_state(); + session->add_command(new MementoCommand(map, before, after)); commit_reversible_command (); map.dump (cerr); @@ -313,9 +315,9 @@ Editor::mouse_add_new_meter_event (jack_nframes_t frame) meter_dialog.get_bbt_time (requested); begin_reversible_command (_("add meter mark")); - session->add_undo (map.get_memento()); + XMLNode &before = map.get_state(); map.add_meter (Meter (bpb, note_type), requested); - session->add_redo_no_execute (map.get_memento()); + session->add_command(new MementoCommand(map, before, map.get_state())); commit_reversible_command (); map.dump (cerr); @@ -364,9 +366,10 @@ Editor::edit_meter_section (MeterSection* section) double note_type = meter_dialog.get_note_type (); begin_reversible_command (_("replace tempo mark")); - session->add_undo (session->tempo_map().get_memento()); + XMLNode &before = session->tempo_map().get_state(); session->tempo_map().replace_meter (*section, Meter (bpb, note_type)); - session->add_redo_no_execute (session->tempo_map().get_memento()); + XMLNode &after = session->tempo_map().get_state(); + session->add_command(new MementoCommand(session->tempo_map(), before, after)); commit_reversible_command (); } @@ -392,10 +395,11 @@ Editor::edit_tempo_section (TempoSection* section) bpm = max (0.01, bpm); begin_reversible_command (_("replace tempo mark")); - session->add_undo (session->tempo_map().get_memento()); + XMLNode &before = session->tempo_map().get_state(); session->tempo_map().replace_tempo (*section, Tempo (bpm)); session->tempo_map().move_tempo (*section, when); - session->add_redo_no_execute (session->tempo_map().get_memento()); + XMLNode &after = session->tempo_map().get_state(); + session->add_command (new MementoCommand(session->tempo_map(), before, after)); commit_reversible_command (); } @@ -441,9 +445,10 @@ gint Editor::real_remove_tempo_marker (TempoSection *section) { begin_reversible_command (_("remove tempo mark")); - session->add_undo (session->tempo_map().get_memento()); + XMLNode &before = session->tempo_map().get_state(); session->tempo_map().remove_tempo (*section); - session->add_redo_no_execute (session->tempo_map().get_memento()); + XMLNode &after = session->tempo_map().get_state(); + session->add_command(new MementoCommand(session->tempo_map(), before, after)); commit_reversible_command (); return FALSE; @@ -474,9 +479,10 @@ gint Editor::real_remove_meter_marker (MeterSection *section) { begin_reversible_command (_("remove tempo mark")); - session->add_undo (session->tempo_map().get_memento()); + XMLNode &before = session->tempo_map().get_state(); session->tempo_map().remove_meter (*section); - session->add_redo_no_execute (session->tempo_map().get_memento()); + XMLNode &after = session->tempo_map().get_state(); + session->add_command(new MementoCommand(session->tempo_map(), before, after)); commit_reversible_command (); return FALSE; } diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc index 79772090f6..3fe0023d07 100644 --- a/gtk2_ardour/editor_timefx.cc +++ b/gtk2_ardour/editor_timefx.cc @@ -25,6 +25,7 @@ #include #include +#include #include "editor.h" #include "audio_time_axis.h" @@ -206,9 +207,10 @@ Editor::do_timestretch (TimeStretchDialog& dialog) return; } - session->add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->replace_region (region, *new_region, region.position()); - session->add_redo_no_execute (playlist->get_memento()); + XMLNode &after = playlist->get_state(); + session->add_command (new MementoCommand(*playlist, before, after)); i = tmp; } diff --git a/gtk2_ardour/gain_automation_time_axis.cc b/gtk2_ardour/gain_automation_time_axis.cc index 5352015f11..c86c1390f3 100644 --- a/gtk2_ardour/gain_automation_time_axis.cc +++ b/gtk2_ardour/gain_automation_time_axis.cc @@ -20,6 +20,7 @@ #include #include +#include #include "gain_automation_time_axis.h" #include "automation_line.h" @@ -63,9 +64,10 @@ GainAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkE _session.begin_reversible_command (_("add gain automation event")); - _session.add_undo (curve.get_memento()); + XMLNode &before = curve.get_state(); curve.add (when, y); - _session.add_redo_no_execute (curve.get_memento()); + XMLNode &after = curve.get_state(); + _session.add_command(new MementoCommand(curve, before, after)); _session.commit_reversible_command (); _session.set_dirty (); } diff --git a/gtk2_ardour/location_ui.cc b/gtk2_ardour/location_ui.cc index f0fe230b57..deb4c1da36 100644 --- a/gtk2_ardour/location_ui.cc +++ b/gtk2_ardour/location_ui.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include "ardour_ui.h" #include "prompter.h" @@ -654,9 +655,10 @@ gint LocationUI::do_location_remove (ARDOUR::Location *loc) } session->begin_reversible_command (_("remove marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->remove (loc); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command(new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); return FALSE; @@ -772,9 +774,10 @@ LocationUI::add_new_location() jack_nframes_t where = session->audible_frame(); Location *location = new Location (where, where, "mark", Location::IsMark); session->begin_reversible_command (_("add marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); } @@ -788,9 +791,10 @@ LocationUI::add_new_range() Location *location = new Location (where, where, "unnamed", Location::IsRangeMarker); session->begin_reversible_command (_("add range marker")); - session->add_undo (session->locations()->get_memento()); + XMLNode &before = session->locations()->get_state(); session->locations()->add (location, true); - session->add_redo_no_execute (session->locations()->get_memento()); + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), before, after)); session->commit_reversible_command (); } } diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc index 778355c858..27dc573706 100644 --- a/gtk2_ardour/main.cc +++ b/gtk2_ardour/main.cc @@ -293,60 +293,43 @@ Please consider the possibilities, and perhaps (re)start JACK.")); static bool maybe_load_session () { + /* If no session name is given: we're not loading a session yet, nor creating a new one */ + if (!session_name.length()) { + ui->hide_splash (); + if (!Config->get_no_new_session_dialog()) { + ui->new_session (true); + } - /* load session, if given */ - string name, path; - - if (session_name.length()){ - bool isnew; - - if (Session::find_session (session_name, path, name, isnew)) { - error << string_compose(_("could not load command line session \"%1\""), session_name) << endmsg; - } else { - - if (new_session) { - - /* command line required that the session be new */ - - if (isnew) { - - /* popup the new session dialog - once everything else is OK. - */ - - Glib::signal_idle().connect (bind (mem_fun (*ui, &ARDOUR_UI::cmdline_new_session), path)); - ui->set_will_create_new_session_automatically (true); - - } else { - - /* it wasn't new, but we require a new session */ + return true; + } - error << string_compose (_("\n\nA session named \"%1\" already exists.\n\ -To avoid this message, start ardour as \"ardour %1"), path) - << endmsg; - return false; - } + /* Load session or start the new session dialog */ + string name, path; - } else { + bool isnew; - /* command line didn't require a new session */ - - if (isnew) { - error << string_compose (_("\n\nNo session named \"%1\" exists.\n\ -To create it from the command line, start ardour as \"ardour --new %1"), path) - << endmsg; - return false; - } + if (Session::find_session (session_name, path, name, isnew)) { + error << string_compose(_("could not load command line session \"%1\""), session_name) << endmsg; + return false; + } - ui->load_session (path, name); - } + if (!new_session) { + + /* Loading a session, but the session doesn't exist */ + if (isnew) { + error << string_compose (_("\n\nNo session named \"%1\" exists.\n\ +To create it from the command line, start ardour as \"ardour --new %1"), path) << endmsg; + return false; } - if (no_splash) { - ui->show(); - } + ui->load_session (path, name); } else { + /* TODO: This bit of code doesn't work properly yet + Glib::signal_idle().connect (bind (mem_fun (*ui, &ARDOUR_UI::cmdline_new_session), path)); + ui->set_will_create_new_session_automatically (true); */ + + /* Show the NSD */ ui->hide_splash (); if (!Config->get_no_new_session_dialog()) { ui->new_session (true); diff --git a/gtk2_ardour/new_session_dialog.cc b/gtk2_ardour/new_session_dialog.cc index d1059cebe0..47a2b2b6d3 100644 --- a/gtk2_ardour/new_session_dialog.cc +++ b/gtk2_ardour/new_session_dialog.cc @@ -32,12 +32,15 @@ #include #include +#include "opts.h" NewSessionDialog::NewSessionDialog() : ArdourDialog ("New Session Dialog") { session_name_label = Gtk::manage(new class Gtk::Label(_("New Session Name :"))); m_name = Gtk::manage(new class Gtk::Entry()); + m_name->set_text(GTK_ARDOUR::session_name); + session_location_label = Gtk::manage(new class Gtk::Label(_("Create Session Directory In :"))); m_folder = Gtk::manage(new class Gtk::FileChooserButton(Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); session_template_label = Gtk::manage(new class Gtk::Label(_("Use Session Template :"))); @@ -324,13 +327,21 @@ NewSessionDialog::NewSessionDialog() m_folder->set_current_folder(getenv ("HOME")); m_folder->set_title(_("select directory")); - set_default_response (Gtk::RESPONSE_OK); - set_response_sensitive (Gtk::RESPONSE_OK, false); - set_response_sensitive (Gtk::RESPONSE_NONE, false); + on_new_session_page = true; m_notebook->set_current_page(0); m_notebook->show(); m_notebook->show_all_children(); + + set_default_response (Gtk::RESPONSE_OK); + if (!GTK_ARDOUR::session_name.length()) { + set_response_sensitive (Gtk::RESPONSE_OK, false); + set_response_sensitive (Gtk::RESPONSE_NONE, false); + } else { + set_response_sensitive (Gtk::RESPONSE_OK, true); + set_response_sensitive (Gtk::RESPONSE_NONE, true); + } + ///@ connect some signals m_connect_inputs->signal_clicked().connect (mem_fun (*this, &NewSessionDialog::connect_inputs_clicked)); @@ -501,11 +512,11 @@ NewSessionDialog::reset_name() bool NewSessionDialog::entry_key_release (GdkEventKey* ev) { - if (m_name->get_text() != "") { - set_response_sensitive (Gtk::RESPONSE_OK, true); + if (m_name->get_text() != "") { + set_response_sensitive (Gtk::RESPONSE_OK, true); set_response_sensitive (Gtk::RESPONSE_NONE, true); } else { - set_response_sensitive (Gtk::RESPONSE_OK, false); + set_response_sensitive (Gtk::RESPONSE_OK, false); } return true; } @@ -513,25 +524,27 @@ NewSessionDialog::entry_key_release (GdkEventKey* ev) void NewSessionDialog::notebook_page_changed (GtkNotebookPage* np, uint pagenum) { - if (pagenum == 1) { - m_okbutton->set_label(_("Open")); - set_response_sensitive (Gtk::RESPONSE_NONE, false); - m_okbutton->set_image (*(new Gtk::Image (Gtk::Stock::OPEN, Gtk::ICON_SIZE_BUTTON))); - if (m_treeview->get_selection()->count_selected_rows() == 0) { - set_response_sensitive (Gtk::RESPONSE_OK, false); + if (pagenum == 1) { + on_new_session_page = false; + m_okbutton->set_label(_("Open")); + set_response_sensitive (Gtk::RESPONSE_NONE, false); + m_okbutton->set_image (*(new Gtk::Image (Gtk::Stock::OPEN, Gtk::ICON_SIZE_BUTTON))); + if (m_treeview->get_selection()->count_selected_rows() == 0) { + set_response_sensitive (Gtk::RESPONSE_OK, false); } else { - set_response_sensitive (Gtk::RESPONSE_OK, true); + set_response_sensitive (Gtk::RESPONSE_OK, true); } } else { - if (m_name->get_text() != "") { - set_response_sensitive (Gtk::RESPONSE_NONE, true); + on_new_session_page = true; + if (m_name->get_text() != "") { + set_response_sensitive (Gtk::RESPONSE_NONE, true); } - m_okbutton->set_label(_("New")); - m_okbutton->set_image (*(new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON))); + m_okbutton->set_label(_("New")); + m_okbutton->set_image (*(new Gtk::Image (Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON))); if (m_name->get_text() == "") { - set_response_sensitive (Gtk::RESPONSE_OK, false); + set_response_sensitive (Gtk::RESPONSE_OK, false); } else { - set_response_sensitive (Gtk::RESPONSE_OK, true); + set_response_sensitive (Gtk::RESPONSE_OK, true); } } } @@ -540,35 +553,37 @@ void NewSessionDialog::treeview_selection_changed () { if (m_treeview->get_selection()->count_selected_rows() == 0) { - if (!m_open_filechooser->get_filename().empty()) { - set_response_sensitive (Gtk::RESPONSE_OK, true); + if (!m_open_filechooser->get_filename().empty()) { + set_response_sensitive (Gtk::RESPONSE_OK, true); } else { - set_response_sensitive (Gtk::RESPONSE_OK, false); + set_response_sensitive (Gtk::RESPONSE_OK, false); } } else { - set_response_sensitive (Gtk::RESPONSE_OK, true); + set_response_sensitive (Gtk::RESPONSE_OK, true); } } void NewSessionDialog::file_chosen () { - m_treeview->get_selection()->unselect_all(); + if (on_new_session_page) return; + + m_treeview->get_selection()->unselect_all(); if (!m_open_filechooser->get_filename().empty()) { - set_response_sensitive (Gtk::RESPONSE_OK, true); + set_response_sensitive (Gtk::RESPONSE_OK, true); } else { - set_response_sensitive (Gtk::RESPONSE_OK, false); + set_response_sensitive (Gtk::RESPONSE_OK, false); } } void NewSessionDialog::template_chosen () { - if (m_template->get_filename() != "" ) {; - set_response_sensitive (Gtk::RESPONSE_NONE, true); + if (m_template->get_filename() != "" ) {; + set_response_sensitive (Gtk::RESPONSE_NONE, true); } else { - set_response_sensitive (Gtk::RESPONSE_NONE, false); + set_response_sensitive (Gtk::RESPONSE_NONE, false); } } diff --git a/gtk2_ardour/new_session_dialog.h b/gtk2_ardour/new_session_dialog.h index 366805d31f..5d652fd122 100644 --- a/gtk2_ardour/new_session_dialog.h +++ b/gtk2_ardour/new_session_dialog.h @@ -182,6 +182,8 @@ protected: void master_bus_button_clicked (); void monitor_bus_button_clicked (); + bool on_new_session_page; + }; diff --git a/gtk2_ardour/opts.cc b/gtk2_ardour/opts.cc index 69b8128824..fcd62de512 100644 --- a/gtk2_ardour/opts.cc +++ b/gtk2_ardour/opts.cc @@ -143,14 +143,19 @@ GTK_ARDOUR::parse_opts (int argc, char *argv[]) break; default: - break; + return print_help(execname); } } if (optind < argc) { + if (new_session) { + cerr << "Illogical combination: you can either create a new session, or a load an existing session but not both!" << endl; + return print_help(execname); + } session_name = argv[optind++]; } + return 0; } diff --git a/gtk2_ardour/pan_automation_time_axis.cc b/gtk2_ardour/pan_automation_time_axis.cc index fcef6f812c..ec884151b5 100644 --- a/gtk2_ardour/pan_automation_time_axis.cc +++ b/gtk2_ardour/pan_automation_time_axis.cc @@ -23,10 +23,12 @@ #include #include +#include #include "pan_automation_time_axis.h" #include "automation_line.h" #include "canvas_impl.h" +#include "route_ui.h" #include "i18n.h" @@ -42,7 +44,7 @@ PanAutomationTimeAxisView::PanAutomationTimeAxisView (Session& s, boost::shared_ { multiline_selector.set_name ("PanAutomationLineSelector"); - controls_table.attach (multiline_selector, 1, 5, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (multiline_selector, 1, 5, 1, 2, Gtk::EXPAND, Gtk::EXPAND); } PanAutomationTimeAxisView::~PanAutomationTimeAxisView () @@ -87,9 +89,10 @@ PanAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEv AutomationList& alist (lines[line_index]->the_list()); _session.begin_reversible_command (_("add pan automation event")); - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); alist.add (when, y); - _session.add_redo_no_execute (alist.get_memento()); + XMLNode &after = alist.get_state(); + _session.add_command(new MementoCommand(alist, before, after)); _session.commit_reversible_command (); _session.set_dirty (); } @@ -105,15 +108,18 @@ void PanAutomationTimeAxisView::add_line (AutomationLine& line) { char buf[32]; - snprintf(buf,32,"Line %ld",lines.size()+1); + snprintf(buf,32,"Line %zu",lines.size()+1); multiline_selector.append_text(buf); if (lines.empty()) { multiline_selector.set_active(0); } - if (lines.size() + 1 > 1) { + if (lines.size() + 1 > 1 && (height_style != Small && height_style != Smaller)) { multiline_selector.show(); + } else { + multiline_selector.hide(); + } AutomationTimeAxisView::add_line(line); @@ -129,9 +135,10 @@ PanAutomationTimeAxisView::set_height (TimeAxisView::TrackHeight th) case Large: case Larger: case Normal: - multiline_selector.show(); - break; - + if (lines.size() > 1) { + multiline_selector.show(); + break; + } default: multiline_selector.hide(); } diff --git a/gtk2_ardour/plugin_selector.cc b/gtk2_ardour/plugin_selector.cc index a34533ade9..e0a62b177f 100644 --- a/gtk2_ardour/plugin_selector.cc +++ b/gtk2_ardour/plugin_selector.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -48,8 +48,6 @@ PluginSelector::PluginSelector (PluginManager *mgr) manager = mgr; session = 0; - o_selected_plug = -1; - i_selected_plug = 0; current_selection = PluginInfo::LADSPA; @@ -305,7 +303,7 @@ void PluginSelector::au_refiller () { guint row; - PluginInfoList &plugs = manager->au_plugin_info (); + PluginInfoList plugs (AUPluginInfo::discover ()); PluginInfoList::iterator i; char ibuf[16], obuf[16]; aumodel->clear(); @@ -346,7 +344,7 @@ PluginSelector::use_plugin (PluginInfoPtr pi) return; } - boost::shared_ptr plugin = manager->load (*session, pi); + PluginPtr plugin = pi->load (*session); if (plugin) { PluginCreated (plugin); diff --git a/gtk2_ardour/plugin_selector.h b/gtk2_ardour/plugin_selector.h index 06c2f1d18e..583506972a 100644 --- a/gtk2_ardour/plugin_selector.h +++ b/gtk2_ardour/plugin_selector.h @@ -30,7 +30,6 @@ namespace ARDOUR { class Session; class PluginManager; - class PluginInfo; } class PluginSelector : public ArdourDialog @@ -134,12 +133,6 @@ class PluginSelector : public ArdourDialog void au_display_selection_changed(); #endif //HAVE_COREAUDIO - ARDOUR::PluginInfo* i_selected_plug; - - // We need an integer for the output side because - // the name isn't promised to be unique. - gint o_selected_plug; - ARDOUR::PluginManager *manager; static void _input_refiller (void *); diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc index beddad4e16..edc94864f2 100644 --- a/gtk2_ardour/plugin_ui.cc +++ b/gtk2_ardour/plugin_ui.cc @@ -90,13 +90,13 @@ PluginUIWindow::PluginUIWindow (AudioEngine &engine, boost::shared_ptradd (*pu); - signal_map_event().connect (mem_fun (*pu, &PluginUI::start_updating)); - signal_unmap_event().connect (mem_fun (*pu, &PluginUI::stop_updating)); + signal_map_event().connect (mem_fun (*pu, &LadspaPluginUI::start_updating)); + signal_unmap_event().connect (mem_fun (*pu, &LadspaPluginUI::stop_updating)); } set_position (Gtk::WIN_POS_MOUSE); @@ -117,7 +117,7 @@ PluginUIWindow::~PluginUIWindow () { } -PluginUI::PluginUI (AudioEngine &engine, boost::shared_ptr pi, bool scrollable) +LadspaPluginUI::LadspaPluginUI (AudioEngine &engine, boost::shared_ptr pi, bool scrollable) : PlugUIBase (pi), engine(engine), button_table (initial_button_rows, initial_button_cols), @@ -165,13 +165,13 @@ PluginUI::PluginUI (AudioEngine &engine, boost::shared_ptr pi, boo pack_start (hpacker, false, false); } - insert->active_changed.connect (mem_fun(*this, &PluginUI::redirect_active_changed)); + insert->active_changed.connect (mem_fun(*this, &LadspaPluginUI::redirect_active_changed)); bypass_button.set_active (!insert->active()); build (engine); } -PluginUI::~PluginUI () +LadspaPluginUI::~LadspaPluginUI () { if (output_controls.size() > 0) { screen_update_connection.disconnect(); @@ -179,7 +179,7 @@ PluginUI::~PluginUI () } void -PluginUI::build (AudioEngine &engine) +LadspaPluginUI::build (AudioEngine &engine) { guint32 i = 0; @@ -326,8 +326,8 @@ PluginUI::build (AudioEngine &engine) } } - n_ins = plugin->get_info().n_inputs; - n_outs = plugin->get_info().n_outputs; + n_ins = plugin->get_info()->n_inputs; + n_outs = plugin->get_info()->n_outputs; if (box->children().empty()) { hpacker.remove (*frame); @@ -350,7 +350,7 @@ PluginUI::build (AudioEngine &engine) button_table.show_all (); } -PluginUI::ControlUI::ControlUI () +LadspaPluginUI::ControlUI::ControlUI () : automate_button (X_("")) // force creation of a label { automate_button.set_name ("PluginAutomateButton"); @@ -370,7 +370,7 @@ PluginUI::ControlUI::ControlUI () meterinfo = 0; } -PluginUI::ControlUI::~ControlUI() +LadspaPluginUI::ControlUI::~ControlUI() { if (adjustment) { delete adjustment; @@ -383,7 +383,7 @@ PluginUI::ControlUI::~ControlUI() } void -PluginUI::automation_state_changed (ControlUI* cui) +LadspaPluginUI::automation_state_changed (ControlUI* cui) { /* update button label */ @@ -413,13 +413,13 @@ static void integer_printer (char buf[32], Adjustment &adj, void *arg) } void -PluginUI::print_parameter (char *buf, uint32_t len, uint32_t param) +LadspaPluginUI::print_parameter (char *buf, uint32_t len, uint32_t param) { plugin->print_parameter (param, buf, len); } -PluginUI::ControlUI* -PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Controllable* mcontrol) +LadspaPluginUI::ControlUI* +LadspaPluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Controllable* mcontrol) { ControlUI* control_ui; @@ -452,8 +452,8 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Contro control_ui->combo = new Gtk::ComboBoxText; //control_ui->combo->set_value_in_list(true, false); set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui)); - control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &PluginUI::control_combo_changed), control_ui)); - plugin->ParameterChanged.connect (bind (mem_fun (*this, &PluginUI::parameter_changed), control_ui)); + control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &LadspaPluginUI::control_combo_changed), control_ui)); + plugin->ParameterChanged.connect (bind (mem_fun (*this, &LadspaPluginUI::parameter_changed), control_ui)); control_ui->pack_start(control_ui->label, true, true); control_ui->pack_start(*control_ui->combo, false, true); @@ -476,7 +476,7 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Contro control_ui->pack_start (*control_ui->button, false, true); control_ui->pack_start (control_ui->automate_button, false, false); - control_ui->button->signal_clicked().connect (bind (mem_fun(*this, &PluginUI::control_port_toggled), control_ui)); + control_ui->button->signal_clicked().connect (bind (mem_fun(*this, &LadspaPluginUI::control_port_toggled), control_ui)); if(plugin->get_parameter (port_index) == 1){ control_ui->button->set_active(true); @@ -514,7 +514,7 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Contro Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->clickbox, "g9999999", 2, 2); control_ui->clickbox->set_print_func (integer_printer, 0); } else { - sigc::slot pslot = sigc::bind (mem_fun(*this, &PluginUI::print_parameter), (uint32_t) port_index); + sigc::slot pslot = sigc::bind (mem_fun(*this, &LadspaPluginUI::print_parameter), (uint32_t) port_index); control_ui->control = new BarController (*control_ui->adjustment, *mcontrol, pslot); // should really match the height of the text in the automation button+label @@ -523,8 +523,8 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Contro control_ui->control->set_style (BarController::LeftToRight); control_ui->control->set_use_parent (true); - control_ui->control->StartGesture.connect (bind (mem_fun(*this, &PluginUI::start_touch), control_ui)); - control_ui->control->StopGesture.connect (bind (mem_fun(*this, &PluginUI::stop_touch), control_ui)); + control_ui->control->StartGesture.connect (bind (mem_fun(*this, &LadspaPluginUI::start_touch), control_ui)); + control_ui->control->StopGesture.connect (bind (mem_fun(*this, &LadspaPluginUI::stop_touch), control_ui)); } @@ -547,14 +547,14 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Contro } control_ui->pack_start (control_ui->automate_button, false, false); - control_ui->adjustment->signal_value_changed().connect (bind (mem_fun(*this, &PluginUI::control_adjustment_changed), control_ui)); - control_ui->automate_button.signal_clicked().connect (bind (mem_fun(*this, &PluginUI::astate_clicked), control_ui, (uint32_t) port_index)); + control_ui->adjustment->signal_value_changed().connect (bind (mem_fun(*this, &LadspaPluginUI::control_adjustment_changed), control_ui)); + control_ui->automate_button.signal_clicked().connect (bind (mem_fun(*this, &LadspaPluginUI::astate_clicked), control_ui, (uint32_t) port_index)); automation_state_changed (control_ui); - plugin->ParameterChanged.connect (bind (mem_fun(*this, &PluginUI::parameter_changed), control_ui)); + plugin->ParameterChanged.connect (bind (mem_fun(*this, &LadspaPluginUI::parameter_changed), control_ui)); insert->automation_list (port_index).automation_state_changed.connect - (bind (mem_fun(*this, &PluginUI::automation_state_changed), control_ui)); + (bind (mem_fun(*this, &LadspaPluginUI::automation_state_changed), control_ui)); } else if (plugin->parameter_is_output (port_index)) { @@ -603,24 +603,24 @@ PluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Contro output_controls.push_back (control_ui); } - plugin->ParameterChanged.connect (bind (mem_fun(*this, &PluginUI::parameter_changed), control_ui)); + plugin->ParameterChanged.connect (bind (mem_fun(*this, &LadspaPluginUI::parameter_changed), control_ui)); return control_ui; } void -PluginUI::start_touch (PluginUI::ControlUI* cui) +LadspaPluginUI::start_touch (LadspaPluginUI::ControlUI* cui) { insert->automation_list (cui->port_index).start_touch (); } void -PluginUI::stop_touch (PluginUI::ControlUI* cui) +LadspaPluginUI::stop_touch (LadspaPluginUI::ControlUI* cui) { insert->automation_list (cui->port_index).stop_touch (); } void -PluginUI::astate_clicked (ControlUI* cui, uint32_t port) +LadspaPluginUI::astate_clicked (ControlUI* cui, uint32_t port) { using namespace Menu_Helpers; @@ -633,25 +633,25 @@ PluginUI::astate_clicked (ControlUI* cui, uint32_t port) items.clear (); items.push_back (MenuElem (_("Off"), - bind (mem_fun(*this, &PluginUI::set_automation_state), (AutoState) Off, cui))); + bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Off, cui))); items.push_back (MenuElem (_("Play"), - bind (mem_fun(*this, &PluginUI::set_automation_state), (AutoState) Play, cui))); + bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Play, cui))); items.push_back (MenuElem (_("Write"), - bind (mem_fun(*this, &PluginUI::set_automation_state), (AutoState) Write, cui))); + bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Write, cui))); items.push_back (MenuElem (_("Touch"), - bind (mem_fun(*this, &PluginUI::set_automation_state), (AutoState) Touch, cui))); + bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Touch, cui))); automation_menu->popup (1, 0); } void -PluginUI::set_automation_state (AutoState state, ControlUI* cui) +LadspaPluginUI::set_automation_state (AutoState state, ControlUI* cui) { insert->set_port_automation_state (cui->port_index, state); } void -PluginUI::control_adjustment_changed (ControlUI* cui) +LadspaPluginUI::control_adjustment_changed (ControlUI* cui) { if (cui->ignore_change) { return; @@ -667,18 +667,18 @@ PluginUI::control_adjustment_changed (ControlUI* cui) } void -PluginUI::parameter_changed (uint32_t abs_port_id, float val, ControlUI* cui) +LadspaPluginUI::parameter_changed (uint32_t abs_port_id, float val, ControlUI* cui) { if (cui->port_index == abs_port_id) { if (!cui->update_pending) { cui->update_pending = true; - Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &PluginUI::update_control_display), cui)); + Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &LadspaPluginUI::update_control_display), cui)); } } } void -PluginUI::update_control_display (ControlUI* cui) +LadspaPluginUI::update_control_display (ControlUI* cui) { /* XXX how do we handle logarithmic stuff here ? */ @@ -715,7 +715,7 @@ PluginUI::update_control_display (ControlUI* cui) } void -PluginUI::control_port_toggled (ControlUI* cui) +LadspaPluginUI::control_port_toggled (ControlUI* cui) { if (!cui->ignore_change) { insert->set_parameter (cui->port_index, cui->button->get_active()); @@ -723,7 +723,7 @@ PluginUI::control_port_toggled (ControlUI* cui) } void -PluginUI::control_combo_changed (ControlUI* cui) +LadspaPluginUI::control_combo_changed (ControlUI* cui) { if (!cui->ignore_change) { string value = cui->combo->get_active_text(); @@ -743,26 +743,26 @@ PluginUIWindow::plugin_going_away (ARDOUR::Redirect* ignored) } void -PluginUI::redirect_active_changed (Redirect* r, void* src) +LadspaPluginUI::redirect_active_changed (Redirect* r, void* src) { - ENSURE_GUI_THREAD(bind (mem_fun(*this, &PluginUI::redirect_active_changed), r, src)); + ENSURE_GUI_THREAD(bind (mem_fun(*this, &LadspaPluginUI::redirect_active_changed), r, src)); bypass_button.set_active (!r->active()); } bool -PluginUI::start_updating (GdkEventAny* ignored) +LadspaPluginUI::start_updating (GdkEventAny* ignored) { if (output_controls.size() > 0 ) { screen_update_connection.disconnect(); screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect - (mem_fun(*this, &PluginUI::output_update)); + (mem_fun(*this, &LadspaPluginUI::output_update)); } return false; } bool -PluginUI::stop_updating (GdkEventAny* ignored) +LadspaPluginUI::stop_updating (GdkEventAny* ignored) { if (output_controls.size() > 0 ) { screen_update_connection.disconnect(); @@ -771,7 +771,7 @@ PluginUI::stop_updating (GdkEventAny* ignored) } void -PluginUI::output_update () +LadspaPluginUI::output_update () { for (vector::iterator i = output_controls.begin(); i != output_controls.end(); ++i) { float val = plugin->get_parameter ((*i)->port_index); @@ -805,7 +805,7 @@ PluginUI::output_update () } vector -PluginUI::setup_scale_values(guint32 port_index, ControlUI* cui) +LadspaPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui) { vector enums; boost::shared_ptr lp = boost::dynamic_pointer_cast (plugin); diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h index 570a224b66..dc1e61887b 100644 --- a/gtk2_ardour/plugin_ui.h +++ b/gtk2_ardour/plugin_ui.h @@ -50,6 +50,7 @@ namespace ARDOUR { class Plugin; class VSTPlugin; class Redirect; + class AUPlugin; } namespace PBD { @@ -86,11 +87,11 @@ class PlugUIBase : public virtual sigc::trackable void bypass_toggled(); }; -class PluginUI : public PlugUIBase, public Gtk::VBox +class LadspaPluginUI : public PlugUIBase, public Gtk::VBox { public: - PluginUI (ARDOUR::AudioEngine &, boost::shared_ptr plug, bool scrollable=false); - ~PluginUI (); + LadspaPluginUI (ARDOUR::AudioEngine &, boost::shared_ptr plug, bool scrollable=false); + ~LadspaPluginUI (); gint get_preferred_height () { return prefheight; } @@ -231,6 +232,22 @@ class VSTPluginUI : public PlugUIBase, public Gtk::VBox bool configure_handler (GdkEventConfigure*, Gtk::Socket*); void save_plugin_setting (); }; -#endif +#endif // VST_SUPPORT + +#ifdef HAVE_COREAUDIO +class AUPluginUI : public PlugUIBase +{ + public: + AUPluginUI (boost::shared_ptr, boost::shared_ptr); + ~AUPluginUI (); + + gint get_preferred_height (); + bool start_updating(GdkEventAny*) {return false;} + bool stop_updating(GdkEventAny*) {return false;} + + private: + boost::shared_ptr au; +}; +#endif // HAVE_COREAUDIO #endif /* __ardour_plugin_ui_h__ */ diff --git a/gtk2_ardour/redirect_automation_time_axis.cc b/gtk2_ardour/redirect_automation_time_axis.cc index a53c1a20e4..e527fd1d5e 100644 --- a/gtk2_ardour/redirect_automation_time_axis.cc +++ b/gtk2_ardour/redirect_automation_time_axis.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "redirect_automation_time_axis.h" #include "automation_line.h" @@ -98,9 +99,10 @@ RedirectAutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, lines.front()->view_to_model_y (y); _session.begin_reversible_command (description); - _session.add_undo (alist.get_memento()); + XMLNode &before = alist.get_state(); alist.add (when, y); - _session.add_redo_no_execute (alist.get_memento()); + XMLNode &after = alist.get_state(); + _session.add_command(new MementoCommand(alist, before, after)); _session.commit_reversible_command (); _session.set_dirty (); } diff --git a/gtk2_ardour/redirect_box.cc b/gtk2_ardour/redirect_box.cc index 0455dfdeb4..74198265d9 100644 --- a/gtk2_ardour/redirect_box.cc +++ b/gtk2_ardour/redirect_box.cc @@ -378,7 +378,7 @@ RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr /* i hate this kind of code */ - if (streams > p.get_info().n_inputs) { + if (streams > p.get_info()->n_inputs) { label.set_text (string_compose (_( "You attempted to add a plugin (%1).\n" "The plugin has %2 inputs\n" @@ -388,9 +388,9 @@ RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr "This makes no sense - you are throwing away\n" "part of the signal."), p.name(), - p.get_info().n_inputs, + p.get_info()->n_inputs, streams)); - } else if (streams < p.get_info().n_inputs) { + } else if (streams < p.get_info()->n_inputs) { label.set_text (string_compose (_( "You attempted to add a plugin (%1).\n" "The plugin has %2 inputs\n" @@ -401,7 +401,7 @@ RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr "side-chain inputs. A future version of Ardour will\n" "support this type of configuration."), p.name(), - p.get_info().n_inputs, + p.get_info()->n_inputs, streams)); } else { label.set_text (string_compose (_( @@ -415,8 +415,8 @@ RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, boost::shared_ptr "\n" "Ardour does not understand what to do in such situations.\n"), p.name(), - p.get_info().n_inputs, - p.get_info().n_outputs, + p.get_info()->n_inputs, + p.get_info()->n_outputs, io->n_inputs(), io->n_outputs(), streams)); diff --git a/gtk2_ardour/region_editor.h b/gtk2_ardour/region_editor.h index 176ced0792..70590b0db5 100644 --- a/gtk2_ardour/region_editor.h +++ b/gtk2_ardour/region_editor.h @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: region_editor.h 231 2006-01-03 14:16:27Z karstenweise $ + $Id: /local/undo/gtk2_ardour/region_editor.h 5 2006-05-31T02:48:48.738745Z paul $ */ #ifndef __gtk_ardour_region_edit_h__ diff --git a/gtk2_ardour/region_gain_line.cc b/gtk2_ardour/region_gain_line.cc index a542be054e..0a4a3d29ea 100644 --- a/gtk2_ardour/region_gain_line.cc +++ b/gtk2_ardour/region_gain_line.cc @@ -1,5 +1,6 @@ #include #include +#include #include "region_gain_line.h" #include "audio_region_view.h" @@ -47,7 +48,8 @@ AudioRegionGainLine::start_drag (ControlPoint* cp, float fraction) { AutomationLine::start_drag(cp,fraction); if (!rv.audio_region().envelope_active()) { - trackview.session().add_undo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), false) ); + trackview.session().add_command(new MementoUndoCommand(rv.audio_region(), rv.audio_region().get_state())); + rv.audio_region().set_envelope_active(false); } } @@ -60,17 +62,18 @@ AudioRegionGainLine::remove_point (ControlPoint& cp) model_representation (cp, mr); trackview.editor.current_session()->begin_reversible_command (_("remove control point")); - trackview.editor.current_session()->add_undo (get_memento()); + XMLNode &before = get_state(); if (!rv.audio_region().envelope_active()) { - trackview.session().add_undo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), false) ); - trackview.session().add_redo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), true) ); + XMLNode &before = rv.audio_region().get_state(); rv.audio_region().set_envelope_active(true); + XMLNode &after = rv.audio_region().get_state(); + trackview.session().add_command(new MementoCommand(rv.audio_region(), before, after)); } alist.erase (mr.start, mr.end); - trackview.editor.current_session()->add_redo_no_execute (get_memento()); + trackview.editor.current_session()->add_command (new MementoCommand(*this, before, get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -79,8 +82,8 @@ void AudioRegionGainLine::end_drag (ControlPoint* cp) { if (!rv.audio_region().envelope_active()) { - trackview.session().add_redo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), true) ); rv.audio_region().set_envelope_active(true); + trackview.session().add_command(new MementoRedoCommand(rv.audio_region(), rv.audio_region().get_state())); } AutomationLine::end_drag(cp); } diff --git a/gtk2_ardour/region_gain_line.h b/gtk2_ardour/region_gain_line.h index bf6de0d810..02340c8bae 100644 --- a/gtk2_ardour/region_gain_line.h +++ b/gtk2_ardour/region_gain_line.h @@ -26,6 +26,7 @@ class AudioRegionGainLine : public AutomationLine void remove_point (ControlPoint&); + PBD::ID id() { return _id; } private: @@ -33,6 +34,8 @@ class AudioRegionGainLine : public AutomationLine AudioRegionView& rv; UndoAction get_memento(); + + PBD::ID _id; }; diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc index 8b47a17511..86ac1e035e 100644 --- a/gtk2_ardour/route_params_ui.cc +++ b/gtk2_ardour/route_params_ui.cc @@ -287,9 +287,9 @@ void RouteParams_UI::cleanup_pre_view (bool stopupdate) { if (_active_pre_view) { - PluginUI * plugui = 0; + LadspaPluginUI * plugui = 0; - if (stopupdate && (plugui = dynamic_cast(_active_pre_view)) != 0) { + if (stopupdate && (plugui = dynamic_cast(_active_pre_view)) != 0) { plugui->stop_updating (0); } @@ -304,9 +304,9 @@ void RouteParams_UI::cleanup_post_view (bool stopupdate) { if (_active_post_view) { - PluginUI * plugui = 0; + LadspaPluginUI * plugui = 0; - if (stopupdate && (plugui = dynamic_cast(_active_post_view)) != 0) { + if (stopupdate && (plugui = dynamic_cast(_active_post_view)) != 0) { plugui->stop_updating (0); } _post_plugin_conn.disconnect(); @@ -556,7 +556,7 @@ RouteParams_UI::redirect_selected (boost::shared_ptr redirect, if ((plugin_insert = boost::dynamic_pointer_cast (insert)) != 0) { - PluginUI *plugin_ui = new PluginUI (session->engine(), plugin_insert, true); + LadspaPluginUI *plugin_ui = new LadspaPluginUI (session->engine(), plugin_insert, true); if (place == PreFader) { cleanup_pre_view(); diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index cb9883b8e6..82d5b53cba 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -575,46 +576,88 @@ RouteTimeAxisView::set_height (TrackHeight h) switch (height_style) { case Largest: xml_node->add_property ("track_height", "largest"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); break; + case Large: xml_node->add_property ("track_height", "large"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); break; + case Larger: xml_node->add_property ("track_height", "larger"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); break; + case Normal: xml_node->add_property ("track_height", "normal"); + break; + + case Smaller: + xml_node->add_property ("track_height", "smaller"); + break; + + case Small: + xml_node->add_property ("track_height", "small"); + break; + } + + switch (height_style) { + case Largest: + case Large: + case Larger: + case Normal: show_name_entry (); hide_name_label (); - controls_table.show_all(); + + mute_button->show_all(); + solo_button->show_all(); + if (rec_enable_button) + rec_enable_button->show_all(); + + edit_group_button.show_all(); + hide_button.show_all(); + visual_button.show_all(); + size_button.show_all(); + automation_button.show_all(); + + if (is_track() && track()->mode() == ARDOUR::Normal) { + playlist_button.show_all(); + } break; + case Smaller: - xml_node->add_property ("track_height", "smaller"); - controls_table.show_all (); show_name_entry (); hide_name_label (); + + mute_button->show_all(); + solo_button->show_all(); + if (rec_enable_button) + rec_enable_button->show_all(); + edit_group_button.hide (); hide_button.hide (); visual_button.hide (); size_button.hide (); automation_button.hide (); - playlist_button.hide (); + + if (is_track() && track()->mode() == ARDOUR::Normal) { + playlist_button.hide (); + } break; + case Small: - xml_node->add_property ("track_height", "small"); - controls_table.hide_all (); - controls_table.show (); hide_name_entry (); show_name_label (); + + mute_button->hide(); + solo_button->hide(); + if (rec_enable_button) + rec_enable_button->hide(); + + edit_group_button.hide (); + hide_button.hide (); + visual_button.hide (); + size_button.hide (); + automation_button.hide (); + playlist_button.hide (); name_label.set_text (_route->name()); break; } @@ -1008,12 +1051,12 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) } } + XMLNode &before = playlist->get_state(); switch (op) { case Cut: - _session.add_undo (playlist->get_memento()); if ((what_we_got = playlist->cut (time)) != 0) { editor.get_cut_buffer().add (what_we_got); - _session.add_redo_no_execute (playlist->get_memento()); + _session.add_command( new MementoCommand(*playlist, before, playlist->get_state())); ret = true; } break; @@ -1024,9 +1067,8 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) break; case Clear: - _session.add_undo (playlist->get_memento()); if ((what_we_got = playlist->cut (time)) != 0) { - _session.add_redo_no_execute (playlist->get_memento()); + _session.add_command( new MementoCommand(*playlist, before, playlist->get_state())); what_we_got->unref (); ret = true; } @@ -1055,9 +1097,9 @@ RouteTimeAxisView::paste (jack_nframes_t pos, float times, Selection& selection, if (get_diskstream()->speed() != 1.0f) pos = session_frame_to_track_frame(pos, get_diskstream()->speed() ); - _session.add_undo (playlist->get_memento()); + XMLNode &before = playlist->get_state(); playlist->paste (**p, pos, times); - _session.add_redo_no_execute (playlist->get_memento()); + _session.add_command( new MementoCommand(*playlist, before, playlist->get_state())); return true; } diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index f4b602d39c..e90355fd0a 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -25,6 +25,7 @@ #include #include +#include #include "route_ui.h" #include "keyboard.h" @@ -130,9 +131,10 @@ RouteUI::mute_press(GdkEventButton* ev) /* ctrl-shift-click applies change to all routes */ _session.begin_reversible_command (_("mute change")); - _session.add_undo (_session.global_mute_memento(this)); + Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this); _session.set_all_mute (!_route->muted()); - _session.add_redo_no_execute (_session.global_mute_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { @@ -205,9 +207,10 @@ RouteUI::solo_press(GdkEventButton* ev) /* ctrl-shift-click applies change to all routes */ _session.begin_reversible_command (_("solo change")); - _session.add_undo (_session.global_solo_memento(this)); + Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this); _session.set_all_solo (!_route->soloed()); - _session.add_redo_no_execute (_session.global_solo_memento(this)); + cmd->mark(); + _session.add_command (cmd); _session.commit_reversible_command (); } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) { @@ -215,10 +218,11 @@ RouteUI::solo_press(GdkEventButton* ev) // ctrl-alt-click: exclusively solo this track, not a toggle */ _session.begin_reversible_command (_("solo change")); - _session.add_undo (_session.global_solo_memento(this)); + Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this); _session.set_all_solo (false); _route->set_solo (true, this); - _session.add_redo_no_execute (_session.global_solo_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) { @@ -278,7 +282,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev) else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) { _session.begin_reversible_command (_("rec-enable change")); - _session.add_undo (_session.global_record_enable_memento(this)); + Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this); if (rec_enable_button->get_active()) { _session.record_disenable_all (); @@ -286,7 +290,8 @@ RouteUI::rec_enable_press(GdkEventButton* ev) _session.record_enable_all (); } - _session.add_redo_no_execute (_session.global_record_enable_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { @@ -555,9 +560,10 @@ RouteUI::set_mix_group_solo(boost::shared_ptr route, bool yn) if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group solo change")); - _session.add_undo (_session.global_solo_memento (this)); + Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this); mix_group->apply(&Route::set_solo, yn, this); - _session.add_redo_no_execute (_session.global_solo_memento(this)); + cmd->mark(); + _session.add_command (cmd); _session.commit_reversible_command (); } else { reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this); @@ -568,8 +574,10 @@ void RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg) { _session.begin_reversible_command (name); - _session.add_undo (bind (mem_fun (*_route, func), !yn, (void *) arg)); - _session.add_redo (bind (mem_fun (*_route, func), yn, (void *) arg)); + XMLNode &before = _route->get_state(); + bind(mem_fun(*_route, func), yn, arg)(); + XMLNode &after = _route->get_state(); + _session.add_command (new MementoCommand(*_route, before, after)); _session.commit_reversible_command (); } @@ -577,8 +585,10 @@ void RouteUI::reversibly_apply_audio_track_boolean (string name, void (AudioTrack::*func)(bool, void *), bool yn, void *arg) { _session.begin_reversible_command (name); - _session.add_undo (bind (mem_fun (*audio_track(), func), !yn, (void *) arg)); - _session.add_redo (bind (mem_fun (*audio_track(), func), yn, (void *) arg)); + XMLNode &before = audio_track()->get_state(); + bind (mem_fun (*audio_track(), func), yn, arg)(); + XMLNode &after = audio_track()->get_state(); + _session.add_command (new MementoCommand(*audio_track(), before, after)); _session.commit_reversible_command (); } @@ -589,9 +599,10 @@ RouteUI::set_mix_group_mute(boost::shared_ptr route, bool yn) if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group mute change")); - _session.add_undo (_session.global_mute_memento (this)); + Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this); mix_group->apply(&Route::set_mute, yn, this); - _session.add_redo_no_execute (_session.global_mute_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else { reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this); @@ -605,9 +616,10 @@ RouteUI::set_mix_group_rec_enable(boost::shared_ptr route, bool yn) if((mix_group = route->mix_group()) != 0){ _session.begin_reversible_command (_("mix group rec-enable change")); - _session.add_undo (_session.global_record_enable_memento (this)); + Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this); mix_group->apply (&Route::set_record_enable, yn, this); - _session.add_redo_no_execute (_session.global_record_enable_memento(this)); + cmd->mark(); + _session.add_command(cmd); _session.commit_reversible_command (); } else { reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this); diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index 842d4046d8..2e1f3c5273 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -128,6 +128,7 @@ TimeAxisView::TimeAxisView (ARDOUR::Session& sess, PublicEditor& ed, TimeAxisVie controls_table.attach (name_hbox, 0, 4, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); controls_table.show_all (); + controls_table.set_no_show_all (); controls_vbox.pack_start (controls_table, false, false); controls_vbox.show (); diff --git a/gtk2_ardour/vst_pluginui.cc b/gtk2_ardour/vst_pluginui.cc index 7adf702f4d..5e65475c46 100644 --- a/gtk2_ardour/vst_pluginui.cc +++ b/gtk2_ardour/vst_pluginui.cc @@ -31,17 +31,17 @@ using namespace Gtk; using namespace ARDOUR; using namespace PBD; -VSTPluginUI::VSTPluginUI (PluginInsert& pi, VSTPlugin& vp) +VSTPluginUI::VSTPluginUI (boost::shared_ptr pi, boost::shared_ptr vp) : PlugUIBase (pi), vst (vp) { - fst_run_editor (vst.fst()); + fst_run_editor (vst->fst()); preset_box.pack_end (bypass_button, false, false, 10); preset_box.pack_end (save_button, false, false); preset_box.pack_end (combo, false, false); - bypass_button.set_active (!insert.active()); + bypass_button.set_active (!insert->active()); pack_start (preset_box, false, false); pack_start (socket, true, true); @@ -55,7 +55,7 @@ VSTPluginUI::~VSTPluginUI () int VSTPluginUI::get_preferred_height () { - return vst.fst()->height; + return vst->fst()->height; } int @@ -69,7 +69,7 @@ VSTPluginUI::package (Gtk::Window& win) this assumes that the window's owner understands the XEmbed protocol. */ - socket.add_id (fst_get_XID (vst.fst())); + socket.add_id (fst_get_XID (vst->fst())); return 0; } diff --git a/libs/appleutility/AUOutputBL.cpp b/libs/appleutility/AUOutputBL.cpp new file mode 100644 index 0000000000..8509f46288 --- /dev/null +++ b/libs/appleutility/AUOutputBL.cpp @@ -0,0 +1,160 @@ +/* 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. +*/ +/*============================================================================= + AUOutputBL.h + +=============================================================================*/ +#include "AUOutputBL.h" + +/* +struct AudioBufferList +{ + UInt32 mNumberBuffers; + AudioBuffer mBuffers[1]; +}; +struct AudioBuffer +{ + UInt32 mNumberChannels; // number of interleaved channels in the buffer + UInt32 mDataByteSize; // the size of the buffer pointed to by mData + void* mData; // the pointer to the buffer +}; +*/ + +AUOutputBL::AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames) + : mFormat (inDesc), + mBufferMemory(NULL), + mBufferList (NULL), + mNumberBuffers (0), // keep this here, so can ensure integrity of ABL + mBufferSize (0), + mFrames(inDefaultNumFrames) +{ + mNumberBuffers = mFormat.IsInterleaved() ? 1 : mFormat.NumberChannels(); + mBufferList = reinterpret_cast(new Byte[sizeof(UInt32) + (mNumberBuffers * sizeof(AudioBuffer))]); +} + +AUOutputBL::~AUOutputBL() +{ + if (mBufferMemory) + delete[] mBufferMemory; + + if (mBufferList) + delete [] mBufferList; +} + +void AUOutputBL::Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated) +{ + UInt32 channelsPerBuffer = mFormat.IsInterleaved() ? mFormat.NumberChannels() : 1; + + if (mBufferMemory == NULL || inWantNullBufferIfAllocated) + { + mBufferList->mNumberBuffers = mNumberBuffers; + AudioBuffer *buf = &mBufferList->mBuffers[0]; + for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) { + buf->mNumberChannels = channelsPerBuffer; + buf->mDataByteSize = mFormat.FramesToBytes (inNumFrames); + buf->mData = NULL; + } + } + else + { + UInt32 nBytes = mFormat.FramesToBytes (inNumFrames); + if ((nBytes * mNumberBuffers) > AllocatedBytes()) + throw OSStatus(-10874);//(kAudioUnitErr_TooManyFramesToProcess); + + mBufferList->mNumberBuffers = mNumberBuffers; + AudioBuffer *buf = &mBufferList->mBuffers[0]; + Byte* p = mBufferMemory; + for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) { + buf->mNumberChannels = channelsPerBuffer; + buf->mDataByteSize = nBytes; + buf->mData = p; + p += mBufferSize; + } + } +} + + +void AUOutputBL::Allocate (UInt32 inNumFrames) +{ + if (inNumFrames) + { + UInt32 nBytes = mFormat.FramesToBytes (inNumFrames); + + if (nBytes <= AllocatedBytes()) + return; + + // align successive buffers for Altivec and to take alternating + // cache line hits by spacing them by odd multiples of 16 + if (mNumberBuffers > 1) + nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10; + + mBufferSize = nBytes; + + UInt32 memorySize = mBufferSize * mNumberBuffers; + Byte *newMemory = new Byte[memorySize]; + memset(newMemory, 0, memorySize); // make buffer "hot" + + Byte *oldMemory = mBufferMemory; + mBufferMemory = newMemory; + delete[] oldMemory; + + mFrames = inNumFrames; + } + else + { + if (mBufferMemory) { + delete [] mBufferMemory; + mBufferMemory = NULL; + } + mBufferSize = 0; + mFrames = 0; + } +} + +#if DEBUG +void AUOutputBL::Print() +{ + printf ("AUOutputBL::Print\n"); + mFormat.Print(); + printf ("Num Buffers:%ld, mFrames:%ld, allocatedMemory:%c\n", mBufferList->mNumberBuffers, mFrames, (mBufferMemory != NULL ? 'T' : 'F')); + AudioBuffer *buf = &mBufferList->mBuffers[0]; + for (UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i, ++buf) + printf ("\tBuffer:%ld, Size:%ld, Chans:%ld, Buffer:%X\n", i, buf->mDataByteSize, buf->mNumberChannels, int(buf->mData)); +} +#endif + diff --git a/libs/appleutility/AUOutputBL.h b/libs/appleutility/AUOutputBL.h new file mode 100644 index 0000000000..b80588abac --- /dev/null +++ b/libs/appleutility/AUOutputBL.h @@ -0,0 +1,115 @@ +/* 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. +*/ +/*============================================================================= + AUOutputBL.h + +=============================================================================*/ + +#ifndef __AUOutputBL_h__ +#define __AUOutputBL_h__ + +#include "CAStreamBasicDescription.h" +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +// ____________________________________________________________________________ +// +// AUOutputBL - Simple Buffer List wrapper targetted to use with retrieving AU output +// Works in one of two ways (both adjustable)... Can use it with NULL pointers, or allocate +// memory to receive the data in. + +// Before using this with any call to AudioUnitRender, it needs to be Prepared +// as some calls to AudioUnitRender can reset the ABL + +class AUOutputBL { +public: + + // you CANNOT use one of these - it will crash! +// AUOutputBL (); + + // this is the constructor that you use + // it can't be reset once you've constructed it + AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames = 512); + ~AUOutputBL(); + + void Prepare () + { + Prepare (mFrames); + } + + // this version can throw if this is an allocted ABL and inNumFrames is > AllocatedFrames() + // you can set the bool to true if you want a NULL buffer list even if allocated + // inNumFrames must be a valid number (will throw if inNumFrames is 0) + void Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated = false); + + AudioBufferList* ABL() { return mBufferList; } + + // You only need to call this if you want to allocate a buffer list + // if you want an empty buffer list, just call Prepare() + // if you want to dispose previously allocted memory, pass in 0 + // then you either have an empty buffer list, or you can re-allocate + // Memory is kept around if an Allocation request is less than what is currently allocated + void Allocate (UInt32 inNumberFrames); + + UInt32 AllocatedFrames() const { return mFrames; } + + const CAStreamBasicDescription& GetFormat() const { return mFormat; } + +#if DEBUG + void Print(); +#endif + +private: + UInt32 AllocatedBytes () const { return (mBufferSize * mNumberBuffers); } + + CAStreamBasicDescription mFormat; + Byte* mBufferMemory; + AudioBufferList* mBufferList; + UInt32 mNumberBuffers; + UInt32 mBufferSize; + UInt32 mFrames; + +// don't want to copy these.. can if you want, but more code to write! + AUOutputBL (const AUOutputBL &c) {} + AUOutputBL& operator= (const AUOutputBL& c) { return *this; } +}; + +#endif // __AUOutputBL_h__ diff --git a/libs/appleutility/CAAudioChannelLayout.cpp b/libs/appleutility/CAAudioChannelLayout.cpp new file mode 100644 index 0000000000..585ff44fb7 --- /dev/null +++ b/libs/appleutility/CAAudioChannelLayout.cpp @@ -0,0 +1,138 @@ +/* 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. +*/ +/*============================================================================= + CAAudioChannelLayout.cpp + +=============================================================================*/ + +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CAAudioChannelLayout.h" +#include +#include + +//============================================================================= +// CAAudioChannelLayout +//============================================================================= + +AudioChannelLayout* CAAudioChannelLayout::Create(UInt32 inNumberChannelDescriptions) +{ + UInt32 theSize = CalculateByteSize(inNumberChannelDescriptions); + AudioChannelLayout* theAnswer = static_cast(calloc(1, theSize)); + if(theAnswer != NULL) + { + SetAllToUnknown(*theAnswer, inNumberChannelDescriptions); + } + return theAnswer; +} + +void CAAudioChannelLayout::Destroy(AudioChannelLayout* inChannelLayout) +{ + free(inChannelLayout); +} + +void CAAudioChannelLayout::SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions) +{ + outChannelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; + outChannelLayout.mChannelBitmap = 0; + outChannelLayout.mNumberChannelDescriptions = inNumberChannelDescriptions; + for(UInt32 theChannelIndex = 0; theChannelIndex < inNumberChannelDescriptions; ++theChannelIndex) + { + outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelLabel = kAudioChannelLabel_Unknown; + outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelFlags = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[0] = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[1] = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[2] = 0; + } +} + +bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y) +{ + // compare based on the number of channel descriptions present + // (this may be too strict a comparison if all you care about are matching layout tags) + UInt32 theSize1 = CAAudioChannelLayout::CalculateByteSize(x.mNumberChannelDescriptions); + UInt32 theSize2 = CAAudioChannelLayout::CalculateByteSize(y.mNumberChannelDescriptions); + + if (theSize1 != theSize2) + return false; + + return !memcmp (&x, &y, theSize1); +} + +// counting the one bits in a word +inline UInt32 CountOnes(UInt32 x) +{ + // secret magic algorithm for counting bits in a word. + UInt32 t; + x = x - ((x >> 1) & 0x55555555); + t = ((x >> 2) & 0x33333333); + x = (x & 0x33333333) + t; + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x << 8); + x = x + (x << 16); + return x >> 24; +} + +UInt32 CAAudioChannelLayout::NumberChannels (const AudioChannelLayout& inLayout) +{ + if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) + return inLayout.mNumberChannelDescriptions; + + if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) + return CountOnes (inLayout.mChannelBitmap); + + return AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag); +} + +void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout) +{ + fprintf (file, "\tTag=0x%lX, ", layout->mChannelLayoutTag); + if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) + fprintf (file, "Using Bitmap:0x%lX\n", layout->mChannelBitmap); + else { + fprintf (file, "Num Chan Descs=%ld\n", layout->mNumberChannelDescriptions); + const AudioChannelDescription *desc = layout->mChannelDescriptions; + for (unsigned int i = 0; i < layout->mNumberChannelDescriptions; ++i, ++desc) { + fprintf (file, "\t\tLabel=%ld, Flags=0x%lX, ", desc->mChannelLabel, desc->mChannelFlags); + fprintf (file, "[az=%f,el=%f,dist=%f]\n", desc->mCoordinates[0], desc->mCoordinates[1], desc->mCoordinates[2]); + } + } +} diff --git a/libs/appleutility/CAAudioChannelLayout.h b/libs/appleutility/CAAudioChannelLayout.h new file mode 100644 index 0000000000..8f995b8614 --- /dev/null +++ b/libs/appleutility/CAAudioChannelLayout.h @@ -0,0 +1,162 @@ +/* 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. +*/ +/*============================================================================= + CAAudioChannelLayout.h + +=============================================================================*/ +#if !defined(__CAAudioChannelLayout_h__) +#define __CAAudioChannelLayout_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif +#include +#include +#include + +#if !HAL_Build + #include "CAReferenceCounted.h" +#endif + +//============================================================================= +// CAAudioChannelLayout +//============================================================================= + +bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y); + +extern "C" void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout); + +class CAAudioChannelLayout +{ +// static Construction/Destruction +public: + static AudioChannelLayout* Create(UInt32 inNumberChannelDescriptions); + static void Destroy(AudioChannelLayout* inChannelLayout); + static UInt32 CalculateByteSize(UInt32 inNumberChannelDescriptions) { + return offsetof(AudioChannelLayout, mChannelDescriptions) + inNumberChannelDescriptions * sizeof(AudioChannelDescription); + } + static void SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions); + static UInt32 NumberChannels(const AudioChannelLayout& inLayout); + +#if !HAL_Build +// object methods +public: + CAAudioChannelLayout (); + + CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround); + // if inChooseSurround is false, then symmetrical speaker arrangements + // are chosen in place of surround layouts if there is a choice + // This call chooses layouts based on the expected defaults in + // AudioUnit usage + CAAudioChannelLayout (AudioChannelLayoutTag inTag); + CAAudioChannelLayout (const CAAudioChannelLayout &c); + CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout); + ~CAAudioChannelLayout(); + + CAAudioChannelLayout& operator= (const AudioChannelLayout* inChannelLayout); + CAAudioChannelLayout& operator= (const CAAudioChannelLayout& c); + bool operator== (const CAAudioChannelLayout &c) const; + + void SetWithTag(AudioChannelLayoutTag inTag); + + bool IsValid() const { return NumberChannels() > 0; } + UInt32 Size() const { return mLayoutHolder ? mLayoutHolder->Size() : 0; } + + UInt32 NumberChannels() const { return NumberChannels(Layout()); } + + AudioChannelLayoutTag Tag() const { return Layout().mChannelLayoutTag; } + const AudioChannelLayout& Layout() const { return mLayoutHolder->Layout(); } + operator const AudioChannelLayout *() const { return &Layout(); } + + void Print () const { Print (stdout); } + void Print (FILE* file) const; + + OSStatus Save (CFPropertyListRef *outData) const; + OSStatus Restore (CFPropertyListRef &inData); + +private: + class ACLRefCounter : public CAReferenceCounted { + public: + ACLRefCounter (UInt32 inDataSize) + { + if (inDataSize < offsetof(AudioChannelLayout, mChannelDescriptions)) + inDataSize = offsetof(AudioChannelLayout, mChannelDescriptions); + + mLayout = static_cast(malloc (inDataSize)); + memset (mLayout, 0, inDataSize); + mByteSize = inDataSize; + } + + const AudioChannelLayout & Layout() const { return *mLayout; } + + UInt32 Size () const { return mByteSize; } + + private: + AudioChannelLayout *mLayout; + UInt32 mByteSize; + + // only the constructors can change the actual state of the layout + friend CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround); + friend OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData); + friend CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout); + friend void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag); + + AudioChannelLayout * GetLayout() { return mLayout; } + ~ACLRefCounter() { if (mLayout) { free(mLayout); mLayout = NULL; } } + + private: + ACLRefCounter () : mLayout(NULL) { } + ACLRefCounter(const ACLRefCounter& c) : mLayout(NULL) { } + ACLRefCounter& operator=(const ACLRefCounter& c) { return *this; } + }; + + ACLRefCounter *mLayoutHolder; +#endif // HAL_Build + +}; + +#endif diff --git a/libs/appleutility/CAAudioChannelLayoutObject.cpp b/libs/appleutility/CAAudioChannelLayoutObject.cpp new file mode 100644 index 0000000000..8c4030048d --- /dev/null +++ b/libs/appleutility/CAAudioChannelLayoutObject.cpp @@ -0,0 +1,199 @@ +/* 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. +*/ +/*============================================================================= + CAAudioChannelLayoutObject.cpp + +=============================================================================*/ + +#include "CAAudioChannelLayout.h" +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + + +CAAudioChannelLayout::CAAudioChannelLayout () +{ + mLayoutHolder = new ACLRefCounter (offsetof(AudioChannelLayout, mChannelDescriptions)); +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround) +{ + // this chooses default layouts based on the number of channels... + UInt32 theSize = CalculateByteSize (inNumberChannels); + + mLayoutHolder = new ACLRefCounter (theSize); + + AudioChannelLayout* layout = mLayoutHolder->GetLayout(); + + layout->mNumberChannelDescriptions = inNumberChannels; + + switch (inNumberChannels) + { + case 1: + layout->mChannelLayoutTag = kAudioChannelLayoutTag_Mono; + break; + case 2: + layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_Binaural : kAudioChannelLayoutTag_Stereo; + break; + case 4: + layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_Ambisonic_B_Format : kAudioChannelLayoutTag_AudioUnit_4; + break; + case 5: + layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_5_0 : kAudioChannelLayoutTag_AudioUnit_5; + break; + case 6: + layout->mChannelLayoutTag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_6_0 : kAudioChannelLayoutTag_AudioUnit_6; + break; + case 7: + layout->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_7_0; + break; + case 8: + layout->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_8; + break; + default: + // here we have a "broken" layout, in the sense that we haven't any idea how to lay this out + // the layout itself is all set to zeros + // ### no longer true ### + SetAllToUnknown(*layout, inNumberChannels); + break; + } +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (AudioChannelLayoutTag inLayoutTag) + : mLayoutHolder(NULL) +{ + SetWithTag(inLayoutTag); +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (const CAAudioChannelLayout &c) + : mLayoutHolder(NULL) +{ + *this = c; +} + + +//============================================================================= +// CAAudioChannelLayout::AudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout) + : mLayoutHolder(NULL) +{ + *this = inChannelLayout; +} + +//============================================================================= +// CAAudioChannelLayout::~CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::~CAAudioChannelLayout () +{ + if (mLayoutHolder) { + mLayoutHolder->release(); + mLayoutHolder = NULL; + } +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout& CAAudioChannelLayout::operator= (const CAAudioChannelLayout &c) +{ + if (mLayoutHolder != c.mLayoutHolder) { + if (mLayoutHolder) + mLayoutHolder->release(); + + if ((mLayoutHolder = c.mLayoutHolder) != NULL) + mLayoutHolder->retain(); + } + + return *this; +} + +CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout) +{ + if (mLayoutHolder) + mLayoutHolder->release(); + + UInt32 theSize = CalculateByteSize (inChannelLayout->mNumberChannelDescriptions); + + mLayoutHolder = new ACLRefCounter (theSize); + + memcpy(mLayoutHolder->mLayout, inChannelLayout, theSize); + return *this; +} + +void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag) +{ + if (mLayoutHolder) + mLayoutHolder->release(); + + mLayoutHolder = new ACLRefCounter(offsetof(AudioChannelLayout, mChannelDescriptions[0])); + AudioChannelLayout* layout = mLayoutHolder->GetLayout(); + layout->mChannelLayoutTag = inTag; +} + +//============================================================================= +// CAAudioChannelLayout::operator== +//============================================================================= +bool CAAudioChannelLayout::operator== (const CAAudioChannelLayout &c) const +{ + if (mLayoutHolder == c.mLayoutHolder) + return true; + return Layout() == c.Layout(); +} + +//============================================================================= +// CAAudioChannelLayout::Print +//============================================================================= +void CAAudioChannelLayout::Print (FILE* file) const +{ + CAShowAudioChannelLayout (file, &Layout()); +} + diff --git a/libs/appleutility/CAAudioUnit.cpp b/libs/appleutility/CAAudioUnit.cpp new file mode 100644 index 0000000000..9244877d29 --- /dev/null +++ b/libs/appleutility/CAAudioUnit.cpp @@ -0,0 +1,1202 @@ +/* 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. +*/ +/*============================================================================= + CAAudioUnit.cpp + +=============================================================================*/ + +#include "CAAudioUnit.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#include "CAReferenceCounted.h" +#include "AUOutputBL.h" //this is for the Preroll only + + +struct StackAUChannelInfo { + StackAUChannelInfo (UInt32 inSize) : mChanInfo ((AUChannelInfo*)malloc (inSize)) {} + ~StackAUChannelInfo() { free (mChanInfo); } + + AUChannelInfo* mChanInfo; +}; + + + +class CAAudioUnit::AUState : public CAReferenceCounted { +public: + AUState (Component inComp) + : mUnit(0), mNode (0) + { + OSStatus result = ::OpenAComponent (inComp, &mUnit); + if (result) + throw result; + Init(); + } + + AUState (const AUNode &inNode, const AudioUnit& inUnit) + : mUnit (inUnit), mNode (inNode) + { + Init(); + } + + ~AUState(); + + AudioUnit mUnit; + AUNode mNode; + + OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const + { + if (mGetParamProc != NULL) { + return reinterpret_cast(mGetParamProc) (mConnInstanceStorage, + inID, scope, element, &outValue); + } + return AudioUnitGetParameter(mUnit, inID, scope, element, &outValue); + } + + OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames) + { + if (mSetParamProc != NULL) { + return reinterpret_cast(mSetParamProc) (mConnInstanceStorage, + inID, scope, element, value, bufferOffsetFrames); + } + return AudioUnitSetParameter(mUnit, inID, scope, element, value, bufferOffsetFrames); + } + + OSStatus Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) + { + if (mRenderProc != NULL) { + return reinterpret_cast(mRenderProc) (mConnInstanceStorage, + ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData); + } + return AudioUnitRender(mUnit, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData); + } + + OSStatus MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) + { +#if !TARGET_OS_WIN32 + if (mMIDIEventProc != NULL) { + return reinterpret_cast(mMIDIEventProc) (mConnInstanceStorage, + inStatus, inData1, inData2, inOffsetSampleFrame); + } + return MusicDeviceMIDIEvent (mUnit, inStatus, inData1, inData2, inOffsetSampleFrame); +#else + return paramErr; +#endif + } + + OSStatus StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) + { +#if !TARGET_OS_WIN32 + return MusicDeviceStartNote (mUnit, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams); +#else + return paramErr; +#endif + } + OSStatus StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) + { +#if !TARGET_OS_WIN32 + return MusicDeviceStopNote (mUnit, inGroupID, inNoteInstanceID, inOffsetSampleFrame); +#else + return paramErr; +#endif + } + +private: + // get the fast dispatch pointers + void Init() + { + UInt32 size = sizeof(AudioUnitRenderProc); + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitRenderSelect, + &mRenderProc, &size) != noErr) + mRenderProc = NULL; + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitGetParameterSelect, + &mGetParamProc, &size) != noErr) + mGetParamProc = NULL; + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitSetParameterSelect, + &mSetParamProc, &size) != noErr) + mSetParamProc = NULL; + + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kMusicDeviceMIDIEventSelect, + &mMIDIEventProc, &size) != noErr) + mMIDIEventProc = NULL; + + if (mRenderProc || mGetParamProc || mSetParamProc || mMIDIEventProc) + mConnInstanceStorage = GetComponentInstanceStorage(mUnit); + else + mConnInstanceStorage = NULL; + } + + ProcPtr mRenderProc, mGetParamProc, mSetParamProc, mMIDIEventProc; + + void * mConnInstanceStorage; + +private: + // get the compiler to tell us when we do a bad thing!!! + AUState () {} + AUState (const AUState&) {} + AUState& operator= (const AUState&) { return *this; } +}; + + +CAAudioUnit::AUState::~AUState () +{ + if (mUnit && (mNode == 0)) { + ::CloseComponent (mUnit); + } + mNode = 0; + mUnit = 0; +} + +OSStatus CAAudioUnit::Open (const CAComponent& inComp, CAAudioUnit &outUnit) +{ + try { + outUnit = inComp; + return noErr; + } catch (OSStatus res) { + return res; + } catch (...) { + return -1; + } +} + +CAAudioUnit::CAAudioUnit (const AudioUnit& inUnit) + : mComp (inUnit), mDataPtr (new AUState (-1, inUnit)) +{ +} + +CAAudioUnit::CAAudioUnit (const CAComponent& inComp) + : mComp (inComp), mDataPtr (0) +{ + mDataPtr = new AUState (mComp.Comp()); +} + +CAAudioUnit::CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit) + : mComp (inUnit), mDataPtr(new AUState (inNode, inUnit)) +{ +} + +CAAudioUnit::~CAAudioUnit () +{ + if (mDataPtr) { + mDataPtr->release(); + mDataPtr = NULL; + } +} + +CAAudioUnit& CAAudioUnit::operator= (const CAAudioUnit &a) +{ + if (mDataPtr != a.mDataPtr) { + if (mDataPtr) + mDataPtr->release(); + + if ((mDataPtr = a.mDataPtr) != NULL) + mDataPtr->retain(); + + mComp = a.mComp; + } + + return *this; +} + +bool CAAudioUnit::operator== (const CAAudioUnit& y) const +{ + if (mDataPtr == y.mDataPtr) return true; + AudioUnit au1 = mDataPtr ? mDataPtr->mUnit : 0; + AudioUnit au2 = y.mDataPtr ? y.mDataPtr->mUnit : 0; + return au1 == au2; +} + +bool CAAudioUnit::operator== (const AudioUnit& y) const +{ + if (!mDataPtr) return false; + return mDataPtr->mUnit == y; +} + +#pragma mark __State Management + +bool CAAudioUnit::IsValid () const +{ + return mDataPtr ? mDataPtr->mUnit != 0 : false; +} + +AudioUnit CAAudioUnit::AU() const +{ + return mDataPtr ? mDataPtr->mUnit : 0; +} + +AUNode CAAudioUnit::GetAUNode () const +{ + return mDataPtr ? mDataPtr->mNode : 0; +} + +#pragma mark __Format Handling + +bool CAAudioUnit::CanDo ( int inChannelsIn, + int inChannelsOut) const +{ + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + // lets see if the unit has any channel restrictions + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // if this property is NOT implemented an FX unit + // is expected to deal with same channel valance in and out + if (result) + { + if (Comp().Desc().IsEffect() && (inChannelsIn == inChannelsOut) + || Comp().Desc().IsOffline() && (inChannelsIn == inChannelsOut)) + { + return true; + } + else + { + // the au should either really tell us about this + // or we will assume the worst + return false; + } + } + + StackAUChannelInfo info (dataSize); + + result = GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize); + if (result) { return false; } + + return ValidateChannelPair (inChannelsIn, inChannelsOut, info.mChanInfo, (dataSize / sizeof (AUChannelInfo))); +} + +bool CAAudioUnit::ValidateChannelPair (int inChannelsIn, + int inChannelsOut, + const AUChannelInfo * info, + UInt32 numChanInfo) const +{ +// we've the following cases (some combinations) to test here: +/* +>0 An explicit number of channels on either side +0 that side (generally input!) has no elements +-1 wild card: +-1,-1 any num channels as long as same channels on in and out +-1,-2 any num channels channels on in and out - special meaning +-2+ indicates total num channs AU can handle + - elements configurable to any num channels, + - element count in scope must be writable +*/ + + //now chan layout can contain -1 for either scope (ie. doesn't care) + for (unsigned int i = 0; i < numChanInfo; ++i) + { + //less than zero on both sides - check for special attributes + if ((info[i].inChannels < 0) && (info[i].outChannels < 0)) + { + // these are our wild card matches + if (info[i].inChannels == -1 && info[i].outChannels == -1) { + if (inChannelsOut == inChannelsIn) { + return true; + } + } + else if ((info[i].inChannels == -1 && info[i].outChannels == -2) + || (info[i].inChannels == -2 && info[i].outChannels == -1)) + { + return true; + } + // these are our total num channels matches + // element count MUST be writable + else { + bool outWrite = false; bool inWrite = false; + IsElementCountWritable (kAudioUnitScope_Output, outWrite); + IsElementCountWritable (kAudioUnitScope_Input, inWrite); + if (inWrite && outWrite) { + if ((inChannelsOut <= abs(info[i].outChannels)) + && (inChannelsIn <= abs(info[i].inChannels))) + { + return true; + } + } + } + } + + // special meaning on input, specific num on output + else if (info[i].inChannels < 0) { + if (info[i].outChannels == inChannelsOut) + { + // can do any in channels + if (info[i].inChannels == -1) { + return true; + } + // total chans on input + else { + bool inWrite = false; + IsElementCountWritable (kAudioUnitScope_Input, inWrite); + if (inWrite && (inChannelsIn <= abs(info[i].inChannels))) { + return true; + } + } + } + } + + // special meaning on output, specific num on input + else if (info[i].outChannels < 0) { + if (info[i].inChannels == inChannelsIn) + { + // can do any out channels + if (info[i].outChannels == -1) { + return true; + } + // total chans on output + else { + bool outWrite = false; + IsElementCountWritable (kAudioUnitScope_Output, outWrite); + if (outWrite && (inChannelsOut <= abs(info[i].outChannels))) { + return true; + } + } + } + } + + // both chans in struct >= 0 - thus has to explicitly match + else if ((info[i].inChannels == inChannelsIn) && (info[i].outChannels == inChannelsOut)) { + return true; + } + + // now check to see if a wild card on the args (inChannelsIn or inChannelsOut chans is zero) is found + // tells us to match just one side of the scopes + else if (inChannelsIn == 0) { + if (info[i].outChannels == inChannelsOut) { + return true; + } + } + else if (inChannelsOut == 0) { + if (info[i].inChannels == inChannelsIn) { + return true; + } + } + } + + return false; +} + +bool CheckDynCount (SInt32 inTotalChans, const CAAUChanHelper &inHelper) +{ + int totalChans = 0; + for (unsigned int i = 0; i < inHelper.mNumEls; ++i) + totalChans += inHelper.mChans[i]; + return (totalChans <= inTotalChans); +} + +bool CAAudioUnit::CheckOneSide (const CAAUChanHelper &inHelper, + bool checkOutput, + const AUChannelInfo *info, + UInt32 numInfo) const +{ + // now we can use the wildcard option (see above impl) to see if this matches + for (unsigned int el = 0; el < inHelper.mNumEls; ++el) { + bool testAlready = false; + for (unsigned int i = 0; i < el; ++i) { + if (inHelper.mChans[i] == inHelper.mChans[el]) { + testAlready = true; + break; + } + } + if (!testAlready) { + if (checkOutput) { + if (!ValidateChannelPair (0, inHelper.mChans[el], info, numInfo)) return false; + } else { + if (!ValidateChannelPair (inHelper.mChans[el], 0, info, numInfo)) return false; + } + } + } + return true; +} + +bool CAAudioUnit::CanDo (const CAAUChanHelper &inputs, + const CAAUChanHelper &outputs) const + +{ +// first check our state + // huh! + if (inputs.mNumEls == 0 && outputs.mNumEls == 0) return false; + + UInt32 elCount; + if (GetElementCount (kAudioUnitScope_Input, elCount)) { return false; } + if (elCount != inputs.mNumEls) return false; + + if (GetElementCount (kAudioUnitScope_Output, elCount)) { return false; } + if (elCount != outputs.mNumEls) return false; + +// (1) special cases (effects and sources (generators and instruments) only) + UInt32 dataSize = 0; + if (GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, &dataSize, NULL) != noErr) + { + if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) { + UInt32 numChan = outputs.mNumEls > 0 ? outputs.mChans[0] : inputs.mChans[0]; + for (unsigned int in = 0; in < inputs.mNumEls; ++in) + if (numChan != inputs.mChans[in]) return false; + for (unsigned int out = 0; out < outputs.mNumEls; ++out) + if (numChan != outputs.mChans[out]) return false; + return true; + } + + // in this case, all the channels have to match the current config + if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) { + for (unsigned int in = 0; in < inputs.mNumEls; ++in) { + UInt32 chan; + if (NumberChannels (kAudioUnitScope_Input, in, chan)) return false; + if (chan != UInt32(inputs.mChans[in])) return false; + } + for (unsigned int out = 0; out < outputs.mNumEls; ++out) { + UInt32 chan; + if (NumberChannels (kAudioUnitScope_Output, out, chan)) return false; + if (chan != UInt32(outputs.mChans[out])) return false; + } + return true; + } + + // if we get here we can't determine anything about channel capabilities + return false; + } + + StackAUChannelInfo info (dataSize); + + if (GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize) != noErr) + { + return false; + } + + int numInfo = dataSize / sizeof(AUChannelInfo); + +// (2) Test for dynamic capability (or no elements on that scope) + SInt32 dynInChans = 0; + if (ValidateDynamicScope (kAudioUnitScope_Input, dynInChans, info.mChanInfo, numInfo)) { + if (CheckDynCount (dynInChans, inputs) == false) return false; + } + + SInt32 dynOutChans = 0; + if (ValidateDynamicScope (kAudioUnitScope_Output, dynOutChans, info.mChanInfo, numInfo)) { + if (CheckDynCount (dynOutChans, outputs) == false) return false; + } + + if (dynOutChans && dynInChans) { return true; } + +// (3) Just need to test one side + if (dynInChans || (inputs.mNumEls == 0)) { + return CheckOneSide (outputs, true, info.mChanInfo, numInfo); + } + + if (dynOutChans || (outputs.mNumEls == 0)) { + return CheckOneSide (inputs, false, info.mChanInfo, numInfo); + } + +// (4) - not a dynamic AU, has ins and outs, and has channel constraints so we test every possible pairing + for (unsigned int in = 0; in < inputs.mNumEls; ++in) + { + bool testInAlready = false; + for (unsigned int i = 0; i < in; ++i) { + if (inputs.mChans[i] == inputs.mChans[in]) { + testInAlready = true; + break; + } + } + if (!testInAlready) { + for (unsigned int out = 0; out < outputs.mNumEls; ++out) { + // try to save a little bit and not test the same pairing multiple times... + bool testOutAlready = false; + for (unsigned int i = 0; i < out; ++i) { + if (outputs.mChans[i] == outputs.mChans[out]) { + testOutAlready = true; + break; + } + } + if (!testOutAlready) { + if (!ValidateChannelPair (inputs.mChans[in], outputs.mChans[out],info.mChanInfo, numInfo)) { + return false; + } + } + } + } + } + + return true; +} + +bool CAAudioUnit::SupportsNumChannels () const +{ + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + // lets see if the unit has any channel restrictions + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // if this property is NOT implemented an FX unit + // is expected to deal with same channel valance in and out + if (result) { + if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) + return true; + } + return result == noErr; +} + +bool CAAudioUnit::GetChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl, + ChannelTagVector &outChannelVector) const +{ + if (HasChannelLayouts (inScope, inEl) == false) return false; + + UInt32 dataSize; + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + &dataSize, NULL); + + if (result == kAudioUnitErr_InvalidProperty) { + // if we get here we can do layouts but we've got the speaker config property + outChannelVector.erase (outChannelVector.begin(), outChannelVector.end()); + outChannelVector.push_back (kAudioChannelLayoutTag_Stereo); + outChannelVector.push_back (kAudioChannelLayoutTag_StereoHeadphones); + outChannelVector.push_back (kAudioChannelLayoutTag_Quadraphonic); + outChannelVector.push_back (kAudioChannelLayoutTag_AudioUnit_5_0); + return true; + } + + if (result) return false; + + bool canDo = false; + // OK lets get our channel layouts and see if the one we want is present + AudioChannelLayoutTag* info = (AudioChannelLayoutTag*)malloc (dataSize); + result = AudioUnitGetProperty (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + info, &dataSize); + if (result) goto home; + + outChannelVector.erase (outChannelVector.begin(), outChannelVector.end()); + for (unsigned int i = 0; i < (dataSize / sizeof (AudioChannelLayoutTag)); ++i) + outChannelVector.push_back (info[i]); + +home: + free (info); + return canDo; +} + +bool CAAudioUnit::HasChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl) const +{ + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + NULL, NULL); + return !result; +} + +OSStatus CAAudioUnit::GetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &outLayout) const +{ + UInt32 size; + OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, &size, NULL); + if (result) return result; + + AudioChannelLayout *layout = (AudioChannelLayout*)malloc (size); + + require_noerr (result = AudioUnitGetProperty (AU(), kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, layout, &size), home); + + outLayout = CAAudioChannelLayout (layout); + +home: + free (layout); + return result; +} + +OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &inLayout) +{ + OSStatus result = AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, + inLayout, inLayout.Size()); + return result; +} + +OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioChannelLayout &inLayout, + UInt32 inSize) +{ + OSStatus result = AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, + &inLayout, inSize); + return result; +} + +OSStatus CAAudioUnit::ClearChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl) +{ + return AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, NULL, 0); +} + +OSStatus CAAudioUnit::GetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioStreamBasicDescription &outFormat) const +{ + UInt32 dataSize = sizeof (AudioStreamBasicDescription); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_StreamFormat, + inScope, inEl, + &outFormat, &dataSize); +} + +OSStatus CAAudioUnit::SetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + const AudioStreamBasicDescription &inFormat) +{ + return AudioUnitSetProperty (AU(), kAudioUnitProperty_StreamFormat, + inScope, inEl, + const_cast(&inFormat), + sizeof (AudioStreamBasicDescription)); +} + +OSStatus CAAudioUnit::GetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 &outRate) const +{ + UInt32 dataSize = sizeof (Float64); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_SampleRate, + inScope, inEl, + &outRate, &dataSize); +} + +OSStatus CAAudioUnit::SetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 inRate) +{ + AudioStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (result) return result; + desc.mSampleRate = inRate; + return SetFormat (inScope, inEl, desc); +} + +OSStatus CAAudioUnit::SetSampleRate (Float64 inSampleRate) +{ + OSStatus result; + + UInt32 elCount; + require_noerr (result = GetElementCount(kAudioUnitScope_Input, elCount), home); + if (elCount) { + for (unsigned int i = 0; i < elCount; ++i) { + require_noerr (result = SetSampleRate (kAudioUnitScope_Input, i, inSampleRate), home); + } + } + + require_noerr (result = GetElementCount(kAudioUnitScope_Output, elCount), home); + if (elCount) { + for (unsigned int i = 0; i < elCount; ++i) { + require_noerr (result = SetSampleRate (kAudioUnitScope_Output, i, inSampleRate), home); + } + } + +home: + return result; +} + +OSStatus CAAudioUnit::NumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const +{ + AudioStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (!result) + outChans = desc.mChannelsPerFrame; + return result; +} + +OSStatus CAAudioUnit::SetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 inChans) +{ + // set this as the output of the AU + CAStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (result) return result; + desc.SetCanonical (inChans, desc.IsInterleaved()); + result = SetFormat (inScope, inEl, desc); + return result; +} + +OSStatus CAAudioUnit::IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const +{ + Boolean isWritable; + UInt32 outDataSize; + OSStatus result = GetPropertyInfo (kAudioUnitProperty_ElementCount, inScope, 0, &outDataSize, &isWritable); + if (result) + return result; + outWritable = isWritable ? true : false; + return noErr; +} + +OSStatus CAAudioUnit::GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const +{ + UInt32 propSize = sizeof(outCount); + return GetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &outCount, &propSize); +} + +OSStatus CAAudioUnit::SetElementCount (AudioUnitScope inScope, UInt32 inCount) +{ + return SetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &inCount, sizeof(inCount)); +} + +bool CAAudioUnit::HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const +{ + // ok - now we need to check the AU's capability here. + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + OSStatus result = GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // AU has to explicitly tell us about this. + if (result) return false; + + StackAUChannelInfo info (dataSize); + + result = GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize); + if (result) return false; + + return ValidateDynamicScope (inScope, outTotalNumChannels, info.mChanInfo, (dataSize / sizeof(AUChannelInfo))); +} + +// as we've already checked that the element count is writable +// the following conditions will match this.. +/* +-1, -2 -> signifies no restrictions +-2, -1 -> signifies no restrictions -> in this case outTotalNumChannels == -1 (any num channels) + +-N (where N is less than -2), signifies the total channel count on the scope side (in or out) +*/ +bool CAAudioUnit::ValidateDynamicScope (AudioUnitScope inScope, + SInt32 &outTotalNumChannels, + const AUChannelInfo *info, + UInt32 numInfo) const +{ + bool writable = false; + OSStatus result = IsElementCountWritable (inScope, writable); + if (result || (writable == false)) + return false; + + //now chan layout can contain -1 for either scope (ie. doesn't care) + for (unsigned int i = 0; i < numInfo; ++i) + { + // lets test the special wild card case first... + // this says the AU can do any num channels on input or output - for eg. Matrix Mixer + if (((info[i].inChannels == -1) && (info[i].outChannels == -2)) + || ((info[i].inChannels == -2) && (info[i].outChannels == -1))) + { + outTotalNumChannels = -1; + return true; + } + + // ok lets now test our special case.... + if (inScope == kAudioUnitScope_Input) { + // isn't dynamic on this side at least + if (info[i].inChannels >= 0) + continue; + + if (info[i].inChannels < -2) { + outTotalNumChannels = abs (info[i].inChannels); + return true; + } + } + + else if (inScope == kAudioUnitScope_Output) { + // isn't dynamic on this side at least + if (info[i].outChannels >= 0) + continue; + + if (info[i].outChannels < -2) { + outTotalNumChannels = abs (info[i].outChannels); + return true; + } + } + + else { + break; // wrong scope was specified + } + } + + return false; +} + +OSStatus CAAudioUnit::ConfigureDynamicScope (AudioUnitScope inScope, + UInt32 inNumElements, + UInt32 *inChannelsPerElement, + Float64 inSampleRate) +{ + SInt32 numChannels = 0; + bool isDyamic = HasDynamicScope (inScope, numChannels); + if (isDyamic == false) + return kAudioUnitErr_InvalidProperty; + + //lets to a sanity check... + // if numChannels == -1, then it can do "any"... + if (numChannels > 0) { + SInt32 count = 0; + for (unsigned int i = 0; i < inNumElements; ++i) + count += inChannelsPerElement[i]; + if (count > numChannels) + return kAudioUnitErr_InvalidPropertyValue; + } + + OSStatus result = SetElementCount (inScope, inNumElements); + if (result) + return result; + + CAStreamBasicDescription desc; + desc.mSampleRate = inSampleRate; + for (unsigned int i = 0; i < inNumElements; ++i) { + desc.SetCanonical (inChannelsPerElement[i], false); + result = SetFormat (inScope, i, desc); + if (result) + return result; + } + return noErr; +} + +#pragma mark __Properties + +bool CAAudioUnit::CanBypass () const +{ + Boolean outWritable; + OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + NULL, &outWritable); + return (!result && outWritable); +} + +bool CAAudioUnit::GetBypass () const +{ + UInt32 dataSize = sizeof (UInt32); + UInt32 outBypass; + OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + &outBypass, &dataSize); + return (result ? false : outBypass); +} + +OSStatus CAAudioUnit::SetBypass (bool inBypass) const +{ + UInt32 bypass = inBypass ? 1 : 0; + return AudioUnitSetProperty (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + &bypass, sizeof (UInt32)); +} + +Float64 CAAudioUnit::Latency () const +{ + Float64 secs; + UInt32 size = sizeof(secs); + if (GetProperty (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &secs, &size)) + return 0; + return secs; +} + +OSStatus CAAudioUnit::GetAUPreset (CFPropertyListRef &outData) const +{ + UInt32 dataSize = sizeof(outData); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, 0, + &outData, &dataSize); +} + +OSStatus CAAudioUnit::SetAUPreset (CFPropertyListRef &inData) +{ + return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, 0, + &inData, sizeof (CFPropertyListRef)); +} + +OSStatus CAAudioUnit::GetPresentPreset (AUPreset &outData) const +{ + UInt32 dataSize = sizeof(outData); + OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_PresentPreset, + kAudioUnitScope_Global, 0, + &outData, &dataSize); + if (result == kAudioUnitErr_InvalidProperty) { + dataSize = sizeof(outData); + result = AudioUnitGetProperty (AU(), kAudioUnitProperty_CurrentPreset, + kAudioUnitScope_Global, 0, + &outData, &dataSize); + if (result == noErr) { + // we now retain the CFString in the preset so for the client of this API + // it is consistent (ie. the string should be released when done) + if (outData.presetName) + CFRetain (outData.presetName); + } + } + return result; +} + +OSStatus CAAudioUnit::SetPresentPreset (AUPreset &inData) +{ + OSStatus result = AudioUnitSetProperty (AU(), kAudioUnitProperty_PresentPreset, + kAudioUnitScope_Global, 0, + &inData, sizeof (AUPreset)); + if (result == kAudioUnitErr_InvalidProperty) { + result = AudioUnitSetProperty (AU(), kAudioUnitProperty_CurrentPreset, + kAudioUnitScope_Global, 0, + &inData, sizeof (AUPreset)); + } + return result; +} + +bool CAAudioUnit::HasCustomView () const +{ + UInt32 dataSize = 0; + OSStatus result = GetPropertyInfo(kAudioUnitProperty_GetUIComponentList, + kAudioUnitScope_Global, 0, + &dataSize, NULL); + if (result || !dataSize) { + dataSize = 0; + result = GetPropertyInfo(kAudioUnitProperty_CocoaUI, + kAudioUnitScope_Global, 0, + &dataSize, NULL); + if (result || !dataSize) + return false; + } + return true; +} + +OSStatus CAAudioUnit::GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const +{ + return mDataPtr ? mDataPtr->GetParameter (inID, scope, element, outValue) : paramErr; +} + +OSStatus CAAudioUnit::SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames) +{ + return mDataPtr ? mDataPtr->SetParameter (inID, scope, element, value, bufferOffsetFrames) : paramErr; +} + +OSStatus CAAudioUnit::MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) +{ + return mDataPtr ? mDataPtr->MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame) : paramErr; +} + +OSStatus CAAudioUnit::StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) +{ + return mDataPtr ? mDataPtr->StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams) + : paramErr; +} + +OSStatus CAAudioUnit::StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) +{ + return mDataPtr ? mDataPtr->StopNote (inGroupID, inNoteInstanceID, inOffsetSampleFrame) : paramErr; +} + +#pragma mark __Render + +OSStatus CAAudioUnit::Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) +{ + return mDataPtr ? mDataPtr->Render (ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData) : paramErr; +} + +static AURenderCallbackStruct sRenderCallback; +static OSStatus PrerollRenderProc ( void * /*inRefCon*/, + AudioUnitRenderActionFlags * /*inActionFlags*/, + const AudioTimeStamp * /*inTimeStamp*/, + UInt32 /*inBusNumber*/, + UInt32 /*inNumFrames*/, + AudioBufferList *ioData) +{ + AudioBuffer *buf = ioData->mBuffers; + for (UInt32 i = ioData->mNumberBuffers; i--; ++buf) + memset((Byte *)buf->mData, 0, buf->mDataByteSize); + + return noErr; +} + +OSStatus CAAudioUnit::Preroll (UInt32 inFrameSize) +{ + CAStreamBasicDescription desc; + OSStatus result = GetFormat (kAudioUnitScope_Input, 0, desc); + bool hasInput = false; + //we have input + if (result == noErr) + { + sRenderCallback.inputProc = PrerollRenderProc; + sRenderCallback.inputProcRefCon = 0; + + result = SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, + 0, &sRenderCallback, sizeof(sRenderCallback)); + if (result) return result; + hasInput = true; + } + + AudioUnitRenderActionFlags flags = 0; + AudioTimeStamp time; + memset (&time, 0, sizeof(time)); + time.mFlags = kAudioTimeStampSampleTimeValid; + + CAStreamBasicDescription outputFormat; + require_noerr (result = GetFormat (kAudioUnitScope_Output, 0, outputFormat), home); + { + AUOutputBL list (outputFormat, inFrameSize); + list.Prepare (); + + require_noerr (result = Render (&flags, &time, 0, inFrameSize, list.ABL()), home); + require_noerr (result = GlobalReset(), home); + } + +home: + if (hasInput) { + // remove our installed callback + sRenderCallback.inputProc = 0; + sRenderCallback.inputProcRefCon = 0; + + SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, + 0, &sRenderCallback, sizeof(sRenderCallback)); + } + return result; +} + +#pragma mark __CAAUChanHelper + +CAAUChanHelper::CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope) + :mChans(NULL), mNumEls(0), mDidAllocate(false) +{ + UInt32 elCount; + if (inAU.GetElementCount (inScope, elCount)) return; + if (elCount > 8) { + mChans = new UInt32[elCount]; + mDidAllocate = true; + memset (mChans, 0, sizeof(int) * elCount); + } else { + mChans = mStaticChans; + memset (mChans, 0, sizeof(int) * 8); + } + for (unsigned int i = 0; i < elCount; ++i) { + UInt32 numChans; + if (inAU.NumberChannels (inScope, i, numChans)) return; + mChans[i] = numChans; + } + mNumEls = elCount; +} + +CAAUChanHelper::~CAAUChanHelper() +{ + if (mDidAllocate) delete [] mChans; +} + +CAAUChanHelper& CAAUChanHelper::operator= (const CAAUChanHelper &c) +{ + if (mDidAllocate) delete [] mChans; + if (c.mDidAllocate) { + mChans = new UInt32[c.mNumEls]; + mDidAllocate = true; + } else { + mDidAllocate = false; + mChans = mStaticChans; + } + memcpy (mChans, c.mChans, c.mNumEls * sizeof(int)); + + return *this; +} + +#pragma mark __Print Utilities + +void CAAudioUnit::Print (FILE* file) const +{ + fprintf (file, "AudioUnit:%p\n", AU()); + if (IsValid()) { + fprintf (file, "\tnode=%ld\t", (long)GetAUNode()); Comp().Print (file); + } +} diff --git a/libs/appleutility/CAAudioUnit.h b/libs/appleutility/CAAudioUnit.h new file mode 100644 index 0000000000..6bc31bf30b --- /dev/null +++ b/libs/appleutility/CAAudioUnit.h @@ -0,0 +1,383 @@ +/* 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. +*/ +/*============================================================================= + CAAudioUnit.h + +=============================================================================*/ + +#ifndef __CAAudioUnit_h__ +#define __CAAudioUnit_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include + #include + #include +#else + #include + #include + #include + #include + #include +#endif + +#include +#include "CAStreamBasicDescription.h" +#include "CAComponent.h" +#include "CAAudioChannelLayout.h" + +// defined below +class CAAUChanHelper; + +// These constructors will NOT throw exceptions - so "check" after creation if AU IsValid() +// The destructor will NOT automatically close the AU down +// This state should be managed by the Caller +// once closed, the unit represented by this object is no longer valid +// it is up to the user of this object to ensure its validity is in sync +// if it is removed from a graph + +// methods that can significantly change the state of the AU (like its format) are +// NOT const whereas those that don't change the externally related state of the AU are not const + +class CAAudioUnit { +public: + typedef std::vector ChannelTagVector; + typedef ChannelTagVector::iterator ChannelTagVectorIter; + +public: + CAAudioUnit () + : mDataPtr(0) {} + + CAAudioUnit (const AudioUnit& inUnit); + + CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit); + + CAAudioUnit (const CAAudioUnit& y) + : mDataPtr(0) { *this = y; } + + static OSStatus Open (const CAComponent& inComp, CAAudioUnit &outUnit); + + ~CAAudioUnit (); + + + CAAudioUnit& operator= (const CAAudioUnit& y); + + bool operator== (const CAAudioUnit& y) const; + + bool operator== (const AudioUnit& y) const; + +#pragma mark __State Management + bool IsValid () const; + + AudioUnit AU() const; + operator AudioUnit () const { return AU(); } + + const CAComponent& Comp() const { return mComp; } + + bool FromAUGraph () const { return GetAUNode() != 0 || GetAUNode() != -1; } + + AUNode GetAUNode () const; + operator AUNode () const { return GetAUNode(); } + +#pragma mark __API Wrapper + OSStatus Initialize() const { return AudioUnitInitialize(AU()); } + OSStatus Uninitialize() const { return AudioUnitUninitialize(AU()); } + OSStatus GetPropertyInfo(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + UInt32 *outDataSize, Boolean *outWritable) const + { + return AudioUnitGetPropertyInfo(AU(), propID, scope, element, outDataSize, outWritable); + } + OSStatus GetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + void *outData, UInt32 *ioDataSize) const + { + return AudioUnitGetProperty(AU(), propID, scope, element, outData, ioDataSize); + } + OSStatus SetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + const void *inData, UInt32 inDataSize) + { + return AudioUnitSetProperty(AU(), propID, scope, element, inData, inDataSize); + } + OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames=0); + + OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const; + + OSStatus Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData); + + OSStatus Reset (AudioUnitScope scope, AudioUnitElement element) + { + return AudioUnitReset (AU(), scope, element); + } + OSStatus GlobalReset () + { + return AudioUnitReset (AU(), kAudioUnitScope_Global, 0); + } + + OSStatus Preroll (UInt32 inFrameSize); + + OSStatus AddRenderNotify (AURenderCallback inProc, void *inProcRefCon) + { + return AudioUnitAddRenderNotify (AU(), inProc, inProcRefCon); + } + + OSStatus RemoveRenderNotify (AURenderCallback inProc, void *inProcRefCon) + { + return AudioUnitRemoveRenderNotify (AU(), inProc, inProcRefCon); + } + + +// Fast dispatch support for MIDI Effects or Music Devices + OSStatus MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame); + + // uses the default VoiceForGroup value - this is the normal case + OSStatus StartNote (MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) + { + return StartNote (kMusicNoteEvent_UseGroupInstrument, + inGroupID, outNoteInstanceID, + inOffsetSampleFrame, inParams); + } + + OSStatus StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams); + + OSStatus StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame); + +#pragma mark __Format Utilities + // typically you ask this about an AU + // These Questions are asking about Input and Output... + + // These ones just say whether an AU can do a single combination of channels + // and is fine if the AU has a single output (and if an input, a single input) + bool CanDo (int inChannelsInOut) const + { + return CanDo (inChannelsInOut, inChannelsInOut); + } + + bool CanDo ( int inChannelsIn, + int inChannelsOut) const; + + // This version does a more thorough test for ANY AU with ANY ins/outs + // you pass in the channel helper (for the current element count on that scope) + + bool CanDo ( const CAAUChanHelper &input, + const CAAUChanHelper &output) const; + + bool SupportsNumChannels () const; + + bool HasChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl) const; + + bool GetChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl, + ChannelTagVector &outChannelVector) const; + + OSStatus GetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &outLayout) const; + + OSStatus SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &inLayout); + + OSStatus SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioChannelLayout &inLayout, + UInt32 inSize); + + OSStatus ClearChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl); + + OSStatus GetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioStreamBasicDescription &outFormat) const; + // if an AudioChannelLayout is either required or set, this call can fail + // and the SetChannelLayout call should be used to set the format + OSStatus SetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + const AudioStreamBasicDescription &inFormat); + + OSStatus GetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 &outRate) const; + OSStatus SetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 inRate); + + // this sets the sample rate on all in/out buses of the AU + OSStatus SetSampleRate (Float64 inSampleRate); + + OSStatus NumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const; + + OSStatus GetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const + { + return NumberChannels (inScope, inEl, outChans); + } + + OSStatus SetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 inChans); + + OSStatus IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const; + + OSStatus GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const; + + OSStatus SetElementCount (AudioUnitScope inScope, UInt32 inCount); + + // value of -1 for outTotalNumChannels indicates no restriction on num channels + // for ex. the Matrix Mixer satisfies this (its in/out element count is writable, and can be set to + // any number of channels. + // outTotalNumChannels is only valid if method returns true... + bool HasDynamicInputs (SInt32 &outTotalNumChannels) const + { + return HasDynamicScope (kAudioUnitScope_Input, outTotalNumChannels); + } + + bool HasDynamicOutputs (SInt32 &outTotalNumChannels) const + { + return HasDynamicScope (kAudioUnitScope_Output, outTotalNumChannels); + } + + // here, if the in (or out) elements are dynamic, then you supply the number of elements + // you want on in (or out) scope, and the number of channels on each consecutive element + OSStatus ConfigureDynamicInput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate) + { + return ConfigureDynamicScope (kAudioUnitScope_Input, inNumElements, inChannelsPerElement, inSampleRate); + } + + OSStatus ConfigureDynamicOutput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate) + { + return ConfigureDynamicScope (kAudioUnitScope_Output, inNumElements, inChannelsPerElement, inSampleRate); + } + + bool CanBypass () const; + + bool GetBypass () const; + + OSStatus SetBypass (bool inBypass) const; + + Float64 Latency () const; + + // these calls just deal with the global preset state + // you could rescope them to deal with presets on the part scope + OSStatus GetAUPreset (CFPropertyListRef &outData) const; + + OSStatus SetAUPreset (CFPropertyListRef &inData); + + OSStatus GetPresentPreset (AUPreset &outData) const; + + OSStatus SetPresentPreset (AUPreset &inData); + + bool HasCustomView () const; + +#pragma mark __Print + void Print () const { Print (stdout); } + void Print (FILE* file) const; + +private: + CAComponent mComp; + + class AUState; + AUState* mDataPtr; + + // this can throw - so wrap this up in a static that returns a result code... + CAAudioUnit (const CAComponent& inComp); + + bool HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const; + OSStatus ConfigureDynamicScope (AudioUnitScope inScope, + UInt32 inNumElements, + UInt32 *inChannelsPerElement, + Float64 inSampleRate); + bool ValidateChannelPair (int inChannelsIn, + int inChannelsOut, + const AUChannelInfo * info, + UInt32 numChanInfo) const; + + bool ValidateDynamicScope (AudioUnitScope inScope, + SInt32 &outTotalNumChannels, + const AUChannelInfo * info, + UInt32 numInfo) const; + bool CheckOneSide (const CAAUChanHelper &inHelper, + bool checkOutput, + const AUChannelInfo *info, + UInt32 numInfo) const; + +}; + +class CAAUChanHelper { +public: + CAAUChanHelper() + : mChans(mStaticChans), mNumEls(0), mDidAllocate(false) + { + memset (mChans, 0, sizeof(UInt32) * 8); + } + CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope); + CAAUChanHelper (const CAAUChanHelper &c) :mChans(mStaticChans), mNumEls(0), mDidAllocate(false) { *this = c; } + + ~CAAUChanHelper(); + + CAAUChanHelper& operator= (const CAAUChanHelper &c); + + UInt32 * mChans; + UInt32 mNumEls; + +private: + UInt32 mStaticChans[8]; + bool mDidAllocate; +}; + +#endif diff --git a/libs/appleutility/CACFDictionary.cpp b/libs/appleutility/CACFDictionary.cpp new file mode 100644 index 0000000000..c209b5fc36 --- /dev/null +++ b/libs/appleutility/CACFDictionary.cpp @@ -0,0 +1,478 @@ +/* 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. +*/ +/*============================================================================= + CACFDictionary.cpp + CAAudioEngine + +=============================================================================*/ + +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CACFDictionary.h" + +// PublicUtility Includes +#include "CACFString.h" +#include "CACFNumber.h" + +//============================================================================= +// CACFDictionary +//============================================================================= + +bool CACFDictionary::HasKey(const CFStringRef inKey) const +{ + return CFDictionaryContainsKey(mCFDictionary, inKey) != 0; +} + +UInt32 CACFDictionary::Size () const +{ + return CFDictionaryGetCount(mCFDictionary); +} + +void CACFDictionary::GetKeys (const void **keys) const +{ + CFDictionaryGetKeysAndValues(mCFDictionary, keys, NULL); +} + +bool CACFDictionary::GetBool(const CFStringRef inKey, bool& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFBooleanGetTypeID())) + { + outValue = CFBooleanGetValue(static_cast(theValue)); + theAnswer = true; + } + else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt32 theNumericValue = 0; + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &theNumericValue); + outValue = theNumericValue != 0; + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetSInt32(const CFStringRef inKey, SInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt32(const CFStringRef inKey, UInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetSInt64(const CFStringRef inKey, SInt64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt64(const CFStringRef inKey, UInt64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat32(const CFStringRef inKey, Float32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberFloat32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat64(const CFStringRef inKey, Float64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberFloat64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetString(const CFStringRef inKey, CFStringRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetArray(const CFStringRef inKey, CFArrayRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetDictionary(const CFStringRef inKey, CFDictionaryRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetData(const CFStringRef inKey, CFDataRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDataGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetCFType(const CFStringRef inKey, CFTypeRef& outValue) const +{ + bool theAnswer = false; + + if(mCFDictionary != NULL) + { + outValue = CFDictionaryGetValue(mCFDictionary, inKey); + theAnswer = (outValue != NULL); + } + + return theAnswer; +} + +bool CACFDictionary::GetCFTypeWithCStringKey(const char* inKey, CFTypeRef& outValue) const +{ + bool theAnswer = false; + + if(mCFDictionary != NULL) + { + CACFString theKey(inKey); + if(theKey.IsValid()) + { + theAnswer = GetCFType(theKey.GetCFString(), outValue); + } + } + + return theAnswer; +} + +bool CACFDictionary::AddSInt32(const CFStringRef inKey, SInt32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddUInt32(const CFStringRef inKey, UInt32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddSInt64(const CFStringRef inKey, SInt64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddUInt64(const CFStringRef inKey, UInt64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddFloat32(const CFStringRef inKey, Float32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddFloat64(const CFStringRef inKey, Float64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddNumber(const CFStringRef inKey, const CFNumberRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddString(const CFStringRef inKey, const CFStringRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddArray(const CFStringRef inKey, const CFArrayRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddDictionary(const CFStringRef inKey, const CFDictionaryRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddData(const CFStringRef inKey, const CFDataRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddCFType(const CFStringRef inKey, const CFTypeRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CFDictionarySetValue(mCFDictionary, inKey, inValue); + theAnswer = true; + } + + return theAnswer; +} + +bool CACFDictionary::AddCFTypeWithCStringKey(const char* inKey, const CFTypeRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFString theKey(inKey); + if(theKey.IsValid()) + { + theAnswer = AddCFType(theKey.GetCFString(), inValue); + } + } + + return theAnswer; +} + +bool CACFDictionary::AddCString(const CFStringRef inKey, const char* inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFString theValue(inValue); + if(theValue.IsValid()) + { + theAnswer = AddCFType(inKey, theValue.GetCFString()); + } + } + + return theAnswer; +} diff --git a/libs/appleutility/CACFDictionary.h b/libs/appleutility/CACFDictionary.h new file mode 100644 index 0000000000..362b1c8821 --- /dev/null +++ b/libs/appleutility/CACFDictionary.h @@ -0,0 +1,141 @@ +/* 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. +*/ +/*============================================================================= + CACFDictionary.h + +=============================================================================*/ +#if !defined(__CACFDictionary_h__) +#define __CACFDictionary_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +//============================================================================= +// CACFDictionary +//============================================================================= + +class CACFDictionary +{ + +// Construction/Destruction +public: + CACFDictionary(bool inRelease) : mCFDictionary(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)), mRelease(inRelease), mMutable(true) {} + CACFDictionary(const CFDictionaryRef inCFDictionary, bool inRelease) : mCFDictionary(const_cast(inCFDictionary)), mRelease(inRelease), mMutable(true) {} + CACFDictionary(const CFMutableDictionaryRef inCFDictionary, bool inRelease) : mCFDictionary(inCFDictionary), mRelease(inRelease), mMutable(true) {} + CACFDictionary(const CACFDictionary& inDictionary) : mCFDictionary(inDictionary.mCFDictionary), mRelease(inDictionary.mRelease), mMutable(inDictionary.mMutable) { if(mRelease && (mCFDictionary != NULL)) { CFRetain(mCFDictionary); } } + CACFDictionary& operator=(const CACFDictionary& inDictionary) { mCFDictionary = inDictionary.mCFDictionary; mRelease = inDictionary.mRelease; mMutable = inDictionary.mMutable; if(mRelease && (mCFDictionary != NULL)) { CFRetain(mCFDictionary); } return *this; } + ~CACFDictionary() { if(mRelease && (mCFDictionary != NULL)) { CFRelease(mCFDictionary); } } + +// Attributes +public: + bool IsValid() const { return mCFDictionary != NULL; } + bool IsMutable() const { return mMutable;} + bool CanModify() const { return mMutable && (mCFDictionary != NULL); } + + bool WillRelease() const { return mRelease; } + void ShouldRelease(bool inRelease) { mRelease = inRelease; } + + CFDictionaryRef GetDict() const { return mCFDictionary; } + CFDictionaryRef GetCFDictionary() const { return mCFDictionary; } + CFDictionaryRef CopyCFDictionary() const { if(mCFDictionary != NULL) { CFRetain(mCFDictionary); } return mCFDictionary; } + + CFMutableDictionaryRef GetMutableDict() { return mCFDictionary; } + CFMutableDictionaryRef GetCFMutableDictionary() const { return mCFDictionary; } + CFMutableDictionaryRef CopyCFMutableDictionary() const { if(mCFDictionary != NULL) { CFRetain(mCFDictionary); } return mCFDictionary; } + void SetCFMutableDictionaryFromCopy(CFDictionaryRef inDictionary, bool inRelease = true) { if(mRelease && (mCFDictionary != NULL)) { CFRelease(mCFDictionary); } mCFDictionary = CFDictionaryCreateMutableCopy(NULL, 0, inDictionary); mMutable = true; mRelease = inRelease; } + + CFPropertyListRef AsPropertyList() const { return mCFDictionary; } + OSStatus GetDictIfMutable(CFMutableDictionaryRef& outDict) const { OSStatus theAnswer = -1; if(mMutable) { outDict = mCFDictionary; theAnswer = 0; } return theAnswer; } + +// Item Operations +public: + bool HasKey(const CFStringRef inKey) const; + UInt32 Size() const; + void GetKeys(const void** keys) const; + + bool GetBool(const CFStringRef inKey, bool& outValue) const; + bool GetSInt32(const CFStringRef inKey, SInt32& outValue) const; + bool GetUInt32(const CFStringRef inKey, UInt32& outValue) const; + bool GetSInt64(const CFStringRef inKey, SInt64& outValue) const; + bool GetUInt64(const CFStringRef inKey, UInt64& outValue) const; + bool GetFloat32(const CFStringRef inKey, Float32& outValue) const; + bool GetFloat64(const CFStringRef inKey, Float64& outValue) const; + bool GetString(const CFStringRef inKey, CFStringRef& outValue) const; + bool GetArray(const CFStringRef inKey, CFArrayRef& outValue) const; + bool GetDictionary(const CFStringRef inKey, CFDictionaryRef& outValue) const; + bool GetData(const CFStringRef inKey, CFDataRef& outValue) const; + bool GetCFType(const CFStringRef inKey, CFTypeRef& outValue) const; + + bool GetCFTypeWithCStringKey(const char* inKey, CFTypeRef& outValue) const; + + bool AddSInt32(const CFStringRef inKey, SInt32 inValue); + bool AddUInt32(const CFStringRef inKey, UInt32 inValue); + bool AddSInt64(const CFStringRef inKey, SInt64 inValue); + bool AddUInt64(const CFStringRef inKey, UInt64 inValue); + bool AddFloat32(const CFStringRef inKey, Float32 inValue); + bool AddFloat64(const CFStringRef inKey, Float64 inValue); + bool AddNumber(const CFStringRef inKey, const CFNumberRef inValue); + bool AddString(const CFStringRef inKey, const CFStringRef inValue); + bool AddArray(const CFStringRef inKey, const CFArrayRef inValue); + bool AddDictionary(const CFStringRef inKey, const CFDictionaryRef inValue); + bool AddData(const CFStringRef inKey, const CFDataRef inValue); + bool AddCFType(const CFStringRef inKey, const CFTypeRef inValue); + + bool AddCFTypeWithCStringKey(const char* inKey, const CFTypeRef inValue); + bool AddCString(const CFStringRef inKey, const char* inValue); + + void Clear() { if(CanModify()) { CFDictionaryRemoveAllValues(mCFDictionary); } } + + void Show() { CFShow(mCFDictionary); } + +// Implementation +private: + CFMutableDictionaryRef mCFDictionary; + bool mRelease; + bool mMutable; +}; + +#endif //__CACFDictionary_h__ diff --git a/libs/appleutility/CACFNumber.cpp b/libs/appleutility/CACFNumber.cpp new file mode 100644 index 0000000000..3b6160c8bb --- /dev/null +++ b/libs/appleutility/CACFNumber.cpp @@ -0,0 +1,65 @@ +/* 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. +*/ +/*============================================================================= + CACFNumber.cp + +=============================================================================*/ + +//============================================================================= +// Includes +//============================================================================= + +#include "CACFNumber.h" + +//============================================================================= +// CACFNumber +//============================================================================= + +Float32 CACFNumber::GetFixed32() const +{ + SInt32 theFixedValue = GetSInt32(); + + // this is a 16.16 value so convert it to a float + Float32 theSign = theFixedValue < 0 ? -1.0 : 1.0; + theFixedValue *= (SInt32)theSign; + Float32 theWholePart = (theFixedValue & 0x7FFF0000) >> 16; + Float32 theFractPart = theFixedValue & 0x0000FFFF; + theFractPart /= 65536.0; + + return theSign * (theWholePart + theFractPart); +} diff --git a/libs/appleutility/CACFNumber.h b/libs/appleutility/CACFNumber.h new file mode 100644 index 0000000000..3991637bac --- /dev/null +++ b/libs/appleutility/CACFNumber.h @@ -0,0 +1,102 @@ +/* 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. +*/ +/*============================================================================= + CACFNumber.h + +=============================================================================*/ +#if !defined(__CACFNumber_h__) +#define __CACFNumber_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//============================================================================= +// CACFNumber +//============================================================================= + +class CACFNumber +{ +// Construction/Destruction +public: + CACFNumber(CFNumberRef inCFNumber, bool inWillRelease = true) : mCFNumber(inCFNumber), mWillRelease(inWillRelease) {} + CACFNumber(SInt32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt32Type, &inValue)), mWillRelease(true) {} + CACFNumber(UInt32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt32Type, &inValue)), mWillRelease(true) {} + CACFNumber(SInt64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt64Type, &inValue)), mWillRelease(true) {} + CACFNumber(UInt64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt64Type, &inValue)), mWillRelease(true) {} + CACFNumber(Float32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberFloat32Type, &inValue)), mWillRelease(true) {} + CACFNumber(Float64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberFloat64Type, &inValue)), mWillRelease(true) {} + ~CACFNumber() { Release(); } + CACFNumber(const CACFNumber& inNumber) : mCFNumber(inNumber.mCFNumber), mWillRelease(inNumber.mWillRelease) { Retain(); } + CACFNumber& operator=(const CACFNumber& inNumber) { Release(); mCFNumber = inNumber.mCFNumber; mWillRelease = inNumber.mWillRelease; Retain(); return *this; } + CACFNumber& operator=(CFNumberRef inCFNumber) { Release(); mCFNumber = inCFNumber; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFNumber != NULL)) { CFRetain(mCFNumber); } } + void Release() { if(mWillRelease && (mCFNumber != NULL)) { CFRelease(mCFNumber); } } + + CFNumberRef mCFNumber; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFNumber != NULL; } + +// Value Access +public: + CFNumberRef GetCFNumber() const { return mCFNumber; } + CFNumberRef CopyCFNumber() const { if(mCFNumber != NULL) { CFRetain(mCFNumber); } return mCFNumber; } + + SInt8 GetSInt8() const { SInt8 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt8Type, &theAnswer); } return theAnswer; } + SInt32 GetSInt32() const { SInt32 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt32Type, &theAnswer); } return theAnswer; } + Float32 GetFloat32() const { Float32 theAnswer = 0.0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberFloat32Type, &theAnswer); } return theAnswer; } + Float32 GetFixed32() const; + SInt64 GetSInt64() const { SInt64 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt64Type, &theAnswer); } return theAnswer; } +}; + +#endif diff --git a/libs/appleutility/CACFString.cpp b/libs/appleutility/CACFString.cpp new file mode 100644 index 0000000000..ec3b18a8b6 --- /dev/null +++ b/libs/appleutility/CACFString.cpp @@ -0,0 +1,106 @@ +/* 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. +*/ +/*============================================================================= + CACFString.cp + +=============================================================================*/ + +//============================================================================= +// Includes +//============================================================================= + +#include "CACFString.h" + +//============================================================================= +// CACFString +//============================================================================= + +UInt32 CACFString::GetStringByteLength(CFStringRef inCFString, CFStringEncoding inEncoding) +{ + UInt32 theAnswer = 0; + + if(inCFString != NULL) + { + CFRange theRange = { 0, CFStringGetLength(inCFString) }; + CFStringGetBytes(inCFString, theRange, inEncoding, 0, false, NULL, 0x7FFFFFFF, (CFIndex*)&theAnswer); + } + + return theAnswer; +} + +void CACFString::GetCString(CFStringRef inCFString, char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding) +{ + if(ioStringSize > 0) + { + if(inCFString != NULL) + { + CFIndex theLength = 0; + CFRange theRange = { 0, CFStringGetLength(inCFString) }; + CFStringGetBytes(inCFString, theRange, inEncoding, 0, false, (UInt8*)outString, ioStringSize - 1, &theLength); + outString[theLength] = 0; + ioStringSize = theLength + 1; + } + else + { + outString[0] = 0; + ioStringSize = 1; + } + } +} + +void CACFString::GetUnicodeString(CFStringRef inCFString, UInt16* outString, UInt32& ioStringSize) +{ + if(ioStringSize > 0) + { + if(inCFString != NULL) + { + CFRange theStringRange = { 0, CFStringGetLength(inCFString) }; + if(static_cast(theStringRange.length) > ioStringSize) + { + theStringRange.length = ioStringSize; + } + CFStringGetCharacters(inCFString, theStringRange, outString); + ioStringSize = theStringRange.length; + } + else + { + outString[0] = 0; + ioStringSize = 0; + } + } +} diff --git a/libs/appleutility/CACFString.h b/libs/appleutility/CACFString.h new file mode 100644 index 0000000000..51fa64ebff --- /dev/null +++ b/libs/appleutility/CACFString.h @@ -0,0 +1,156 @@ +/* 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. +*/ +/*============================================================================= + CACFString.h + +=============================================================================*/ +#if !defined(__CACFString_h__) +#define __CACFString_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//============================================================================= +// CACFString +//============================================================================= + +class CACFString +{ +// Construction/Destruction +public: + CACFString() : mCFString(NULL), mWillRelease(true) {} + CACFString(CFStringRef inCFString, bool inWillRelease = true) : mCFString(inCFString), mWillRelease(inWillRelease) {} + CACFString(const char* inCString, bool inWillRelease = true) : mCFString(CFStringCreateWithCString(NULL, inCString, kCFStringEncodingASCII)), mWillRelease(inWillRelease) {} + CACFString(const char* inCString, CFStringEncoding inCStringEncoding, bool inWillRelease = true) : mCFString(CFStringCreateWithCString(NULL, inCString, inCStringEncoding)), mWillRelease(inWillRelease) {} + ~CACFString() { Release(); } + CACFString(const CACFString& inString) : mCFString(inString.mCFString), mWillRelease(inString.mWillRelease) { Retain(); } + CACFString& operator=(const CACFString& inString) { Release(); mCFString = inString.mCFString; mWillRelease = inString.mWillRelease; Retain(); return *this; } + CACFString& operator=(CFStringRef inCFString) { Release(); mCFString = inCFString; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFString != NULL)) { CFRetain(mCFString); } } + void Release() { if(mWillRelease && (mCFString != NULL)) { CFRelease(mCFString); } } + + CFStringRef mCFString; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() const { return mCFString != NULL; } + bool StartsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringHasPrefix(mCFString, inString); } return theAnswer; } + bool EndsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringHasSuffix(mCFString, inString); } return theAnswer; } + +// Value Access +public: + CFStringRef GetCFString() const { return mCFString; } + CFStringRef CopyCFString() const { if(mCFString != NULL) { CFRetain(mCFString); } return mCFString; } + UInt32 GetLength() const { UInt32 theAnswer = 0; if(mCFString != NULL) { theAnswer = CFStringGetLength(mCFString); } return theAnswer; } + UInt32 GetByteLength(CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { UInt32 theAnswer = 0; if(mCFString != NULL) { theAnswer = GetStringByteLength(mCFString, inEncoding); } return theAnswer; } + void GetCString(char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { GetCString(mCFString, outString, ioStringSize, inEncoding); } + void GetUnicodeString(UInt16* outString, UInt32& ioStringSize) const { GetUnicodeString(mCFString, outString, ioStringSize); } + + static UInt32 GetStringByteLength(CFStringRef inCFString, CFStringEncoding inEncoding = kCFStringEncodingUTF8); + static void GetCString(CFStringRef inCFString, char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8); + static void GetUnicodeString(CFStringRef inCFString, UInt16* outString, UInt32& ioStringSize); + +}; + +inline bool operator<(const CACFString& x, const CACFString& y) { return CFStringCompare(x.GetCFString(), y.GetCFString(), 0) == kCFCompareLessThan; } +inline bool operator==(const CACFString& x, const CACFString& y) { return CFStringCompare(x.GetCFString(), y.GetCFString(), 0) == kCFCompareEqualTo; } +inline bool operator!=(const CACFString& x, const CACFString& y) { return !(x == y); } +inline bool operator<=(const CACFString& x, const CACFString& y) { return (x < y) || (x == y); } +inline bool operator>=(const CACFString& x, const CACFString& y) { return !(x < y); } +inline bool operator>(const CACFString& x, const CACFString& y) { return !((x < y) || (x == y)); } + +//============================================================================= +// CACFMutableString +//============================================================================= + +class CACFMutableString +{ +// Construction/Destruction +public: + CACFMutableString() : mCFMutableString(NULL), mWillRelease(true) {} + CACFMutableString(CFMutableStringRef inCFMutableString, bool inWillRelease = true) : mCFMutableString(inCFMutableString), mWillRelease(inWillRelease) {} + CACFMutableString(CFStringRef inStringToCopy, bool /*inMakeCopy*/, bool inWillRelease = true) : mCFMutableString(CFStringCreateMutableCopy(NULL, 0, inStringToCopy)), mWillRelease(inWillRelease) {} + CACFMutableString(const char* inCString, bool inWillRelease = true) : mCFMutableString(NULL), mWillRelease(inWillRelease) { CACFString theString(inCString); mCFMutableString = CFStringCreateMutableCopy(NULL, 0, theString.GetCFString()); } + CACFMutableString(const char* inCString, CFStringEncoding inCStringEncoding, bool inWillRelease = true) : mCFMutableString(NULL), mWillRelease(inWillRelease) { CACFString theString(inCString, inCStringEncoding); mCFMutableString = CFStringCreateMutableCopy(NULL, 0, theString.GetCFString()); } + ~CACFMutableString() { Release(); } + CACFMutableString(const CACFMutableString& inString) : mCFMutableString(inString.mCFMutableString), mWillRelease(inString.mWillRelease) { Retain(); } + CACFMutableString operator=(const CACFMutableString& inString) { Release(); mCFMutableString = inString.mCFMutableString; mWillRelease = inString.mWillRelease; Retain(); return *this; } + CACFMutableString operator=(CFMutableStringRef inCFMutableString) { Release(); mCFMutableString = inCFMutableString; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFMutableString != NULL)) { CFRetain(mCFMutableString); } } + void Release() { if(mWillRelease && (mCFMutableString != NULL)) { CFRelease(mCFMutableString); } } + + CFMutableStringRef mCFMutableString; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFMutableString != NULL; } + bool StartsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringHasPrefix(mCFMutableString, inString); } return theAnswer; } + bool EndsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringHasSuffix(mCFMutableString, inString); } return theAnswer; } + void Append(CFStringRef inString) { if(mCFMutableString != NULL) { CFStringAppend(mCFMutableString, inString); } } + +// Value Access +public: + CFMutableStringRef GetCFMutableString() const { return mCFMutableString; } + CFMutableStringRef CopyCFMutableString() const { if(mCFMutableString != NULL) { CFRetain(mCFMutableString); } return mCFMutableString; } + UInt32 GetLength() const { UInt32 theAnswer = 0; if(mCFMutableString != NULL) { theAnswer = CFStringGetLength(mCFMutableString); } return theAnswer; } + UInt32 GetByteLength(CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { UInt32 theAnswer = 0; if(mCFMutableString != NULL) { theAnswer = CACFString::GetStringByteLength(mCFMutableString, inEncoding); } return theAnswer; } + void GetCString(char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { CACFString::GetCString(mCFMutableString, outString, ioStringSize, inEncoding); } + void GetUnicodeString(UInt16* outString, UInt32& ioStringSize) const { CACFString::GetUnicodeString(mCFMutableString, outString, ioStringSize); } + +}; + +#endif diff --git a/libs/appleutility/CAComponent.cpp b/libs/appleutility/CAComponent.cpp new file mode 100644 index 0000000000..700d9e2b3e --- /dev/null +++ b/libs/appleutility/CAComponent.cpp @@ -0,0 +1,257 @@ +/* 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. +*/ +/*============================================================================= + CAComponent.cpp + +=============================================================================*/ + +#include "CAComponent.h" +#include "CAComponentDescription.h" +#include "CACFDictionary.h" +#include + +CAComponent::CAComponent (const ComponentDescription& inDesc, CAComponent* next) + : mManuName(0), mAUName(0), mCompName(0), mCompInfo (0) +{ + mComp = FindNextComponent ((next ? next->Comp() : NULL), const_cast(&inDesc)); + if (mComp) + GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); + else + memcpy (&mDesc, &inDesc, sizeof(ComponentDescription)); +} + +CAComponent::CAComponent (const Component& comp) + : mComp (comp), + mManuName(0), + mAUName(0), + mCompName(0), + mCompInfo (0) +{ + GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); +} + +CAComponent::CAComponent (const ComponentInstance& compInst) + : mComp (Component(compInst)), + mManuName(0), + mAUName(0), + mCompName(0), + mCompInfo (0) +{ + GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); +} + +CAComponent::CAComponent (OSType inType, OSType inSubtype, OSType inManu) + : mDesc (inType, inSubtype, inManu), + mManuName(0), mAUName(0), mCompName(0), mCompInfo (0) +{ + mComp = FindNextComponent (NULL, &mDesc); + GetComponentInfo (Comp(), &mDesc, NULL, NULL, NULL); +} + +CAComponent::~CAComponent () +{ + Clear(); +} + +OSStatus CAComponent::GetResourceVersion (UInt32 &outVersion) const +{ + bool versionFound = false; + short componentResFileID = kResFileNotOpened; + OSStatus result; + short thngResourceCount; + + short curRes = CurResFile(); + require_noerr (result = OpenAComponentResFile( mComp, &componentResFileID), home); + require_noerr (result = componentResFileID <= 0, home); + + UseResFile(componentResFileID); + + thngResourceCount = Count1Resources(kComponentResourceType); + + require_noerr (result = ResError(), home); + // only go on if we successfully found at least 1 thng resource + require_noerr (thngResourceCount <= 0 ? -1 : 0, home); + + // loop through all of the Component thng resources trying to + // find one that matches this Component description + for (short i = 0; i < thngResourceCount && (!versionFound); i++) + { + // try to get a handle to this code resource + Handle thngResourceHandle = Get1IndResource(kComponentResourceType, i+1); + if (thngResourceHandle != NULL && ((*thngResourceHandle) != NULL)) + { + if (UInt32(GetHandleSize(thngResourceHandle)) >= sizeof(ExtComponentResource)) + { + ExtComponentResource * componentThng = (ExtComponentResource*) (*thngResourceHandle); + + // check to see if this is the thng resource for the particular Component that we are looking at + // (there often is more than one Component described in the resource) + if ((componentThng->cd.componentType == mDesc.Type()) + && (componentThng->cd.componentSubType == mDesc.SubType()) + && (componentThng->cd.componentManufacturer == mDesc.Manu())) + { + outVersion = componentThng->componentVersion; + versionFound = true; + } + } + ReleaseResource(thngResourceHandle); + } + } + + if (!versionFound) + result = resNotFound; + + UseResFile(curRes); // revert + + if ( componentResFileID != kResFileNotOpened ) + CloseComponentResFile(componentResFileID); + +home: + return result; +} + +void CAComponent::Clear () +{ + if (mManuName) { CFRelease (mManuName); mManuName = 0; } + if (mAUName) { CFRelease (mAUName); mAUName = 0; } + if (mCompName) { CFRelease (mCompName); mCompName = 0; } + if (mCompInfo) { CFRelease (mCompInfo); mCompInfo = 0; } +} + +CAComponent& CAComponent::operator= (const CAComponent& y) +{ + Clear(); + + mComp = y.mComp; + mDesc = y.mDesc; + + if (y.mManuName) { mManuName = y.mManuName; CFRetain (mManuName); } + if (y.mAUName) { mAUName = y.mAUName; CFRetain (mAUName); } + if (y.mCompName) { mCompName = y.mCompName; CFRetain (mCompName); } + if (y.mCompInfo) { mCompInfo = y.mCompInfo; CFRetain (mCompInfo); } + + return *this; +} + +void CAComponent::SetCompNames () const +{ + if (!mCompName) { + Handle h1 = NewHandle(4); + CAComponentDescription desc; + OSStatus err = GetComponentInfo (Comp(), &desc, h1, 0, 0); + + if (err) { DisposeHandle(h1); return; } + + HLock(h1); + char* ptr1 = *h1; + // Get the manufacturer's name... look for the ':' character convention + int len = *ptr1++; + char* displayStr = 0; + + const_cast(this)->mCompName = CFStringCreateWithPascalString(NULL, (const unsigned char*)*h1, kCFStringEncodingMacRoman); + + for (int i = 0; i < len; ++i) { + if (ptr1[i] == ':') { // found the name + ptr1[i] = 0; + displayStr = ptr1; + break; + } + } + + if (displayStr) + { + const_cast(this)->mManuName = CFStringCreateWithCString(NULL, displayStr, kCFStringEncodingMacRoman); + + //move displayStr ptr past the manu, to the name + // we move the characters down a index, because the handle doesn't have any room + // at the end for the \0 + int i = strlen(displayStr), j = 0; + while (displayStr[++i] == ' ' && i < len) + ; + while (i < len) + displayStr[j++] = displayStr[i++]; + displayStr[j] = 0; + + const_cast(this)->mAUName = CFStringCreateWithCString(NULL, displayStr, kCFStringEncodingMacRoman); + } + + DisposeHandle (h1); + } +} + +void CAComponent::SetCompInfo () const +{ + if (!mCompInfo) { + Handle h1 = NewHandle(4); + CAComponentDescription desc; + OSStatus err = GetComponentInfo (Comp(), &desc, 0, h1, 0); + if (err) return; + HLock (h1); + const_cast(this)->mCompInfo = CFStringCreateWithPascalString(NULL, (const unsigned char*)*h1, kCFStringEncodingMacRoman); + + DisposeHandle (h1); + } +} + +void _ShowCF (FILE* file, CFStringRef str) +{ + if (CFGetTypeID(str) != CFStringGetTypeID()) { + CFShow(str); + return; + } + + UInt32 len = CFStringGetLength(str); + char* chars = (char*)malloc (len * 2); // give us plenty of room for unichar chars + if (CFStringGetCString (str, chars, len * 2, kCFStringEncodingUTF8)) + fprintf (file, "%s", chars); + else + CFShow (str); + + free (chars); +} + +void CAComponent::Print(FILE* file) const +{ + fprintf (file, "CAComponent: 0x%X", int(Comp())); + if (mManuName) { + fprintf (file, ", Manu:"); _ShowCF (file, mManuName); + if (mAUName) fprintf (file, ", Name:"); _ShowCF (file, mAUName); + } + fprintf (file, ", "); + Desc ().Print(file); +} diff --git a/libs/appleutility/CAComponent.h b/libs/appleutility/CAComponent.h new file mode 100644 index 0000000000..2ace42532d --- /dev/null +++ b/libs/appleutility/CAComponent.h @@ -0,0 +1,120 @@ +/* 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. +*/ +/*============================================================================= + CAComponent.h + +=============================================================================*/ + +#ifndef __CAComponent_h__ +#define __CAComponent_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include + #include +#endif + +#include "CAComponentDescription.h" + +class CAComponent +{ +public: + CAComponent () + : mComp (0), mDesc(), mManuName(0), mAUName(0), mCompName(0), mCompInfo (0) {} + + // if next is specifed that is used to find the next component after that one + CAComponent (const ComponentDescription& inDesc, CAComponent* next = 0); + + CAComponent (const CAComponent& y) + : mComp (0), mDesc(), mManuName(0), mAUName(0), mCompName(0), mCompInfo (0) { *this = y; } + + CAComponent (const Component& comp); + + CAComponent (const ComponentInstance& compInst); + + CAComponent (OSType inType, OSType inSubtype = 0, OSType inManu = 0); + + ~CAComponent (); + + CAComponent& operator= (const CAComponent& y); + + // returns true if this object references a valid component + bool IsValid () const { return Comp() != 0; } + + bool HasAUStrings() const { SetCompNames (); return mManuName != 0; } + + // CFStringRef should be retained by caller if needed beyond lifetime of this object + + // Can return NULL if component doesn't follow AU naming conventions + CFStringRef GetAUManu () const { SetCompNames (); return mManuName; } + CFStringRef GetAUName () const { SetCompNames (); return mAUName ? mAUName : mCompName; } + + // Return value of NULL indicates a problem getting that information from the component + CFStringRef GetCompName () const { SetCompNames(); return mCompName; } + CFStringRef GetCompInfo () const { SetCompInfo(); return mCompInfo; } + + const CAComponentDescription& Desc () const { return mDesc; } + + OSStatus Open (ComponentInstance& outInst) const + { + return OpenAComponent (Comp(), &outInst); + } + + OSStatus GetResourceVersion (UInt32 &outVersion) const; + + const Component& Comp() const { return mComp; } + + void Print(FILE* file = stdout) const; + + OSStatus Save (CFPropertyListRef *outData) const; + + OSStatus Restore (CFPropertyListRef &inData); + +private: + Component mComp; + CAComponentDescription mDesc; + + CFStringRef mManuName, mAUName, mCompName, mCompInfo; + + void SetCompNames () const; + void SetCompInfo () const; + void Clear (); +}; + +#endif diff --git a/libs/appleutility/CAComponentDescription.cpp b/libs/appleutility/CAComponentDescription.cpp new file mode 100644 index 0000000000..261a2b881c --- /dev/null +++ b/libs/appleutility/CAComponentDescription.cpp @@ -0,0 +1,123 @@ +/* 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. +*/ +/*============================================================================= + CAComponentDescription.cpp + +=============================================================================*/ + +#include "CAComponentDescription.h" +#include + +extern "C" void CAShowComponentDescription(const ComponentDescription *desc) +{ + CAComponentDescription::_CAShowComponentDescription (desc, stdout); +} + +char *StringForOSType (OSType t, char *writeLocation) +{ + char *p = writeLocation; + unsigned char str[4], *q = str; + *(UInt32 *)str = EndianU32_NtoB(t); + for (int i = 0; i < 4; ++i) { + if (isprint(*q) && *q != '\\') + *p++ = *q++; + else { + sprintf(p, "\\x%02X", *q++); + p += 4; + } + } + *p = '\0'; + return writeLocation; +} + + +void CAComponentDescription::_CAShowComponentDescription(const ComponentDescription *desc, FILE* file) +{ + if (desc) + { + char str[24]; + fprintf (file, "ComponentDescription: %s - ", StringForOSType(desc->componentType, str)); + fprintf (file, "%s - ", StringForOSType(desc->componentSubType, str)); + fprintf (file, "%s", StringForOSType(desc->componentManufacturer, str)); + fprintf (file, ", 0x%lX, 0x%lX\n", desc->componentFlags, desc->componentFlagsMask); + } +} + +CAComponentDescription::CAComponentDescription (OSType inType, OSType inSubtype, OSType inManu) +{ + componentType = inType; + componentSubType = inSubtype; + componentManufacturer = inManu; + componentFlags = 0; + componentFlagsMask = 0; +} + +bool CAComponentDescription::IsAU () const +{ + bool flag = IsEffect() || IsMusicDevice() || IsOffline(); + if (flag) return true; + + switch (componentType) { + case kAudioUnitType_Output: + case kAudioUnitType_FormatConverter: + case kAudioUnitType_Mixer: + return true; + } + return false; +} + +inline bool _MatchTest (const OSType &inTypeA, const OSType &inTypeB) +{ + return ((inTypeA == inTypeB) || (!inTypeA && !inTypeB) || (inTypeA && !inTypeB) || (!inTypeA && inTypeB)); +} + +bool CAComponentDescription::Matches (const ComponentDescription &desc) const +{ + bool matches = false; + + // see if the type matches + matches = _MatchTest (componentType, desc.componentType); + + if (matches) + matches = _MatchTest (componentSubType, desc.componentSubType); + + if (matches) + matches = _MatchTest (componentManufacturer, desc.componentManufacturer); + + return matches; +} diff --git a/libs/appleutility/CAComponentDescription.h b/libs/appleutility/CAComponentDescription.h new file mode 100644 index 0000000000..a681902b91 --- /dev/null +++ b/libs/appleutility/CAComponentDescription.h @@ -0,0 +1,148 @@ +/* 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. +*/ +/*============================================================================= + CAComponentDescription.h + +=============================================================================*/ + +#ifndef __CAComponentDescription_h__ +#define __CAComponentDescription_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include + #include +#endif + +#include "CACFDictionary.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void CAShowComponentDescription(const ComponentDescription *desc); + +#ifdef __cplusplus +} +#endif + + +// ____________________________________________________________________________ +// +// CAComponentDescription +class CAComponentDescription : public ComponentDescription { +public: + CAComponentDescription() { memset (this, 0, sizeof (ComponentDescription)); } + + CAComponentDescription (OSType inType, OSType inSubtype = 0, OSType inManu = 0); + + CAComponentDescription(const ComponentDescription& desc) { memcpy (this, &desc, sizeof (ComponentDescription)); } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // interrogation + + bool IsAU () const; + + bool IsAUFX() const { return componentType == kAudioUnitType_Effect; } + bool IsAUFM() const { return componentType == kAudioUnitType_MusicEffect; } + + bool IsEffect () const { return IsAUFX() || IsAUFM() || IsPanner(); } + + bool IsOffline () const { return componentType == 'auol'; } + + bool IsFConv () const { return componentType == kAudioUnitType_FormatConverter; } + + bool IsPanner () const { return componentType == kAudioUnitType_Panner; } + + bool IsMusicDevice () const { return componentType == kAudioUnitType_MusicDevice; } + +#ifndef MAC_OS_X_VERSION_10_4 + bool IsGenerator () const { return componentType =='augn'; } +#else + bool IsGenerator () const { return componentType ==kAudioUnitType_Generator; } +#endif + + bool IsOutput () const { return componentType == kAudioUnitType_Output; } + + bool IsSource () const { return IsMusicDevice() || IsGenerator(); } + + OSType Type () const { return componentType; } + OSType SubType () const { return componentSubType; } + OSType Manu () const { return componentManufacturer; } + + int Count() const { return CountComponents(const_cast(this)); } + + // does a semantic match where "wild card" values for type, subtype, manu will match + bool Matches (const ComponentDescription &desc) const; + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // other + + void Print(FILE* file = stdout) const { _CAShowComponentDescription (this, file); } + + OSStatus Save (CFPropertyListRef *outData) const; + OSStatus Restore (CFPropertyListRef &inData); + +private: + static void _CAShowComponentDescription (const ComponentDescription *desc, FILE* file); + friend void CAShowComponentDescription (const ComponentDescription *desc); +}; + +inline bool operator< (const ComponentDescription& x, const ComponentDescription& y) +{ + return memcmp (&x, &y, offsetof (ComponentDescription, componentFlags)) < 0; +} + +inline bool operator== (const ComponentDescription& x, const ComponentDescription& y) +{ + return !memcmp (&x, &y, offsetof (ComponentDescription, componentFlags)); +} + +inline bool operator!= (const ComponentDescription& x, const ComponentDescription& y) +{ + return !(x == y); +} + +#endif diff --git a/libs/appleutility/CAConditionalMacros.h b/libs/appleutility/CAConditionalMacros.h new file mode 100644 index 0000000000..62f642709a --- /dev/null +++ b/libs/appleutility/CAConditionalMacros.h @@ -0,0 +1,74 @@ +/* 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. +*/ +/*============================================================================= + CAConditionalMacros.h + +=============================================================================*/ +#if !defined(__CAConditionalMacros_h__) +#define __CAConditionalMacros_h__ + +//============================================================================= +// This file exists to make figuring out how to include system headers +// easier in a cross platform world. We throw in an include of the standard +// ConditionalMacros too. +//============================================================================= + +// ########## THIS FILE SHOULD GO AWAY SOON, replaced by __COREAUDIO_USE_FLAT_INCLUDES__ +// but for now, use this as a way to define __COREAUDIO_USE_FLAT_INCLUDES__ programmatically + +// TargetConditionals.h defines the bare minimum we need +#include "TargetConditionals.h" + +// Determine whether or not to use framework style includes for system headers +#if !defined(CoreAudio_Use_Framework_Includes) && !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #if TARGET_RT_MAC_MACHO + #define CoreAudio_Use_Framework_Includes 1 + #else + #define CoreAudio_Use_Framework_Includes 0 + #endif +#endif + +// Include the regular ConditionalMacros.h too, since it has useful stuff that +// TargetConditionals.h lacks for some reason. +#if CoreAudio_Use_Framework_Includes + #include +#else + #include "ConditionalMacros.h" +#endif + +#endif diff --git a/libs/appleutility/CADebugMacros.cpp b/libs/appleutility/CADebugMacros.cpp new file mode 100644 index 0000000000..edee1f3d51 --- /dev/null +++ b/libs/appleutility/CADebugMacros.cpp @@ -0,0 +1,84 @@ +/* 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. +*/ +/*============================================================================= + CADebugMacros.cp + +=============================================================================*/ + +#include "CADebugMacros.h" +#include +#include +#if TARGET_API_MAC_OSX + #include +#endif + +#if DEBUG +#include + +void DebugPrint(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} +#endif // DEBUG + +#if TARGET_API_MAC_OSX +void LogError(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); +#if DEBUG + vprintf(fmt, args); +#endif + vsyslog(LOG_ERR, fmt, args); + va_end(args); +} + +void LogWarning(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); +#if DEBUG + vprintf(fmt, args); +#endif + vsyslog(LOG_WARNING, fmt, args); + va_end(args); +} +#endif diff --git a/libs/appleutility/CADebugMacros.h b/libs/appleutility/CADebugMacros.h new file mode 100644 index 0000000000..1abae40187 --- /dev/null +++ b/libs/appleutility/CADebugMacros.h @@ -0,0 +1,414 @@ +/* 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. +*/ +/*============================================================================= + CADebugMacros.h + +=============================================================================*/ +#if !defined(__CADebugMacros_h__) +#define __CADebugMacros_h__ + +//============================================================================= +// CADebugMacros +//============================================================================= + +//#define CoreAudio_StopOnFailure 1 +//#define CoreAudio_TimeStampMessages 1 +//#define CoreAudio_ThreadStampMessages 1 +//#define CoreAudio_FlushDebugMessages 1 + +#define CA4CCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 } + +#pragma mark Basic Definitions + +#if DEBUG || CoreAudio_Debug + + // can be used to break into debugger immediately, also see CADebugger + #define BusError() (*(long *)0 = 0) + + // basic debugging print routines + #if TARGET_OS_MAC && !TARGET_API_MAC_CARBON + extern pascal void DebugStr(const unsigned char* debuggerMsg); + #define DebugMessage(msg) DebugStr("\p"msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) + #else + #include "CADebugPrintf.h" + + #if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile) + #define FlushRtn ;fflush(DebugPrintfFile) + #else + #define FlushRtn + #endif + + #if CoreAudio_ThreadStampMessages + #include + #include "CAHostTimeBase.h" + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: %s"DebugPrintfLineEnding, pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFile, "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #elif CoreAudio_TimeStampMessages + #include "CAHostTimeBase.h" + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFile, "%.4f: %s"DebugPrintfLineEnding, pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFile, "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #else + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFile, "%s"DebugPrintfLineEnding, msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFile, msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #endif + #endif + void DebugPrint(const char *fmt, ...); // can be used like printf + #define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h) + #if VERBOSE + #define vprint(msg) DEBUGPRINT(msg) + #else + #define vprint(msg) + #endif + + #if CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP CADebuggerStop() + #else + #define STOP + #endif + +#else + #define DebugMessage(msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) + #define DebugMessageN4(msg, N1, N2, N3, N4) + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) + #define DEBUGPRINT(msg) + #define vprint(msg) + #define STOP +#endif + +void LogError(const char *fmt, ...); // writes to syslog (and stderr if debugging) +void LogWarning(const char *fmt, ...); // writes to syslog (and stderr if debugging) + +#if DEBUG || CoreAudio_Debug + +#pragma mark Debug Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", __Err, __4CC); \ + STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inException, inMessage) \ + { \ + kern_return_t __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", __Err, __4CC); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + kern_return_t __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", __Err, __4CC); \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + DebugMessage(inMethodName": Subclasses must implement this method"); \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#else + +#pragma mark Release Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inException, inMessage) \ + if((inKernelError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfError(inError, inException, inMessage) \ + if((inError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#if defined(__cplusplus) + +#define Throw(inException) STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + kern_return_t __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#endif // DEBUG || CoreAudio_Debug + +#endif diff --git a/libs/appleutility/CAMath.h b/libs/appleutility/CAMath.h new file mode 100644 index 0000000000..32b4e7f0b3 --- /dev/null +++ b/libs/appleutility/CAMath.h @@ -0,0 +1,64 @@ +/* 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. +*/ +/*============================================================================= + CAMath.h + +=============================================================================*/ + +#ifndef __CAMath_h__ +#define __CAMath_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +inline bool fiszero(Float64 f) { return (f == 0.); } +inline bool fiszero(Float32 f) { return (f == 0.f); } + +inline bool fnonzero(Float64 f) { return !fiszero(f); } +inline bool fnonzero(Float32 f) { return !fiszero(f); } + +inline bool fequal(const Float64 &a, const Float64 &b) { return a == b; } +inline bool fequal(const Float32 &a, const Float32 &b) { return a == b; } + +inline bool fnotequal(const Float64 &a, const Float64 &b) { return !fequal(a, b); } +inline bool fnotequal(const Float32 &a, const Float32 &b) { return !fequal(a, b); } + +#endif // __CAMath_h__ diff --git a/libs/appleutility/CAReferenceCounted.h b/libs/appleutility/CAReferenceCounted.h new file mode 100644 index 0000000000..d57f97c31f --- /dev/null +++ b/libs/appleutility/CAReferenceCounted.h @@ -0,0 +1,83 @@ +/* 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. +*/ +/*============================================================================= + CAReferenceCounted.h + +=============================================================================*/ + +#ifndef __CAReferenceCounted_h__ +#define __CAReferenceCounted_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#if TARGET_OS_WIN32 + #include "CAWindows.h" +#endif + +// base class for reference-counted objects +class CAReferenceCounted { +public: + CAReferenceCounted() : mRefCount(1) {} + + void retain() { IncrementAtomic(&mRefCount); } + + void release() + { + // this returns the ORIGINAL value, not the new one. + SInt32 rc = DecrementAtomic(&mRefCount); + if (rc == 1) { + delete this; + } + } + +protected: + virtual ~CAReferenceCounted() { } + +private: + SInt32 mRefCount; + + CAReferenceCounted(const CAReferenceCounted &a) : mRefCount(0) { } + CAReferenceCounted operator=(const CAReferenceCounted &a) { return *this; } +}; + + +#endif // __CAReferenceCounted_h__ diff --git a/libs/appleutility/CAStreamBasicDescription.cpp b/libs/appleutility/CAStreamBasicDescription.cpp new file mode 100644 index 0000000000..f65bdd99ac --- /dev/null +++ b/libs/appleutility/CAStreamBasicDescription.cpp @@ -0,0 +1,520 @@ +/* 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. +*/ +/*============================================================================= + CAStreamBasicDescription.cpp + +=============================================================================*/ + +#include "CAConditionalMacros.h" + +#include "CAStreamBasicDescription.h" +#include "CAMath.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it + +const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID, + UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, + UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, + UInt32 inBitsPerChannel, UInt32 inFormatFlags) +{ + mSampleRate = inSampleRate; + mFormatID = inFormatID; + mBytesPerPacket = inBytesPerPacket; + mFramesPerPacket = inFramesPerPacket; + mBytesPerFrame = inBytesPerFrame; + mChannelsPerFrame = inChannelsPerFrame; + mBitsPerChannel = inBitsPerChannel; + mFormatFlags = inFormatFlags; +} + +void CAStreamBasicDescription::PrintFormat(FILE *f, const char *indent, const char *name) const +{ + fprintf(f, "%s%s ", indent, name); + char formatID[5]; + *(UInt32 *)formatID = CFSwapInt32HostToBig(mFormatID); + formatID[4] = '\0'; + fprintf(f, "%2ld ch, %6.0f Hz, '%-4.4s' (0x%08lX) ", + NumberChannels(), mSampleRate, formatID, + mFormatFlags); + if (mFormatID == kAudioFormatLinearPCM) { + bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat); + int wordSize = SampleWordSize(); + const char *endian = (wordSize > 1) ? + ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : ""; + const char *sign = isInt ? + ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : ""; + const char *floatInt = isInt ? "integer" : "float"; + char packed[32]; + if (wordSize > 0 && PackednessIsSignificant()) { + if (mFormatFlags & kLinearPCMFormatFlagIsPacked) + sprintf(packed, "packed in %d bytes", wordSize); + else + sprintf(packed, "unpacked in %d bytes", wordSize); + } else + packed[0] = '\0'; + const char *align = (wordSize > 0 && AlignmentIsSignificant()) ? + ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : ""; + const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : ""; + const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : ""; + + fprintf(f, "%ld-bit%s%s %s%s%s%s%s\n", + mBitsPerChannel, endian, sign, floatInt, + commaSpace, packed, align, deinter); + } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless + int sourceBits = 0; + switch (mFormatFlags) + { + case 1: // kAppleLosslessFormatFlag_16BitSourceData + sourceBits = 16; + break; + case 2: // kAppleLosslessFormatFlag_20BitSourceData + sourceBits = 20; + break; + case 3: // kAppleLosslessFormatFlag_24BitSourceData + sourceBits = 24; + break; + case 4: // kAppleLosslessFormatFlag_32BitSourceData + sourceBits = 32; + break; + } + if (sourceBits) + fprintf(f, "from %d-bit source, ", sourceBits); + else + fprintf(f, "from UNKNOWN source bit depth, "); + + fprintf(f, "%ld frames/packet\n", mFramesPerPacket); + } + else + fprintf(f, "%ld bits/channel, %ld bytes/packet, %ld frames/packet, %ld bytes/frame\n", + mBitsPerChannel, mBytesPerPacket, mFramesPerPacket, mBytesPerFrame); +} + +void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription) +{ + // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format + if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0)) + { + // the canonical linear PCM format is 32 bit native endian floats + ioDescription.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; + ioDescription.mBytesPerPacket = sizeof(Float32) * ioDescription.mChannelsPerFrame; + ioDescription.mFramesPerPacket = 1; + ioDescription.mBytesPerFrame = sizeof(Float32) * ioDescription.mChannelsPerFrame; + ioDescription.mBitsPerChannel = 8 * sizeof(Float32); + } +} + +void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription) +{ + ioDescription.mSampleRate = 0; + ioDescription.mFormatID = 0; + ioDescription.mBytesPerPacket = 0; + ioDescription.mFramesPerPacket = 0; + ioDescription.mBytesPerFrame = 0; + ioDescription.mChannelsPerFrame = 0; + ioDescription.mBitsPerChannel = 0; + ioDescription.mFormatFlags = 0; +} + +void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription) +{ + if(fiszero(ioDescription.mSampleRate)) + { + ioDescription.mSampleRate = inTemplateDescription.mSampleRate; + } + if(ioDescription.mFormatID == 0) + { + ioDescription.mFormatID = inTemplateDescription.mFormatID; + } + if(ioDescription.mFormatFlags == 0) + { + ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags; + } + if(ioDescription.mBytesPerPacket == 0) + { + ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket; + } + if(ioDescription.mFramesPerPacket == 0) + { + ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket; + } + if(ioDescription.mBytesPerFrame == 0) + { + ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame; + } + if(ioDescription.mChannelsPerFrame == 0) + { + ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame; + } + if(ioDescription.mBitsPerChannel == 0) + { + ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel; + } +} + +void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate) +{ + switch(inDescription.mFormatID) + { + case kAudioFormatLinearPCM: + { + const char* theEndianString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) + { + #if TARGET_RT_LITTLE_ENDIAN + theEndianString = "Big Endian"; + #endif + } + else + { + #if TARGET_RT_BIG_ENDIAN + theEndianString = "Little Endian"; + #endif + } + + const char* theKindString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0) + { + theKindString = (inAbbreviate ? "Float" : "Floating Point"); + } + else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) + { + theKindString = (inAbbreviate ? "SInt" : "Signed Integer"); + } + else + { + theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer"); + } + + const char* thePackingString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0) + { + if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0) + { + thePackingString = "High"; + } + else + { + thePackingString = "Low"; + } + } + + const char* theMixabilityString = NULL; + if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0) + { + theMixabilityString = "Mixable"; + } + else + { + theMixabilityString = "Unmixable"; + } + + if(inAbbreviate) + { + if(theEndianString != NULL) + { + if(thePackingString != NULL) + { + sprintf(outName, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + sprintf(outName, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel); + } + } + else + { + if(thePackingString != NULL) + { + sprintf(outName, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8)); + } + else + { + sprintf(outName, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel); + } + } + } + else + { + if(theEndianString != NULL) + { + if(thePackingString != NULL) + { + sprintf(outName, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + sprintf(outName, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString); + } + } + else + { + if(thePackingString != NULL) + { + sprintf(outName, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + sprintf(outName, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString); + } + } + } + } + break; + + case kAudioFormatAC3: + strcpy(outName, "AC-3"); + break; + + case kAudioFormat60958AC3: + strcpy(outName, "AC-3 for SPDIF"); + break; + + default: + { + char* the4CCString = (char*)&inDescription.mFormatID; + outName[0] = the4CCString[0]; + outName[1] = the4CCString[1]; + outName[2] = the4CCString[2]; + outName[3] = the4CCString[3]; + outName[4] = 0; + } + break; + }; +} + +#if CoreAudio_Debug +#include "CALogMacros.h" + +void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc) +{ + PrintFloat (" Sample Rate: ", inDesc.mSampleRate); + Print4CharCode (" Format ID: ", inDesc.mFormatID); + PrintHex (" Format Flags: ", inDesc.mFormatFlags); + PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket); + PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket); + PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame); + PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame); + PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel); +} +#endif + +bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + bool theAnswer = false; + bool isDone = false; + + // note that if either side is 0, that field is skipped + + // format ID is the first order sort + if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0))) + { + if(x.mFormatID != y.mFormatID) + { + // formats are sorted numerically except that linear + // PCM is always first + if(x.mFormatID == kAudioFormatLinearPCM) + { + theAnswer = true; + } + else if(y.mFormatID == kAudioFormatLinearPCM) + { + theAnswer = false; + } + else + { + theAnswer = x.mFormatID < y.mFormatID; + } + isDone = true; + } + } + + + // mixable is always better than non-mixable for linear PCM and should be the second order sort item + if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) + { + if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0)) + { + theAnswer = true; + isDone = true; + } + else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0)) + { + theAnswer = false; + isDone = true; + } + } + + // floating point vs integer for linear PCM only + if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) + { + if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat)) + { + // floating point is better than integer + theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat; + isDone = true; + } + } + + // bit depth + if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0))) + { + if(x.mBitsPerChannel != y.mBitsPerChannel) + { + // deeper bit depths are higher quality + theAnswer = x.mBitsPerChannel < y.mBitsPerChannel; + isDone = true; + } + } + + // sample rate + if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate)) + { + if(fnotequal(x.mSampleRate, y.mSampleRate)) + { + // higher sample rates are higher quality + theAnswer = x.mSampleRate < y.mSampleRate; + isDone = true; + } + } + + // number of channels + if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0))) + { + if(x.mChannelsPerFrame != y.mChannelsPerFrame) + { + // more channels is higher quality + theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame; + isDone = true; + } + } + + return theAnswer; +} + +static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + UInt32 xFlags = x.mFormatFlags; + UInt32 yFlags = y.mFormatFlags; + + // match wildcards + if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0) + return true; + + if (x.mFormatID == kAudioFormatLinearPCM) + { + // knock off the all clear flag + xFlags = xFlags & ~kAudioFormatFlagsAreAllClear; + yFlags = yFlags & ~kAudioFormatFlagsAreAllClear; + + // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit. + if (xFlags & yFlags & kAudioFormatFlagIsPacked) { + xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh; + yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh; + } + + // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit. + if (xFlags & yFlags & kAudioFormatFlagIsFloat) { + xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger; + yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger; + } + + // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness + if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + xFlags = xFlags & ~kAudioFormatFlagIsBigEndian; + } + if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + yFlags = yFlags & ~kAudioFormatFlagIsBigEndian; + } + + // if the number of channels is 0 or 1, we don't care about non-interleavedness + if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) { + xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + } + } + return xFlags == yFlags; +} + +bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + // the semantics for equality are: + // 1) Values must match exactly + // 2) wildcard's are ignored in the comparison + +#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name)) + + return + // check the sample rate + (fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate)) + + // check the format ids + && MATCH(mFormatID) + + // check the format flags + && MatchFormatFlags(x, y) + + // check the bytes per packet + && MATCH(mBytesPerPacket) + + // check the frames per packet + && MATCH(mFramesPerPacket) + + // check the bytes per frame + && MATCH(mBytesPerFrame) + + // check the channels per frame + && MATCH(mChannelsPerFrame) + + // check the channels per frame + && MATCH(mBitsPerChannel) ; +} + +bool SanityCheck(const AudioStreamBasicDescription& x) +{ + return (x.mSampleRate >= 0.); +} diff --git a/libs/appleutility/CAStreamBasicDescription.h b/libs/appleutility/CAStreamBasicDescription.h new file mode 100644 index 0000000000..aa41c40fe4 --- /dev/null +++ b/libs/appleutility/CAStreamBasicDescription.h @@ -0,0 +1,224 @@ +/* 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. +*/ +/*============================================================================= + CAStreamBasicDescription.h + +=============================================================================*/ + +#ifndef __CAStreamBasicDescription_h__ +#define __CAStreamBasicDescription_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include "CoreAudioTypes.h" + #include "CoreFoundation.h" +#endif + +#include "CADebugMacros.h" +#include // for memset, memcpy +#include // for FILE * + +#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it + +// define the IsMixable format flag for all versions of the system +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) + enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable }; +#else + enum { kIsNonMixableFlag = (1L << 6) }; +#endif + +//============================================================================= +// CAStreamBasicDescription +// +// This is a wrapper class for the AudioStreamBasicDescription struct. +// It adds a number of convenience routines, but otherwise adds nothing +// to the footprint of the original struct. +//============================================================================= +class CAStreamBasicDescription : + public AudioStreamBasicDescription +{ + +// Constants +public: + static const AudioStreamBasicDescription sEmpty; + +// Construction/Destruction +public: + CAStreamBasicDescription() { memset (this, 0, sizeof(AudioStreamBasicDescription)); } + + CAStreamBasicDescription(const AudioStreamBasicDescription &desc) + { + SetFrom(desc); + } + + CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID, + UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, + UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, + UInt32 inBitsPerChannel, UInt32 inFormatFlags); + +// Assignment + CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; } + + void SetFrom(const AudioStreamBasicDescription &desc) + { + memcpy(this, &desc, sizeof(AudioStreamBasicDescription)); + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // interrogation + + bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; } + + bool PackednessIsSignificant() const + { + Assert(IsPCM(), "PackednessIsSignificant only applies for PCM"); + return (SampleWordSize() << 3) != mBitsPerChannel; + } + + bool AlignmentIsSignificant() const + { + return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0; + } + + bool IsInterleaved() const + { + return !IsPCM() || !(mFormatFlags & kAudioFormatFlagIsNonInterleaved); + } + + // for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these: + UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; } + UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; } + UInt32 NumberChannels() const { return mChannelsPerFrame; } + UInt32 SampleWordSize() const { return (mBytesPerFrame > 0) ? mBytesPerFrame / NumberInterleavedChannels() : 0;} + + UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; } + UInt32 BytesToFrames(UInt32 nbytes) const { + Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames"); + return nbytes / mBytesPerFrame; + } + + bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const + { + return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved(); + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // manipulation + + void SetCanonical(UInt32 nChannels, bool interleaved) + // note: leaves sample rate untouched + { + mFormatID = kAudioFormatLinearPCM; + mFormatFlags = kAudioFormatFlagsNativeFloatPacked; + mBitsPerChannel = 32; + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + if (interleaved) + mBytesPerPacket = mBytesPerFrame = nChannels * sizeof(Float32); + else { + mBytesPerPacket = mBytesPerFrame = sizeof(Float32); + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + void ChangeNumberChannels(UInt32 nChannels, bool interleaved) + // alter an existing format + { + Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats"); + UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING + if (wordSize == 0) + wordSize = (mBitsPerChannel + 7) / 8; + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + if (interleaved) { + mBytesPerPacket = mBytesPerFrame = nChannels * wordSize; + mFormatFlags &= ~kAudioFormatFlagIsNonInterleaved; + } else { + mBytesPerPacket = mBytesPerFrame = wordSize; + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // other + + void Print() const + { + Print (stdout); + } + + void Print(FILE* file) const + { + PrintFormat (file, "", "AudioStreamBasicDescription:"); + } + + void PrintFormat(FILE *f, const char *indent, const char *name) const; + + OSStatus Save(CFPropertyListRef *outData) const; + + OSStatus Restore(CFPropertyListRef &inData); + +// Operations + static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); } + static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription); + static void ResetFormat(AudioStreamBasicDescription& ioDescription); + static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription); + static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, bool inAbbreviate); +#if CoreAudio_Debug + static void PrintToLog(const AudioStreamBasicDescription& inDesc); +#endif +}; + +bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); +bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); +#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600)) +inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); } +inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); } +inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); } +inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); } +#endif + +bool SanityCheck(const AudioStreamBasicDescription& x); + + +#endif // __CAStreamBasicDescription_h__ diff --git a/libs/appleutility/SConscript b/libs/appleutility/SConscript new file mode 100644 index 0000000000..2f3280f8b6 --- /dev/null +++ b/libs/appleutility/SConscript @@ -0,0 +1,23 @@ +# -*- python -*- + +import os +import os.path +import glob + +appleutility_files = glob.glob('*.cpp') + +Import('env install_prefix') +appleutility = env.Copy() + +appleutility.Append(LINKFLAGS='-framework AudioToolbox') +appleutility.Append(LINKFLAGS='-framework AudioUnit') +appleutility.Append(LINKFLAGS='-framework CoreFoundation') +appleutility.Append(LINKFLAGS='-framework CoreServices') + +libappleutility = appleutility.SharedLibrary('appleutility', appleutility_files) + +Default(libappleutility) + +env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libappleutility)) + +env.Alias('tarball', env.Distribute (env['DISTTREE'], ['SConscript'] + appleutility_files + glob.glob('*.h') )) diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index fc94a13888..feb93ec293 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -83,6 +83,7 @@ send.cc session.cc session_butler.cc session_click.cc +session_command.cc session_events.cc session_export.cc session_midi.cc @@ -215,6 +216,9 @@ ardour.Merge ([ if ardour['LIBLO']: ardour.Merge ([ libraries['lo'] ]) +if ardour['COREAUDIO']: + ardour.Merge ([ libraries['appleutility'] ]) + ardour.VersionBuild(['version.cc', 'ardour/version.h'], 'SConscript') def SharedAsmObjectEmitter(target, source, env): diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h index ba92416339..c138cbf32f 100644 --- a/libs/ardour/ardour/ardour.h +++ b/libs/ardour/ardour/ardour.h @@ -45,7 +45,7 @@ namespace ARDOUR { static const jack_nframes_t max_frames = JACK_MAX_FRAMES; - int init (AudioEngine&, bool with_vst, bool try_optimization); + int init (AudioEngine& engine, bool with_vst, bool try_optimization); int cleanup (); diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h index ec437109a4..1c8d6cbc2d 100644 --- a/libs/ardour/ardour/audio_unit.h +++ b/libs/ardour/ardour/audio_unit.h @@ -21,36 +21,93 @@ #ifndef __ardour_audio_unit_h__ #define __ardour_audio_unit_h__ +#include + #include +#include +#include +#include #include #include -struct ComponentDescription; +class CAComponent; +class CAAudioUnit; +class CAComponentDescription; +struct AudioBufferList; namespace ARDOUR { +class AudioEngine; +class Session; + class AUPlugin : public ARDOUR::Plugin { public: - AUPlugin (AudioEngine& engine, Session& session) : Plugin(engine, session) {}; - virtual ~AUPlugin () {}; + AUPlugin (AudioEngine& engine, Session& session, CAComponent* comp); + virtual ~AUPlugin (); + + uint32_t unique_id () const; + const char * label () const; + const char * name () const { return _info->name.c_str(); } + const char * maker () const; + uint32_t parameter_count () const; + float default_value (uint32_t port); + jack_nframes_t latency () const; + void set_parameter (uint32_t which, float val); + float get_parameter (uint32_t which) const; + + int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const; + uint32_t nth_parameter (uint32_t which, bool& ok) const; + void activate (); + void deactivate (); + void set_block_size (jack_nframes_t nframes); + + int connect_and_run (vector& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset); + std::set automatable() const; + void store_state (ARDOUR::PluginState&); + void restore_state (ARDOUR::PluginState&); + string describe_parameter (uint32_t); + string state_node_name () const { return "audiounit"; } + void print_parameter (uint32_t, char*, uint32_t len) const; + + bool parameter_is_audio (uint32_t) const; + bool parameter_is_control (uint32_t) const; + bool parameter_is_input (uint32_t) const; + bool parameter_is_output (uint32_t) const; + + XMLNode& get_state(); + int set_state(const XMLNode& node); + + bool save_preset (string name); + bool load_preset (const string preset_label); + std::vector get_presets (); + + bool has_editor () const; + + private: + CAComponent* comp; + CAAudioUnit* unit; + + AudioBufferList* in_list; + AudioBufferList* out_list; + + std::vector > parameter_map; }; class AUPluginInfo : public PluginInfo { - public: - typedef boost::shared_ptr CompDescPtr; - + public: AUPluginInfo () { }; - ~AUPluginInfo () { }; + ~AUPluginInfo (); - CompDescPtr desc; + CAComponentDescription* desc; static PluginInfoList discover (); + PluginPtr load (Session& session); private: - friend class PluginManager; + static std::string get_name (CAComponentDescription&); }; typedef boost::shared_ptr AUPluginInfoPtr; @@ -58,4 +115,3 @@ typedef boost::shared_ptr AUPluginInfoPtr; } // namespace ARDOUR #endif // __ardour_audio_unit_h__ - diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h index 78daa531dd..5864de73c6 100644 --- a/libs/ardour/ardour/automation_event.h +++ b/libs/ardour/ardour/automation_event.h @@ -51,7 +51,7 @@ struct ControlEvent { }; -class AutomationList : public StateManager +class AutomationList : public StateManager, public Stateful { public: typedef std::list AutomationEventList; @@ -153,6 +153,11 @@ class AutomationList : public StateManager virtual void store_state (XMLNode& node) const; virtual void load_state (const XMLNode&); + 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; } @@ -179,6 +184,7 @@ class AutomationList : public StateManager }; protected: + PBD::ID _id; struct State : public ARDOUR::StateManager::State { AutomationEventList events; diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h index e4aba93ef6..99fc884898 100644 --- a/libs/ardour/ardour/ladspa_plugin.h +++ b/libs/ardour/ardour/ladspa_plugin.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -137,6 +137,17 @@ class LadspaPlugin : public ARDOUR::Plugin void run (jack_nframes_t nsamples); void latency_compute_run (); }; -} + +class LadspaPluginInfo : public PluginInfo { + public: + LadspaPluginInfo () { }; + ~LadspaPluginInfo () { }; + + PluginPtr load (Session& session); +}; + +typedef boost::shared_ptr LadspaPluginInfoPtr; + +} // namespace ARDOUR #endif /* __ardour_ladspa_plugin_h__ */ diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h index 30c02a80a1..ff953d1d78 100644 --- a/libs/ardour/ardour/location.h +++ b/libs/ardour/ardour/location.h @@ -119,7 +119,10 @@ class Location : public Stateful, public sigc::trackable 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; @@ -145,6 +148,7 @@ class Locations : public Stateful, public StateManager XMLNode& get_state (void); int set_state (const XMLNode&); + PBD::ID id() { return _id; } Location* auto_loop_location () const; Location* auto_punch_location () const; @@ -197,6 +201,8 @@ class Locations : public Stateful, public StateManager Change restore_state (StateManager::State&); StateManager::State* state_factory (std::string why) const; + + PBD::ID _id; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index 9fb5b0eb2b..b389258860 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -76,6 +76,7 @@ class Playlist : public Stateful, public StateManager { EditMode get_edit_mode() const { return _edit_mode; } void set_edit_mode (EditMode); + PBD::ID id() { return _id; } /* Editing operations */ void add_region (const Region&, jack_nframes_t position, float times = 1, bool with_save = true); @@ -273,6 +274,8 @@ class Playlist : public Stateful, public StateManager { void unset_freeze_child (Playlist*); void timestamp_layer_op (Region&); + + PBD::ID _id; }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index 86666c19af..6b11a975ca 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,8 +18,8 @@ $Id$ */ -#ifndef __ardour_ladspa_h__ -#define __ardour_ladspa_h__ +#ifndef __ardour_plugin_h__ +#define __ardour_plugin_h__ #include #include @@ -46,6 +46,9 @@ namespace ARDOUR { class AudioEngine; class Session; +class Plugin; +typedef boost::shared_ptr PluginPtr; + class PluginInfo { public: enum Type { @@ -54,11 +57,12 @@ class PluginInfo { VST }; - PluginInfo () { }; + PluginInfo () { } PluginInfo (const PluginInfo &o) : name(o.name), n_inputs(o.n_inputs), n_outputs(o.n_outputs), unique_id(o.unique_id), path (o.path), index(o.index) {} - ~PluginInfo () { }; + virtual ~PluginInfo () { } + string name; string category; uint32_t n_inputs; @@ -67,7 +71,9 @@ class PluginInfo { long unique_id; - private: + virtual PluginPtr load (Session& session) = 0; + + protected: friend class PluginManager; string path; uint32_t index; @@ -82,7 +88,7 @@ class Plugin : public Stateful, public sigc::trackable public: Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&); Plugin (const Plugin&); - ~Plugin (); + virtual ~Plugin (); struct ParameterDescriptor { @@ -143,8 +149,8 @@ class Plugin : public Stateful, public sigc::trackable PBD::Controllable *get_nth_control (uint32_t); - PluginInfo & get_info() { return _info; } - void set_info (const PluginInfo &inf) { _info = inf; } + PluginInfoPtr get_info() { return _info; } + void set_info (const PluginInfoPtr inf) { _info = inf; } ARDOUR::AudioEngine& engine() const { return _engine; } ARDOUR::Session& session() const { return _session; } @@ -155,7 +161,7 @@ class Plugin : public Stateful, public sigc::trackable protected: ARDOUR::AudioEngine& _engine; ARDOUR::Session& _session; - PluginInfo _info; + PluginInfoPtr _info; uint32_t _cycles; map presets; bool save_preset(string name, string domain /* vst, ladspa etc. */); @@ -181,9 +187,7 @@ class Plugin : public Stateful, public sigc::trackable vector controls; }; -/* this is actually defined in plugin_manager.cc */ - -boost::shared_ptr find_plugin(ARDOUR::Session&, string name, long unique_id, PluginInfo::Type); +PluginPtr find_plugin(ARDOUR::Session&, string name, long unique_id, PluginInfo::Type); } // namespace ARDOUR diff --git a/libs/ardour/ardour/plugin_manager.h b/libs/ardour/ardour/plugin_manager.h index 8543ad5285..8e6c0bd1c7 100644 --- a/libs/ardour/ardour/plugin_manager.h +++ b/libs/ardour/ardour/plugin_manager.h @@ -5,42 +5,34 @@ #include #include -#include - #include #include #include namespace ARDOUR { -class PluginInfo; class Plugin; class Session; class AudioEngine; class PluginManager { public: - PluginManager (ARDOUR::AudioEngine&); + PluginManager (); ~PluginManager (); ARDOUR::PluginInfoList &vst_plugin_info () { return _vst_plugin_info; } ARDOUR::PluginInfoList &ladspa_plugin_info () { return _ladspa_plugin_info; } - ARDOUR::PluginInfoList &au_plugin_info () { return _au_plugin_info; } void refresh (); int add_ladspa_directory (std::string dirpath); int add_vst_directory (std::string dirpath); - boost::shared_ptr load (ARDOUR::Session& s, PluginInfoPtr info); - static PluginManager* the_manager() { return _manager; } private: - ARDOUR::AudioEngine& _engine; ARDOUR::PluginInfoList _vst_plugin_info; ARDOUR::PluginInfoList _ladspa_plugin_info; - ARDOUR::PluginInfoList _au_plugin_info; std::map rdf_type; std::string ladspa_path; @@ -60,8 +52,6 @@ class PluginManager { int ladspa_discover_from_path (std::string path); int ladspa_discover (std::string path); - int au_discover (); - std::string get_ladspa_category (uint32_t id); static PluginManager* _manager; // singleton diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 8271c1cf6a..d1db818e40 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -97,7 +97,7 @@ class Route : public IO virtual int silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset, bool can_record, bool rec_monitors_input); virtual void toggle_monitor_input (); - virtual bool can_record() const { return false; } + virtual bool can_record() { return false; } virtual void set_record_enable (bool yn, void *src) {} virtual bool record_enabled() const { return false; } virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_redirects); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index d39807be3f..6eb025f076 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -489,6 +489,7 @@ class Session : public sigc::trackable, public Stateful int save_state (string snapshot_name, bool pending = false); int restore_state (string snapshot_name); int save_template (string template_name); + int save_history (); static int rename_template (string old_name, string new_name); @@ -501,7 +502,7 @@ class Session : public sigc::trackable, public Stateful static vector* possible_states(string path); XMLNode& get_state(); - int set_state(const XMLNode& node); + int set_state(const XMLNode& node); // not idempotent XMLNode& get_template(); void add_instant_xml (XMLNode&, const std::string& dir); @@ -844,23 +845,65 @@ class Session : public sigc::trackable, public Stateful string next_undo() const { return history.next_undo(); } string next_redo() const { return history.next_redo(); } - void begin_reversible_command (string cmd_name, UndoAction *private_undo = 0); - void commit_reversible_command (UndoAction* private_redo = 0); + void begin_reversible_command (string cmd_name); + void commit_reversible_command (Command* cmd = 0); - void add_undo (const UndoAction& ua) { - current_cmd.add_undo (ua); - } - void add_redo (const UndoAction& ua) { - current_cmd.add_redo (ua); - } - void add_redo_no_execute (const UndoAction& ua) { - current_cmd.add_redo_no_execute (ua); + void add_command (Command *const cmd) { + current_trans.add_command (cmd); } - UndoAction global_solo_memento (void *src); - UndoAction global_mute_memento (void *src); - UndoAction global_record_enable_memento (void *src); - UndoAction global_metering_memento (void *src); + // these commands are implemented in libs/ardour/session_command.cc + class GlobalSoloStateCommand : public Command + { + GlobalRouteBooleanState before, after; + Session &sess; + void *src; + public: + GlobalSoloStateCommand(Session &, void *src); + void operator()(); + void undo(); + XMLNode &get_state(); + void mark(); + }; + + class GlobalMuteStateCommand : public Command + { + GlobalRouteBooleanState before, after; + Session &sess; + void *src; + public: + GlobalMuteStateCommand(Session &, void *src); + void operator()(); + void undo(); + XMLNode &get_state(); + void mark(); + }; + + class GlobalRecordEnableStateCommand : public Command + { + GlobalRouteBooleanState before, after; + Session &sess; + void *src; + public: + GlobalRecordEnableStateCommand(Session &, void *src); + void operator()(); + void undo(); + XMLNode &get_state(); + void mark(); + }; + + class GlobalMeteringStateCommand : public Command + { + GlobalRouteMeterState before, after; + Session &sess; + void *src; + public: + GlobalMeteringStateCommand(Session &, void *src); + void operator()(); + void undo(); + XMLNode &get_state(); + void mark(); + }; /* edit mode */ @@ -1635,7 +1678,7 @@ class Session : public sigc::trackable, public Stateful void reverse_diskstream_buffers (); UndoHistory history; - UndoCommand current_cmd; + UndoTransaction current_trans; GlobalRouteBooleanState get_global_route_boolean (bool (Route::*method)(void) const); GlobalRouteMeterState get_global_route_metering (); diff --git a/libs/ardour/ardour/state_manager.h b/libs/ardour/ardour/state_manager.h index 19ee2e624a..99bfcfc3ce 100644 --- a/libs/ardour/ardour/state_manager.h +++ b/libs/ardour/ardour/state_manager.h @@ -35,6 +35,8 @@ class StateManager : public sigc::trackable state_id_t _current_state_id; + virtual bool should_save_state () const { return true; } + static void prohibit_save (); static void allow_save (const char* why, bool dosave); diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index db06894607..bfd3e429c3 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -238,6 +238,7 @@ class TempoMap : public Stateful, public StateManager { XMLNode& get_state (void); int set_state (const XMLNode&); + PBD::ID id() { return _id; } void dump (std::ostream&) const; void clear (); @@ -315,6 +316,8 @@ class TempoMap : public Stateful, public StateManager { void save_state (std::string why); + PBD::ID _id; + }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index f16e9d29d9..4e2af5c80e 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -48,7 +48,7 @@ class Track : public Route void toggle_monitor_input (); - bool can_record() const { return true; } + virtual bool can_record(); Diskstream& diskstream() const { return *_diskstream; } diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h index 3cb10d1779..5253da7b0a 100644 --- a/libs/ardour/ardour/vst_plugin.h +++ b/libs/ardour/ardour/vst_plugin.h @@ -104,6 +104,15 @@ class VSTPlugin : public ARDOUR::Plugin bool been_resumed; }; -} +class VSTPluginInfo : public PluginInfo +{ + public: + VSTPluginInfo () {} + ~VSTPluginInfo () {} + + PluginPtr load (Session& session); +}; + +} // namespace ARDOUR #endif /* __ardour_vst_plugin_h__ */ diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 7f0cb55821..7d2a2103bb 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -1594,7 +1595,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n"; - _session.add_undo (_playlist->get_memento()); + XMLNode &before = _playlist->get_state(); _playlist->freeze (); for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) { @@ -1625,7 +1626,8 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca } _playlist->thaw (); - _session.add_redo_no_execute (_playlist->get_memento()); + XMLNode &after = _playlist->get_state(); + _session.add_command (new MementoCommand(*_playlist, before, after)); } mark_write_completed = true; diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc index 52cfc187af..25c8aeb53b 100644 --- a/libs/ardour/audio_unit.cc +++ b/libs/ardour/audio_unit.cc @@ -18,95 +18,361 @@ */ +#include +#include + +#include #include +#include #include +#include + #include #include +#include "i18n.h" + +using namespace std; +using namespace PBD; using namespace ARDOUR; -PluginInfoList -AUPluginInfo::discover () +AUPlugin::AUPlugin (AudioEngine& engine, Session& session, CAComponent* _comp) + : + Plugin (engine, session), + comp (_comp), + unit (new CAAudioUnit) +{ + OSErr err = CAAudioUnit::Open (*comp, *unit); + if (err != noErr) { + error << _("AudioUnit: Could not convert CAComponent to CAAudioUnit") << endmsg; + delete unit; + delete comp; + throw failed_constructor (); + } + + unit->Initialize (); +} + +AUPlugin::~AUPlugin () { - PluginInfoList plugs; + if (unit) { + unit->Uninitialize (); + delete unit; + } + + if (comp) { + delete comp; + } + + if (in_list) { + delete in_list; + } + + if (out_list) { + delete out_list; + } +} + +AUPluginInfo::~AUPluginInfo () +{ + if (desc) { + delete desc; + } +} - int numTypes = 2; // this magic number was retrieved from the apple AUHost example. +uint32_t +AUPlugin::unique_id () const +{ + return 0; +} - ComponentDescription desc; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - desc.componentSubType = 0; - desc.componentManufacturer = 0; +const char * +AUPlugin::label () const +{ + return "AUPlugin label"; +} - vector vCompDescs; +const char * +AUPlugin::maker () const +{ + return "AUplugin maker"; +} - for (int i = 0; i < numTypes; ++i) { - if (i == 1) { - desc.componentType = kAudioUnitType_MusicEffect; - } else { - desc.componentType = kAudioUnitType_Effect; - } +uint32_t +AUPlugin::parameter_count () const +{ + return 0; +} + +float +AUPlugin::default_value (uint32_t port) +{ + // AudioUnits don't have default values. Maybe presets though? + return 0; +} + +jack_nframes_t +AUPlugin::latency () const +{ + return unit->Latency (); +} + +void +AUPlugin::set_parameter (uint32_t which, float val) +{ + unit->SetParameter (parameter_map[which].first, parameter_map[which].second, 0, val); +} + +float +AUPlugin::get_parameter (uint32_t which) const +{ + float outValue = 0.0; + + unit->GetParameter(parameter_map[which].first, parameter_map[which].second, 0, outValue); + + return outValue; +} + +int +AUPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const +{ + return -1; +} + +uint32_t +AUPlugin::nth_parameter (uint32_t which, bool& ok) const +{ + return 0; +} + +void +AUPlugin::activate () +{ + unit->GlobalReset (); +} + +void +AUPlugin::deactivate () +{ + // not needed. GlobalReset () takes care of it. +} - Component comp = 0; +void +AUPlugin::set_block_size (jack_nframes_t nframes) +{ + +} + +int +AUPlugin::connect_and_run (vector& bufs, uint32_t maxbuf, int32_t& in, int32_t& out, jack_nframes_t nframes, jack_nframes_t offset) +{ + AudioUnitRenderActionFlags flags = 0; + AudioTimeStamp ts; + + AudioBufferList abl; + abl.mNumberBuffers = 1; + abl.mBuffers[0].mNumberChannels = 1; + abl.mBuffers[0].mDataByteSize = nframes * sizeof(Sample); + abl.mBuffers[0].mData = &bufs[0]; + + + unit->Render (&flags, &ts, 0, 0, &abl); + + return 0; +} + +set +AUPlugin::automatable() const +{ + set automates; + + return automates; +} - comp = FindNextComponent (NULL, &desc); - while (comp != NULL) { - ComponentDescription temp; - GetComponentInfo (comp, &temp, NULL, NULL, NULL); - vCompDescs.push_back(temp); - comp = FindNextComponent (comp, &desc); +void +AUPlugin::store_state (ARDOUR::PluginState&) +{ + +} + +void +AUPlugin::restore_state (ARDOUR::PluginState&) +{ + +} + +string +AUPlugin::describe_parameter (uint32_t) +{ + return ""; +} + +void +AUPlugin::print_parameter (uint32_t, char*, uint32_t len) const +{ + +} + +bool +AUPlugin::parameter_is_audio (uint32_t) const +{ + return false; +} + +bool +AUPlugin::parameter_is_control (uint32_t) const +{ + return false; +} + +bool +AUPlugin::parameter_is_input (uint32_t) const +{ + return false; +} + +bool +AUPlugin::parameter_is_output (uint32_t) const +{ + return false; +} + +XMLNode& +AUPlugin::get_state() +{ + XMLNode* root = new XMLNode (state_node_name()); + + return *root; +} + +int +AUPlugin::set_state(const XMLNode& node) +{ + return -1; +} + +bool +AUPlugin::save_preset (string name) +{ + return false; +} + +bool +AUPlugin::load_preset (const string preset_label) +{ + return false; +} + +vector +AUPlugin::get_presets () +{ + vector presets; + + return presets; +} + +bool +AUPlugin::has_editor () const +{ + return false; +} + +PluginPtr +AUPluginInfo::load (Session& session) +{ + try { + PluginPtr plugin; + + CAComponent* comp = new CAComponent(*desc); + + if (!comp->IsValid()) { + error << ("AudioUnit: not a valid Component") << endmsg; + } else { + plugin.reset (new AUPlugin (session.engine(), session, comp)); } + + plugin->set_info(PluginInfoPtr(new AUPluginInfo(*this))); + return plugin; } - for (unsigned int i = 0; i < vCompDescs.size(); ++i) { - - // the following large block is just for determining the name of the plugin. - CFStringRef itemName = NULL; - // Marc Poirier -style item name - Component auComponent = FindNextComponent (0, &(vCompDescs[i])); - if (auComponent != NULL) { - ComponentDescription dummydesc; - Handle nameHandle = NewHandle(sizeof(void*)); - if (nameHandle != NULL) { - OSErr err = GetComponentInfo(auComponent, &dummydesc, nameHandle, NULL, NULL); - if (err == noErr) { - ConstStr255Param nameString = (ConstStr255Param) (*nameHandle); - if (nameString != NULL) { - itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding()); - } - } - DisposeHandle(nameHandle); - } - } + catch (failed_constructor &err) { + return PluginPtr ((Plugin*) 0); + } +} - // if Marc-style fails, do the original way - if (itemName == NULL) { - CFStringRef compTypeString = UTCreateStringForOSType(vCompDescs[i].componentType); - CFStringRef compSubTypeString = UTCreateStringForOSType(vCompDescs[i].componentSubType); - CFStringRef compManufacturerString = UTCreateStringForOSType(vCompDescs[i].componentManufacturer); - - itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"), - compTypeString, compManufacturerString, compSubTypeString); - - if (compTypeString != NULL) - CFRelease(compTypeString); - if (compSubTypeString != NULL) - CFRelease(compSubTypeString); - if (compManufacturerString != NULL) - CFRelease(compManufacturerString); - } - string realname = CFStringRefToStdString(itemName); +PluginInfoList +AUPluginInfo::discover () +{ + PluginInfoList plugs; + + CAComponentDescription desc; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + desc.componentSubType = 0; + desc.componentManufacturer = 0; + desc.componentType = kAudioUnitType_Effect; + + Component comp = 0; + comp = FindNextComponent (NULL, &desc); + while (comp != NULL) { + CAComponentDescription temp; + GetComponentInfo (comp, &temp, NULL, NULL, NULL); + AUPluginInfoPtr plug(new AUPluginInfo); - plug->name = realname; + plug->name = AUPluginInfo::get_name (temp); plug->type = PluginInfo::AudioUnit; plug->n_inputs = 0; plug->n_outputs = 0; plug->category = "AudioUnit"; + plug->desc = new CAComponentDescription(temp); plugs.push_back(plug); + + comp = FindNextComponent (comp, &desc); } return plugs; } + +string +AUPluginInfo::get_name (CAComponentDescription& comp_desc) +{ + CFStringRef itemName = NULL; + // Marc Poirier -style item name + CAComponent auComponent (comp_desc); + if (auComponent.IsValid()) { + CAComponentDescription dummydesc; + Handle nameHandle = NewHandle(sizeof(void*)); + if (nameHandle != NULL) { + OSErr err = GetComponentInfo(auComponent.Comp(), &dummydesc, nameHandle, NULL, NULL); + if (err == noErr) { + ConstStr255Param nameString = (ConstStr255Param) (*nameHandle); + if (nameString != NULL) { + itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding()); + } + } + DisposeHandle(nameHandle); + } + } + + // if Marc-style fails, do the original way + if (itemName == NULL) { + CFStringRef compTypeString = UTCreateStringForOSType(comp_desc.componentType); + CFStringRef compSubTypeString = UTCreateStringForOSType(comp_desc.componentSubType); + CFStringRef compManufacturerString = UTCreateStringForOSType(comp_desc.componentManufacturer); + + itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"), + compTypeString, compManufacturerString, compSubTypeString); + + if (compTypeString != NULL) + CFRelease(compTypeString); + if (compSubTypeString != NULL) + CFRelease(compSubTypeString); + if (compManufacturerString != NULL) + CFRelease(compManufacturerString); + } + + return CFStringRefToStdString(itemName); +} diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc index 63492b375b..dc1767d1e7 100644 --- a/libs/ardour/automation_event.cc +++ b/libs/ardour/automation_event.cc @@ -1246,3 +1246,17 @@ AutomationList::load_state (const XMLNode& node) add (x, y); } } + +XMLNode &AutomationList::get_state () +{ + XMLNode *node = new XMLNode("AutomationList"); + store_state(*node); + return *node; +} + +int AutomationList::set_state(const XMLNode &s) +{ + load_state(s); + return 0; +} + diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 4eafbbe9a1..6f3b772ece 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -193,9 +193,9 @@ setup_midi (AudioEngine& engine ) } int -ARDOUR::init (AudioEngine& engine, bool use_vst, bool try_optimization) +ARDOUR::init (ARDOUR::AudioEngine& engine, bool use_vst, bool try_optimization) { - bool generic_mix_functions = true; + bool generic_mix_functions = true; (void) bindtextdomain(PACKAGE, LOCALEDIR); @@ -303,7 +303,7 @@ ARDOUR::init (AudioEngine& engine, bool use_vst, bool try_optimization) } /* singleton - first object is "it" */ - new PluginManager (engine); + new PluginManager (); /* singleton - first object is "it" */ new ControlProtocolManager (); diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc index 11b1e25a74..a057fef931 100644 --- a/libs/ardour/insert.cc +++ b/libs/ardour/insert.cc @@ -186,25 +186,25 @@ PluginInsert::auto_state_changed (uint32_t which) uint32_t PluginInsert::output_streams() const { - return _plugins[0]->get_info().n_outputs * _plugins.size(); + return _plugins[0]->get_info()->n_outputs * _plugins.size(); } uint32_t PluginInsert::input_streams() const { - return _plugins[0]->get_info().n_inputs * _plugins.size(); + return _plugins[0]->get_info()->n_inputs * _plugins.size(); } uint32_t PluginInsert::natural_output_streams() const { - return _plugins[0]->get_info().n_outputs; + return _plugins[0]->get_info()->n_outputs; } uint32_t PluginInsert::natural_input_streams() const { - return _plugins[0]->get_info().n_inputs; + return _plugins[0]->get_info()->n_inputs; } bool @@ -214,7 +214,7 @@ PluginInsert::is_generator() const a specific "instrument" flag, for example. */ - return _plugins[0]->get_info().n_inputs == 0; + return _plugins[0]->get_info()->n_inputs == 0; } void @@ -350,7 +350,7 @@ PluginInsert::silence (jack_nframes_t nframes, jack_nframes_t offset) if (active()) { for (vector >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { - n = (*i) -> get_info().n_inputs; + n = (*i) -> get_info()->n_inputs; (*i)->connect_and_run (_session.get_silent_buffers (n), n, in_index, out_index, nframes, offset); } } @@ -367,8 +367,8 @@ PluginInsert::run (vector& bufs, uint32_t nbufs, jack_nframes_t nframe connect_and_run (bufs, nbufs, nframes, offset, false); } } else { - uint32_t in = _plugins[0]->get_info().n_inputs; - uint32_t out = _plugins[0]->get_info().n_outputs; + uint32_t in = _plugins[0]->get_info()->n_inputs; + uint32_t out = _plugins[0]->get_info()->n_outputs; if (out > in) { @@ -524,7 +524,7 @@ PluginInsert::plugin_factory (boost::shared_ptr other) int32_t PluginInsert::compute_output_streams (int32_t cnt) const { - return _plugins[0]->get_info().n_outputs * cnt; + return _plugins[0]->get_info()->n_outputs * cnt; } int32_t @@ -536,8 +536,8 @@ PluginInsert::configure_io (int32_t magic, int32_t in, int32_t out) int32_t PluginInsert::can_support_input_configuration (int32_t in) const { - int32_t outputs = _plugins[0]->get_info().n_outputs; - int32_t inputs = _plugins[0]->get_info().n_inputs; + int32_t outputs = _plugins[0]->get_info()->n_outputs; + int32_t inputs = _plugins[0]->get_info()->n_inputs; if (inputs == 0) { @@ -591,7 +591,7 @@ PluginInsert::state (bool full) node->add_property("id", string(buf)); if (_plugins[0]->state_node_name() == "ladspa") { char buf[32]; - snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info().unique_id); + snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info()->unique_id); node->add_property("unique-id", string(buf)); } node->add_property("count", string_compose("%1", _plugins.size())); @@ -761,7 +761,7 @@ PluginInsert::set_state(const XMLNode& node) } // The name of the PluginInsert comes from the plugin, nothing else - set_name(plugin->get_info().name,this); + set_name(plugin->get_info()->name,this); return 0; } diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 2dfd735a6b..4d2d26f801 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -170,7 +170,7 @@ IO::silence (jack_nframes_t nframes, jack_nframes_t offset) void IO::apply_declick (vector& bufs, uint32_t nbufs, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity) { - jack_nframes_t declick = min ((jack_nframes_t)4096, nframes); + jack_nframes_t declick = min ((jack_nframes_t)128, nframes); gain_t delta; Sample *buffer; double fractional_shift; diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc index fa19a682e7..6b773b9e0b 100644 --- a/libs/ardour/ladspa_plugin.cc +++ b/libs/ardour/ladspa_plugin.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2002 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -641,3 +641,26 @@ LadspaPlugin::latency_compute_run () run (bufsize); deactivate (); } + +PluginPtr +LadspaPluginInfo::load (Session& session) +{ + try { + PluginPtr plugin; + void *module; + + if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) { + error << string_compose(_("LADSPA: cannot load module from \"%1\""), path) << endmsg; + error << dlerror() << endmsg; + } else { + plugin.reset (new LadspaPlugin (module, session.engine(), session, index, session.frame_rate())); + } + + plugin->set_info(PluginInfoPtr(new LadspaPluginInfo(*this))); + return plugin; + } + + catch (failed_constructor &err) { + return PluginPtr ((Plugin*) 0); + } +} diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 6763e7f508..8ea95b8903 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include @@ -240,3 +242,43 @@ Plugin::save_preset (string name, string domain) return true; } + +PluginPtr +ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginInfo::Type type) +{ + PluginManager *mgr = PluginManager::the_manager(); + PluginInfoList plugs; + + switch (type) { + case PluginInfo::LADSPA: + plugs = mgr->ladspa_plugin_info(); + break; + +#ifdef VST_SUPPORT + case PluginInfo::VST: + plugs = mgr->vst_plugin_info(); + unique_id = 0; // VST plugins don't have a unique id. + break; +#endif + +#ifdef HAVE_COREAUDIO + case PluginInfo::AudioUnit: + plugs = AUPluginInfo::discover (); + unique_id = 0; // Neither do AU. + break; +#endif + + default: + return PluginPtr ((Plugin *) 0); + } + + PluginInfoList::iterator i; + for (i = plugs.begin(); i != plugs.end(); ++i) { + if ((name == "" || (*i)->name == name) && + (unique_id == 0 || (*i)->unique_id == unique_id)) { + return (*i)->load (session); + } + } + + return PluginPtr ((Plugin*) 0); +} diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index 06a944189a..2a753617e8 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2004 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,8 +36,10 @@ #include #include #include + +#ifdef VST_SUPPORT #include -#include +#endif #include #include @@ -49,8 +51,7 @@ using namespace PBD; PluginManager* PluginManager::_manager = 0; -PluginManager::PluginManager (AudioEngine& e) - : _engine (e) +PluginManager::PluginManager () { char* s; string lrdf_path; @@ -97,10 +98,6 @@ PluginManager::refresh () vst_refresh (); } #endif // VST_SUPPORT - -#ifdef HAVE_COREAUDIO - _au_plugin_info = AUPluginInfo::discover (); -#endif // HAVE_COREAUDIO } void @@ -250,7 +247,7 @@ PluginManager::ladspa_discover (string path) break; } - PluginInfoPtr info(new PluginInfo); + PluginInfoPtr info(new LadspaPluginInfo); info->name = descriptor->Name; info->category = get_ladspa_category(descriptor->UniqueID); info->path = path; @@ -280,85 +277,6 @@ PluginManager::ladspa_discover (string path) return 0; } -boost::shared_ptr -PluginManager::load (Session& session, PluginInfoPtr info) -{ - void *module; - - try { - boost::shared_ptr plugin; - - if (info->type == PluginInfo::VST) { - -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - FSTHandle* handle; - - if ((handle = fst_load (info->path.c_str())) == 0) { - error << string_compose(_("VST: cannot load module from \"%1\""), info->path) << endmsg; - } else { - plugin.reset (new VSTPlugin (_engine, session, handle)); - } - } else { - error << _("You asked ardour to not use any VST plugins") << endmsg; - } -#else // !VST_SUPPORT - error << _("This version of ardour has no support for VST plugins") << endmsg; - return boost::shared_ptr ((Plugin*) 0); -#endif // !VST_SUPPORT - - } else { - - if ((module = dlopen (info->path.c_str(), RTLD_NOW)) == 0) { - error << string_compose(_("LADSPA: cannot load module from \"%1\""), info->path) << endmsg; - error << dlerror() << endmsg; - } else { - plugin.reset (new LadspaPlugin (module, _engine, session, info->index, session.frame_rate())); - } - } - - plugin->set_info(*info); - return plugin; - } - - catch (failed_constructor &err) { - return boost::shared_ptr ((Plugin*) 0); - } -} - -boost::shared_ptr -ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginInfo::Type type) -{ - PluginManager *mgr = PluginManager::the_manager(); - PluginInfoList* plugs = 0; - - switch (type) { - case PluginInfo::LADSPA: - plugs = &mgr->ladspa_plugin_info(); - break; - case PluginInfo::VST: - plugs = &mgr->vst_plugin_info(); - unique_id = 0; // VST plugins don't have a unique id. - break; - case PluginInfo::AudioUnit: - plugs = &mgr->au_plugin_info(); - unique_id = 0; - break; - default: - return boost::shared_ptr ((Plugin *) 0); - } - - PluginInfoList::iterator i; - for (i = plugs->begin(); i != plugs->end(); ++i) { - if ((name == "" || (*i)->name == name) && - (unique_id == 0 || (*i)->unique_id == unique_id)) { - return mgr->load (session, *i); - } - } - - return boost::shared_ptr ((Plugin*) 0); -} - string PluginManager::get_ladspa_category (uint32_t plugin_id) { @@ -464,7 +382,7 @@ PluginManager::vst_discover (string path) << endl; } - PluginInfoPtr info(new PluginInfo); + PluginInfoPtr info(new VSTPluginInfo); /* what a goddam joke freeware VST is */ diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 902da43d91..bfcb69572a 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1023,6 +1023,7 @@ Session::auto_punch_start_changed (Location* location) if (get_record_enabled() && get_punch_in()) { /* capture start has been changed, so save new pending state */ save_state ("", true); + save_history(); } } @@ -1344,6 +1345,7 @@ Session::maybe_enable_record () */ save_state ("", true); + save_history(); if (_transport_speed) { if (!punch_in) { @@ -2131,6 +2133,7 @@ Session::add_diskstream (Diskstream* dstream) set_dirty(); save_state (_current_snapshot_name); + save_history(); DiskstreamAdded (dstream); /* EMIT SIGNAL */ } @@ -2882,6 +2885,7 @@ Session::remove_source (Source* source) */ save_state (_current_snapshot_name); + save_history(); } SourceRemoved(source); /* EMIT SIGNAL */ diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc new file mode 100644 index 0000000000..9a43de55de --- /dev/null +++ b/libs/ardour/session_command.cc @@ -0,0 +1,101 @@ +#include +#include + +namespace ARDOUR { +// solo +Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session &sess, void *src) + : sess(sess), src(src) +{ + after = before = sess.get_global_route_boolean(&Route::soloed); +} +void Session::GlobalSoloStateCommand::mark() +{ + after = sess.get_global_route_boolean(&Route::soloed); +} +void Session::GlobalSoloStateCommand::operator()() +{ + sess.set_global_solo(after, src); +} +void Session::GlobalSoloStateCommand::undo() +{ + sess.set_global_solo(before, src); +} +XMLNode &Session::GlobalSoloStateCommand::get_state() +{ + XMLNode *node = new XMLNode("GlobalSoloStateCommand"); + return *node; +} + +// mute +Session::GlobalMuteStateCommand::GlobalMuteStateCommand(Session &sess, void *src) + : sess(sess), src(src) +{ + after = before = sess.get_global_route_boolean(&Route::muted); +} +void Session::GlobalMuteStateCommand::mark() +{ + after = sess.get_global_route_boolean(&Route::muted); +} +void Session::GlobalMuteStateCommand::operator()() +{ + sess.set_global_mute(after, src); +} +void Session::GlobalMuteStateCommand::undo() +{ + sess.set_global_mute(before, src); +} +XMLNode &Session::GlobalMuteStateCommand::get_state() +{ + XMLNode *node = new XMLNode("GlobalMuteStateCommand"); + return *node; +} + +// record enable +Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand(Session &sess, void *src) + : sess(sess), src(src) +{ + after = before = sess.get_global_route_boolean(&Route::record_enabled); +} +void Session::GlobalRecordEnableStateCommand::mark() +{ + after = sess.get_global_route_boolean(&Route::record_enabled); +} +void Session::GlobalRecordEnableStateCommand::operator()() +{ + sess.set_global_record_enable(after, src); +} +void Session::GlobalRecordEnableStateCommand::undo() +{ + sess.set_global_record_enable(before, src); +} +XMLNode &Session::GlobalRecordEnableStateCommand::get_state() +{ + XMLNode *node = new XMLNode("GlobalRecordEnableStateCommand"); + return *node; +} + +// metering +Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand(Session &sess, void *src) + : sess(sess), src(src) +{ + after = before = sess.get_global_route_metering(); +} +void Session::GlobalMeteringStateCommand::mark() +{ + after = sess.get_global_route_metering(); +} +void Session::GlobalMeteringStateCommand::operator()() +{ + sess.set_global_route_metering(after, src); +} +void Session::GlobalMeteringStateCommand::undo() +{ + sess.set_global_route_metering(before, src); +} +XMLNode &Session::GlobalMeteringStateCommand::get_state() +{ + XMLNode *node = new XMLNode("GlobalMeteringStateCommand"); + return *node; +} + +} // namespace ARDOUR diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 8d11fd3b3f..bb319511b7 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -611,6 +611,7 @@ Session::create (bool& new_session, string* mix_template, jack_nframes_t initial _state_of_the_state = Clean; if (save_state (_current_snapshot_name)) { + save_history(); return -1; } } @@ -1697,6 +1698,7 @@ Session::set_state (const XMLNode& node) if (state_was_pending) { save_state (_current_snapshot_name); + save_history(); remove_pending_capture_state (); state_was_pending = false; } @@ -2498,6 +2500,7 @@ void Session::auto_save() { save_state (_current_snapshot_name); + save_history(); } RouteGroup * @@ -2590,29 +2593,25 @@ Session::set_meter_falloff (float val) void -Session::begin_reversible_command (string name, UndoAction* private_undo) +Session::begin_reversible_command (string name) { - current_cmd.clear (); - current_cmd.set_name (name); - - if (private_undo) { - current_cmd.add_undo (*private_undo); - } + current_trans.clear (); + current_trans.set_name (name); } void -Session::commit_reversible_command (UndoAction* private_redo) +Session::commit_reversible_command (Command *cmd) { struct timeval now; - if (private_redo) { - current_cmd.add_redo_no_execute (*private_redo); + if (cmd) { + current_trans.add_command (cmd); } gettimeofday (&now, 0); - current_cmd.set_timestamp (now); + current_trans.set_timestamp (now); - history.add (current_cmd); + history.add (current_trans); } Session::GlobalRouteBooleanState @@ -2691,6 +2690,7 @@ Session::set_global_record_enable (GlobalRouteBooleanState s, void* src) set_global_route_boolean (s, &Route::set_record_enable, src); } +#if 0 UndoAction Session::global_mute_memento (void* src) { @@ -2714,6 +2714,7 @@ Session::global_record_enable_memento (void* src) { return sigc::bind (mem_fun (*this, &Session::set_global_record_enable), get_global_route_boolean (&Route::record_enabled), src); } +#endif static bool template_filter (const string &str, void *arg) @@ -3301,3 +3302,48 @@ Session::add_instant_xml (XMLNode& node, const std::string& dir) Stateful::add_instant_xml (node, dir); Config->add_instant_xml (node, get_user_ardour_path()); } + + +int +Session::save_history () +{ + XMLTree tree; + string xml_path; + string bak_path; + + tree.set_root (&history.get_state()); + + xml_path = _path + _current_snapshot_name + ".history"; + + bak_path = xml_path + ".bak"; + + if ((access (xml_path.c_str(), F_OK) == 0) && + (rename (xml_path.c_str(), bak_path.c_str()))) + { + error << _("could not backup old history file, current history not saved.") << endmsg; + return -1; + } + + if (!tree.write (xml_path)) + { + error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg; + + /* don't leave a corrupt file lying around if it is + * possible to fix. + */ + + if (unlink (xml_path.c_str())) + { + error << string_compose (_("could not remove corrupt history file %1"), xml_path) << endmsg; + } else { + if (rename (bak_path.c_str(), xml_path.c_str())) + { + error << string_compose (_("could not restore history file from backup %1"), bak_path) << endmsg; + } + } + + return -1; + } + + return 0; +} diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index bff8ae5955..592f9c86c6 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -325,8 +326,10 @@ Session::non_realtime_stop (bool abort) } if (change_end) { - add_undo (sigc::retype_return(sigc::bind (mem_fun (*loc, &Location::set_end), loc->end()))); - add_redo (sigc::retype_return(sigc::bind (mem_fun (*loc, &Location::set_end), _transport_frame))); + XMLNode &before = loc->get_state(); + loc->set_end(_transport_frame); + XMLNode &after = loc->get_state(); + add_command (new MementoCommand(*loc, before, after)); } _end_location_is_free = false; @@ -410,6 +413,7 @@ Session::non_realtime_stop (bool abort) if ((post_transport_work & PostTransportLocate) && get_record_enabled()) { /* capture start has been changed, so save pending state */ save_state ("", true); + save_history(); } /* always try to get rid of this */ diff --git a/libs/ardour/state_manager.cc b/libs/ardour/state_manager.cc index bcffe381c3..153773ed30 100644 --- a/libs/ardour/state_manager.cc +++ b/libs/ardour/state_manager.cc @@ -72,6 +72,9 @@ StateManager::use_state (state_id_t id) void StateManager::save_state (std::string why) { + if (!should_save_state()) + return; + if (!_allow_save) { SaveAllowed.connect (mem_fun (*this, &StateManager::save_state)); return; diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 3b3b705a87..f81ef9de4d 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include "i18n.h" @@ -146,6 +147,18 @@ Track::record_enabled () const { return _diskstream->record_enabled (); } + +bool +Track::can_record() +{ + bool will_record = true; + for (size_t i = 0; i < _inputs.size() && will_record; i++) { + if (!_inputs[i]->connected()) + will_record = false; + } + + return will_record; +} void Track::set_record_enable (bool yn, void *src) @@ -159,8 +172,13 @@ Track::set_record_enable (bool yn, void *src) return; } - /* keep track of the meter point as it was before we rec-enabled */ + // Do not set rec enabled if the track can't record. + if (yn && !can_record()) { + error << string_compose( _("Can not arm track '%1'. Check the input connections"), name() ) << endmsg; + return; + } + /* keep track of the meter point as it was before we rec-enabled */ if (!_diskstream->record_enabled()) { _saved_meter_point = _meter_point; } @@ -206,6 +224,7 @@ Track::set_name (string str, void *src) if ((ret = IO::set_name (str, src)) == 0) { _session.save_state (""); + _session.save_history(); } return ret; } diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc index 352b887e13..4c09ba3440 100644 --- a/libs/ardour/vst_plugin.cc +++ b/libs/ardour/vst_plugin.cc @@ -479,3 +479,33 @@ VSTPlugin::print_parameter (uint32_t param, char *buf, uint32_t len) const memmove (buf, first_nonws, strlen (buf) - (first_nonws - buf) + 1); } + +PluginPtr +VSTPluginInfo::load (Session& session) +{ + try { + PluginPtr plugin; + + if (Config->get_use_vst()) { + FSTHandle* handle; + + handle = fst_load(path.c_str()); + + if ( (int)handle == -1) { + error << string_compose(_("VST: cannot load module from \"%1\""), path) << endmsg; + } else { + plugin.reset (new VSTPlugin (session.engine(), session, handle)); + } + } else { + error << _("You asked ardour to not use any VST plugins") << endmsg; + return PluginPtr ((Plugin*) 0); + } + + plugin->set_info(PluginInfoPtr(new VSTPluginInfo(*this))); + return plugin; + } + + catch (failed_constructor &err) { + return PluginPtr ((Plugin*) 0); + } +} diff --git a/libs/libsndfile/src/flac.c b/libs/libsndfile/src/flac.c index 1f0872f0bd..b74a4e3253 100644 --- a/libs/libsndfile/src/flac.c +++ b/libs/libsndfile/src/flac.c @@ -128,38 +128,38 @@ static const int legal_sample_rates [] = { 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000 } ; -static inline void +static void s2flac8_array (const short *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 8 ; } /* s2flac8_array */ -static inline void +static void s2flac16_array (const short *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] ; } /* s2flac16_array */ -static inline void +static void s2flac24_array (const short *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] << 8 ; } /* s2flac24_array */ -static inline void +static void i2flac8_array (const int *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 24 ; } /* i2flac8_array */ -static inline void +static void i2flac16_array (const int *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 16 ; } /* i2flac16_array */ -static inline void +static void i2flac24_array (const int *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 8 ; diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript index 36fb02885f..4b15dd70d1 100644 --- a/libs/pbd/SConscript +++ b/libs/pbd/SConscript @@ -21,6 +21,7 @@ pbd_files = Split(""" basename.cc base_ui.cc convert.cc +command.cc controllable.cc dmalloc.cc error.cc diff --git a/libs/pbd/command.cc b/libs/pbd/command.cc new file mode 100644 index 0000000000..5b41691c07 --- /dev/null +++ b/libs/pbd/command.cc @@ -0,0 +1,10 @@ +#include +#include + + +XMLNode &Command::get_state() +{ + XMLNode *node = new XMLNode ("Command"); + node->add_content("WARNING: Somebody forgot to subclass Command."); + return *node; +} diff --git a/libs/pbd/id.cc b/libs/pbd/id.cc index f9afa72c98..0de0d052c3 100644 --- a/libs/pbd/id.cc +++ b/libs/pbd/id.cc @@ -8,6 +8,7 @@ #include #include +#include using namespace std; using namespace PBD; @@ -45,6 +46,13 @@ ID::print (char* buf) const snprintf (buf, 16, "%" PRIu64, id); } +string ID::to_s() const +{ + char buf[16]; // see print() + print(buf); + return string(buf); +} + ID& ID::operator= (string str) { diff --git a/libs/pbd/pbd/command.h b/libs/pbd/pbd/command.h new file mode 100644 index 0000000000..cd9bf0e08a --- /dev/null +++ b/libs/pbd/pbd/command.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2006 Hans Fugal & Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: /local/undo/libs/pbd3/pbd/undo.h 80 2006-06-22T22:37:01.079855Z fugalh $ +*/ + +#ifndef __lib_pbd_command_h__ +#define __lib_pbd_command_h__ + +#include + +class Command : public Stateful +{ + public: + virtual ~Command() {} + virtual void operator() () = 0; + virtual void undo() = 0; + virtual void redo() { (*this)(); } + virtual XMLNode &get_state(); + virtual int set_state(const XMLNode&) { /* noop */ return 0; } +}; + +#endif // __lib_pbd_command_h_ diff --git a/libs/pbd/pbd/id.h b/libs/pbd/pbd/id.h index 9a3f10478d..1ce448d58b 100644 --- a/libs/pbd/pbd/id.h +++ b/libs/pbd/pbd/id.h @@ -28,6 +28,7 @@ class ID { } void print (char* buf) const; + std::string to_s() const; static uint64_t counter() { return _counter; } static void init_counter (uint64_t val) { _counter = val; } diff --git a/libs/pbd/pbd/memento_command.h b/libs/pbd/pbd/memento_command.h new file mode 100644 index 0000000000..46c724e9ea --- /dev/null +++ b/libs/pbd/pbd/memento_command.h @@ -0,0 +1,99 @@ +/* + Copyright (C) 2006 Hans Fugal & Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: /local/undo/libs/pbd3/pbd/undo.h 132 2006-06-29T18:45:16.609763Z fugalh $ +*/ + +#ifndef __lib_pbd_memento_command_h__ +#define __lib_pbd_memento_command_h__ + +#include +#include +#include + +/** This command class is initialized with before and after mementos + * (from Stateful::get_state()), so undo becomes restoring the before + * memento, and redo is restoring the after memento. + */ +template +class MementoCommand : public Command +{ + public: + MementoCommand(obj_T &obj, + XMLNode &before, + XMLNode &after + ) + : obj(obj), before(before), after(after) {} + void operator() () { obj.set_state(after); } + void undo() { obj.set_state(before); } + virtual XMLNode &get_state() + { + XMLNode *node = new XMLNode("MementoCommand"); + node->add_property("obj_id", obj.id().to_s()); + node->add_child_nocopy(before); + node->add_child_nocopy(after); + return *node; + } + // TODO does this need a copy constructor? + protected: + obj_T &obj; + XMLNode &before, &after; +}; + +template +class MementoUndoCommand : public Command +{ +public: + MementoUndoCommand(obj_T &obj, + XMLNode &before) + : obj(obj), before(before) {} + void operator() () { /* noop */ } + void undo() { obj.set_state(before); } + virtual XMLNode &get_state() + { + XMLNode *node = new XMLNode("MementoUndoCommand"); + node->add_property("obj_id", obj.id().to_s()); + node->add_child_nocopy(before); + return *node; + } +protected: + obj_T &obj; + XMLNode &before; +}; + +template +class MementoRedoCommand : public Command +{ +public: + MementoRedoCommand(obj_T &obj, + XMLNode &after) + : obj(obj), after(after) {} + void operator() () { obj.set_state(after); } + void undo() { /* noop */ } + virtual XMLNode &get_state() + { + XMLNode *node = new XMLNode("MementoRedoCommand"); + node->add_property("obj_id", obj.id().to_s()); + node->add_child_nocopy(after); + return *node; + } +protected: + obj_T &obj; + XMLNode &after; +}; + +#endif // __lib_pbd_memento_h__ diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h index f067635ed3..724e86aaa0 100644 --- a/libs/pbd/pbd/undo.h +++ b/libs/pbd/pbd/undo.h @@ -23,29 +23,33 @@ #include #include +#include #include +#include #include +#include using std::string; using std::list; typedef sigc::slot UndoAction; -class UndoCommand +class UndoTransaction : public Command { public: - UndoCommand (); - UndoCommand (const UndoCommand&); - UndoCommand& operator= (const UndoCommand&); + UndoTransaction (); + UndoTransaction (const UndoTransaction&); + UndoTransaction& operator= (const UndoTransaction&); void clear (); - void add_undo (const UndoAction&); - void add_redo (const UndoAction&); - void add_redo_no_execute (const UndoAction&); + void add_command (Command *const); + void operator() (); void undo(); void redo(); + + XMLNode &get_state(); void set_name (const string& str) { _name = str; @@ -61,8 +65,7 @@ class UndoCommand } private: - list redo_actions; - list undo_actions; + list actions; struct timeval _timestamp; string _name; }; @@ -73,7 +76,7 @@ class UndoHistory UndoHistory() {} ~UndoHistory() {} - void add (UndoCommand uc); + void add (UndoTransaction ut); void undo (unsigned int n); void redo (unsigned int n); @@ -87,9 +90,11 @@ class UndoHistory void clear_undo (); void clear_redo (); + XMLNode &get_state(); + void save_state(); private: - list UndoList; - list RedoList; + list UndoList; + list RedoList; }; diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc index f2f11b1c5c..8d1b416c16 100644 --- a/libs/pbd/undo.cc +++ b/libs/pbd/undo.cc @@ -21,81 +21,84 @@ #include #include +#include +#include using namespace std; using namespace sigc; -UndoCommand::UndoCommand () +UndoTransaction::UndoTransaction () { } -UndoCommand::UndoCommand (const UndoCommand& rhs) +UndoTransaction::UndoTransaction (const UndoTransaction& rhs) { _name = rhs._name; clear (); - undo_actions.insert(undo_actions.end(),rhs.undo_actions.begin(),rhs.undo_actions.end()); - redo_actions.insert(redo_actions.end(),rhs.redo_actions.begin(),rhs.redo_actions.end()); + actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end()); } -UndoCommand& -UndoCommand::operator= (const UndoCommand& rhs) +UndoTransaction& +UndoTransaction::operator= (const UndoTransaction& rhs) { if (this == &rhs) return *this; _name = rhs._name; clear (); - undo_actions.insert(undo_actions.end(),rhs.undo_actions.begin(),rhs.undo_actions.end()); - redo_actions.insert(redo_actions.end(),rhs.redo_actions.begin(),rhs.redo_actions.end()); + actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end()); return *this; } void -UndoCommand::add_undo (const UndoAction& action) +UndoTransaction::add_command (Command *const action) { - undo_actions.push_back (action); + actions.push_back (action); } void -UndoCommand::add_redo (const UndoAction& action) +UndoTransaction::clear () { - redo_actions.push_back (action); - redo_actions.back()(); // operator() + actions.clear (); } void -UndoCommand::add_redo_no_execute (const UndoAction& action) +UndoTransaction::operator() () { - redo_actions.push_back (action); -} - -void -UndoCommand::clear () -{ - undo_actions.clear (); - redo_actions.clear (); + for (list::iterator i = actions.begin(); i != actions.end(); ++i) { + (*(*i))(); + } } void -UndoCommand::undo () +UndoTransaction::undo () { cerr << "Undo " << _name << endl; - for (list::reverse_iterator i = undo_actions.rbegin(); i != undo_actions.rend(); ++i) { - (*i)(); + for (list::reverse_iterator i = actions.rbegin(); i != actions.rend(); ++i) { + (*i)->undo(); } } void -UndoCommand::redo () +UndoTransaction::redo () { cerr << "Redo " << _name << endl; - for (list::iterator i = redo_actions.begin(); i != redo_actions.end(); ++i) { - (*i)(); - } + (*this)(); +} + +XMLNode &UndoTransaction::get_state() +{ + XMLNode *node = new XMLNode ("UndoTransaction"); + + list::iterator it; + for (it=actions.begin(); it!=actions.end(); it++) + node->add_child_nocopy((*it)->get_state()); + + return *node; } void -UndoHistory::add (UndoCommand uc) +UndoHistory::add (UndoTransaction ut) { - UndoList.push_back (uc); + UndoList.push_back (ut); } void @@ -105,10 +108,10 @@ UndoHistory::undo (unsigned int n) if (UndoList.size() == 0) { return; } - UndoCommand uc = UndoList.back (); + UndoTransaction ut = UndoList.back (); UndoList.pop_back (); - uc.undo (); - RedoList.push_back (uc); + ut.undo (); + RedoList.push_back (ut); } } @@ -119,10 +122,10 @@ UndoHistory::redo (unsigned int n) if (RedoList.size() == 0) { return; } - UndoCommand cmd = RedoList.back (); + UndoTransaction ut = RedoList.back (); RedoList.pop_back (); - cmd.redo (); - UndoList.push_back (cmd); + ut.redo (); + UndoList.push_back (ut); } } @@ -144,3 +147,14 @@ UndoHistory::clear () RedoList.clear (); UndoList.clear (); } + +XMLNode & UndoHistory::get_state() +{ + XMLNode *node = new XMLNode ("UndoHistory"); + + list::iterator it; + for (it=UndoList.begin(); it != UndoList.end(); it++) + node->add_child_nocopy(it->get_state()); + + return *node; +} diff --git a/libs/surfaces/control_protocol/basic_ui.cc b/libs/surfaces/control_protocol/basic_ui.cc index 3dc93cc64a..47401c8cfe 100644 --- a/libs/surfaces/control_protocol/basic_ui.cc +++ b/libs/surfaces/control_protocol/basic_ui.cc @@ -145,6 +145,7 @@ void BasicUI::save_state () { session->save_state (""); + session->save_history(); } void -- cgit v1.2.3