merge from 2.0-ongoing by hand, minus key binding editor
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 11 Oct 2007 22:07:47 +0000 (22:07 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 11 Oct 2007 22:07:47 +0000 (22:07 +0000)
git-svn-id: svn://localhost/ardour2/trunk@2539 d708f5d6-7413-0410-9779-e7cbd77b26cf

134 files changed:
SConstruct
gtk2_ardour/SConscript
gtk2_ardour/ardbg
gtk2_ardour/ardev
gtk2_ardour/ardour.menus
gtk2_ardour/ardour.sh.in
gtk2_ardour/ardour2_ui_dark.rc.in
gtk2_ardour/ardour2_ui_default.conf
gtk2_ardour/ardour2_ui_light.rc.in
gtk2_ardour/ardour_dialog.cc
gtk2_ardour/ardour_dialog.h
gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/ardour_ui2.cc
gtk2_ardour/ardour_ui_dependents.cc
gtk2_ardour/ardour_ui_dialogs.cc
gtk2_ardour/ardour_ui_ed.cc
gtk2_ardour/ardour_ui_options.cc
gtk2_ardour/arprof
gtk2_ardour/arval
gtk2_ardour/audio_region_view.cc
gtk2_ardour/audio_streamview.cc
gtk2_ardour/axis_view.h
gtk2_ardour/editing.h
gtk2_ardour/editing_syms.h
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_actions.cc
gtk2_ardour/editor_audio_import.cc
gtk2_ardour/editor_audiotrack.cc
gtk2_ardour/editor_canvas.cc
gtk2_ardour/editor_keyboard.cc
gtk2_ardour/editor_markers.cc
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/editor_region_list.cc
gtk2_ardour/editor_route_list.cc
gtk2_ardour/editor_rulers.cc
gtk2_ardour/engine_dialog.cc [new file with mode: 0644]
gtk2_ardour/engine_dialog.h [new file with mode: 0644]
gtk2_ardour/enums.cc
gtk2_ardour/keyboard.cc
gtk2_ardour/keyboard.h
gtk2_ardour/main.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/mixer_ui.cc
gtk2_ardour/mixer_ui.h
gtk2_ardour/new_session_dialog.cc
gtk2_ardour/new_session_dialog.h
gtk2_ardour/option_editor.cc
gtk2_ardour/option_editor.h
gtk2_ardour/opts.cc
gtk2_ardour/opts.h
gtk2_ardour/processor_box.cc
gtk2_ardour/processor_box.h
gtk2_ardour/send_ui.cc
gtk2_ardour/sfdb_ui.cc
gtk2_ardour/sfdb_ui.h
gtk2_ardour/streamview.cc
gtk2_ardour/utils.cc
libs/ardour/SConscript
libs/ardour/ardour/ardour.h
libs/ardour/ardour/audiofilesource.h
libs/ardour/ardour/audiosource.h
libs/ardour/ardour/automatable.h
libs/ardour/ardour/configuration.h
libs/ardour/ardour/configuration_vars.h
libs/ardour/ardour/io.h
libs/ardour/ardour/profile.h
libs/ardour/ardour/resampled_source.h [new file with mode: 0644]
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/ardour/sndfilesource.h
libs/ardour/ardour/source_factory.h
libs/ardour/ardour/types.h
libs/ardour/ardour/utils.h
libs/ardour/audio_playlist.cc
libs/ardour/audioengine.cc
libs/ardour/audiofilesource.cc
libs/ardour/audiosource.cc
libs/ardour/auditioner.cc
libs/ardour/automatable.cc
libs/ardour/configuration.cc
libs/ardour/crossfade.cc
libs/ardour/globals.cc
libs/ardour/import.cc
libs/ardour/io.cc
libs/ardour/playlist.cc
libs/ardour/resampled_source.cc [new file with mode: 0644]
libs/ardour/route.cc
libs/ardour/session.cc
libs/ardour/session_events.cc
libs/ardour/session_state.cc
libs/ardour/sndfilesource.cc
libs/ardour/source_factory.cc
libs/ardour/utils.cc
libs/clearlooks/SConscript
libs/clearlooks/clearlooks_style.c
libs/gtkmm2/gtk/gtkmm/toolbar.cc
libs/midi++2/SConscript
libs/midi++2/alsa_sequencer_midiport.cc
libs/midi++2/coremidi_midiport.cc
libs/midi++2/fd_midiport.cc
libs/midi++2/fifomidi.cc
libs/midi++2/jack_midiport.cc
libs/midi++2/midi++/alsa_rawmidi.h
libs/midi++2/midi++/alsa_sequencer.h
libs/midi++2/midi++/coremidi_midiport.h
libs/midi++2/midi++/factory.h
libs/midi++2/midi++/fd_midiport.h
libs/midi++2/midi++/fifomidi.h
libs/midi++2/midi++/jack.h
libs/midi++2/midi++/manager.h
libs/midi++2/midi++/nullmidi.h
libs/midi++2/midi++/port.h
libs/midi++2/midi++/port_request.h [deleted file]
libs/midi++2/midifactory.cc
libs/midi++2/midimanager.cc
libs/midi++2/midiport.cc
libs/midi++2/miditrace.cc
libs/midi++2/mmctest.cc
libs/midi++2/port_request.cc [deleted file]
libs/pbd/SConscript
libs/pbd/convert.cc
libs/pbd/file_utils.cc
libs/pbd/misc.c [new file with mode: 0644]
libs/pbd/pbd/convert.h
libs/pbd/pbd/functor_command.h [new file with mode: 0644]
libs/pbd/pbd/misc.h [new file with mode: 0644]
libs/pbd/pbd/undo.h
libs/pbd/undo.cc
libs/surfaces/generic_midi/generic_midi_control_protocol.cc
libs/surfaces/mackie/mackie_control_protocol_poll.cc
libs/surfaces/powermate/powermate.cc

index cddc7384c892be487c476a6269c473340a7ae4d7..5f6bde510312653bb719e346c094ff73b4e35e97 100644 (file)
@@ -16,7 +16,7 @@ import SCons.Node.FS
 SConsignFile()
 EnsureSConsVersion(0, 96)
 
-ardour_version = '2.1pre'
+ardour_version = '3.0'
 
 subst_dict = { }
 
@@ -30,6 +30,7 @@ opts.AddOptions(
     BoolOption('AUDIOUNITS', 'Compile with Apple\'s AudioUnit library. (experimental)', 0),
     BoolOption('CMT', 'Compile with support for CMT Additions', 1),
     BoolOption('COREAUDIO', 'Compile with Apple\'s CoreAudio library', 0),
+    BoolOption('GTKOSX', 'Compile for use with GTK-OSX, not GTK-X11', 0),
     BoolOption('DEBUG', 'Set to build with debugging information and no optimizations', 1),
     PathOption('DESTDIR', 'Set the intermediate install "prefix"', '/'),
     EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'none' ), ignorecase=2),
@@ -711,8 +712,13 @@ if env['LIBLO']:
 
 def prep_libcheck(topenv, libinfo):
     if topenv['DIST_TARGET'] == 'panther' or topenv['DIST_TARGET'] == 'tiger':
+        #
+        # rationale: GTK-Quartz uses jhbuild and installs to /opt/gtk by default.
+        #            All libraries needed should be built against this location
+        if topenv['GTKOSX']:
+            libinfo.Append(CCFLAGS="-I/opt/gtk/include", LINKFLAGS="-L/opt/gtk/lib")
         libinfo.Append(CCFLAGS="-I/opt/local/include", LINKFLAGS="-L/opt/local/lib")
-
+            
 prep_libcheck(env, env)
 
 #
@@ -803,10 +809,18 @@ else:
 libraries['dmalloc'] = conf.Finish ()
 
 #
-# Audio/MIDI library (needed for MIDI, since audio is all handled via JACK)
+# Audio/MIDI library (needed for MIDI, since audio is all handled via JACK. Note, however, that
+#                     we still need ALSA & CoreAudio to discover audio devices for the engine
+#                     dialog, regardless of what MIDI subsystem is being used)
 #
 
 conf = Configure(env)
+
+if conf.CheckCHeader('alsa/asoundlib.h'):
+    libraries['sysaudio'] = LibraryInfo (LIBS='asound')
+elif conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
+    libraries['sysaudio'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
+
 if conf.CheckCHeader('jack/midiport.h'):
     libraries['sysmidi'] = LibraryInfo (LIBS='jack')
     env['SYSMIDI'] = 'JACK MIDI'
@@ -821,7 +835,13 @@ elif conf.CheckCHeader('alsa/asoundlib.h'):
     print "Using ALSA MIDI"
 elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
     # this line is needed because scons can't handle -framework in ParseConfig() yet.
-    libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
+    if env['GTKOSX']:
+        # We need Carbon as well as the rest
+        libraries['sysmidi'] = LibraryInfo (
+               LINKFLAGS = ' -framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -framework Carbon -bind_at_load' )
+    else:
+        libraries['sysmidi'] = LibraryInfo (
+               LINKFLAGS = ' -framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load' )
     env['SYSMIDI'] = 'CoreMIDI'
     subst_dict['%MIDITAG%'] = "ardour"
     subst_dict['%MIDITYPE%'] = "coremidi"
@@ -1148,9 +1168,14 @@ if os.path.exists('.svn'):
 # specbuild = env.SubstInFile ('ardour.spec','ardour.spec.in', SUBST_DICT = subst_dict)
 
 the_revision = env.Command ('frobnicatory_decoy', [], create_stored_revision)
+remove_ardour = env.Command ('frobnicatory_decoy2', [],
+                             [ Delete ('$PREFIX/etc/ardour2'),
+                               Delete ('$PREFIX/lib/ardour2'),
+                               Delete ('$PREFIX/bin/ardour2')])
 
 env.Alias('revision', the_revision)
 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
+env.Alias('uninstall', remove_ardour)
 
 Default (sysrcbuild)
 
index b96498602e1d5b69cc0d022002694effa55d2343..12e3225f895b2758a550df337461e56945a0c2d6 100644 (file)
@@ -13,7 +13,7 @@ gtkmmtests = env.Copy()
 # this defines the version number of the GTK interface to ardour
 #
 
-domain = 'gtk_ardour'
+domain = 'gtk2_ardour'
 
 gtkardour.Append(DOMAIN=domain, MAJOR=1,MINOR=0,MICRO=2)
 gtkardour.Append(CCFLAGS="-DPACKAGE=\\\"" + domain + "\\\"")
@@ -24,6 +24,9 @@ gtkardour.Append(CPPPATH="#/")  # for top level svn_revision.h
 gtkardour.Append(PACKAGE=domain)
 gtkardour.Append(POTFILE=domain + '.pot')
 
+if gtkardour['DIST_TARGET'] == 'panther' or gtkardour['DIST_TARGET'] == 'tiger':
+       gtkardour.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
+
 gtkardour.Merge ([
     libraries['ardour'],
     libraries['ardour_cp'],
@@ -48,7 +51,8 @@ gtkardour.Merge ([
     libraries['xslt'],
     libraries['soundtouch'],
     libraries['samplerate'],
-    libraries['jack']
+    libraries['jack'],
+    libraries['sysaudio']
 ])
 
 gtkmmtests.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
@@ -80,6 +84,15 @@ audiounit_files=Split("""
 au_pluginui.cc
 """)
 
+gtkosx_files=Split("""
+sync-menu.c
+cocoacarbon.c
+""")
+
+x11_files=Split("""
+x11.cc
+""")
+
 gtkardour_files=Split("""
 about.cc
 actions.cc
@@ -143,6 +156,7 @@ editor_selection.cc
 editor_selection_list.cc
 editor_tempodisplay.cc
 editor_timefx.cc
+engine_dialog.cc
 export_dialog.cc
 export_session_dialog.cc
 export_region_dialog.cc
@@ -258,6 +272,12 @@ if env['CMT']:
     extra_sources += cmt_files
     gtkardour.Append (CCFLAGS="-DWITH_CMT")
 
+if gtkardour['GTKOSX']:
+   extra_sources += gtkosx_files
+   gtkardour.Append (CCFLAGS="-DTOP_MENUBAR -DGTKOSX")
+else:
+   extra_sources += x11_files
+       
 if gtkardour['AUDIOUNITS']:
     extra_sources += audiounit_files
     gtkardour.Append(CCFLAGS='-DHAVE_AUDIOUNITS')
@@ -292,41 +312,43 @@ if gtkardour['DIST_TARGET'] == 'panther' or gtkardour['DIST_TARGET'] == 'tiger':
        #
        # OS X font rendering is different even with X11
        #
-       my_font_dict['%FONT_TINY%'] = 'sans 7'
-       my_font_dict['%FONT_SMALLER%'] = 'sans 9'
-       my_font_dict['%FONT_SMALL%'] = 'sans 10'
-       my_font_dict['%FONT_NORMAL%'] = 'sans 11'
-       my_font_dict['%FONT_BIG%'] = 'sans 15'
-       my_font_dict['%FONT_BIGGER%'] = 'sans 16'
-       my_font_dict['%FONT_LARGE%'] = 'sans 20'
-       my_font_dict['%FONT_LARGER%'] = 'sans 28'
-       my_font_dict['%FONT_HUGER%'] = 'sans 36'
-       my_font_dict['%FONT_MASSIVE%'] = 'sans 60'
-       my_font_dict['%FONT_BOLD_TINY%'] = 'sans bold 7'
-       my_font_dict['%FONT_BOLD_SMALLER%'] = 'sans bold 9'
-       my_font_dict['%FONT_BOLD_SMALL%'] = 'sans bold 10'
-       my_font_dict['%FONT_BOLD_NORMAL%'] = 'sans bold 11'
-       my_font_dict['%FONT_BOLD_BIG%'] = 'sans bold 15'
-       my_font_dict['%FONT_BOLD_BIGGER%'] = 'sans bold 16'
-       my_font_dict['%FONT_BOLD_LARGE%'] = 'sans bold 20'
-       my_font_dict['%FONT_BOLD_LARGER%'] = 'sans bold 28'
-       my_font_dict['%FONT_BOLD_HUGER%'] = 'sans bold 36'
-       my_font_dict['%FONT_BOLD_MASSIVE%'] = 'sans bold 60'
-       my_font_dict['%FONT_ITALIC_TINY%'] = 'sans italic 7'
-       my_font_dict['%FONT_ITALIC_SMALLER%'] = 'sans italic 9'
-       my_font_dict['%FONT_ITALIC_SMALL%'] = 'sans italic 10'
-       my_font_dict['%FONT_ITALIC_NORMAL%'] = 'sans italic 11'
-       my_font_dict['%FONT_ITALIC_BIG%'] = 'sans italic 15'
-       my_font_dict['%FONT_ITALIC_BIGGER%'] = 'sans italic 16'
-       my_font_dict['%FONT_ITALIC_LARGE%'] = 'sans italic 20'
-       my_font_dict['%FONT_ITALIC_LARGER%'] = 'sans italic 28'
-       my_font_dict['%FONT_ITALIC_HUGER%'] = 'sans italic 36'
-       my_font_dict['%FONT_ITALIC_MASSIVE%'] = 'sans italic 60'
+       my_font_dict['%FONT_TINY%'] = 'Lucida Grande 7'
+       my_font_dict['%FONT_SMALLERER%'] = 'Lucida Grande 8'
+       my_font_dict['%FONT_SMALLER%'] = 'Lucida Grande 9'
+       my_font_dict['%FONT_SMALL%'] = 'Lucida Grande 10'
+       my_font_dict['%FONT_NORMAL%'] = 'Lucida Grande 11'
+       my_font_dict['%FONT_BIG%'] = 'Lucida Grande 12'
+       my_font_dict['%FONT_BIGGER%'] = 'Lucida Grande 14'
+       my_font_dict['%FONT_LARGE%'] = 'Lucida Grande 18'
+       my_font_dict['%FONT_LARGER%'] = 'Lucida Grande 28'
+       my_font_dict['%FONT_HUGER%'] = 'Lucida Grande 36'
+       my_font_dict['%FONT_MASSIVE%'] = 'Lucida Grande 60'
+       my_font_dict['%FONT_BOLD_TINY%'] = 'Lucida Grande bold 7'
+       my_font_dict['%FONT_BOLD_SMALLER%'] = 'Lucida Grande bold 9'
+       my_font_dict['%FONT_BOLD_SMALL%'] = 'Lucida Grande bold 10'
+       my_font_dict['%FONT_BOLD_NORMAL%'] = 'Lucida Grande bold 11'
+       my_font_dict['%FONT_BOLD_BIG%'] = 'Lucida Grande bold 13'
+       my_font_dict['%FONT_BOLD_BIGGER%'] = 'Lucida Grande bold 14'
+       my_font_dict['%FONT_BOLD_LARGE%'] = 'Lucida Grande bold 20'
+       my_font_dict['%FONT_BOLD_LARGER%'] = 'Lucida Grande bold 25'
+       my_font_dict['%FONT_BOLD_HUGER%'] = 'Lucida Grande bold 36'
+       my_font_dict['%FONT_BOLD_MASSIVE%'] = 'Lucida Grande bold 60'
+       my_font_dict['%FONT_ITALIC_TINY%'] = 'Lucida Grande italic 7'
+       my_font_dict['%FONT_ITALIC_SMALLER%'] = 'Lucida Grande italic 9'
+       my_font_dict['%FONT_ITALIC_SMALL%'] = 'Lucida Grande italic 10'
+       my_font_dict['%FONT_ITALIC_NORMAL%'] = 'Lucida Grande italic 11'
+       my_font_dict['%FONT_ITALIC_BIG%'] = 'Lucida Grande italic 15'
+       my_font_dict['%FONT_ITALIC_BIGGER%'] = 'Lucida Grande italic 16'
+       my_font_dict['%FONT_ITALIC_LARGE%'] = 'Lucida Grande italic 20'
+       my_font_dict['%FONT_ITALIC_LARGER%'] = 'Lucida Grande italic 28'
+       my_font_dict['%FONT_ITALIC_HUGER%'] = 'Lucida Grande italic 36'
+       my_font_dict['%FONT_ITALIC_MASSIVE%'] = 'Lucida Grande italic 60'
 else:
        #
        # Linux/X11 font rendering
        #
        my_font_dict['%FONT_TINY%'] = 'sans 4'
+       my_font_dict['%FONT_SMALLERER%'] = 'sans 6'
        my_font_dict['%FONT_SMALLER%'] = 'sans 6'
        my_font_dict['%FONT_SMALL%'] = 'sans 7'
        my_font_dict['%FONT_NORMAL%'] = 'sans 8'
@@ -411,6 +433,7 @@ if env['NLS']:
 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), ardour_dark_theme))
 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), ardour_light_theme))
 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.menus'))
+env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour-sae.menus'))
 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.bindings'))
 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour2_ui_default.conf'))
 # data files
@@ -428,7 +451,9 @@ env.Alias ('tarball', env.Distribute (env['DISTTREE'],
                                        'ardev_common.sh.in',
                                        'ardev', 'ardbg',
                                         'ardour2_ui_dark.rc', 'ardour2_ui_light.rc', 'splash.png',
-                                        'ardour.menus', 'ardour.bindings.in', 'ardour2_ui_default.conf',
+                                        'ardour.menus',
+                                        'ardour-sae.menus',
+                                       'ardour.bindings.in', 'ardour2_ui_default.conf',
                                        'editor_xpms'
                                         ] +
                                       gtkardour_files +
@@ -437,6 +462,8 @@ env.Alias ('tarball', env.Distribute (env['DISTTREE'],
                                      icon_files +
                                      skipped_files +
                                      audiounit_files + 
+                                     gtkosx_files +
+                                     x11_files +
                                      fft_analysis_files +
                                      glob.glob('po/*.po') + glob.glob('*.h')))
 
index ab99296f450df07b6ac4559aee8cff20654e72e9..063b2b1b6d489bec51aca45543a3e577c11ebd4f 100755 (executable)
@@ -2,4 +2,4 @@
 dir=`dirname "$0"`
 . $dir/ardev_common.sh
 LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
-exec gdb $EXECUTABLE $*
+exec gdb $EXECUTABLE "$@"
index 5dd8fc9d1390a2c5ae826387973fb321bb35d093..7980c43d93c959f2c262edb0fda44c36ca8f9dba 100755 (executable)
@@ -1,4 +1,4 @@
 #!/bin/sh
 . `dirname "$0"`/ardev_common.sh
 LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
-exec $EXECUTABLE $*
+exec $EXECUTABLE "$@"
index 24adba9f7fa760ef8714cef36fc95988500146d6..128ca81c278151d31afbfa422861950e888903d5 100644 (file)
            <separator/>
            <menuitem action='AddTrackBus'/>    
            <separator/>
-           <menu action='addExistingAudioFiles'>
-              <menuitem action='addExternalAudioAsRegion'/>           
-              <menuitem action='addExternalAudioToTrack'/>            
-               <separator/>
-              <menuitem action='addExternalAudioAsTrack'/>            
-              <menuitem action='addExternalAudioAsTapeTrack'/>        
-           </menu>
+           <menuitem action='addExistingAudioFiles'/>
            <separator/>
            <menu name='Export' action='Export'>
                <menuitem action='ExportSession'/>
                        <menuitem action='set-mouse-mode-gain'/>
                        <menuitem action='set-mouse-mode-zoom'/>
                        <menuitem action='set-mouse-mode-timefx'/>
-                       <menuitem action='set-mouse-mode-note'/>
           </menu>
         </menu>         
         <menu name='View' action = 'View'>
                <menuitem action='ToggleMeasureVisibility'/>
               <separator/>
               <menuitem action='show-editor-mixer'/>
-              <menuitem action='show-editor-list'/>
+              <menuitem action='SyncEditorAndMixerTrackOrder'/>
          </menu>
         <menu name='JACK' action='JACK'>
                <menuitem action='JACKDisconnect'/>
                    <menuitem action='UseHardwareMonitoring'/>
                    <menuitem action='UseSoftwareMonitoring'/>
                    <menuitem action='UseExternalMonitoring'/>
-               </menu>
-                  <menu action='Plugins'>
-                       <menuitem action='DisableAllPlugins'/>
-                       <menuitem action='ABAllPlugins'/>
                </menu>
               <menu action='Metering'>
                    <menu action='MeteringFallOffRate'>
                <menuitem action='GainReduceFastTransport'/>
               <menuitem action='PrimaryClockDeltaEditCursor'/>
               <menuitem action='SecondaryClockDeltaEditCursor'/>
+              <menuitem action='OnlyCopyImportedFiles'/>
+              <separator/>
          </menu>
         <menu name='Help' action='Help'>
             <menuitem action='About'/>
        </menu>
      </menubar>
 
-     <popup name='processormenu'>
+     <popup name='redirectmenu'>
         <menuitem action='newplugin'/>
         <menuitem action='newinsert'/>
         <menuitem action='newsend'/>
         <menuitem action='activate_all'/>
         <menuitem action='deactivate_all'/>
          <separator/>
-        <menuitem action='deactivate_plugins'/>
-        <menuitem action='a_b_plugins'/>
-         <separator/>
         <menuitem action='edit'/>
       </popup>
 
index beed436cbe4108d30fc5038b333930be07a7f733..2f1092c3fe13e213794d02edb3842a5c099f9ed8 100644 (file)
@@ -15,6 +15,6 @@ fi
 
 ulimit -c unlimited
 
-exec %INSTALL_PREFIX%/%LIBDIR%/ardour2/ardour-%VERSION% $*
+exec %INSTALL_PREFIX%/%LIBDIR%/ardour2/ardour-%VERSION% "$@"
 
 
index 1420fc86602fc8116ae57b5c0044fb2db9510f60..ba8e5fe1e1183970f5201d1179c8cd9313b53827 100644 (file)
@@ -4,17 +4,17 @@
 
 style "very_small_text"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
 }
 
 style "small_text"
 {
-       font_name = "%FONT_NORMAL%"
+       font_name = "%FONT_SMALL%"
 }
 
 style "small_bold_text"
 {
-       font_name = "%FONT_BOLD_NORMAL%"
+       font_name = "%FONT_BOLD_SMALL%"
 }
 
 style "medium_bold_text"
@@ -73,7 +73,7 @@ style "verbose_canvas_cursor"
 
 style "marker_text" 
 {
-       font_name = "%FONT_NORMAL%"
+       font_name = "%FONT_SMALL%"
 }
 
 style "time_axis_view_item_name"
@@ -159,7 +159,7 @@ style "default_buttons_menus"
 
 style "very_small_button" = "default_buttons_menus"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        ythickness = 0
        xthickness = 0
 }
@@ -220,21 +220,21 @@ style "track_rec_enable_button_alternate" = "small_button"
 
 style "mixer_track_rec_enable_button" = "track_rec_enable_button"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_track_rec_enable_button_alternate" = "track_rec_enable_button_alternate"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_track_rec_enable_button_active" = "track_rec_enable_button_active"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        xthickness = 0
        ythickness = 0
 }
@@ -272,20 +272,20 @@ style "solo_button_active" = "small_button"
 
 style "mixer_solo_button" = "solo_button"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_solo_button_alternate" = "solo_button_alternate"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
 style "mixer_solo_button_active" = "solo_button_active"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
@@ -323,21 +323,21 @@ style "mute_button_active" = "small_button"
 
 style "mixer_mute_button" = "mute_button"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_mute_button_alternate" = "mute_button_alternate"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_mute_button_active" = "mute_button_active"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
@@ -351,7 +351,7 @@ style "multiline_combo" = "small_button"
 
 style "mixer_mute_button" = "mute_button"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        xthickness = 0
        ythickness = 0
 }
@@ -454,7 +454,7 @@ style "ardour_progressbars" = "default_buttons_menus"
   bg[PRELIGHT] = { 0.00, 0.36, 0.40 }
 }
 
-style "options_window"  = "default_base"
+style "preferences"  = "default_base"
 {
        font_name = "%FONT_NORMAL%"
        fg[PRELIGHT] = { 0.80, 0.80, 0.80 }
@@ -667,7 +667,7 @@ style "transport_clock_display_delta" = "transport_clock_display"
 
 style "tempo_meter_clock_display"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        fg[NORMAL] = { 1.0, 1.0, 1.0 }
        fg[ACTIVE] = { 1.0, 1.0, 0.0 }
        fg[SELECTED] = { 1.0, 0, 0 }
@@ -694,31 +694,6 @@ style "editor_time_ruler" = "small_text"
        bg[NORMAL] = { 0.09, 0.09, 0.09 }
 }
 
-style "time_bar_label_base" = "default_base"
-{
-  font_name = "sans 6"
-  fg[NORMAL] = { 0.77, 0.77, 0.72 }    
-  bg[NORMAL] = { 0.28, 0.29, 0.34 }
-  bg[ACTIVE] = { 0.30, 0.30, 0.34 }    
-  bg[PRELIGHT] = { 0.30, 0.30, 0.34 }
-  bg[INSENSITIVE] = { 0.30, 0.30, 0.34 }
-  bg[SELECTED] = { 0.30, 0.30, 0.34 }
-}
-
-style "time_bar_padding" = "default_base"
-{
-  fg[NORMAL] = { 0.09, 0.09, 0.09 }
-  fg[ACTIVE] = { 0.09, 0.09, 0.09 }    
-  fg[PRELIGHT] = { 0.09, 0.09, 0.09 }
-  fg[INSENSITIVE] = { 0.09, 0.09, 0.09 }
-  fg[SELECTED] = { 0.09, 0.09, 0.09 }
-  bg[NORMAL] = { 0.09, 0.09, 0.09 }
-  bg[ACTIVE] = { 0.09, 0.09, 0.09 }    
-  bg[PRELIGHT] = { 0.09, 0.09, 0.09 }
-  bg[INSENSITIVE] = { 0.09, 0.09, 0.09 }
-  bg[SELECTED] = { 0.09, 0.09, 0.09 }
-}
-
 style "audio_bus_base"
 {
   font_name = "%FONT_SMALLER%"
@@ -758,6 +733,38 @@ style "midi_track_base" = "default_base"
   bg[SELECTED] = { 0.20, 0.20, 0.20 }
 }
 
+style "track_controls_inactive" 
+{
+       bg[NORMAL] =      { 0.60, 0.60, 0.66 }
+       bg[ACTIVE] =      { 0.60, 0.60, 0.66 }
+       bg[INSENSITIVE] = { 0.60, 0.60, 0.66 }
+       bg[SELECTED] =    { 0.60, 0.60, 0.66 }
+       bg[PRELIGHT] =    { 0.60, 0.60, 0.66 }
+
+       #font_name = "sans 18"
+       fg[NORMAL] = { 0.7, 0.8, 0.2 }  
+}
+
+style "audio_track_metrics" = "audio_track_base"
+{
+       font_name = "%FONT_TINY%"
+}
+
+style "audio_bus_metrics" = "audio_bus_base"
+{
+       font_name = "%FONT_TINY%"
+}
+
+style "audio_track_metrics_inactive" = "track_controls_inactive"
+{
+       font_name = "%FONT_TINY%"
+}
+
+style "audio_bus_metrics_inactive" = "track_controls_inactive"
+{
+       font_name = "%FONT_TINY%"
+}
+
 style "track_name_display"
 {
        font_name = "%FONT_NORMAL%"
@@ -864,11 +871,11 @@ style "treeview_display" = "small_bold_text"
 
 style "main_canvas_area"
 {
-       bg[NORMAL] = { 0.40, 0.40, 0.44 }
-       bg[ACTIVE] = { 0.40, 0.40, 0.44 }
-       bg[INSENSITIVE] = { 0.40, 0.40, 0.44 }
-       bg[SELECTED] = { 0.40, 0.40, 0.44 }
-       bg[PRELIGHT] = { 0.40, 0.40, 0.44 }
+       bg[NORMAL] = { 0.30, 0.30, 0.34 }
+       bg[ACTIVE] = { 0.30, 0.30, 0.34 }
+       bg[INSENSITIVE] = { 0.30, 0.30, 0.34 }
+       bg[SELECTED] = { 0.30, 0.30, 0.34 }
+       bg[PRELIGHT] = { 0.30, 0.30, 0.34 }
 }
 
 style "track_controls_inactive"
@@ -1123,12 +1130,6 @@ style "tearoff_arrow" = "medium_bold_entry"
        bg[PRELIGHT] = { 0.80, 0.80, 0.80 }
 }
 
-style "meter_metrics_strip" = "default_base"
-{
-       font_name = "%FONT_TINY%"
-       fg[NORMAL] = { 1.0, 0.8, 0.2 }  
-}
-
 style "location_row_button" = "default_buttons_menus"
 {
        font_name = "%FONT_BIG%"
@@ -1234,15 +1235,15 @@ widget "*MixerMonitorInputButton.*" style:highest "very_small_button"
 widget "*MixerIOButton" style:highest "very_small_button"
 widget "*MixerIOButtonLabel" style:highest "very_small_button"
 widget "*AddRouteDialogSpinner" style:highest "ardour_adjusters"
-widget "*AddRouteDialogRadioButton*" style:highest "options_window"
-widget "*OptionsNotebook" style:highest "options_window"
-widget "*OptionEditorToggleButton*" style:highest "options_window"
-widget "*OptionsLabel" style:highest "options_window"
-widget "*OptionEditorAuditionerLabel" style:highest "options_window"
+widget "*AddRouteDialogRadioButton*" style:highest "preferences"
+widget "*OptionsNotebook" style:highest "preferences"
+widget "*OptionEditorToggleButton*" style:highest "preferences"
+widget "*OptionsLabel" style:highest "preferences"
+widget "*OptionEditorAuditionerLabel" style:highest "preferences"
 widget "*OptionsEntry" style:highest "option_entry"
-widget "*InspectorNotebook" style:highest "options_window"
-widget "*NewSessionDialog" style:highest "options_window"
-widget "*NewSessionDialogButton*" style:highest "options_window"
+widget "*InspectorNotebook" style:highest "preferences"
+widget "*NewSessionDialog" style:highest "preferences"
+widget "*NewSessionDialogButton*" style:highest "preferences"
 widget "*MixerSendSwitch*" style:highest "very_small_red_active_and_selected_button"
 widget "*OptionEditorToggleButton" style:highest "small_red_active_and_selected_button"
 widget "*NewSessionDialogButton" style:highest "small_red_active_and_selected_button"
@@ -1346,15 +1347,24 @@ widget "*BBTRuler" style:highest "editor_time_ruler"
 widget "*FramesRuler" style:highest "editor_time_ruler"
 widget "*MinSecRuler" style:highest "editor_time_ruler"
 widget "*BaseFrame" style:highest "base_frame"
+
 widget "*AudioTrackStripBase" style:highest "audio_track_base"
+widget "*AudioBusStripBase" style:highest "audio_bus_base"
 widget "*MidiTrackStripBase" style:highest "midi_track_base"
-widget "*TimebarLabelBase" style:highest "time_bar_label_base"
-widget "*TimebarPadding" style:highest "time_bar_padding"
+widget "*AudioTrackStripBaseInactive" style:highest "track_controls_inactive"
+widget "*AudioBusStripBaseInactive" style:highest "track_controls_inactive"
+widget "*MidiTrackStripBaseInactive" style:highest "track_controls_inactive"
+widget "*FaderMetricsStrip" style:highest "audio_track_metrics"
+widget "*AudioTrackMetrics" style:highest "audio_track_metrics"
+widget "*AudioBusMetrics" style:highest "audio_bus_metrics"
+widget "*AudioTrackMetricsInactive" style:highest "audio_track_metrics_inactive"
+widget "*AudioBusMetricsInactive" style:highest "audio_bus_metrics_inactive"
+
 widget "*TimeAxisViewControlsBaseUnselected" style:highest "audio_track_base"
 widget "*AudioTrackControlsBaseUnselected" style:highest "audio_track_base"
 widget "*MidiTrackControlsBaseUnselected" style:highest "midi_track_base"
 widget "*AudioTrackFader" style:highest "gain_fader"
-widget "*AudioBusStripBase" style:highest "audio_bus_base"
+
 widget "*BusControlsBaseUnselected" style:highest "audio_bus_base"
 widget "*AudioBusFader" style:highest "gain_fader"
 widget "*TrackSeparator" style:highest "track_separator"
@@ -1386,9 +1396,6 @@ widget "*AutomationTrackName" style:highest "automation_track_name"
 widget "*AudioTrackControlsBaseInactiveSelected" style:highest "track_controls_inactive"
 widget "*BusControlsBaseInactiveSelected" style:highest "track_controls_inactive"
 widget "*AutomationTrackControlsBaseInactiveSelected" style:highest "track_controls_inactive"
-widget "*AudioTrackStripBaseInactive" style:highest "track_controls_inactive"
-widget "*MidiTrackStripBaseInactive" style:highest "track_controls_inactive"
-widget "*AudioBusStripBaseInactive" style:highest "track_controls_inactive"
 widget "*AudioTrackControlsBaseSelected" style:highest "edit_controls_base_selected"
 widget "*MidiTrackControlsBaseSelected" style:highest "edit_controls_base_selected"
 widget "*BusControlsBaseSelected" style:highest "edit_controls_base_selected"
@@ -1485,8 +1492,7 @@ widget "*PluginSaveButton" style:highest "small_button"
 widget "*PluginSaveButton*" style:highest "small_button"
 widget "*PluginLoadButton" style:highest "small_button"
 widget "*PluginLoadButton*" style:highest "small_button"
-widget "*FaderMetricsStrip" style:highest "meter_metrics_strip"
-widget "*MeterMetricsStrip" style:highest "meter_metrics_strip"
+
 widget "*MetricDialogFrame" style:highest "base_frame"
 widget "*MetricEntry" style:highest "medium_bold_entry"
 widget "*MetricButton" style:highest "default_buttons_menus"
index e0d6ea2773c0e3a80443614c64b96762f962f418..034dd75b0fd291c1ed89bdb66b7d9532c5c40968 100644 (file)
@@ -3,21 +3,21 @@
   <Canvas>
     <Option name="waveform" value="000000cc"/>
     <Option name="clipped waveform" value="ff0000e5"/>
-    <Option name="region base" value="bfbfc172"/>
-    <Option name="selected region base" value="b591a8d0"/>
-    <Option name="audio track base" value="b6c3cb88"/>
-    <Option name="audio bus base" value="cbc1de78"/>
-    <Option name="midi track base" value="ffd0d850"/>
-    <Option name="midi bus base" value="ffceea40"/>
+    <Option name="region base" value="bfbfc1aa"/>
+    <Option name="selected region base" value="b591a8ff"/>
+    <Option name="audio track base" value="c6d3d868"/>
+    <Option name="audio bus base" value="dbd1ea68"/>
+    <Option name="midi track base" value="ff8f8f3d"/>
+    <Option name="midi bus base" value="ff0000ee"/>
     <Option name="time-stretch-fill" value="e2b5b596"/>
     <Option name="time-stretch-outline" value="63636396"/>
     <Option name="automation line" value="44bc59ff"/>
     <Option name="processor automation line" value="7aa3f9ff"/>
-    <Option name="control point fill" value="ffffff66"/>
-    <Option name="control point outline" value="ffffffaa"/>
+    <Option name="control point fill" value="000000ff"/>
+    <Option name="control point outline" value="000000ff"/>
     <Option name="entered control point outline" value="ff0000ee"/>
     <Option name="entered control point selected" value="ff3535ff"/>
-    <Option name="entered control point" value="ffffffaa"/>
+    <Option name="entered control point" value="000000cc"/>
     <Option name="control point selected" value="00ff00ff"/>
     <Option name="control point" value="ff0000ff"/>
     <Option name="automation track fill" value="a0a0ce68"/>
@@ -40,7 +40,7 @@
     <Option name="location punch" value="7c3a3aff"/>
     <Option name="verbose canvas cursor" value="f4f214bc"/>
     <Option name="marker label" value="000000ff"/>
-    <Option name="marker bar separator" value="aaaaaa77"/>
+    <Option name="marker bar separator" value="30303088"/>
     <Option name="tempo bar" value="72727fff"/>
     <Option name="meterbar" value="666672ff"/>
     <Option name="markerbar" value="7f7f8cff"/>
@@ -60,8 +60,8 @@
     <Option name="EnteredMarker" value="dd6363ff"/>
     <Option name="MeterMarker" value="f2425bff"/>
     <Option name="TempoMarker" value="f2425bff"/>
-    <Option name="MeasureLineBeat" value="b5b5b576"/>
-    <Option name="MeasureLineBar" value="d9d9d99c"/>
+    <Option name="MeasureLineBeat" value="72727266"/>
+    <Option name="MeasureLineBar" value="8c8c988c"/>
     <Option name="GhostTrackBase" value="44007c7f"/>
     <Option name="GhostTrackWave" value="02fd004c"/>
     <Option name="GhostTrackWaveClip" value="ff000000"/>
@@ -74,8 +74,8 @@
     <Option name="RecordingRect" value="e5c6c6ff"/>
     <Option name="SelectionRect" value="e8f4d377"/>
     <Option name="Selection" value="636363b2"/>
-    <Option name="VestigialFrame" value="0000000f"/>
-    <Option name="TimeAxisFrame" value="0000000f"/>
+    <Option name="VestigialFrame" value="44007c0f"/>
+    <Option name="TimeAxisFrame" value="44007c0f"/>
     <Option name="NameHighlightFill" value="0000ffff"/>
     <Option name="NameHighlightOutline" value="7c00ff96"/>
     <Option name="FrameHandle" value="7c00ff96"/>
     <Option name="TrimHandle" value="1900ff44"/>
     <Option name="EditCursor" value="0000ffff"/>
     <Option name="PlayHead" value="ff0000ff"/>
-    <Option name="MidiSelectRectOutline" value="5555ffff"/>
-    <Option name="MidiSelectRectFill" value="8888ff88"/>
-    <Option name="MidiNoteOutlineMin" value="22ff22b0"/>
-    <Option name="MidiNoteOutlineMid" value="ffff22b0"/>
-    <Option name="MidiNoteOutlineMax" value="ff2222b0"/>
-    <Option name="MidiNoteFillMin" value="33ee338a"/>
-    <Option name="MidiNoteFillMid" value="eeee338a"/>
-    <Option name="MidiNoteFillMax" value="ee33338a"/>
-    <Option name="MidiNoteSelectedOutline" value="5566ffee"/>
   </Canvas>
 </Ardour>
 
index 4172b73a5be886ccdce740b2bfddd74090c828cd..b8c3683e91ba8d0c9fd1590a852ad1912e97c48d 100644 (file)
@@ -4,17 +4,17 @@
 
 style "very_small_text"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
 }
 
 style "small_text"
 {
-       font_name = "%FONT_NORMAL%"
+       font_name = "%FONT_SMALL%"
 }
 
 style "small_bold_text"
 {
-       font_name = "%FONT_BOLD_NORMAL%"
+       font_name = "%FONT_BOLD_SMALL%"
 }
 
 style "medium_bold_text"
@@ -162,7 +162,7 @@ style "default_buttons_menus"
 
 style "very_small_button" = "default_buttons_menus"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        ythickness = 0
        xthickness = 0
 }
@@ -223,21 +223,21 @@ style "track_rec_enable_button_alternate" = "small_button"
 
 style "mixer_track_rec_enable_button" = "track_rec_enable_button"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_track_rec_enable_button_alternate" = "track_rec_enable_button_alternate"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_track_rec_enable_button_active" = "track_rec_enable_button_active"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        xthickness = 0
        ythickness = 0
 }
@@ -275,20 +275,20 @@ style "solo_button_active" = "small_button"
 
 style "mixer_solo_button" = "solo_button"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_solo_button_alternate" = "solo_button_alternate"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
 style "mixer_solo_button_active" = "solo_button_active"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
@@ -326,21 +326,21 @@ style "mute_button_active" = "small_button"
 
 style "mixer_mute_button" = "mute_button"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_mute_button_alternate" = "mute_button_alternate"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
 
 style "mixer_mute_button_active" = "mute_button_active"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
@@ -354,7 +354,7 @@ style "multiline_combo" = "small_button"
 
 style "mixer_mute_button" = "mute_button"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLERER%"
        xthickness = 0
        ythickness = 0
 }
@@ -457,7 +457,7 @@ style "ardour_progressbars" = "default_buttons_menus"
   bg[PRELIGHT] = { 0.00, 0.36, 0.40 }
 }
 
-style "options_window"  = "default_base"
+style "preferences"  = "default_base"
 {
        font_name = "%FONT_NORMAL%"
        fg[PRELIGHT] = { 0.80, 0.80, 0.80 }
@@ -672,7 +672,7 @@ style "transport_clock_display_delta" = "transport_clock_display"
 
 style "tempo_meter_clock_display"
 {
-       font_name = "%FONT_SMALL%"
+       font_name = "%FONT_SMALLER%"
        fg[NORMAL] = { 1.0, 1.0, 1.0 }
        fg[ACTIVE] = { 1.0, 1.0, 0.0 }
        fg[SELECTED] = { 1.0, 0, 0 }
@@ -737,6 +737,38 @@ style "midi_track_base" = "default_base"
   bg[SELECTED] = { 0.70, 0.70, 0.80 } 
 }
 
+style "track_controls_inactive" 
+{
+       bg[NORMAL] =      { 0.60, 0.60, 0.66 }
+       bg[ACTIVE] =      { 0.60, 0.60, 0.66 }
+       bg[INSENSITIVE] = { 0.60, 0.60, 0.66 }
+       bg[SELECTED] =    { 0.60, 0.60, 0.66 }
+       bg[PRELIGHT] =    { 0.60, 0.60, 0.66 }
+
+       #font_name = "sans 18"
+       fg[NORMAL] = { 0.7, 0.8, 0.2 }  
+}
+
+style "audio_track_metrics" = "audio_track_base"
+{
+       font_name = "%FONT_TINY%"
+}
+
+style "audio_bus_metrics" = "audio_bus_base"
+{
+       font_name = "%FONT_TINY%"
+}
+
+style "audio_track_metrics_inactive" = "track_controls_inactive"
+{
+       font_name = "%FONT_TINY%"
+}
+
+style "audio_bus_metrics_inactive" = "track_controls_inactive"
+{
+       font_name = "%FONT_TINY%"
+}
+
 style "track_name_display"
 {
        font_name = "%FONT_NORMAL%"
@@ -1102,15 +1134,9 @@ style "tearoff_arrow" = "medium_bold_entry"
        bg[PRELIGHT] = { 0.30, 0.30, 0.30 }
 }
 
-style "meter_metrics_strip" = "default_base"
-{
-       font_name = "%FONT_TINY%"
-       fg[NORMAL] = { 1.0, 0.8, 0.2 }
-}
-
 style "location_row_button" = "default_buttons_menus"
 {
-       font_name = "%FONT_BIG%"
+       font_name = "%FONT_SMALL%"
 }
 
 style "location_rows_clock" = "default_clock_display"
@@ -1213,15 +1239,15 @@ widget "*MixerMonitorInputButton.*" style:highest "very_small_button"
 widget "*MixerIOButton" style:highest "very_small_button"
 widget "*MixerIOButtonLabel" style:highest "very_small_button"
 widget "*AddRouteDialogSpinner" style:highest "ardour_adjusters"
-widget "*AddRouteDialogRadioButton*" style:highest "options_window"
-widget "*OptionsNotebook" style:highest "options_window"
-widget "*OptionEditorToggleButton*" style:highest "options_window"
-widget "*OptionsLabel" style:highest "options_window"
-widget "*OptionEditorAuditionerLabel" style:highest "options_window"
+widget "*AddRouteDialogRadioButton*" style:highest "preferences"
+widget "*OptionsNotebook" style:highest "preferences"
+widget "*OptionEditorToggleButton*" style:highest "preferences"
+widget "*OptionsLabel" style:highest "preferences"
+widget "*OptionEditorAuditionerLabel" style:highest "preferences"
 widget "*OptionsEntry" style:highest "option_entry"
-widget "*InspectorNotebook" style:highest "options_window"
-widget "*NewSessionDialog" style:highest "options_window"
-widget "*NewSessionDialogButton*" style:highest "options_window"
+widget "*InspectorNotebook" style:highest "preferences"
+widget "*NewSessionDialog" style:highest "preferences"
+widget "*NewSessionDialogButton*" style:highest "preferences"
 widget "*MixerSendSwitch*" style:highest "very_small_red_active_and_selected_button"
 widget "*OptionEditorToggleButton" style:highest "small_red_active_and_selected_button"
 widget "*NewSessionDialogButton" style:highest "small_red_active_and_selected_button"
@@ -1325,11 +1351,24 @@ widget "*BBTRuler" style:highest "editor_time_ruler"
 widget "*FramesRuler" style:highest "editor_time_ruler"
 widget "*MinSecRuler" style:highest "editor_time_ruler"
 widget "*BaseFrame" style:highest "base_frame"
-widget "*AudioTrackStripBase*" style:highest "audio_track_base"
+
+widget "*AudioTrackStripBase" style:highest "audio_track_base"
+widget "*AudioBusStripBase" style:highest "audio_bus_base"
+widget "*MidiTrackStripBase" style:highest "midi_track_base"
+widget "*AudioTrackStripBaseInactive" style:highest "track_controls_inactive"
+widget "*AudioBusStripBaseInactive" style:highest "track_controls_inactive"
+widget "*MidiTrackStripBaseInactive" style:highest "track_controls_inactive"
+widget "*FaderMetricsStrip" style:highest "audio_track_metrics"
+widget "*AudioTrackMetrics" style:highest "audio_track_metrics"
+widget "*AudioBusMetrics" style:highest "audio_bus_metrics"
+widget "*AudioTrackMetricsInactive" style:highest "audio_track_metrics_inactive"
+widget "*AudioBusMetricsInactive" style:highest "audio_bus_metrics_inactive"
+
 widget "*TimeAxisViewControlsBaseUnselected" style:highest "audio_track_base"
 widget "*AudioTrackControlsBaseUnselected" style:highest "audio_track_base"
+widget "*MidiTrackControlsBaseUnselected" style:highest "midi_track_base"
 widget "*AudioTrackFader" style:highest "gain_fader"
-widget "*AudioBusStripBase" style:highest "audio_bus_base"
+
 widget "*BusControlsBaseUnselected" style:highest "audio_bus_base"
 widget "*AudioBusFader" style:highest "gain_fader"
 widget "*TrackSeparator" style:highest "track_separator"
@@ -1361,9 +1400,8 @@ widget "*AutomationTrackName" style:highest "automation_track_name"
 widget "*AudioTrackControlsBaseInactiveSelected" style:highest "track_controls_inactive"
 widget "*BusControlsBaseInactiveSelected" style:highest "track_controls_inactive"
 widget "*AutomationTrackControlsBaseInactiveSelected" style:highest "track_controls_inactive"
-widget "*AudioTrackStripBaseInactive" style:highest "track_controls_inactive"
-widget "*AudioBusStripBaseInactive" style:highest "track_controls_inactive"
 widget "*AudioTrackControlsBaseSelected" style:highest "edit_controls_base_selected"
+widget "*MidiTrackControlsBaseSelected" style:highest "edit_controls_base_selected"
 widget "*BusControlsBaseSelected" style:highest "edit_controls_base_selected"
 widget "*AutomationTrackControlsBase" style:highest "automation_track_controls_base"
 widget "*AutomationTrackControlsBaseSelected" style:highest "edit_controls_base_selected"
@@ -1458,8 +1496,7 @@ widget "*PluginSaveButton" style:highest "small_button"
 widget "*PluginSaveButton*" style:highest "small_button"
 widget "*PluginLoadButton" style:highest "small_button"
 widget "*PluginLoadButton*" style:highest "small_button"
-widget "*FaderMetricsStrip" style:highest "meter_metrics_strip"
-widget "*MeterMetricsStrip" style:highest "meter_metrics_strip"
+
 widget "*MetricDialogFrame" style:highest "base_frame"
 widget "*MetricEntry" style:highest "medium_bold_entry"
 widget "*MetricButton" style:highest "default_buttons_menus"
index c5162919d405337eeee1864c2936e0d5cb271913..795b924075deb01e511ed7fbc64e8abd72ecf572 100644 (file)
@@ -34,6 +34,15 @@ ArdourDialog::ArdourDialog (string title, bool modal, bool use_seperator)
        set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG);
 }
 
+ArdourDialog::ArdourDialog (Gtk::Window& parent, string title, bool modal, bool use_seperator)
+       : Dialog (title, parent, modal, use_seperator)
+{
+       session = 0;
+
+       set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG);
+       set_position (Gtk::WIN_POS_CENTER_ON_PARENT);
+}
+
 ArdourDialog::~ArdourDialog ()
 {
 }
index 069768c1436b245e66cc69f6cf15f9bfadd77d61..13248e14de1a3a02b8d2982b0504c80b75c4cff7 100644 (file)
@@ -37,6 +37,7 @@ class ArdourDialog : public Gtk::Dialog
 {
   public:
        ArdourDialog (std::string title, bool modal = false, bool use_separator = false);
+       ArdourDialog (Gtk::Window& parent, std::string title, bool modal = false, bool use_separator = false);  
        ~ArdourDialog();
 
        bool on_enter_notify_event (GdkEventCrossing*);
index cac63dc7529006d33098aa9108bd789136e0d385..962ada5035e787efcdb9ebdc4455aa6518b26e05 100644 (file)
@@ -36,6 +36,7 @@
 #include <gtkmm/accelmap.h>
 
 #include <pbd/error.h>
+#include <pbd/misc.h>
 #include <pbd/compose.h>
 #include <pbd/failed_constructor.h>
 #include <pbd/enumwriter.h>
@@ -50,8 +51,7 @@
 #include <gtkmm2ext/popup.h>
 #include <gtkmm2ext/window_title.h>
 
-#include <midi++/port.h>
-#include <midi++/mmc.h>
+#include <midi++/manager.h>
 
 #include <ardour/ardour.h>
 #include <ardour/profile.h>
@@ -157,12 +157,18 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
 
          auditioning_alert_button (_("AUDITION")),
          solo_alert_button (_("SOLO")),
-         shown_flag (false)
+         shown_flag (false),
+         error_log_button (_("Errors"))
+
 {
        using namespace Gtk::Menu_Helpers;
 
        Gtkmm2ext::init();
        
+
+#ifdef TOP_MENUBAR
+       _auto_display_errors = false;
+#endif
        about = 0;
 
        if (theArdourUI == 0) {
@@ -180,6 +186,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
        session_selector_window = 0;
        last_key_press_time = 0;
        connection_editor = 0;
+       _will_create_new_session_automatically = false;
+       new_session_dialog = 0;
+       loading_dialog = 0;
        add_route_dialog = 0;
        route_params = 0;
        option_editor = 0;
@@ -190,7 +199,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
        session_loaded = false;
        last_speed_displayed = -1.0f;
        ab_direction = true;
-
+       
        sys::path key_bindings_file;
 
        find_file_in_search_path (ardour_search_path() + system_config_search_path(),
@@ -225,31 +234,80 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
 
        ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
 
-       /* have to wait for AudioEngine and Configuration before proceeding */
+       /* lets get this party started */
+
+       try {
+               ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization);
+               setup_gtk_ardour_enums ();
+               Config->set_current_owner (ConfigVariableBase::Interface);
+               setup_profile ();
+
+       } catch (failed_constructor& err) {
+               error << _("could not initialize Ardour.") << endmsg;
+               // pass it on up
+               throw err;
+       } 
+
+       /* we like keyboards */
+
+       keyboard = new Keyboard;
+
+       starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
+       stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
+
+       platform_specific ();
 }
 
-void
-ARDOUR_UI::set_engine (AudioEngine& e)
+int
+ARDOUR_UI::create_engine ()
 {
-       engine = &e;
+       // this gets called every time by new_session()
+
+       if (engine) {
+               return 0;
+       }
+
+       try { 
+               engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
+
+       } catch (...) {
+
+               return -1;
+       }
 
        engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
        engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
        engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
        engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
 
-       ActionManager::init ();
-       new_session_dialog = new NewSessionDialog();
+       post_engine ();
 
-       _tooltips.enable();
+       return 0;
+}
 
-       keyboard = new Keyboard;
+void
+ARDOUR_UI::post_engine ()
+{
+       extern int setup_midi ();
+
+       /* Things to be done once we create the AudioEngine
+        */
+
+       MIDI::Manager::instance()->set_api_data (engine->jack());
+       setup_midi ();
+
+       check_memory_locking();
+
+               ActionManager::init ();
+       _tooltips.enable();
 
        if (setup_windows ()) {
                throw failed_constructor ();
        }
 
-       if (GTK_ARDOUR::show_key_actions) {
+       /* this is the first point at which all the keybindings are available */
+
+       if (ARDOUR_COMMAND_LINE::show_key_actions) {
                vector<string> names;
                vector<string> paths;
                vector<string> keys;
@@ -266,9 +324,6 @@ ARDOUR_UI::set_engine (AudioEngine& e)
                exit (0);
        }
 
-       /* start with timecode, metering enabled
-       */
-       
        blink_timeout_tag = -1;
 
        /* the global configuration object is now valid */
@@ -287,15 +342,26 @@ ARDOUR_UI::set_engine (AudioEngine& e)
 
        /* start the time-of-day-clock */
        
+#ifndef GTKOSX
+       /* OS X provides an always visible wallclock, so don't be stupid */
        update_wall_clock ();
        Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
+#endif
 
        update_disk_space ();
        update_cpu_load ();
        update_sample_rate (engine->frame_rate());
 
-       starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
-       stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
+       /* now start and maybe save state */
+
+       if (do_engine_start () == 0) {
+               if (session && _session_is_new) {
+                       /* we need to retain initial visual 
+                          settings for a new session 
+                       */
+                       session->save_state ("");
+               }
+       }
 }
 
 ARDOUR_UI::~ARDOUR_UI ()
@@ -317,6 +383,11 @@ ARDOUR_UI::~ARDOUR_UI ()
        if (add_route_dialog) {
                delete add_route_dialog;
        }
+
+
+       if (new_session_dialog) {
+               delete new_session_dialog;
+       }
 }
 
 gint
@@ -436,7 +507,7 @@ ARDOUR_UI::save_ardour_state ()
 
        if (session) {
                session->add_instant_xml (enode);
-               session->add_instant_xml (mnode);
+       session->add_instant_xml (mnode);
        } else {
                Config->add_instant_xml (enode);
                Config->add_instant_xml (mnode);
@@ -478,10 +549,152 @@ ARDOUR_UI::update_autosave ()
        }
 }
 
+void
+ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
+{
+       string title;
+       if (we_set_params) {
+               title = _("Ardour could not start JACK");
+       } else {
+               title = _("Ardour could not connect to JACK.");
+       }
+
+       MessageDialog win (title,
+                          false,
+                          Gtk::MESSAGE_INFO,
+                          Gtk::BUTTONS_NONE);
+       
+       if (we_set_params) {
+               win.set_secondary_text(_("There are several possible reasons:\n\
+\n\
+1) You requested audio parameters that are not supported..\n\
+2) JACK is running as another user.\n\
+\n\
+Please consider the possibilities, and perhaps try different parameters."));
+       } else {
+               win.set_secondary_text(_("There are several possible reasons:\n\
+\n\
+1) JACK is not running.\n\
+2) JACK is running as another user, perhaps root.\n\
+3) There is already another client called \"ardour\".\n\
+\n\
+Please consider the possibilities, and perhaps (re)start JACK."));
+       }
+
+       if (toplevel) {
+               win.set_transient_for (*toplevel);
+       }
+
+       if (we_set_params) {
+               win.add_button (Stock::OK, RESPONSE_CLOSE);
+       } else {
+               win.add_button (Stock::QUIT, RESPONSE_CLOSE);
+       }
+
+       win.set_default_response (RESPONSE_CLOSE);
+       
+       win.show_all ();
+       win.set_position (Gtk::WIN_POS_CENTER);
+
+       if (!ARDOUR_COMMAND_LINE::no_splash) {
+               hide_splash ();
+       }
+
+       /* we just don't care about the result, but we want to block */
+
+       win.run ();
+}
+
 void
 ARDOUR_UI::startup ()
 {
-       check_memory_locking();
+       string name, path;
+       bool isnew;
+
+       new_session_dialog = new NewSessionDialog();
+       
+       /* If no session name is given: we're not loading a session yet, nor creating a new one */
+       
+       if (ARDOUR_COMMAND_LINE::session_name.length()) {
+       
+               /* Load session or start the new session dialog */
+               
+               if (find_session (ARDOUR_COMMAND_LINE::session_name, path, name, isnew)) {
+                       error << string_compose(_("could not load command line session \"%1\""), 
+                                               ARDOUR_COMMAND_LINE::session_name) << endmsg;
+                       return;
+               }
+
+               if (!ARDOUR_COMMAND_LINE::new_session) {
+                       
+                       /* Supposed to be loading an existing 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;
+                       }
+               }
+               
+               new_session_dialog->set_session_name (name);
+               new_session_dialog->set_session_folder (Glib::path_get_basename (path));
+               _session_is_new = isnew;
+       }
+
+       hide_splash ();
+
+       bool have_backend = EngineControl::engine_running();
+       bool need_nsd;
+       bool load_needed = false;
+
+       if (have_backend) {
+
+               /* backend audio is working */
+
+               if (ARDOUR_COMMAND_LINE::session_name.empty() || ARDOUR_COMMAND_LINE::new_session) {
+                       /* need NSD to get session name and other info */
+                       need_nsd = true;
+               } else {
+                       need_nsd = false;
+               }
+               
+       } else {
+
+               XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
+               
+               if (audio_setup) {
+                       new_session_dialog->engine_control.set_state (*audio_setup);
+               }
+
+               /* no backend audio, must bring up NSD to check configuration */
+               
+               need_nsd = true;
+       }
+
+       if (need_nsd) {
+
+               if (!get_session_parameters (ARDOUR_COMMAND_LINE::session_name, have_backend, ARDOUR_COMMAND_LINE::new_session)) {
+                       return;
+               }
+
+       } else {
+
+               if (create_engine ()) {
+                       backend_audio_error (false);
+                       exit (1);
+               }
+
+               load_needed = true;
+       }
+       
+       if (load_needed) {
+               if (load_session (ARDOUR_COMMAND_LINE::session_name, name)) {
+                       return;
+               }
+       }
+
+       show ();
 }
 
 void
@@ -679,6 +892,8 @@ ARDOUR_UI::every_point_one_seconds ()
 gint
 ARDOUR_UI::every_point_zero_one_seconds ()
 {
+       // august 2007: actual update frequency: 40Hz, not 100Hz
+
        SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
        return TRUE;
 }
@@ -1001,6 +1216,7 @@ ARDOUR_UI::open_session ()
                open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
                open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
                open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
+               open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
 
                FileFilter session_filter;
                session_filter.add_pattern ("*.ardour");
@@ -1524,21 +1740,6 @@ ARDOUR_UI::setup_theme ()
        theme_manager->setup_theme();
 }
 
-gint
-ARDOUR_UI::start_engine ()
-{
-       if (do_engine_start () == 0) {
-               if (session && _session_is_new) {
-                       /* we need to retain initial visual 
-                          settings for a new session 
-                       */
-                       session->save_state ("");
-               }
-       }
-
-       return FALSE;
-}
-
 void
 ARDOUR_UI::update_clocks ()
 {
@@ -1832,30 +2033,34 @@ ARDOUR_UI::save_template ()
 }
 
 bool
-ARDOUR_UI::new_session (std::string predetermined_path)
+ARDOUR_UI::get_session_parameters (Glib::ustring predetermined_path, bool have_engine, bool should_be_new)
 {
        string session_name;
        string session_path;
+       string template_name;
 
-       if (!check_audioengine()) {
-               return false;
+       if (!loading_dialog) {
+               loading_dialog = new MessageDialog (*new_session_dialog, 
+                                                   "",
+                                                   false,
+                                                   Gtk::MESSAGE_INFO,
+                                                   Gtk::BUTTONS_NONE);
        }
-
+               
        int response = Gtk::RESPONSE_NONE;
 
        new_session_dialog->set_modal(true);
        new_session_dialog->set_name (predetermined_path);
        new_session_dialog->reset_recent();
-       new_session_dialog->show();
+       new_session_dialog->set_position (WIN_POS_CENTER);
        new_session_dialog->set_current_page (0);
 
        do {
-               response = new_session_dialog->run ();
+               new_session_dialog->set_have_engine (have_engine);
 
-               if (!check_audioengine()) {
-                       new_session_dialog->hide ();
-                       return false;
-               }
+               new_session_dialog->show();
+               new_session_dialog->present ();
+               response = new_session_dialog->run ();
 
                _session_is_new = false;
 
@@ -1869,65 +2074,119 @@ ARDOUR_UI::new_session (std::string predetermined_path)
 
                } else if (response == Gtk::RESPONSE_NONE) {
 
-                       /* Clear was pressed */
-                       new_session_dialog->reset();
+                       /* Clear was pressed */
+                       new_session_dialog->reset();
+                       continue;
+               }
 
-               } else if (response == Gtk::RESPONSE_YES) {
+               /* first things first ... if we're here to help set up audio parameters
+                  this is where want to do that.
+               */
 
-                       /* YES  == OPEN, but there's no enum for that */
+               if (!have_engine) {
+                       if (new_session_dialog->engine_control.setup_engine ()) {
+                               new_session_dialog->hide ();
+                               return false;
+                       } 
+               }
 
-                       session_name = new_session_dialog->session_name();
+#ifdef GTKOSX
+               /* X11 users will always have fontconfig info around, but new GTK-OSX users 
+                  may not and it can take a while to build it. Warn them.
+               */
 
+               Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
+               
+               if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
+                       MessageDialog msg (*new_session_dialog,
+                                          _("Welcome to Ardour.\n\n"
+                                            "The program will take a bit longer to start up\n"
+                                            "while the system fonts are checked.\n\n"
+                                            "This will only be done once, and you will\n"
+                                            "not see this message again\n"),
+                                          true,
+                                          Gtk::MESSAGE_INFO,
+                                          Gtk::BUTTONS_OK);
+                       msg.show_all ();
+                       msg.present ();
+                       msg.run ();
+               }
+#endif
+               loading_dialog->set_message (_("Starting audio engine"));
+               loading_dialog->show_all ();
+               flush_pending ();
+               
+               if (create_engine ()) {
+                       backend_audio_error (!have_engine, new_session_dialog);
+                       loading_dialog->hide ();
+                       flush_pending ();
+                       /* audio setup page */
+                       new_session_dialog->set_current_page (2);
+                       /* try again */
+                       response = Gtk::RESPONSE_NONE;
+                       continue;
+               }
+
+               have_engine = true;             
+                       
+               /* now handle possible affirmative responses */
+
+               if (response == Gtk::RESPONSE_YES) {
+
+                       /* YES == OPEN from the session selector */
+
+                       session_name = new_session_dialog->session_name();
+                       
                        if (session_name.empty()) {
                                response = Gtk::RESPONSE_NONE;
                                continue;
                        } 
 
                        if (session_name[0] == '/' || 
-                                       (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
-                                       (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
+                           (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
+                           (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
                                load_session (Glib::path_get_dirname (session_name), session_name);
                        } else {
                                session_path = new_session_dialog->session_folder();
                                load_session (session_path, session_name);
                        }
-
+                       
                } else if (response == Gtk::RESPONSE_OK) {
 
-                       session_name = new_session_dialog->session_name();
-
-                       if (!new_session_dialog->on_new_session_page ()) {
-
-                               /* XXX this is a bit of a hack.. 
-                                  i really want the new sesion dialog to return RESPONSE_YES
-                                  if we're on page 1 (the load page)
-                                  Unfortunately i can't see how atm.. 
-                               */
+                       /* OK == OPEN button */
 
-                               if (session_name.empty()) {
-                                       response = Gtk::RESPONSE_NONE;
-                                       continue;
-                               } 
+                       session_name = new_session_dialog->session_name();
+               
+                       if (session_name.empty()) {
+                               response = Gtk::RESPONSE_NONE;
+                               continue;
+                       } 
+                               
+                       switch (new_session_dialog->get_current_page()) {
+                       case 1: /* recent session selector */
+                       case 2: /* audio engine control */
 
                                if (session_name[0] == '/' || 
-                                               (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
-                                               (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
+                                   (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
+                                   (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
                                        load_session (Glib::path_get_dirname (session_name), session_name);
                                } else {
                                        session_path = new_session_dialog->session_folder();
                                        load_session (session_path, session_name);
                                }
+                               break;
 
-                       } else {
+                       case 0: /* nominally the "new" session creator, but could be in use for an old session */
 
-                               if (session_name.empty()) {
-                                       response = Gtk::RESPONSE_NONE;
-                                       continue;
-                               } 
+                               if (new_session_dialog->get_current_page() == 0 && ARDOUR_COMMAND_LINE::session_name.empty()) {
+                                       should_be_new = true;
+                               }
+
+                               /* handle what appear to be paths rather than just a name */
 
                                if (session_name[0] == '/' || 
-                                               (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
-                                               (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
+                                   (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
+                                   (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
 
                                        session_path = Glib::path_get_dirname (session_name);
                                        session_name = Glib::path_get_basename (session_name);
@@ -1937,108 +2196,144 @@ ARDOUR_UI::new_session (std::string predetermined_path)
                                        session_path = new_session_dialog->session_folder();
 
                                }
-
+                               
                                //XXX This is needed because session constructor wants a 
                                //non-existant path. hopefully this will be fixed at some point.
-
+                               
                                session_path = Glib::build_filename (session_path, session_name);
+                               
+                               if (!should_be_new) {
 
-                               if (g_file_test (session_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
+                                       load_session (session_path, session_name);
+                                       continue; /* leaves while() loop because response != NONE */
+
+                               } else if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
 
                                        Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
 
                                        MessageDialog msg (str,
-                                                       false,
-                                                       Gtk::MESSAGE_WARNING,
-                                                       Gtk::BUTTONS_YES_NO,
-                                                       true);
+                                                          false,
+                                                          Gtk::MESSAGE_WARNING,
+                                                          Gtk::BUTTONS_YES_NO,
+                                                          true);
 
 
                                        msg.set_name (X_("CleanupDialog"));
                                        msg.set_wmclass (X_("existing_session"), "Ardour");
                                        msg.set_position (Gtk::WIN_POS_MOUSE);
-
+                                       
                                        switch (msg.run()) {
-                                               case RESPONSE_YES:
-                                                       load_session (session_path, session_name);
-                                                       goto done;
-                                                       break;
-                                               default:
-                                                       response = RESPONSE_NONE;
-                                                       new_session_dialog->reset ();
-                                                       continue;
+                                       case RESPONSE_YES:
+                                               new_session_dialog->hide ();
+                                               goto_editor_window ();
+                                               flush_pending ();
+                                               load_session (session_path, session_name);
+                                               goto done;
+                                               break;
+                                       default:
+                                               response = RESPONSE_NONE;
+                                               new_session_dialog->reset ();
+                                               continue;
                                        }
-                               }
+                               } 
 
-                               _session_is_new = true;
+                               _session_is_new = true;
+                                               
+                               if (new_session_dialog->use_session_template()) {
 
-                               std::string template_name = new_session_dialog->session_template_name();
+                                       template_name = new_session_dialog->session_template_name();
 
-                               if (new_session_dialog->use_session_template()) {
+                                       new_session_dialog->hide ();
+                                       goto_editor_window ();
+                                       flush_pending ();
 
                                        load_session (session_path, session_name, &template_name);
-
+                         
                                } else {
 
                                        uint32_t cchns;
                                        uint32_t mchns;
                                        AutoConnectOption iconnect;
                                        AutoConnectOption oconnect;
+                                       uint32_t nphysin;
+                                       uint32_t nphysout;
+                                       
+                                       if (Profile->get_sae()) {
 
-                                       if (new_session_dialog->create_control_bus()) {
-                                               cchns = (uint32_t) new_session_dialog->control_channel_count();
-                                       } else {
                                                cchns = 0;
-                                       }
+                                               mchns = 2;
+                                               iconnect = AutoConnectPhysical;
+                                               oconnect = AutoConnectMaster;
+                                               nphysin = 0; // use all available
+                                               nphysout = 0; // use all available
 
-                                       if (new_session_dialog->create_master_bus()) {
-                                               mchns = (uint32_t) new_session_dialog->master_channel_count();
                                        } else {
-                                               mchns = 0;
-                                       }
 
-                                       if (new_session_dialog->connect_inputs()) {
-                                               iconnect = AutoConnectPhysical;
-                                       } else {
-                                               iconnect = AutoConnectOption (0);
+                                               /* get settings from advanced section of NSD */
+                                               
+                                               if (new_session_dialog->create_control_bus()) {
+                                                       cchns = (uint32_t) new_session_dialog->control_channel_count();
+                                               } else {
+                                                       cchns = 0;
+                                               }
+                                               
+                                               if (new_session_dialog->create_master_bus()) {
+                                                       mchns = (uint32_t) new_session_dialog->master_channel_count();
+                                               } else {
+                                                       mchns = 0;
+                                               }
+                                               
+                                               if (new_session_dialog->connect_inputs()) {
+                                                       iconnect = AutoConnectPhysical;
+                                               } else {
+                                                       iconnect = AutoConnectOption (0);
+                                               }
+                                               
+                                               /// @todo some minor tweaks.
+                                               
+                                               if (new_session_dialog->connect_outs_to_master()) {
+                                                       oconnect = AutoConnectMaster;
+                                               } else if (new_session_dialog->connect_outs_to_physical()) {
+                                                       oconnect = AutoConnectPhysical;
+                                               } else {
+                                                       oconnect = AutoConnectOption (0);
+                                               } 
+                                               
+                                               nphysin = (uint32_t) new_session_dialog->input_limit_count();
+                                               nphysout = (uint32_t) new_session_dialog->output_limit_count();
                                        }
 
-                                       /// @todo some minor tweaks.
-
-                                       if (new_session_dialog->connect_outs_to_master()) {
-                                               oconnect = AutoConnectMaster;
-                                       } else if (new_session_dialog->connect_outs_to_physical()) {
-                                               oconnect = AutoConnectPhysical;
-                                       } else {
-                                               oconnect = AutoConnectOption (0);
-                                       } 
-
-                                       uint32_t nphysin = (uint32_t) new_session_dialog->input_limit_count();
-                                       uint32_t nphysout = (uint32_t) new_session_dialog->output_limit_count();
-
-                                       if (!build_session (session_path,
-                                                               session_name,
-                                                               cchns,
-                                                               mchns,
-                                                               iconnect,
-                                                               oconnect,
-                                                               nphysin,
-                                                               nphysout, 
-                                                               engine->frame_rate() * 60 * 5)) {
-
+                                       new_session_dialog->hide ();
+                                       goto_editor_window ();
+                                       flush_pending ();
+
+                                       if (build_session (session_path,
+                                                          session_name,
+                                                          cchns,
+                                                          mchns,
+                                                          iconnect,
+                                                          oconnect,
+                                                          nphysin,
+                                                          nphysout, 
+                                                          engine->frame_rate() * 60 * 5)) {
+                                               
                                                response = Gtk::RESPONSE_NONE;
                                                new_session_dialog->reset ();
                                                continue;
                                        }
                                }
+                               break;
+
+                       default:
+                               break;
                        }
                }
-
+               
        } while (response == Gtk::RESPONSE_NONE);
 
   done:
        show();
-       new_session_dialog->get_window()->set_cursor();
+       loading_dialog->hide ();
        new_session_dialog->hide();
        return true;
 }
@@ -2050,21 +2345,32 @@ ARDOUR_UI::close_session()
                return;
        }
 
-       unload_session();
-       new_session ();
+       unload_session (true);
+
+       get_session_parameters ("", true, false);
 }
 
 int
 ARDOUR_UI::load_session (const string & path, const string & snap_name, string* mix_template)
 {
        Session *new_session;
+       int unload_status;
+       int retval = -1;
+
        session_loaded = false;
-       
+
        if (!check_audioengine()) {
                return -1;
        }
 
-       if(!unload_session ()) return -1;
+       unload_status = unload_session ();
+
+       if (unload_status < 0) {
+               goto out;
+       } else if (unload_status > 0) {
+               retval = 0;
+               goto out;
+       }
 
        /* if it already exists, we must have write access */
 
@@ -2072,17 +2378,23 @@ ARDOUR_UI::load_session (const string & path, const string & snap_name, string*
                MessageDialog msg (*editor, _("You do not have write access to this session.\n"
                                              "This prevents the session from being loaded."));
                msg.run ();
-               return -1;
+               goto out;
+       }
+
+       if (loading_dialog) {
+               loading_dialog->set_markup (_("Please wait while Ardour loads your session"));
+               flush_pending ();
        }
 
+       disable_screen_updates ();
+
        try {
                new_session = new Session (*engine, path, snap_name, mix_template);
        }
 
        catch (...) {
-
                error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
-               return -1;
+               goto out;
        }
 
        connect_to_session (new_session);
@@ -2098,10 +2410,15 @@ ARDOUR_UI::load_session (const string & path, const string & snap_name, string*
        }
 
        editor->edit_cursor_position (true);
-       return 0;
+       enable_screen_updates ();
+       flush_pending ();
+       retval = 0;
+
+  out:
+       return retval;
 }
 
-bool
+int
 ARDOUR_UI::build_session (const string & path, const string & snap_name, 
                          uint32_t control_channels,
                          uint32_t master_channels, 
@@ -2112,14 +2429,21 @@ ARDOUR_UI::build_session (const string & path, const string & snap_name,
                          nframes_t initial_length)
 {
        Session *new_session;
+       int x;
 
        if (!check_audioengine()) {
-               return false;
+               return -1;
        }
 
        session_loaded = false;
 
-       if (!unload_session ()) return false;
+       x = unload_session ();
+
+       if (x < 0) {
+               return -1;
+       } else if (x > 0) {
+               return 0;
+       }
        
        _session_is_new = true;
 
@@ -2132,13 +2456,13 @@ ARDOUR_UI::build_session (const string & path, const string & snap_name,
 
                MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
                msg.run ();
-               return false;
+               return -1;
        }
 
        connect_to_session (new_session);
 
        session_loaded = true;
-       return true;
+       return 0;
 }
 
 void
@@ -2616,8 +2940,10 @@ ARDOUR_UI::cmdline_new_session (string path)
                path = str;
        }
 
-       new_session (path);
-       
+       get_session_parameters (path, false, true);
+
+       _will_create_new_session_automatically = false; /* done it */
+
        return FALSE; /* don't call it again */
 }
 
@@ -2868,6 +3194,12 @@ ARDOUR_UI::setup_profile ()
        if (gdk_screen_width() < 1200) {
                Profile->set_small_screen ();
        }
+
+
+       if (getenv ("ARDOUR_SAE")) {
+               Profile->set_sae ();
+               Profile->set_single_package ();
+       }
 }
 
 void
index 39bd8db4a6ad9bc9ad697b094bc30e1344e5980f..427d40dffe3f1197daf538e0da141e2ade69a61d 100644 (file)
@@ -50,6 +50,7 @@
 #include <gtkmm/togglebutton.h>
 #include <gtkmm/treeview.h>
 #include <gtkmm/menubar.h>
+#include <gtkmm/textbuffer.h>
 #include <gtkmm/adjustment.h>
 #include <gtkmm2ext/gtk_ui.h>
 #include <gtkmm2ext/click_box.h>
@@ -111,8 +112,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI
        
        int load_session (const string & path, const string & snapshot, string* mix_template = 0);
        bool session_loaded;
-       /// @return true if building the session was successful
-       bool build_session (const string & path, const string & snapshot, 
+       /// @return zero if building the session was successful
+       int build_session (const string & path, const string & snapshot, 
                           uint32_t ctl_chns, 
                           uint32_t master_chns,
                           ARDOUR::AutoConnectOption input_connect,
@@ -124,11 +125,20 @@ class ARDOUR_UI : public Gtkmm2ext::UI
 
        ARDOUR::Session* the_session() { return session; }
 
-       bool new_session(std::string path = string());
+       bool will_create_new_session_automatically() const {
+               return _will_create_new_session_automatically;
+       }
+
+       void set_will_create_new_session_automatically (bool yn) {
+               _will_create_new_session_automatically = yn;
+       }
+
+       bool get_session_parameters (Glib::ustring path, bool have_engine = false, bool should_be_new = false);
+
        gint cmdline_new_session (string path);
        
        /// @return true if session was successfully unloaded.
-       bool unload_session ();
+       int unload_session (bool hide_stuff = false);
        void close_session(); 
 
        int  save_state_canfail (string state_name = "");
@@ -204,8 +214,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI
                session_add_midi_route (false);
        }*/
 
-       void set_engine (ARDOUR::AudioEngine&);
-       gint start_engine ();
+       int  create_engine ();
+       void post_engine ();
 
        gint exit_on_main_window_close (GdkEventAny *);
 
@@ -221,6 +231,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI
        void setup_profile ();
        void setup_theme ();
 
+       void set_shuttle_fract (double);
+
   protected:
        friend class PublicEditor;
 
@@ -293,6 +305,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
 
        static ARDOUR_UI *theArdourUI;
 
+       void backend_audio_error (bool we_set_params, Gtk::Window* toplevel = 0);
        void startup ();
        void shutdown ();
 
@@ -438,7 +451,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI
        gint shuttle_box_expose (GdkEventExpose*);
        gint mouse_shuttle (double x, bool force);
        void use_shuttle_fract (bool force);
-       void set_shuttle_fract (double);
 
        bool   shuttle_grabbed;
        double shuttle_fract;
@@ -507,6 +519,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
        Gtk::EventBox menu_bar_base;
        Gtk::HBox     menu_hbox;
 
+       void use_menubar_as_top_menubar ();
        void build_menu_bar ();
        void build_control_surface_menu ();
 
@@ -541,6 +554,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI
 
        gint session_menu (GdkEventButton *);
 
+       bool _will_create_new_session_automatically;
+
        NewSessionDialog* new_session_dialog;
        
        void open_session ();
@@ -683,6 +698,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
        void set_remote_model (ARDOUR::RemoteModel);
        void set_denormal_model (ARDOUR::DenormalModel);
 
+       void toggle_sync_order_keys ();
        void toggle_StopPluginsWithTransport();
        void toggle_DoNotRunPluginsWhileRecording();
        void toggle_VerifyRemoveLastCapture();
@@ -696,16 +712,19 @@ class ARDOUR_UI : public Gtkmm2ext::UI
        void toggle_RegionEquivalentsOverlap ();
        void toggle_PrimaryClockDeltaEditCursor ();
        void toggle_SecondaryClockDeltaEditCursor ();
+       void toggle_only_copy_imported_files ();
 
        void mtc_port_changed ();
        void map_solo_model ();
        void map_monitor_model ();
        void map_denormal_model ();
+       void map_denormal_protection ();
        void map_remote_model ();
        void map_file_header_format ();
        void map_file_data_format ();
        void map_input_auto_connect ();
        void map_output_auto_connect ();
+       void map_only_copy_imported_files ();
        void parameter_changed (const char*);
 
        void set_meter_hold (ARDOUR::MeterHold);
@@ -725,6 +744,16 @@ class ARDOUR_UI : public Gtkmm2ext::UI
        bool ab_direction;
        void disable_all_plugins ();
        void ab_all_plugins ();
+
+       void audioengine_setup ();
+
+       void display_message (const char *prefix, gint prefix_len, 
+                             Glib::RefPtr<Gtk::TextBuffer::Tag> ptag, Glib::RefPtr<Gtk::TextBuffer::Tag> mtag, const char *msg);
+       Gtk::Label status_bar_label;
+       Gtk::ToggleButton error_log_button;
+       Gtk::MessageDialog* loading_dialog;
+
+       void platform_specific ();
 };
 
 #endif /* __ardour_gui_h__ */
index 489728286ce3ff9fb2c53cc20bed081470835072..8f755a3d93b9b8530df33d53c6c47417730a298d 100644 (file)
@@ -78,14 +78,54 @@ ARDOUR_UI::setup_windows ()
 
        theme_manager->signal_unmap().connect (bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleThemeManager")));
 
-       top_packer.pack_start (menu_bar_base, false, false);
-       top_packer.pack_start (transport_frame, false, false);
+       top_packer.pack_start (transport_frame, false, false);
+
+#ifdef TOP_MENUBAR
+       HBox* status_bar_packer = manage (new HBox);
+       
+       status_bar_label.set_size_request (300, -1);
+       status_bar_packer->pack_start (status_bar_label, true, true, 6);
+       status_bar_packer->pack_start (error_log_button, false, false);
+       
+       error_log_button.signal_clicked().connect (mem_fun (*this, &UI::toggle_errors));
+
+       editor->get_status_bar_packer().pack_start (*status_bar_packer, true, true);
+       editor->get_status_bar_packer().pack_start (menu_bar_base, false, false, 6);
+#else
+       top_packer.pack_start (menu_bar_base, false, false);
+#endif 
 
        editor->add_toplevel_controls (top_packer);
 
        return 0;
 }
 
+ void
+ARDOUR_UI::display_message (const char *prefix, gint prefix_len, RefPtr<TextBuffer::Tag> ptag, RefPtr<TextBuffer::Tag> mtag, const char *msg)
+{
+       ustring text;
+
+       UI::display_message (prefix, prefix_len, ptag, mtag, msg);
+#ifdef TOP_MENUBAR
+
+       if (strcmp (prefix, _("[ERROR]: ")) == 0) {
+               text = "<span color=\"red\" weight=\"bold\">";
+       } else if (strcmp (prefix, _("[WARNING]: ")) == 0) {
+               text = "<span color=\"yellow\" weight=\"bold\">";
+       } else if (strcmp (prefix, _("[INFO]: ")) == 0) {
+               text = "<span color=\"green\" weight=\"bold\">";
+       } else {
+               text = "<span color=\"blue\" weight=\"bold\">???";
+       }
+
+       text += prefix;
+       text += "</span>";
+       text += msg;
+
+       status_bar_label.set_markup (text);
+#endif
+}
+
 void
 ARDOUR_UI::transport_stopped ()
 {
index 725180e0abf7d6748dea8234aa5897e2e8323c1a..6464c529679bb352fa0d20f27abeaf99210fccde 100644 (file)
@@ -47,7 +47,8 @@ void
 ARDOUR_UI::shutdown ()
 {
        if (session) {
-               delete session;
+               /* we're exiting cleanly, so remove any auto-save data */
+               session->remove_pending_capture_state ();
                session = 0;
        }
 
@@ -109,11 +110,13 @@ void
 ARDOUR_UI::goto_editor_window ()
 {
        editor->show_window ();
+       editor->present ();
 }
 void
 ARDOUR_UI::goto_mixer_window ()
 {
        mixer->show_window ();
+       mixer->present ();
 }
 
 gint
index c6353df782d63c7d4881b454eb7d7d088609a55e..9a71443489685a1befe1083c48c6cb69f8323a83 100644 (file)
@@ -162,21 +162,26 @@ ARDOUR_UI::connect_to_session (Session *s)
        point_zero_one_second_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
 }
 
-bool
-ARDOUR_UI::unload_session ()
+int
+ARDOUR_UI::unload_session (bool hide_stuff)
 {
        if (session && session->dirty()) {
                switch (ask_about_saving_session (_("close"))) {
                case -1:
                        // cancel
-                       return false;
+                       return 1;
                        
                case 1:
                        session->save_state ("");
                        break;
                }
        }
-       editor->hide ();
+
+       if (hide_stuff) {
+               editor->hide ();
+               mixer->hide ();
+       }
+
        second_connection.disconnect ();
        point_one_second_connection.disconnect ();
        point_oh_five_second_connection.disconnect ();
@@ -204,16 +209,12 @@ ARDOUR_UI::unload_session ()
                option_editor->set_session (0);
        }
 
-       if (mixer) {
-               mixer->hide ();
-       }
-
        delete session;
        session = 0;
 
        update_buffer_load ();
 
-       return true;
+       return 0;
 }
 
 int
index a043128700414ab531b5393221cd0deedb24a07a..c850d72048803a2d9b22d339fa0728a5e46732fc 100644 (file)
 #include "ardour_ui.h"
 #include "public_editor.h"
 #include "audio_clock.h"
+#include "engine_dialog.h"
 #include "editor.h"
 #include "actions.h"
+#include "sync-menu.h"
 
 #include <ardour/session.h>
 #include <ardour/profile.h>
@@ -80,6 +82,8 @@ ARDOUR_UI::install_actions ()
        /* menus + submenus that need action items */
 
        ActionManager::register_action (main_actions, X_("Session"), _("Session"));
+       ActionManager::register_action (main_actions, X_("Files"), _("Files"));
+       ActionManager::register_action (main_actions, X_("Regions"), _("Regions"));
        ActionManager::register_action (main_actions, X_("Cleanup"), _("Cleanup"));
        ActionManager::register_action (main_actions, X_("Sync"), _("Sync"));
        ActionManager::register_action (main_actions, X_("Options"), _("Options"));
@@ -98,7 +102,7 @@ ARDOUR_UI::install_actions ()
 
        /* the real actions */
 
-       act = ActionManager::register_action (main_actions, X_("New"), _("New"),  hide_return (bind (mem_fun(*this, &ARDOUR_UI::new_session), string ())));
+       act = ActionManager::register_action (main_actions, X_("New"), _("New"),  hide_return (bind (mem_fun(*this, &ARDOUR_UI::get_session_parameters), string (), true, true)));
 
        ActionManager::register_action (main_actions, X_("Open"), _("Open"),  mem_fun(*this, &ARDOUR_UI::open_session));
        ActionManager::register_action (main_actions, X_("Recent"), _("Recent"),  mem_fun(*this, &ARDOUR_UI::open_recent_session));
@@ -191,7 +195,7 @@ ARDOUR_UI::install_actions ()
 
        ActionManager::register_action (common_actions, X_("goto-editor"), _("Show Editor"),  mem_fun(*this, &ARDOUR_UI::goto_editor_window));
        ActionManager::register_action (common_actions, X_("goto-mixer"), _("Show Mixer"),  mem_fun(*this, &ARDOUR_UI::goto_mixer_window));
-       ActionManager::register_toggle_action (common_actions, X_("ToggleOptionsEditor"), _("Options Editor"), mem_fun(*this, &ARDOUR_UI::toggle_options_window));
+       ActionManager::register_toggle_action (common_actions, X_("ToggleOptionsEditor"), _("Preferences"), mem_fun(*this, &ARDOUR_UI::toggle_options_window));
        act = ActionManager::register_toggle_action (common_actions, X_("ToggleInspector"), _("Track/Bus Inspector"), mem_fun(*this, &ARDOUR_UI::toggle_route_params_window));
        ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_toggle_action (common_actions, X_("ToggleConnections"), _("Connections"), mem_fun(*this, &ARDOUR_UI::toggle_connection_editor));
@@ -200,7 +204,6 @@ ARDOUR_UI::install_actions ()
        ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_toggle_action (common_actions, X_("ToggleBigClock"), _("Big Clock"), mem_fun(*this, &ARDOUR_UI::toggle_big_clock_window));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (common_actions, X_("About"), _("About"),  mem_fun(*this, &ARDOUR_UI::show_splash));
        act = ActionManager::register_toggle_action (common_actions, X_("ToggleThemeManager"), _("Theme Manager"), mem_fun(*this, &ARDOUR_UI::toggle_theme_manager));
        ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_action (common_actions, X_("AddAudioTrack"), _("Add Audio Track"), bind (mem_fun(*this, &ARDOUR_UI::session_add_audio_track), 1, 1, ARDOUR::Normal, 1));
@@ -216,6 +219,8 @@ ARDOUR_UI::install_actions ()
        act = ActionManager::register_action (common_actions, X_("RemoveLastCapture"), _("Remove Last Capture"), mem_fun(*this, &ARDOUR_UI::remove_last_capture));
        ActionManager::session_sensitive_actions.push_back (act);
 
+       ActionManager::register_action (common_actions, X_("About"), _("About"),  mem_fun(*this, &ARDOUR_UI::show_splash));
+
        Glib::RefPtr<ActionGroup> transport_actions = ActionGroup::create (X_("Transport"));
 
        /* do-nothing action for the "transport" menu bar item */
@@ -402,6 +407,7 @@ ARDOUR_UI::install_actions ()
        act->set_sensitive (false);
 #endif
 
+       ActionManager::register_toggle_action (option_actions, X_("SyncEditorAndMixerTrackOrder"), _("Sync Editor and Mixer track order"), mem_fun (*this, &ARDOUR_UI::toggle_sync_order_keys));
        ActionManager::register_toggle_action (option_actions, X_("StopPluginsWithTransport"), _("Stop plugins with transport"), mem_fun (*this, &ARDOUR_UI::toggle_StopPluginsWithTransport));
        ActionManager::register_toggle_action (option_actions, X_("VerifyRemoveLastCapture"), _("Verify remove last capture"), mem_fun (*this, &ARDOUR_UI::toggle_VerifyRemoveLastCapture));
        ActionManager::register_toggle_action (option_actions, X_("PeriodicSafetyBackups"), _("Make periodic safety backups"), mem_fun (*this, &ARDOUR_UI::toggle_PeriodicSafetyBackups));
@@ -412,26 +418,45 @@ ARDOUR_UI::install_actions ()
        ActionManager::register_toggle_action (option_actions, X_("RegionEquivalentsOverlap"), _("Region equivalents overlap"), mem_fun (*this, &ARDOUR_UI::toggle_RegionEquivalentsOverlap));
        ActionManager::register_toggle_action (option_actions, X_("PrimaryClockDeltaEditCursor"), _("Primary Clock delta to edit cursor"), mem_fun (*this, &ARDOUR_UI::toggle_PrimaryClockDeltaEditCursor));
        ActionManager::register_toggle_action (option_actions, X_("SecondaryClockDeltaEditCursor"), _("Secondary Clock delta to edit cursor"), mem_fun (*this, &ARDOUR_UI::toggle_SecondaryClockDeltaEditCursor));      
+       ActionManager::register_toggle_action (option_actions, X_("OnlyCopyImportedFiles"), _("Always copy imported files"), mem_fun (*this, &ARDOUR_UI::toggle_only_copy_imported_files));     
 
        RadioAction::Group denormal_group;
 
        ActionManager::register_toggle_action (option_actions, X_("DenormalProtection"), _("Use DC bias"), mem_fun (*this, &ARDOUR_UI::toggle_denormal_protection));
-       
-       FPU fpu;
-
        ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalNone"), _("No processor handling"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalNone));
 
-       act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalFTZ"), _("Use FlushToZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalFTZ));
-       if (!fpu.has_flush_to_zero()) {
+       // as of September 10th 2007, Valgrind cannot handle various FPU flag setting instructions
+       // so avoid them
+
+       if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
+
+               /* we still need these actions to exist, but make them all insensitive */
+
+               act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalFTZ"), _("Use FlushToZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalFTZ));
                act->set_sensitive (false);
-       }
-       act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalDAZ"), _("Use DenormalsAreZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalDAZ));
-       if (!fpu.has_denormals_are_zero()) {
+               act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalDAZ"), _("Use DenormalsAreZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalDAZ));
                act->set_sensitive (false);
-       }
-       act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalFTZDAZ"), _("Use FlushToZero & DenormalsAreZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalFTZDAZ));
-       if (!fpu.has_flush_to_zero() || !fpu.has_denormals_are_zero()) {
+               act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalFTZDAZ"), _("Use FlushToZero & DenormalsAreZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalFTZDAZ));
                act->set_sensitive (false);
+
+       } else {
+
+               FPU fpu;
+
+               act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalFTZ"), _("Use FlushToZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalFTZ));
+               if (!fpu.has_flush_to_zero()) {
+                       act->set_sensitive (false);
+               }
+
+               act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalDAZ"), _("Use DenormalsAreZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalDAZ));
+               if (!fpu.has_denormals_are_zero()) {
+                       act->set_sensitive (false);
+               }
+
+               act = ActionManager::register_radio_action (option_actions, denormal_group, X_("DenormalFTZDAZ"), _("Use FlushToZero & DenormalsAreZero"), bind (mem_fun (*this, &ARDOUR_UI::set_denormal_model), DenormalFTZDAZ));
+               if (!fpu.has_flush_to_zero() || !fpu.has_denormals_are_zero()) {
+                       act->set_sensitive (false);
+               }
        }
 
        act = ActionManager::register_toggle_action (option_actions, X_("DoNotRunPluginsWhileRecording"), _("Do not run plugins while recording"), mem_fun (*this, &ARDOUR_UI::toggle_DoNotRunPluginsWhileRecording));
@@ -696,7 +721,9 @@ ARDOUR_UI::build_control_surface_menu ()
 void
 ARDOUR_UI::build_menu_bar ()
 {
-       build_control_surface_menu ();
+       if (!Profile->get_sae()) {
+               build_control_surface_menu ();
+       }
 
        menu_bar = dynamic_cast<MenuBar*> (ActionManager::get_widget (X_("/Main")));
        menu_bar->set_name ("MainMenuBar");
@@ -731,11 +758,20 @@ ARDOUR_UI::build_menu_bar ()
        sample_rate_box.set_name ("SampleRate");
        sample_rate_label.set_name ("SampleRate");
 
-       menu_hbox.pack_start (*menu_bar, true, true);
-       if (!Profile->get_small_screen()) {
-               menu_hbox.pack_end (wall_clock_box, false, false, 2);
-               menu_hbox.pack_end (disk_space_box, false, false, 4);
+#ifndef TOP_MENUBAR
+       menu_hbox.pack_start (*menu_bar, true, true);
+#else
+       use_menubar_as_top_menubar ();
+#endif
+
+       if (!Profile->get_small_screen()) {
+#ifndef GTKOSX         
+               // OSX provides its own wallclock, thank you very much
+               menu_hbox.pack_end (wall_clock_box, false, false, 2);
+#endif
+               menu_hbox.pack_end (disk_space_box, false, false, 4);
        }
+
        menu_hbox.pack_end (cpu_load_box, false, false, 4);
        menu_hbox.pack_end (buffer_load_box, false, false, 4);
        menu_hbox.pack_end (sample_rate_box, false, false, 4);
@@ -744,6 +780,16 @@ ARDOUR_UI::build_menu_bar ()
        menu_bar_base.add (menu_hbox);
 }
 
+void
+ARDOUR_UI::use_menubar_as_top_menubar ()
+{
+#ifdef GTKOSX
+       ige_mac_menu_set_menu_bar ((GtkMenuShell*) menu_bar->gobj());
+       // ige_mac_menu_set_quit_menu_item (some_item->gobj());
+#endif
+}
+
+
 void
 ARDOUR_UI::setup_clock ()
 {
@@ -751,6 +797,7 @@ ARDOUR_UI::setup_clock ()
        
        big_clock_window = new Window (WINDOW_TOPLEVEL);
        
+       big_clock_window->set_keep_above (true);
        big_clock_window->set_border_width (0);
        big_clock_window->add  (big_clock);
 
@@ -761,9 +808,5 @@ ARDOUR_UI::setup_clock ()
        big_clock_window->signal_realize().connect (bind (sigc::ptr_fun (set_decoration), big_clock_window,  (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)));
        big_clock_window->signal_unmap().connect (bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleBigClock")));
 
-       if (editor) {
-               editor->ensure_float (*big_clock_window);
-       }
-
        manage_window (*big_clock_window);
 }
index 4a6bef6b5f33be338561089f80568ba8f2c4ef0c..d013f98e5b142cda00d09186fa2fc1eaef25ed8e 100644 (file)
@@ -81,6 +81,13 @@ ARDOUR_UI::toggle_denormal_protection ()
        ActionManager::toggle_config_state ("options", "DenormalProtection", &Configuration::set_denormal_protection, &Configuration::get_denormal_protection);
 }
 
+void
+ARDOUR_UI::toggle_only_copy_imported_files ()
+{
+       ActionManager::toggle_config_state ("options", "OnlyCopyImportedFiles", &Configuration::set_only_copy_imported_files, &Configuration::get_only_copy_imported_files);
+}
+
+
 void
 ARDOUR_UI::set_native_file_header_format (HeaderFormat hf)
 {
@@ -458,6 +465,12 @@ ARDOUR_UI::toggle_StopRecordingOnXrun()
        ActionManager::toggle_config_state ("options", "StopRecordingOnXrun", &Configuration::set_stop_recording_on_xrun, &Configuration::get_stop_recording_on_xrun);
 }
 
+void
+ARDOUR_UI::toggle_sync_order_keys ()
+{
+       ActionManager::toggle_config_state ("options", "SyncEditorAndMixerTrackOrder", &Configuration::set_sync_all_route_ordering, &Configuration::get_sync_all_route_ordering);
+}
+
 void
 ARDOUR_UI::toggle_StopTransportAtEndOfSession()
 {
@@ -576,6 +589,19 @@ ARDOUR_UI::map_monitor_model ()
        }
 }
 
+void
+ARDOUR_UI::map_denormal_protection ()
+{
+       Glib::RefPtr<Action> act = ActionManager::get_action ("options", X_("DenormalProtection"));
+       if (act) {
+               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+
+               if (tact && !tact->get_active()) {
+                       tact->set_active (Config->get_denormal_protection());
+               }
+       }
+}
+
 void
 ARDOUR_UI::map_denormal_model ()
 {
@@ -761,6 +787,21 @@ ARDOUR_UI::map_output_auto_connect ()
        }
 }
 
+void
+ARDOUR_UI::map_only_copy_imported_files ()
+{
+       Glib::RefPtr<Action> act = ActionManager::get_action ("options", X_("OnlyCopyImportedFiles"));
+       if (act) {
+               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+
+               if (tact && !tact->get_active()) {
+                       tact->set_active (Config->get_only_copy_imported_files());
+               }
+       }
+
+}
+
+
 void
 ARDOUR_UI::map_meter_falloff ()
 {
@@ -995,12 +1036,16 @@ ARDOUR_UI::parameter_changed (const char* parameter_name)
                ActionManager::map_some_state ("options",  "PeriodicSafetyBackups", &Configuration::get_periodic_safety_backups);
        } else if (PARAM_IS ("stop-recording-on-xrun")) {
                ActionManager::map_some_state ("options",  "StopRecordingOnXrun", &Configuration::get_stop_recording_on_xrun);
+       } else if (PARAM_IS ("sync-all-route-ordering")) {
+               ActionManager::map_some_state ("options",  "SyncEditorAndMixerTrackOrder", &Configuration::get_sync_all_route_ordering);
        } else if (PARAM_IS ("stop-at-session-end")) {
                ActionManager::map_some_state ("options",  "StopTransportAtEndOfSession", &Configuration::get_stop_at_session_end);
        } else if (PARAM_IS ("monitoring-model")) {
                map_monitor_model ();
        } else if (PARAM_IS ("denormal-model")) {
                map_denormal_model ();
+       } else if (PARAM_IS ("denormal-protection")) {
+               map_denormal_protection ();
        } else if (PARAM_IS ("remote-model")) {
                map_remote_model ();
        } else if (PARAM_IS ("use-video-sync")) {
@@ -1062,8 +1107,9 @@ ARDOUR_UI::parameter_changed (const char* parameter_name)
                ActionManager::map_some_state ("options",  "PrimaryClockDeltaEditCursor", &Configuration::get_primary_clock_delta_edit_cursor);
        } else if (PARAM_IS ("secondary-clock-delta-edit-cursor")) {
                ActionManager::map_some_state ("options",  "SecondaryClockDeltaEditCursor", &Configuration::get_secondary_clock_delta_edit_cursor);
-       } 
-                          
+       } else if (PARAM_IS ("only-copy-imported-files")) {
+               map_only_copy_imported_files ();
+       }
 
 #undef PARAM_IS
 }
index 05a469cb1763d38a773af6bf3f8dd1bed6ec2a36..47c11cdb992a11ebd951521512599347b5deb533 100755 (executable)
@@ -6,4 +6,4 @@ if [ gprofhelper.c -nt gprofhelper.so ] ; then
 fi
 
 . ardev_common.sh
-LDPRELOAD=./gprofhelper.so $EXECUTABLE $*
+LDPRELOAD=./gprofhelper.so $EXECUTABLE "$@"
index 920e7cb1a897efe5a09927dfdc24e0325b6fa3b7..5661b4cd1103d2fa2c9bd0c6e1b0a7718febb5ca 100755 (executable)
@@ -1,4 +1,4 @@
 #!/bin/sh
 . ardev_common.sh
 export ARDOUR_RUNNING_UNDER_VALGRIND=TRUE
-exec valgrind  --num-callers=50 --tool=memcheck $EXECUTABLE --novst $*
+exec valgrind  --num-callers=50 --tool=memcheck $EXECUTABLE --novst "$@"
index dc6de8d0f6e3dbf6c9a81cfbb7a8c8bae2c26d8c..4bc10e93ec6e1995e8dfd87eb6cb00ea94da3c91 100644 (file)
@@ -28,6 +28,8 @@
 #include <ardour/audioregion.h>
 #include <ardour/audiosource.h>
 #include <ardour/audio_diskstream.h>
+#include <ardour/profile.h>
+
 #include <pbd/memento_command.h>
 #include <pbd/stacktrace.h>
 
@@ -177,7 +179,9 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
        line_name += ':';
        line_name += "gain";
 
-       gain_line = new AudioRegionGainLine (line_name, trackview.session(), *this, *group, audio_region()->envelope());
+       if (!Profile->get_sae()) {
+               gain_line = new AudioRegionGainLine (line_name, trackview.session(), *this, *group, audio_region()->envelope());
+       }
 
        if (!(_flags & EnvelopeVisible)) {
                gain_line->hide ();
@@ -814,6 +818,8 @@ AudioRegionView::create_waves ()
                        if (audio_region()->audio_source(n)->peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) {
                                create_one_wave (n, true);
                        } else {
+                               // we'll get a PeaksReady signal from the source in the future
+                               // and will call create_one_wave(n) then.
                        }
                } else {
                        create_one_wave (n, true);
index bbe573dab23c8f43c810b00e50c3f9e73f582060..22f8fa623972a3ef5298f92ea615eb9e8c652d31 100644 (file)
@@ -74,6 +74,7 @@ AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
 
        use_rec_regions = tv.editor.show_waveforms_recording ();
 
+
 }
 
 AudioStreamView::~AudioStreamView ()
index 51f744c4e550e7cbd38fadb5a70d6ca7fb1f89d0..e64ef99b160b216bb9d3fa136c65f07ede4f7df7 100644 (file)
@@ -62,6 +62,9 @@ class AxisView : public virtual Selectable
        sigc::signal<void> Hiding;
        sigc::signal<void> GoingAway;
 
+       void set_old_order_key (uint32_t ok) { _old_order_key = ok; }
+       uint32_t old_order_key() const { return _old_order_key; }
+
   protected:
 
        AxisView (ARDOUR::Session& sess);
@@ -84,7 +87,8 @@ class AxisView : public virtual Selectable
        Gtk::Label name_label;
 
        bool _marked_for_display;
-       
+       uint32_t _old_order_key;
+
 }; /* class AxisView */
 
 #endif /* __ardour_gtk_axis_view_h__ */
index d7f8f6ece8d1c64e1506b55e4e5ade87213d8125..93bbb603eec6658337c76010544714eb80e4464f 100644 (file)
@@ -34,6 +34,8 @@
 #define ZOOMFOCUS(a) /*empty*/
 #define DISPLAYCONTROL(a) /*empty*/
 #define IMPORTMODE(a) /*empty*/
+#define IMPORTPOSITION(a)
+#define IMPORTDISPOSITION(a)
 
 namespace Editing {
 
@@ -135,6 +137,7 @@ DisplayControl str2displaycontrol (const std::string &);
 #undef DISPLAYCONTROL
 #define DISPLAYCONTROL(a) /*empty*/
 
+
 // IMPORTMODE
 #undef IMPORTMODE
 #define IMPORTMODE(a) a,
@@ -142,13 +145,29 @@ enum ImportMode {
        #include "editing_syms.h"
 };
 
-extern const char *importmodestrs[];
-inline const char* enum2str(ImportMode m) {return importmodestrs[m];}
-ImportMode str2importmode (const std::string &);
-
 #undef IMPORTMODE
 #define IMPORTMODE(a) /*empty*/
 
+// IMPORTPOSITION
+#undef IMPORTPOSITION
+#define IMPORTPOSITION(a) a,
+enum ImportPosition {
+       #include "editing_syms.h"
+};
+
+#undef IMPORTPOSITION
+#define IMPORTPOSITION(a) /*empty*/
+
+// IMPORTDISPOSITION
+#undef IMPORTDISPOSITION
+#define IMPORTDISPOSITION(a) a,
+enum ImportDisposition {
+       #include "editing_syms.h"
+};
+
+#undef IMPORTDISPOSITION
+#define IMPORTDISPOSITION(a) /*empty*/
+
 /////////////////////
 // These don't need their state saved. yet...
 enum CutCopyOp {
index a057f6dd64296c5639b51c00228b5d478f707d2a..a520b0d318a3414f291b1991574997f334a8edeb 100644 (file)
@@ -83,3 +83,15 @@ IMPORTMODE(ImportAsRegion=0)
 IMPORTMODE(ImportToTrack=1)
 IMPORTMODE(ImportAsTrack=2)
 IMPORTMODE(ImportAsTapeTrack=3)
+
+// if this is changed, remember to update the string table in sfdb_ui.cc
+IMPORTPOSITION(ImportAtTimestamp=0)
+IMPORTPOSITION(ImportAtEditCursor=1)
+IMPORTPOSITION(ImportAtPlayhead=2)
+IMPORTPOSITION(ImportAtStart=3)
+
+// if this is changed, remember to update the string table in sfdb_ui.cc
+IMPORTDISPOSITION(ImportDistinctFiles=0)
+IMPORTDISPOSITION(ImportMergeFiles=1)
+IMPORTDISPOSITION(ImportSerializeFiles=2)
+IMPORTDISPOSITION(ImportDistinctChannels=3)
index 031262c41e32e226d25d6cfc1940a714460ee40a..f0a2bfa809c67a099271afccfb600719e4202c24 100644 (file)
@@ -25,6 +25,8 @@
 #include <string>
 #include <algorithm>
 
+#include <boost/none.hpp>
+
 #include <sigc++/bind.h>
 
 #include <pbd/convert.h>
@@ -56,6 +58,7 @@
 #include <ardour/session_state_utils.h>
 #include <ardour/tempo.h>
 #include <ardour/utils.h>
+#include <ardour/profile.h>
 
 #include <control_protocol/control_protocol.h>
 
@@ -77,6 +80,7 @@
 #include "crossfade_edit.h"
 #include "canvas_impl.h"
 #include "actions.h"
+#include "sfdb_ui.h"
 #include "gui_thread.h"
 
 #ifdef FFT_ANALYSIS
@@ -139,8 +143,8 @@ static const gchar *_zoom_focus_strings[] = {
        N_("Left"),
        N_("Right"),
        N_("Center"),
-       N_("Play"),
-       N_("Edit"),
+       N_("Playhead"),
+       N_("Edit Cursor"),
        0
 };
 
@@ -267,6 +271,7 @@ Editor::Editor ()
        autoscroll_active = false;
        autoscroll_timeout_tag = -1;
        interthread_progress_window = 0;
+       logo_item = 0;
 
 #ifdef FFT_ANALYSIS
        analysis_window = 0;
@@ -278,6 +283,7 @@ Editor::Editor ()
        _show_waveforms_recording = true;
        first_action_message = 0;
        export_dialog = 0;
+       export_range_markers_dialog = 0;
        show_gain_after_trim = false;
        ignore_route_list_reorder = false;
        no_route_list_redisplay = false;
@@ -302,6 +308,8 @@ Editor::Editor ()
        new_transport_marker_menu = 0;
        editor_mixer_strip_width = Wide;
        show_editor_mixer_when_tracks_arrive = false;
+       region_edit_menu_split_multichannel_item = 0;
+       region_edit_menu_split_item = 0;
        temp_location = 0;
        leftmost_frame = 0;
        ignore_mouse_mode_toggle = false;
@@ -321,6 +329,17 @@ Editor::Editor ()
        _dragging_playhead = false;
        _dragging_hscrollbar = false;
 
+       _scrubbing = false;
+       mouse_direction = 1;
+       mouse_speed_update = -1;
+       mouse_speed_size = 16;
+       mouse_speed = new double[mouse_speed_size];
+       memset (mouse_speed, 0, sizeof(double) * mouse_speed_size);
+       mouse_speed_entries = 0;
+
+       sfbrowser = 0;
+       ignore_route_order_sync = false;
+
        location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
        location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
        location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
@@ -345,7 +364,7 @@ Editor::Editor ()
 
        edit_controls_vbox.set_spacing (0);
        horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
-       vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
+       vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
        
        track_canvas.set_hadjustment (horizontal_adjustment);
        track_canvas.set_vadjustment (vertical_adjustment);
@@ -688,6 +707,9 @@ Editor::Editor ()
        set_name ("EditorWindow");
        add_accel_group (ActionManager::ui_manager->get_accel_group());
 
+       status_bar_hpacker.show ();
+
+       vpacker.pack_end (status_bar_hpacker, false, false);
        vpacker.pack_end (global_hpacker, true, true);
 
        /* register actions now so that set_state() can find them and set toggles/checks etc */
@@ -756,6 +778,7 @@ Editor::Editor ()
        ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
 
        Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
+       Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
 
        constructed = true;
        instant_save ();
@@ -854,9 +877,27 @@ void
 Editor::tie_vertical_scrolling ()
 {
        double y1 = vertical_adjustment.get_value();
+
+       playhead_cursor->set_y_axis (y1);
+       edit_cursor->set_y_axis (y1);
+       if (logo_item) {
+               logo_item->property_y() = y1;
+       }
+
        controls_layout.get_vadjustment()->set_value (y1);
-       playhead_cursor->set_y_axis(y1);
-       edit_cursor->set_y_axis(y1);
+
+#ifdef GTKOSX
+       /* the way idle updates and immediate window flushing work on GTK-Quartz
+          requires that we force an immediate redraw right here. The controls
+          layout will do the same all by itself, as does the canvas widget, but
+          most of the time, the canvas itself hasn't updated itself because its
+          idle handler hasn't run. consequently, the call that its layout makes
+          to gdk_window_process_updates() finds nothing to do. here, we force
+          the update to happen, then request a flush of the new window state.
+       */
+       track_canvas.update_now ();
+       gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
+#endif
 }
 
 void
@@ -912,40 +953,65 @@ Editor::control_scroll (float fraction)
        }
 
        double step = fraction * current_page_frames();
-       nframes_t target;
 
-       if ((fraction < 0.0f) && (session->transport_frame() < (nframes_t) fabs(step))) {
-               target = 0;
-       } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) {
-               target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen
+       /*
+               _control_scroll_target is an optional<T>
+       
+               it acts like a pointer to an nframes_t, with
+               a operator conversion to boolean to check
+               that it has a value could possibly use
+               playhead_cursor->current_frame to store the
+               value and a boolean in the class to know
+               when it's out of date
+       */
+
+       if (!_control_scroll_target) {
+               _control_scroll_target = session->transport_frame();
+               _dragging_playhead = true;
+       }
+
+       if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
+               *_control_scroll_target = 0;
+       } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
+               *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
        } else {
-               target = (session->transport_frame() + (nframes_t) floor ((fraction * current_page_frames())));
+               *_control_scroll_target += (nframes_t) floor (step);
        }
 
        /* move visuals, we'll catch up with it later */
 
-       playhead_cursor->set_position (target);
-
-       if (target > (current_page_frames() / 2)) {
+       playhead_cursor->set_position (*_control_scroll_target);
+       UpdateAllTransportClocks (*_control_scroll_target);
+       
+       if (*_control_scroll_target > (current_page_frames() / 2)) {
                /* try to center PH in window */
-               reset_x_origin (target - (current_page_frames()/2));
+               reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
        } else {
                reset_x_origin (0);
        }
 
-       /* cancel the existing */
+       /*
+               Now we do a timeout to actually bring the session to the right place
+               according to the playhead. This is to avoid reading disk buffers on every
+               call to control_scroll, which is driven by ScrollTimeline and therefore
+               probably by a control surface wheel which can generate lots of events.
+       */
+       /* cancel the existing timeout */
 
        control_scroll_connection.disconnect ();
 
-       /* add the next one */
+       /* add the next timeout */
 
-       control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50);
+       control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
 }
 
 bool
 Editor::deferred_control_scroll (nframes_t target)
 {
-       session->request_locate (target);
+       session->request_locate (*_control_scroll_target, session->transport_rolling());
+       // reset for next stream
+       _control_scroll_target = boost::none;
+       _dragging_playhead = false;
        return false;
 }
 
@@ -1153,6 +1219,10 @@ Editor::connect_to_session (Session *t)
        session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
        session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
 
+       if (sfbrowser) {
+               sfbrowser->set_session (session);
+       }
+
        handle_new_duration ();
 
        redisplay_regions ();
@@ -1271,12 +1341,18 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i
                }
                
                items.push_back (SeparatorElem());
-               
-               items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
-               items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
-               items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
-               items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
-               items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
+
+               if (Profile->get_sae()) {
+                       items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
+                       items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
+               } else {
+                       items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
+                       items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
+                       items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
+                       items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
+                       items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
+               }
+
                break;
 
        case FadeOutItem:
@@ -1289,11 +1365,16 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i
                
                items.push_back (SeparatorElem());
                
-               items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
-               items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
-               items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
-               items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
-               items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
+               if (Profile->get_sae()) {
+                       items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
+                       items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
+               } else {
+                       items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
+                       items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
+                       items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
+                       items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
+                       items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
+               }
 
                break;
 
@@ -1486,6 +1567,7 @@ void
 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
 {
        using namespace Menu_Helpers;
+       sigc::connection fooc;
        Menu *region_menu = manage (new Menu);
        MenuList& items = region_menu->items();
        region_menu->set_name ("ArdourContextMenu");
@@ -1515,14 +1597,52 @@ Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
 
        items.push_back (SeparatorElem());
 
-       items.push_back (MenuElem (_("Lock"), bind (mem_fun (*this, &Editor::set_region_lock), true)));
-       items.push_back (MenuElem (_("Unlock"), bind (mem_fun (*this, &Editor::set_region_lock), false)));
-       items.push_back (MenuElem (_("Lock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), true)));
-       items.push_back (MenuElem (_("Unlock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), false)));
-       items.push_back (MenuElem (_("Mute"), bind (mem_fun (*this, &Editor::set_region_mute), true)));
-       items.push_back (MenuElem (_("Unmute"), bind (mem_fun (*this, &Editor::set_region_mute), false)));
-       items.push_back (MenuElem (_("Opaque"), bind (mem_fun (*this, &Editor::set_region_opaque), true)));
-       items.push_back (MenuElem (_("Transparent"), bind (mem_fun (*this, &Editor::set_region_opaque), false)));
+       items.push_back (CheckMenuElem (_("Lock")));
+       region_lock_item = static_cast<CheckMenuItem*>(&items.back());
+       fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
+
+#if FIXUP_REGION_MENU
+       if (region->locked()) {
+               fooc.block (true);
+               region_lock_item->set_active();
+               fooc.block (false);
+       }
+#endif
+
+       items.push_back (CheckMenuElem (_("Lock Position")));
+       region_lock_position_item = static_cast<CheckMenuItem*>(&items.back());
+       fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_position_lock));
+#if FIXUP_REGION_MENU
+       if (region->locked()) {
+               fooc.block (true);
+               region_lock_position_item->set_active();
+               fooc.block (false);
+       }
+#endif
+
+       items.push_back (CheckMenuElem (_("Mute")));
+       region_mute_item = static_cast<CheckMenuItem*>(&items.back());
+       fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
+#if FIXUP_REGION_MENU
+       if (region->muted()) {
+               fooc.block (true);
+               region_mute_item->set_active();
+               fooc.block (false);
+       }
+#endif
+       
+       if (!Profile->get_sae()) {
+               items.push_back (CheckMenuElem (_("Opaque")));
+               region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
+               fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
+#if FIXUP_REGION_MENU
+               if (region->opaque()) {
+                       fooc.block (true);
+                       region_opaque_item->set_active();
+                       fooc.block (false);
+               }
+#endif
+       }
 
        /* We allow "Original position" if at least one region is not at its
           natural position 
@@ -1549,16 +1669,48 @@ Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
                MenuList& envelopes_items = envelopes_menu->items();
                envelopes_menu->set_name ("ArdourContextMenu");
 
-               envelopes_items.push_back (MenuElem (_("Reset"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
-               envelopes_items.push_back (MenuElem (_("Visible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), true)));
-               envelopes_items.push_back (MenuElem (_("Invisible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), false)));
-               envelopes_items.push_back (MenuElem (_("Active"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), true)));
-               envelopes_items.push_back (MenuElem (_("Inactive"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), false)));
+#if FIXUP_REGION_MENU
+
+   XXX NEED TO RESOLVE ONE v. MANY REGION ISSUE                
+
+               RegionView* rv = sv->find_view (ar);
+               AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
+
+               if (!Profile->get_sae()) {
+                       envelopes_items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
+
+                       envelopes_items.push_back (CheckMenuElem (_("Envelope Visible")));
+                       region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
+                       fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
+                       if (arv->envelope_visible()) {
+                               fooc.block (true);
+                               region_envelope_visible_item->set_active (true);
+                               fooc.block (false);
+                       }
+               
+                       envelopes_items.push_back (CheckMenuElem (_("Envelope Active")));
+                       region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
+                       fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
+                       
+                       if (ar->envelope_active()) {
+                               fooc.block (true);
+                               region_envelope_active_item->set_active (true);
+                               fooc.block (false);
+                       }
+
+                       items.push_back (SeparatorElem());
+               }
+#endif
 
                items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
                
-               items.push_back (MenuElem (_("Denormalize"), mem_fun (*this, &Editor::denormalize_regions)));
-               items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
+#if FIXUP_REGION_MENU
+               if (ar->scale_amplitude() != 1.0f) {
+                       items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_regions)));
+               } else {
+                       items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_regions)));
+               }
+#endif
        }
        
        /* Find out if we have a selected MIDI region */
@@ -1631,7 +1783,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
        selection_menu->set_name ("ArdourContextMenu");
 
        items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
-       items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
+       items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
 
 #ifdef FFT_ANALYSIS
        items.push_back (SeparatorElem());
@@ -1639,15 +1791,22 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
 #endif
        
        items.push_back (SeparatorElem());
-       items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection)));
-       items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection)));
+       items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
+       items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
+
+       items.push_back (SeparatorElem());
+       items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
+       items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
        
        items.push_back (SeparatorElem());
        items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
+
+       items.push_back (SeparatorElem());
+       items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
+       items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
+       
        items.push_back (SeparatorElem());
-       items.push_back (MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_selection)));
-       items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
-       items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
+       items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
        items.push_back (SeparatorElem());
        items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
        items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
@@ -1656,9 +1815,6 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
        items.push_back (SeparatorElem());
        items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
        items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
-
-       edit_items.push_back (MenuElem (_("Range"), *selection_menu));
-       edit_items.push_back (SeparatorElem());
 }
 
 /** Add context menu items relevant to busses or audio tracks.
@@ -2685,8 +2841,10 @@ Editor::convert_drop_to_paths (vector<ustring>& paths,
 
        vector<ustring> uris = data.get_uris();
 
+       cerr << "there were " << uris.size() << " in that drag data\n";
+
        if (uris.empty()) {
-               
+
                /* This is seriously fucked up. Nautilus doesn't say that its URI lists
                   are actually URI lists. So do it by hand.
                */
@@ -2736,10 +2894,34 @@ Editor::convert_drop_to_paths (vector<ustring>& paths,
        }
        
        for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
+
                if ((*i).substr (0,7) == "file://") {
-                       string p = *i;
+                       
+                       ustring p = *i;
                         PBD::url_decode (p);
-                       paths.push_back (p.substr (7));
+
+                       // scan forward past three slashes
+                       
+                       ustring::size_type slashcnt = 0;
+                       ustring::size_type n = 0;
+                       ustring::iterator x = p.begin();
+
+                       while (slashcnt < 3 && x != p.end()) {
+                               if ((*x) == '/') {
+                                       slashcnt++;
+                               } else if (slashcnt == 3) {
+                                       break;
+                               }
+                               ++n;
+                               ++x;
+                       }
+
+                       if (slashcnt != 3 || x == p.end()) {
+                               error << _("malformed URL passed to drag-n-drop code") << endmsg;
+                               continue;
+                       }
+
+                       paths.push_back (p.substr (n - 1));
                }
        }
 
@@ -3838,3 +4020,60 @@ Editor::edit_cursor_position(bool sync)
        return edit_cursor->current_frame;
 }
 
+
+void
+Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
+{
+       if (!session) return;
+
+       begin_reversible_command (cmd);
+       
+       Location* tll;
+
+       if ((tll = transport_loop_location()) == 0) {
+               Location* loc = new Location (start, end, _("Loop"),  Location::IsAutoLoop);
+                XMLNode &before = session->locations()->get_state();
+               session->locations()->add (loc, true);
+               session->set_auto_loop_location (loc);
+                XMLNode &after = session->locations()->get_state();
+               session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
+       }
+       else {
+                XMLNode &before = tll->get_state();
+               tll->set_hidden (false, this);
+               tll->set (start, end);
+                XMLNode &after = tll->get_state();
+                session->add_command (new MementoCommand<Location>(*tll, &before, &after));
+       }
+       
+       commit_reversible_command ();
+}
+
+void
+Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
+{
+       if (!session) return;
+
+       begin_reversible_command (cmd);
+       
+       Location* tpl;
+
+       if ((tpl = transport_punch_location()) == 0) {
+               Location* loc = new Location (start, end, _("Loop"),  Location::IsAutoPunch);
+                XMLNode &before = session->locations()->get_state();
+               session->locations()->add (loc, true);
+               session->set_auto_loop_location (loc);
+                XMLNode &after = session->locations()->get_state();
+               session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
+       }
+       else {
+                XMLNode &before = tpl->get_state();
+               tpl->set_hidden (false, this);
+               tpl->set (start, end);
+                XMLNode &after = tpl->get_state();
+                session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
+       }
+       
+       commit_reversible_command ();
+}
+
index 976ad68188ced51ad6bbe091e39f5d5edb1d9c05..63cbc042ac359c7a06464e3c315479a8bd2f39ea 100644 (file)
 #include <string>
 #include <sys/time.h>
 
+#include <glibmm/ustring.h>
+
+#include <boost/optional.hpp>
+
 #include <libgnomecanvasmm/canvas.h>
 #include <libgnomecanvasmm/group.h>
 #include <libgnomecanvasmm/line.h>
+#include <libgnomecanvasmm/pixbuf.h>
 
 #include <cmath>
 
@@ -100,6 +105,7 @@ class MixerStrip;
 class StreamView;
 class AudioStreamView;
 class ControlPoint;
+class SoundFileOmega;
 #ifdef FFT_ANALYSIS
 class AnalysisWindow;
 #endif
@@ -249,6 +255,7 @@ class Editor : public PublicEditor
 
 
        void add_toplevel_controls (Gtk::Container&);
+       Gtk::HBox& get_status_bar_packer()  { return status_bar_hpacker; }
 
        void      set_zoom_focus (Editing::ZoomFocus);
        Editing::ZoomFocus get_zoom_focus () const { return zoom_focus; }
@@ -298,6 +305,7 @@ class Editor : public PublicEditor
        void toggle_waveform_visibility ();
        void toggle_waveforms_while_recording ();
        void toggle_measure_visibility ();
+       void toggle_logo_visibility ();
 
        /* SMPTE timecode & video sync */
 
@@ -346,6 +354,8 @@ class Editor : public PublicEditor
        void reposition_and_zoom (nframes_t, double);
 
        nframes_t edit_cursor_position(bool);
+       bool update_mouse_speed ();
+       bool decelerate_mouse_speed ();
 
   protected:
        void map_transport_state ();
@@ -360,6 +370,9 @@ class Editor : public PublicEditor
        ARDOUR::Session     *session;
        bool                 constructed;
 
+       // to keep track of the playhead position for control_scroll
+       boost::optional<nframes_t> _control_scroll_target;
        PlaylistSelector* _playlist_selector;
 
        void          set_frames_per_unit (double);
@@ -464,6 +477,9 @@ class Editor : public PublicEditor
        void set_selected_regionview_from_region_list (boost::shared_ptr<ARDOUR::Region> region, Selection::Operation op = Selection::Set);
        void collect_new_region_view (RegionView *);
 
+       Gtk::MenuItem* region_edit_menu_split_item;
+       Gtk::MenuItem* region_edit_menu_split_multichannel_item;
+
        void popup_track_context_menu (int, int, nframes_t);
        Gtk::Menu* build_track_context_menu (nframes_t);
        void add_bus_or_audio_track_context_items (Gtk::Menu_Helpers::MenuList&);
@@ -507,6 +523,7 @@ class Editor : public PublicEditor
        Gtk::Frame         time_button_frame;
 
        ArdourCanvas::Group      *minsec_group;
+       ArdourCanvas::Pixbuf     *logo_item;
        ArdourCanvas::Group      *bbt_group;
        ArdourCanvas::Group      *smpte_group;
        ArdourCanvas::Group      *frame_group;
@@ -671,6 +688,7 @@ class Editor : public PublicEditor
        Gtk::VBox           track_canvas_vbox;
        Gtk::VBox           time_canvas_vbox;
        Gtk::VBox           edit_controls_vbox;
+       Gtk::HBox           edit_controls_hbox;
 
        void control_scroll (float);
        bool deferred_control_scroll (nframes_t);
@@ -728,6 +746,7 @@ class Editor : public PublicEditor
 
        Gtk::Menu          *region_list_menu;
        Gtk::ScrolledWindow region_list_scroller;
+       Gtk::Frame          region_list_frame;
 
        bool region_list_display_key_press (GdkEventKey *);
        bool region_list_display_key_release (GdkEventKey *);
@@ -868,10 +887,10 @@ class Editor : public PublicEditor
        /* EDITING OPERATIONS */
        
        void reset_point_selection ();
-       void set_region_mute (bool);
-       void set_region_lock (bool);
-       void set_region_position_lock (bool);
-       void set_region_opaque (bool);
+       void toggle_region_mute ();
+       void toggle_region_lock ();
+       void toggle_region_opaque ();
+       void toggle_region_position_lock ();
        void raise_region_to_top ();
        void lower_region_to_bottom ();
        void split_region ();
@@ -951,15 +970,32 @@ class Editor : public PublicEditor
        void insert_region_list_drag (boost::shared_ptr<ARDOUR::Region>, int x, int y);
        void insert_region_list_selection (float times);
 
+       /* import & embed */
+       
        void add_external_audio_action (Editing::ImportMode);
+       void external_audio_dialog ();
+       bool check_multichannel_status (const std::vector<Glib::ustring>& paths);
+
+       SoundFileOmega* sfbrowser;
+       
+       void bring_in_external_audio (Editing::ImportMode mode,  nframes64_t& pos);
+       void do_import (vector<Glib::ustring> paths, Editing::ImportDisposition, Editing::ImportMode mode, ARDOUR::SrcQuality, nframes64_t&);
+
+       void _do_embed (vector<Glib::ustring> paths, Editing::ImportDisposition, Editing::ImportMode mode,  nframes64_t&);
+       void do_embed (vector<Glib::ustring> paths, Editing::ImportDisposition, Editing::ImportMode mode,  nframes64_t&);
+       bool idle_do_embed (vector<Glib::ustring> paths, Editing::ImportDisposition, Editing::ImportMode mode,  nframes64_t&);
 
-       void bring_in_external_audio (Editing::ImportMode mode, ARDOUR::AudioTrack*, nframes_t& pos, bool prompt);
-       void do_import (vector<Glib::ustring> paths, bool split, Editing::ImportMode mode, ARDOUR::AudioTrack*, nframes_t&, bool);
-       void do_embed (vector<Glib::ustring> paths, bool split, Editing::ImportMode mode, ARDOUR::AudioTrack*, nframes_t&, bool);
-       int  import_sndfile (vector<Glib::ustring> paths, Editing::ImportMode mode, ARDOUR::AudioTrack* track, nframes_t& pos);
-       int  embed_sndfile (vector<Glib::ustring> paths, bool split, bool multiple_files, bool& check_sample_rate, Editing::ImportMode mode, 
-                           ARDOUR::AudioTrack* track, nframes_t& pos, bool prompt);
-       int finish_bringing_in_audio (boost::shared_ptr<ARDOUR::AudioRegion> region, uint32_t, uint32_t, ARDOUR::AudioTrack* track, nframes_t& pos, Editing::ImportMode mode);
+       int  import_sndfiles (vector<Glib::ustring> paths, Editing::ImportMode mode,  ARDOUR::SrcQuality, nframes64_t& pos,
+                             int target_regions, int target_tracks, boost::shared_ptr<ARDOUR::AudioTrack>&);
+       int  embed_sndfiles (vector<Glib::ustring> paths, bool multiple_files, bool& check_sample_rate, Editing::ImportMode mode, 
+                            nframes64_t& pos, int target_regions, int target_tracks, boost::shared_ptr<ARDOUR::AudioTrack>&);
+
+       int add_sources (vector<Glib::ustring> paths, ARDOUR::SourceList& sources, nframes64_t& pos, Editing::ImportMode,
+                        int target_regions, int target_tracks, boost::shared_ptr<ARDOUR::AudioTrack>&, bool add_channel_suffix);
+       int finish_bringing_in_audio (boost::shared_ptr<ARDOUR::AudioRegion> region, uint32_t, uint32_t,  nframes64_t& pos, Editing::ImportMode mode,
+                                     boost::shared_ptr<ARDOUR::AudioTrack>& existing_track);
+
+       boost::shared_ptr<ARDOUR::AudioTrack> get_nth_selected_audio_track (int nth) const;
 
        /* generic interthread progress window */
        
@@ -1030,7 +1066,11 @@ class Editor : public PublicEditor
 
        void add_location_from_audio_region ();
        void add_location_from_selection ();
-       void set_route_loop_selection ();
+       void set_loop_from_selection (bool play);
+       void set_punch_from_selection ();
+       
+       void set_loop_range (nframes_t start, nframes_t end, std::string cmd);
+       void set_punch_range (nframes_t start, nframes_t end, std::string cmd);
 
        void add_location_from_playhead_cursor ();
 
@@ -1040,6 +1080,18 @@ class Editor : public PublicEditor
        void start_scrolling ();
        void stop_scrolling ();
 
+       bool _scrubbing;
+       bool have_full_mouse_speed;
+       nframes64_t last_scrub_frame;
+       double last_scrub_time;
+       int mouse_speed_update;
+       double mouse_direction;
+       double compute_mouse_speed ();
+       void add_mouse_speed (double, double);
+       double* mouse_speed;
+       size_t mouse_speed_entries;
+       size_t mouse_speed_size;
+
        void keyboard_selection_begin ();
        void keyboard_selection_finish (bool add);
        bool have_pending_keyboard_selection;
@@ -1488,10 +1540,12 @@ class Editor : public PublicEditor
                    add (text);
                    add (visible);
                    add (tv);
+                   add (route);
            }
            Gtk::TreeModelColumn<Glib::ustring>  text;
            Gtk::TreeModelColumn<bool>           visible;
            Gtk::TreeModelColumn<TimeAxisView*>  tv;
+           Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Route> >  route;
        };
 
        RouteDisplayModelColumns         route_display_columns;
@@ -1502,11 +1556,16 @@ class Editor : public PublicEditor
        Gtk::ScrolledWindow                   route_list_scroller;
        Gtk::Menu*                            route_list_menu;
 
+       void sync_order_keys ();
+       bool ignore_route_order_sync;
+
        bool route_list_display_button_press (GdkEventButton*);
        bool route_list_selection_filter (const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path, bool yn);
 
        void route_list_change (const Gtk::TreeModel::Path&,const Gtk::TreeModel::iterator&);
        void route_list_delete (const Gtk::TreeModel::Path&);
+       void track_list_reorder (const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter, int* new_order);
+
        void initial_route_list_display ();
        void redisplay_route_list();
        void route_list_reordered (const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter, int* what);
@@ -1858,14 +1917,15 @@ class Editor : public PublicEditor
 
        bool _new_regionviews_show_envelope;
 
-       void set_gain_envelope_visibility (bool);
-       void set_gain_envelope_active (bool);
+       void toggle_gain_envelope_visibility ();
+       void toggle_gain_envelope_active ();
        void reset_region_gain_envelopes ();
 
        Gtk::CheckMenuItem* region_envelope_visible_item;
        Gtk::CheckMenuItem* region_envelope_active_item;
        Gtk::CheckMenuItem* region_mute_item;
        Gtk::CheckMenuItem* region_lock_item;
+       Gtk::CheckMenuItem* region_lock_position_item;
        Gtk::CheckMenuItem* region_opaque_item;
        
        bool on_key_press_event (GdkEventKey*);
@@ -1876,6 +1936,8 @@ class Editor : public PublicEditor
        Glib::RefPtr<Gtk::Action>              redo_action;
 
        void history_changed ();
+
+       Gtk::HBox      status_bar_hpacker;
 };
 
 #endif /* __ardour_editor_h__ */
index 7fe0de9aae57d23ff06abe3dcd3199229180f42e..051af2c89854a0c9af376fc20dd5c5aaf3e659da 100644 (file)
@@ -66,7 +66,6 @@ Editor::register_actions ()
 
        /* add named actions for the editor */
 
-
        act = ActionManager::register_toggle_action (editor_actions, "show-editor-mixer", _("Show Editor Mixer"), mem_fun (*this, &Editor::editor_mixer_button_toggled));
        ActionManager::session_sensitive_actions.push_back (act);
        act = ActionManager::register_toggle_action (editor_actions, "show-editor-list", _("Show Editor List"), mem_fun (*this, &Editor::editor_list_button_toggled));
@@ -385,19 +384,17 @@ Editor::register_actions ()
 
        act = ActionManager::register_action (editor_actions, X_("addExternalAudioToRegionList"), _("Add External Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsRegion));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, X_("addExternalAudioAsRegion"), _("as Region(s)"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsRegion));
-       ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, X_("addExternalAudioAsTrack"), _("as Tracks"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsTrack));
-       ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, X_("addExternalAudioAsTapeTrack"), _("as Tape Tracks"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportAsTapeTrack));
-       ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, X_("addExternalAudioToTrack"), _("to Tracks"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack));
-       ActionManager::session_sensitive_actions.push_back (act);
 
        ActionManager::register_toggle_action (editor_actions, X_("ToggleWaveformVisibility"), _("Show Waveforms"), mem_fun (*this, &Editor::toggle_waveform_visibility));
        ActionManager::register_toggle_action (editor_actions, X_("ToggleWaveformsWhileRecording"), _("Show Waveforms While Recording"), mem_fun (*this, &Editor::toggle_waveforms_while_recording));
        act = ActionManager::register_toggle_action (editor_actions, X_("ToggleMeasureVisibility"), _("Show Measures"), mem_fun (*this, &Editor::toggle_measure_visibility));
        
+       /* if there is a logo in the editor canvas, its always visible at startup */
+
+       act = ActionManager::register_toggle_action (editor_actions, X_("ToggleLogoVisibility"), _("Show Logo"), mem_fun (*this, &Editor::toggle_logo_visibility));
+       Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+       tact->set_active (true);
+
        RadioAction::Group layer_model_group;
 
        ActionManager::register_radio_action (editor_actions, layer_model_group,  X_("LayerLaterHigher"), _("Later is Higher"), bind (mem_fun (*this, &Editor::set_layer_model), LaterHigher));
@@ -473,6 +470,23 @@ Editor::toggle_measure_visibility ()
        }
 }
 
+void
+Editor::toggle_logo_visibility ()
+{
+       Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleLogoVisibility"));
+
+       if (act) {
+               Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+               if (logo_item) {
+                       if (tact->get_active()) {
+                               logo_item->show ();
+                       } else {
+                               logo_item->hide ();
+                       }
+               }
+       }
+}
+
 void
 Editor::set_crossfade_model (CrossfadeModel model)
 {
index 263ac0c31f2aa2b8b480de4ed50792ee7452acff..0dc0d707c0b1f99cd1cf3160b988bce8b0c29536 100644 (file)
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <errno.h>
 #include <unistd.h>
 
+#include <sndfile.h>
+
 #include <pbd/pthread_utils.h>
 #include <pbd/basename.h>
 #include <pbd/shortpath.h>
@@ -63,166 +66,307 @@ using Glib::ustring;
 /* Functions supporting the incorporation of external (non-captured) audio material into ardour */
 
 void
-Editor::add_external_audio_action (ImportMode mode)
+Editor::add_external_audio_action (ImportMode mode_hint)
 {
-       nframes_t& pos = edit_cursor->current_frame;
-       boost::shared_ptr<AudioTrack> track;
-
-       if (!selection->tracks.empty()) {
-               AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.front());
-               if (atv) {
-                       track = atv->audio_track();
-               }
+       if (session == 0) {
+               MessageDialog msg (0, _("You can't import or embed an audiofile until you have a session loaded."));
+               msg.run ();
+               return;
+       }
+       
+       if (sfbrowser == 0) {
+               sfbrowser = new SoundFileOmega (*this, _("Add existing audio"), session, 0, true, mode_hint);
+       } else {
+               sfbrowser->set_mode (mode_hint);
        }
 
-       bring_in_external_audio (mode, track.get(), pos, false);
+       external_audio_dialog ();
 }
 
 void
-Editor::bring_in_external_audio (ImportMode mode, AudioTrack* track, nframes_t& pos, bool prompt)
+Editor::external_audio_dialog ()
 {
+       vector<Glib::ustring> paths;
+       uint32_t track_cnt;
+
        if (session == 0) {
                MessageDialog msg (0, _("You can't import or embed an audiofile until you have a session loaded."));
                msg.run ();
                return;
        }
+       
+       track_cnt = 0;
 
-       SoundFileOmega sfdb (_("Add existing audio to session"), session);
-       sfdb.set_mode (mode);
+       for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
+               AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
+               
+               if (!atv) {
+                       continue;
+               } else if (atv->is_audio_track()) {
+                       track_cnt++;
+               }
+       }
+
+       if (sfbrowser == 0) {
+               sfbrowser = new SoundFileOmega (*this, _("Add existing audio"), session, track_cnt, true);
+       } else {
+               sfbrowser->reset (track_cnt);
+       }
+
+       sfbrowser->show_all ();
+
+  again:
+       int response = sfbrowser->run ();
 
-       switch (sfdb.run()) {
-       case SoundFileOmega::ResponseImport:
-               do_import (sfdb.get_paths(), sfdb.get_split(), sfdb.get_mode(), track, pos, prompt);
+       switch (response) {
+       case RESPONSE_APPLY:
+               // leave the dialog open
                break;
-               
-       case SoundFileOmega::ResponseEmbed:
-               do_embed (sfdb.get_paths(), sfdb.get_split(), sfdb.get_mode(), track, pos, prompt);
+
+       case RESPONSE_OK:
+               sfbrowser->hide ();
                break;
 
        default:
+               // cancel from the browser - we are done
+               sfbrowser->hide ();
+               return;
+       }
+
+       /* lets do it */
+       
+       paths = sfbrowser->get_paths ();
+
+       ImportPosition pos = sfbrowser->get_position ();
+       ImportMode mode = sfbrowser->get_mode ();
+       ImportDisposition chns = sfbrowser->get_channel_disposition ();
+       nframes64_t where;
+
+       switch (pos) {
+       case ImportAtEditCursor:
+               where = edit_cursor->current_frame;
+               break;
+       case ImportAtTimestamp:
+               where = -1;
+               break;
+       case ImportAtPlayhead:
+               where = playhead_cursor->current_frame;
                break;
+       case ImportAtStart:
+               where = session->current_start_frame();
+               break;
+       }
+
+       SrcQuality quality = sfbrowser->get_src_quality();
+
+       if (sfbrowser->copy_files_btn.get_active()) {
+               do_import (paths, chns, mode, quality, where);
+       } else {
+               do_embed (paths, chns, mode, where);
+       }
+
+       if (response == RESPONSE_APPLY) {
+               sfbrowser->clear_selection ();
+               goto again;
        }
 }
 
-void
-Editor::do_import (vector<ustring> paths, bool split, ImportMode mode, AudioTrack* track, nframes_t& pos, bool prompt)
+boost::shared_ptr<AudioTrack>
+Editor::get_nth_selected_audio_track (int nth) const
 {
-       /* SFDB sets "multichan" to true to indicate "split channels"
-          so reverse the setting to match the way libardour
-          interprets it.
-       */
+       AudioTimeAxisView* atv;
+       TrackSelection::iterator x;
        
-       import_status.multichan = !split;
+       for (x = selection->tracks.begin(); nth > 0 && x != selection->tracks.end(); ++x) {
 
-       if (interthread_progress_window == 0) {
-               build_interthread_progress_window ();
+               atv = dynamic_cast<AudioTimeAxisView*>(*x);
+               
+               if (!atv) {
+                       continue;
+               } else if (atv->is_audio_track()) {
+                       --nth;
+               }
        }
+       
+       if (x == selection->tracks.end()) {
+               atv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.back());
+       } else {
+               atv = dynamic_cast<AudioTimeAxisView*>(*x);
+       }
+       
+       if (!atv || !atv->is_audio_track()) {
+               return boost::shared_ptr<AudioTrack>();
+       }
+       
+       return atv->audio_track();
+}      
 
+void
+Editor::do_import (vector<ustring> paths, ImportDisposition chns, ImportMode mode, SrcQuality quality, nframes64_t& pos)
+{
+       boost::shared_ptr<AudioTrack> track;
        vector<ustring> to_import;
+       bool ok = false;
+       int nth = 0;
 
-       for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
-
-               to_import.clear ();
-               to_import.push_back (*a);
-
-               import_sndfile (to_import, mode, track, pos);
+       if (interthread_progress_window == 0) {
+               build_interthread_progress_window ();
        }
 
-       interthread_progress_window->hide_all ();
-}
+       switch (chns) {
+       case Editing::ImportDistinctFiles:
+               for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
 
-void
-Editor::do_embed (vector<ustring> paths, bool split, ImportMode mode, AudioTrack* track, nframes_t& pos, bool prompt)
-{
-       bool multiple_files = paths.size() > 1;
-       bool check_sample_rate = true;
-       vector<ustring>::iterator a;
+                       to_import.clear ();
+                       to_import.push_back (*a);
 
-       for (a = paths.begin(); a != paths.end(); ) {
+                       if (mode == Editing::ImportToTrack) {
+                               track = get_nth_selected_audio_track (nth++);
+                       }
+                       
+                       if (import_sndfiles (to_import, mode, quality, pos, 1, -1, track)) {
+                               goto out;
+                       }
 
-               cerr << "Considering embed of " << (*a) << endl;
-       
-               Glib::ustring path = *a;
-               Glib::ustring pair_base;
-               vector<ustring> to_embed;
+               }
+               break;
 
-               to_embed.push_back (path);
-               a = paths.erase (a);
+       case Editing::ImportDistinctChannels:
+               for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
 
-               if (path_is_paired (path, pair_base)) {
+                       to_import.clear ();
+                       to_import.push_back (*a);
 
-                       ustring::size_type len = pair_base.length();
+                       if (import_sndfiles (to_import, mode, quality, pos, -1, -1, track)) {
+                               goto out;
+                       }
 
-                       for (vector<Glib::ustring>::iterator b = paths.begin(); b != paths.end(); ) {
+               }
+               break;
 
-                               if (((*b).substr (0, len) == pair_base) && ((*b).length() == path.length())) {
+       case Editing::ImportMergeFiles:
+               /* create 1 region from all paths, add to 1 track,
+                  ignore "track"
+               */
+               if (import_sndfiles (paths, mode, quality, pos, 1, 1, track)) {
+                       goto out;
+               }
+               break;
 
-                                       to_embed.push_back (*b);
-                                               
-                                       /* don't process this one again */
+       case Editing::ImportSerializeFiles:
+               for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
 
-                                       b = paths.erase (b);
-                                       break;
+                       to_import.clear ();
+                       to_import.push_back (*a);
+                       
+                       /* create 1 region from this path, add to 1 track,
+                          reuse "track" across paths
+                       */
 
-                               } else {
-                                       ++b;
-                               }
+                       if (import_sndfiles (to_import, mode, quality, pos, 1, 1, track)) {
+                               goto out;
                        }
+
                }
+               break;
+       }
 
-               if (to_embed.size() > 1) {
+       ok = true;
+       
+  out: 
+       if (ok) {
+               session->save_state ("");
+       }
 
-                       vector<string> choices;
+       interthread_progress_window->hide_all ();
+}
 
-                       choices.push_back (string_compose (_("Import as a %1 region"),
-                                                          to_embed.size() > 2 ? _("multichannel") : _("stereo")));
-                       choices.push_back (_("Import as multiple regions"));
-                       
-                       Choice chooser (string_compose (_("Paired files detected (%1, %2 ...).\nDo you want to:"),
-                                                                  to_embed[0],
-                                                                  to_embed[1]),
-                                                  choices);
-                       
-                       if (chooser.run () == 0) {
-                               
-                               /* keep them paired */
+bool
+Editor::idle_do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
+{
+       _do_embed (paths, chns, mode, pos);
+       return false;
+}
 
-                               if (embed_sndfile (to_embed, split, multiple_files, check_sample_rate, mode, track, pos, prompt) < -1) {
-                                       break;
-                               }
+void
+Editor::do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
+{
+#ifdef GTKOSX
+       Glib::signal_idle().connect (bind (mem_fun (*this, &Editor::idle_do_embed), paths, chns, mode, pos));
+#else
+       _do_embed (paths, chns, mode, pos);
+#endif
+}
 
-                       } else {
+void
+Editor::_do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
+{
+       boost::shared_ptr<AudioTrack> track;
+       bool check_sample_rate = true;
+       bool ok = false;
+       vector<ustring> to_embed;
+       bool multi = paths.size() > 1;
+       int nth = 0;
 
-                               /* one thing per file */
+       switch (chns) {
+       case Editing::ImportDistinctFiles:
+               for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
 
-                               vector<ustring> foo;
+                       to_embed.clear ();
+                       to_embed.push_back (*a);
 
-                               for (vector<ustring>::iterator x = to_embed.begin(); x != to_embed.end(); ++x) {
+                       if (mode == Editing::ImportToTrack) {
+                               track = get_nth_selected_audio_track (nth++);
+                       }
 
-                                       foo.clear ();
-                                       foo.push_back (*x);
+                       if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, 1, -1, track) < -1) {
+                               goto out;
+                       }
+               }
+               break;
+               
+       case Editing::ImportDistinctChannels:
+               for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
 
-                                       if (embed_sndfile (foo, split, multiple_files, check_sample_rate, mode, track, pos, prompt) < -1) {
-                                               break;
-                                       }
-                               }
+                       to_embed.clear ();
+                       to_embed.push_back (*a);
+
+                       if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, -1, -1, track) < -1) {
+                               goto out;
                        }
+               }
+               break;
 
-               } else {
-                       
-                       if (embed_sndfile (to_embed, split, multiple_files, check_sample_rate, mode, track, pos, prompt) < -1) {
-                               break;
+       case Editing::ImportMergeFiles:
+               if (embed_sndfiles (paths, multi, check_sample_rate, mode, pos, 1, 1, track) < -1) {
+                       goto out;
+               }
+       break;
+
+       case Editing::ImportSerializeFiles:
+               for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
+
+                       to_embed.clear ();
+                       to_embed.push_back (*a);
+
+                       if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, 1, 1, track) < -1) {
+                               goto out;
                        }
                }
+               break;
        }
+
+       ok = true;
        
-       if (a == paths.end()) {
+  out: 
+       if (ok) {
                session->save_state ("");
        }
 }
 
 int
-Editor::import_sndfile (vector<ustring> paths, ImportMode mode, AudioTrack* track, nframes_t& pos)
+Editor::import_sndfiles (vector<ustring> paths, ImportMode mode, SrcQuality quality, nframes64_t& pos, 
+                        int target_regions, int target_tracks, boost::shared_ptr<AudioTrack>& track)
 {
        WindowTitle title = string_compose (_("importing %1"), paths.front());
 
@@ -238,7 +382,8 @@ Editor::import_sndfile (vector<ustring> paths, ImportMode mode, AudioTrack* trac
        import_status.cancel = false;
        import_status.freeze = false;
        import_status.done = 0.0;
-       
+       import_status.quality = quality;
+
        interthread_progress_connection = Glib::signal_timeout().connect 
                (bind (mem_fun(*this, &Editor::import_progress_timeout), (gpointer) 0), 100);
        
@@ -262,28 +407,31 @@ Editor::import_sndfile (vector<ustring> paths, ImportMode mode, AudioTrack* trac
        interthread_progress_connection.disconnect ();
        
        /* import thread finished - see if we should build a new track */
+
+       boost::shared_ptr<AudioRegion> r;
        
-       if (!import_status.new_regions.empty()) {
-               boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(import_status.new_regions.front());
-               finish_bringing_in_audio (region, region->n_channels(), region->n_channels(), track, pos, mode);
+       if (import_status.cancel || import_status.sources.empty()) {
+               goto out;
+       }
+
+       if (add_sources (paths, import_status.sources, pos, mode, target_regions, target_tracks, track, false) == 0) {
+               session->save_state ("");
        }
 
+  out:
        track_canvas.get_window()->set_cursor (*current_canvas_cursor);
        return 0;
 }
 
 int
-Editor::embed_sndfile (vector<Glib::ustring> paths, bool split, bool multiple_files, bool& check_sample_rate, ImportMode mode, 
-                      AudioTrack* track, nframes_t& pos, bool prompt)
+Editor::embed_sndfiles (vector<Glib::ustring> paths, bool multifile,
+                       bool& check_sample_rate, ImportMode mode, nframes64_t& pos, int target_regions, int target_tracks,
+                       boost::shared_ptr<AudioTrack>& track)
 {
        boost::shared_ptr<AudioFileSource> source;
        SourceList sources;
-       boost::shared_ptr<AudioRegion> region;
        string linked_path;
        SoundFileInfo finfo;
-       ustring region_name;
-       uint32_t input_chan = 0;
-       uint32_t output_chan = 0;
        int ret = 0;
 
        track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
@@ -294,10 +442,8 @@ Editor::embed_sndfile (vector<Glib::ustring> paths, bool split, bool multiple_fi
                ustring path = *p;
 
                /* lets see if we can link it into the session */
-
-               sys::path tmp = session->session_directory().sound_path();
-
-               tmp /= Glib::path_get_basename(path);
+               
+               sys::path tmp = session->session_directory().sound_path() / Glib::path_get_basename(path);
                linked_path = tmp.to_string();
                
                if (link (path.c_str(), linked_path.c_str()) == 0) {
@@ -323,22 +469,21 @@ Editor::embed_sndfile (vector<Glib::ustring> paths, bool split, bool multiple_fi
                                        }
                                }
                        }
-
                }
                
                /* note that we temporarily truncated _id at the colon */
                
                string error_msg;
-               
+
                if (!AudioFileSource::get_soundfile_info (path, finfo, error_msg)) {
-                       error << string_compose(_("Editor: cannot open file \"%1\", (%2)"), selection, error_msg ) << endmsg;
+                       error << string_compose(_("Editor: cannot open file \"%1\", (%2)"), path, error_msg ) << endmsg;
                        goto out;
                }
                
                if (check_sample_rate  && (finfo.samplerate != (int) session->frame_rate())) {
                        vector<string> choices;
                        
-                       if (multiple_files) {
+                       if (multifile) {
                                choices.push_back (_("Cancel entire import"));
                                choices.push_back (_("Don't embed it"));
                                choices.push_back (_("Embed all without questions"));
@@ -390,14 +535,8 @@ Editor::embed_sndfile (vector<Glib::ustring> paths, bool split, bool multiple_fi
                }
                
                track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
-               ARDOUR_UI::instance()->flush_pending ();
-       
-               /* make the proper number of channels in the region */
-               
-               input_chan += finfo.channels;
 
-               for (int n = 0; n < finfo.channels; ++n)
-               {
+               for (int n = 0; n < finfo.channels; ++n) {
                        try {
 
                                /* check if we have this thing embedded already */
@@ -409,7 +548,8 @@ Editor::embed_sndfile (vector<Glib::ustring> paths, bool split, bool multiple_fi
                                                                                               (DataType::AUDIO, *session, path,  n,
                                                                                                (mode == ImportAsTapeTrack ? 
                                                                                                 AudioFileSource::Destructive : 
-                                                                                                AudioFileSource::Flag (0))));
+                                                                                                AudioFileSource::Flag (0)),
+                                                                                               true, true));
                                } else {
                                        source = boost::dynamic_pointer_cast<AudioFileSource> (s);
                                }
@@ -430,14 +570,74 @@ Editor::embed_sndfile (vector<Glib::ustring> paths, bool split, bool multiple_fi
                goto out;
        }
 
-       if (sources[0]->natural_position() != 0) {
-               pos = sources[0]->natural_position();
-       } 
+       ret = add_sources (paths, sources, pos, mode, target_regions, target_tracks, track, true);
 
-       region_name = region_name_from_path (paths.front(), (sources.size() > 1));
-       
-       region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, 0, sources[0]->length(), region_name, 0,
-                                                                                 Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External)));
+  out:
+       track_canvas.get_window()->set_cursor (*current_canvas_cursor);
+       return ret;
+}
+
+int
+Editor::add_sources (vector<Glib::ustring> paths, SourceList& sources, nframes64_t& pos, ImportMode mode, 
+                    int target_regions, int target_tracks, boost::shared_ptr<AudioTrack>& track, bool add_channel_suffix)
+{
+       vector<boost::shared_ptr<AudioRegion> > regions;
+       ustring region_name;
+       uint32_t input_chan = 0;
+       uint32_t output_chan = 0;
+
+       if (pos == -1) { // "use timestamp"
+               if (sources[0]->natural_position() != 0) {
+                       pos = sources[0]->natural_position();
+               } else {
+                       // XXX is this the best alternative ?
+                       pos = edit_cursor->current_frame;
+               }
+       }
+
+       if (target_regions == 1) {
+
+               /* take all the sources we have and package them up as a region */
+
+               region_name = region_name_from_path (paths.front(), (sources.size() > 1), false);
+               
+               regions.push_back (boost::dynamic_pointer_cast<AudioRegion> 
+                                  (RegionFactory::create (sources, 0, sources[0]->length(), region_name, 0,
+                                                          Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External))));
+               
+       } else if (target_regions == -1) {
+
+               /* take each source and create a region for each one */
+
+               SourceList just_one;
+               SourceList::iterator x;
+               uint32_t n;
+
+               for (n = 0, x = sources.begin(); x != sources.end(); ++x, ++n) {
+
+                       just_one.clear ();
+                       just_one.push_back (*x);
+                       
+                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*x);
+
+                       region_name = region_name_from_path (afs->path(), false, true, sources.size(), n);
+
+                       regions.push_back (boost::dynamic_pointer_cast<AudioRegion> 
+                                          (RegionFactory::create (just_one, 0, (*x)->length(), region_name, 0,
+                                                                  Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External))));
+
+               }
+       }
+
+       if (target_regions == 1) {
+               input_chan = regions.front()->n_channels();
+       } else {
+               if (target_tracks == 1) {
+                       input_chan = regions.size();
+               } else {
+                       input_chan = 1;
+               }
+       }
 
        if (Config->get_output_auto_connect() & AutoConnectMaster) {
                output_chan = (session->master_out() ? session->master_out()->n_inputs().n_audio() : input_chan);
@@ -445,15 +645,31 @@ Editor::embed_sndfile (vector<Glib::ustring> paths, bool split, bool multiple_fi
                output_chan = input_chan;
        }
 
-       finish_bringing_in_audio (region, input_chan, output_chan, track, pos, mode);
-       
-  out:
-       track_canvas.get_window()->set_cursor (*current_canvas_cursor);
-       return ret;
-}
+       int n = 0;
+
+       for (vector<boost::shared_ptr<AudioRegion> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
+
+               finish_bringing_in_audio (*r, input_chan, output_chan, pos, mode, track);
 
+               if (target_tracks != 1) {
+                       track.reset ();
+               } else {
+                       pos += (*r)->length();
+               } 
+       }
+
+       /* setup peak file building in another thread */
+
+       for (SourceList::iterator x = sources.begin(); x != sources.end(); ++x) {
+               SourceFactory::setup_peakfile (*x, true);
+       }
+
+       return 0;
+}
+       
 int
-Editor::finish_bringing_in_audio (boost::shared_ptr<AudioRegion> region, uint32_t in_chans, uint32_t out_chans, AudioTrack* track, nframes_t& pos, ImportMode mode)
+Editor::finish_bringing_in_audio (boost::shared_ptr<AudioRegion> region, uint32_t in_chans, uint32_t out_chans, nframes64_t& pos, 
+                                 ImportMode mode, boost::shared_ptr<AudioTrack>& existing_track)
 {
        switch (mode) {
        case ImportAsRegion:
@@ -461,38 +677,52 @@ Editor::finish_bringing_in_audio (boost::shared_ptr<AudioRegion> region, uint32_
                break;
                
        case ImportToTrack:
-               if (track) {
-                       boost::shared_ptr<Playlist> playlist = track->diskstream()->playlist();
-                       
-                       boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
-                       begin_reversible_command (_("insert sndfile"));
-                        XMLNode &before = playlist->get_state();
-                       playlist->add_region (copy, pos);
-                       session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
-                       commit_reversible_command ();
+       {
+               if (!existing_track) {
+
+                       existing_track = get_nth_selected_audio_track (0);
 
-                       pos += region->length();
+                       if (!existing_track) {
+                               return -1;
+                       }
                }
+
+               boost::shared_ptr<Playlist> playlist = existing_track->diskstream()->playlist();
+               boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
+               begin_reversible_command (_("insert sndfile"));
+               XMLNode &before = playlist->get_state();
+               playlist->add_region (copy, pos);
+               session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
+               commit_reversible_command ();
                break;
-               
+       }
+
        case ImportAsTrack:
        { 
-               list<boost::shared_ptr<AudioTrack> > at (session->new_audio_track (in_chans, out_chans, Normal, 1));
-               if (!at.empty()) {
-                       boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
-                       at.front()->diskstream()->playlist()->add_region (copy, pos);
-                       at.front()->set_name(short_path(copy->name(), 32));
+               if (!existing_track) {
+                       list<boost::shared_ptr<AudioTrack> > at (session->new_audio_track (in_chans, out_chans, Normal, 1));
+
+                       if (at.empty()) {
+                               return -1;
+                       }
+
+                       existing_track = at.front();
+                       existing_track->set_name (region->name());
                }
+
+               boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
+               existing_track->diskstream()->playlist()->add_region (copy, pos);
                break;
        }
 
+
        case ImportAsTapeTrack:
        {
                list<boost::shared_ptr<AudioTrack> > at (session->new_audio_track (in_chans, out_chans, Destructive));
                if (!at.empty()) {
                        boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
+                       at.front()->set_name (basename_nosuffix (copy->name()));
                        at.front()->diskstream()->playlist()->add_region (copy, pos);
-                       at.front()->set_name(short_path(copy->name(), 32));
                }
                break;
        }
index cdcbb43f76e81f593937e4e3741f0ae047e14edf..87fa8a06b854deac76e4cfa4861f0e64a27f1684 100644 (file)
 #include "audio_region_view.h"
 #include "selection.h"
 
+#include "i18n.h"
+
 using namespace ARDOUR;
 using namespace PBD;
 
 void
-Editor::set_route_loop_selection ()
+Editor::set_loop_from_selection (bool play)
 {
        if (session == 0 || selection->time.empty()) {
                return;
@@ -38,18 +40,26 @@ Editor::set_route_loop_selection ()
 
        nframes_t start = selection->time[clicked_selection].start;
        nframes_t end = selection->time[clicked_selection].end;
+       
+       set_loop_range (start, end,  _("set loop range from selection"));
 
-       Location* loc = transport_loop_location();
-
-       if (loc) {
-               
-               loc->set (start, end);
-
-               // enable looping, reposition and start rolling
+       if (play) {
                session->request_play_loop (true);
-               session->request_locate (loc->start(), true);
+               session->request_locate (start, true);
+       }
+}
+
+void
+Editor::set_punch_from_selection ()
+{
+       if (session == 0 || selection->time.empty()) {
+               return;
        }
 
+       nframes_t start = selection->time[clicked_selection].start;
+       nframes_t end = selection->time[clicked_selection].end;
+       
+       set_punch_range (start, end,  _("set punch range from selection"));
 }
 
 void
index c5a86951589dd652a59fcdb87852a4142c02e605..86beec387e84876139f6b284cb8bb396a1300ac7 100644 (file)
@@ -22,6 +22,7 @@
 #include <gtkmm2ext/utils.h>
 
 #include <ardour/audioregion.h>
+#include <ardour/profile.h>
 
 #include "ardour_ui.h"
 #include "editor.h"
@@ -143,11 +144,21 @@ Editor::initialize_canvas ()
 
        verbose_cursor_visible = false;
        
-       cursor_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
+       if (Profile->get_sae()) {
+               Image img (::get_icon (X_("saelogo")));
+               logo_item = new ArdourCanvas::Pixbuf (*track_canvas.root(), 0.0, 0.0, img.get_pixbuf());
+               // logo_item->property_height_in_pixels() = true;
+               // logo_item->property_width_in_pixels() = true;
+               // logo_item->property_height_set() = true;
+               // logo_item->property_width_set() = true;
+               logo_item->show ();
+       }
+       
+       /* a group to hold time (measure) lines */
        
        time_line_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
        tempo_lines = new TempoLines(track_canvas, time_line_group);
-
+       cursor_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0);
        time_canvas.set_name ("EditorTimeCanvas");
        time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
        time_canvas.set_flags (CAN_FOCUS);
@@ -257,6 +268,10 @@ Editor::initialize_canvas ()
        initial_ruler_update_required = true;
        track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate));
 
+       if (logo_item) {
+               logo_item->lower_to_bottom ();
+       }
+
        ColorsChanged.connect (mem_fun (*this, &Editor::color_handler));
        color_handler();
 
@@ -348,6 +363,11 @@ Editor::track_canvas_size_allocated ()
                
        update_fixed_rulers();
        redisplay_tempo (true);
+
+       if (logo_item) {
+               // logo_item->property_height() = canvas_height;
+               // logo_item->property_width() = canvas_width;
+       }
        
        Resized (); /* EMIT_SIGNAL */
 
@@ -455,7 +475,7 @@ Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
        vector<ustring> paths;
        string spath;
        GdkEvent ev;
-       nframes_t frame;
+       nframes64_t frame;
 
        if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
                goto out;
@@ -483,15 +503,18 @@ Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
 
                /* drop onto canvas background: create new tracks */
 
-               nframes_t pos = 0;
-               do_embed (paths, false, ImportAsTrack, 0, pos, false);
+               do_embed (paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
                
        } else if ((tv = dynamic_cast<RouteTimeAxisView*>(tvp)) != 0) {
 
                /* check that its an audio track, not a bus */
                
+               /* check that its an audio track, not a bus */
+               
                if (tv->get_diskstream()) {
-                       do_embed (paths, false, ImportToTrack, tv->audio_track().get(), frame, true);
+                       /* select the track, then embed */
+                       selection->set (tv);
+                       do_embed (paths, Editing::ImportDistinctFiles, ImportToTrack, frame);
                }
        }
 
@@ -697,6 +720,10 @@ Editor::canvas_horizontally_scrolled ()
                reset_scrolling_region ();
        }
        
+       if (logo_item) {
+               logo_item->property_x() = horizontal_adjustment.get_value ();
+       }
+
        update_fixed_rulers ();
 
        redisplay_tempo (!_dragging_hscrollbar);
index 4b0088f0753496a719b236612ed88083fdc6a1be..28b86f53fc6493edbf6b25027f51273694f3ea7c 100644 (file)
@@ -43,6 +43,14 @@ Editor::kbd_driver (sigc::slot<void,GdkEvent*> theslot, bool use_track_canvas, b
                doit = true;
        }
 
+       /* any use of "keyboard mouse buttons" invalidates an existing grab
+       */
+       
+       if (drag_info.item) {
+               drag_info.item->ungrab (GDK_CURRENT_TIME);
+               drag_info.item = 0;
+       }
+
        if (doit) {
 
                if (entered_regionview && can_select) {
index 29a212f2f594e6ad6ecd6c78e7fa7ee0e4735c4c..724ff2c31ac9de4b34293c06966346d01b9558e4 100644 (file)
@@ -909,56 +909,13 @@ Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
 void
 Editor::new_transport_marker_menu_set_loop ()
 {
-       if (!session) return;
-       
-       begin_reversible_command (_("set loop range"));
-       
-       Location* tll;
-
-       if ((tll = transport_loop_location()) == 0) {
-               Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"),  Location::IsAutoLoop);
-                XMLNode &before = session->locations()->get_state();
-               session->locations()->add (loc, true);
-               session->set_auto_loop_location (loc);
-                XMLNode &after = session->locations()->get_state();
-               session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
-       }
-       else {
-                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<Location>(*tll, &before, &after));
-       }
-       
-       commit_reversible_command ();
+       set_loop_range (temp_location->start(), temp_location->end(), _("set loop range"));
 }
 
 void
 Editor::new_transport_marker_menu_set_punch ()
 {
-       if (!session) return;
-       
-       begin_reversible_command (_("set punch range"));
-       
-       Location* tpl;
-
-       if ((tpl = transport_punch_location()) == 0) {
-               tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
-                XMLNode &before = session->locations()->get_state();
-               session->locations()->add (tpl, true);
-               session->set_auto_punch_location (tpl);
-                XMLNode &after = session->locations()->get_state();
-               session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
-       } else {
-                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<Location>(*tpl, &before, &after));
-       }
-       
-       commit_reversible_command ();
+       set_punch_range (temp_location->start(), temp_location->end(), _("set punch range"));
 }
 
 void
index e8bc98a73c0d22ad4fac3b67d31b12e38b23595e..da95d50d95949e8088db8361d67a6d1850879f80 100644 (file)
@@ -442,8 +442,23 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
        
        switch (item_type) {
        case RegionItem:
-       case RegionViewNameHighlight:
-       case RegionViewName:
+               if (mouse_mode != MouseRange) {
+                       commit = set_selected_regionview_from_click (press, op, true);
+               } else if (event->type == GDK_BUTTON_PRESS) {
+                       commit = set_selected_track_from_click (press, op, false);
+               }
+               break;
+               
+       case RegionViewNameHighlight:
+       case RegionViewName:
+               if (mouse_mode != MouseRange) {
+                       commit = set_selected_regionview_from_click (press, op, true);
+               } else if (event->type == GDK_BUTTON_PRESS) {
+                       commit = set_selected_track_from_click (press, op, false);
+               }
+               break;
+
+
        case FadeInHandleItem:
        case FadeInItem:
        case FadeOutHandleItem:
@@ -754,7 +769,12 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                        break;
 
                case MouseAudition:
-                       /* handled in release */
+                       _scrubbing = true;
+                       last_scrub_frame = 0;
+                       last_scrub_time = 0;
+                       have_full_mouse_speed = false;
+                       memset (mouse_speed, 0, sizeof (double) * mouse_speed_size);
+                       /* rest handled in motion & release */
                        break;
 
                default:
@@ -906,10 +926,19 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                break;
 
                        case StreamItem:
+                               popup_track_context_menu (1, event->button.time, where);
+                               break;
+                               
                        case RegionItem:
                        case RegionViewNameHighlight:
                        case RegionViewName:
+                               popup_track_context_menu (1, event->button.time, where);
+                               break;
+                               
                        case SelectionItem:
+                               popup_track_context_menu (1, event->button.time, where);
+                               break;
+
                        case AutomationTrackItem:
                        case CrossfadeViewItem:
                                popup_track_context_menu (1, event->button.time, where);
@@ -1073,13 +1102,20 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        break;
                        
                case MouseAudition:
-                       switch (item_type) {
-                       case RegionItem:
-                               audition_selected_region ();
-                               break;
-                       default:
-                               break;
-                       }
+                       _scrubbing = false;
+                       if (last_scrub_frame == 0) {
+                               /* no drag, just a click */
+                               switch (item_type) {
+                               case RegionItem:
+                                       audition_selected_region ();
+                                       break;
+                               default:
+                                       break;
+                               }
+                       } else {
+                               /* make sure we stop */
+                               session->request_transport_speed (0.0);
+                       }
                        break;
 
                default:
@@ -1424,6 +1460,12 @@ Editor::left_automation_track ()
        return false;
 }
 
+static gboolean
+_update_mouse_speed (void *arg)
+{
+       return static_cast<Editor*>(arg)->update_mouse_speed ();
+}
+
 bool
 Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
 {
@@ -1455,6 +1497,66 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
        drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
                                                       &drag_info.current_pointer_y);
 
+       switch (mouse_mode) {
+       case MouseAudition:
+               if (_scrubbing) {
+                       struct timeval tmnow;
+
+                       if (last_scrub_frame == 0) {
+
+                               /* first motion, just set up the variables */
+
+                               last_scrub_frame = (nframes64_t) drag_info.current_pointer_frame;
+                               gettimeofday (&tmnow, 0);
+                               last_scrub_time = tmnow.tv_sec * 1000000.0 + tmnow.tv_usec;
+                               session->request_locate (last_scrub_frame, true);
+
+                       } else {
+                               /* how fast is the mouse moving ? */
+
+                               double speed;
+                               nframes_t distance;
+                               double time;
+                               double dir;
+
+#if 1
+                               if (last_scrub_frame < (nframes64_t) drag_info.current_pointer_frame) {
+                                       distance = (nframes64_t) drag_info.current_pointer_frame - last_scrub_frame;
+                                       dir = 1.0;
+                               } else {
+                                       distance = last_scrub_frame - (nframes64_t) drag_info.current_pointer_frame;
+                                       dir = -1.0;
+                               }
+#else
+                               if (drag_info.grab_x < drag_info.current_pointer_x) {
+                                       distance = drag_info.current_pointer_x - drag_info.grab_x;
+                                       dir = -1.0;
+                               } else {
+                                       distance = drag_info.grab_x - drag_info.current_pointer_x;
+                                       dir = 1.0;
+                               }
+#endif
+
+                               gettimeofday (&tmnow, 0);
+                               time = (tmnow.tv_sec * 1000000.0 + tmnow.tv_usec) - last_scrub_time;
+                               last_scrub_frame = drag_info.current_pointer_frame;
+                               last_scrub_time = (tmnow.tv_sec * 1000000.0) + tmnow.tv_usec;
+                               speed = ((double)distance/session->frame_rate()) / (time/1000000.0); // frames/sec
+
+                               add_mouse_speed (speed, dir);
+
+                               if (mouse_speed_update < 0) {
+                                       mouse_speed_update = g_timeout_add (10, _update_mouse_speed, this);
+                                       update_mouse_speed ();
+                               }
+                       }
+               }
+
+       default:
+               break;
+       }
+
+
        if (!from_autoscroll && drag_info.item) {
                /* item != 0 is the best test i can think of for dragging.
                */
@@ -3469,6 +3571,10 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                                        rtv->reveal_dependent_views (*latest_regionview);
                                        selection->add (latest_regionview);
                                }
+
+                               /* if the original region was locked, we don't care for the new one */
+                               
+                               newregion->set_locked (false);                  
                                
                        } else {
 
@@ -4832,6 +4938,11 @@ Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
        if (drag_info.first_move) {
                return;
        }
+
+       if (drag_info.last_pointer_frame < clicked_regionview->region()->position()) {
+               /* backwards drag of the left edge - not usable */
+               return;
+       }
        
        nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region()->position();
        float percentage = (float) ((double) newlen - (double) clicked_regionview->region()->length()) / ((double) newlen) * 100.0f;
@@ -4909,3 +5020,91 @@ Editor::track_height_step_timeout ()
        }
        return true;
 }
+
+
+void
+Editor::add_mouse_speed (double speed, double dir)
+{
+       size_t index;
+
+       mouse_direction = dir;
+
+       index = mouse_speed_entries;
+
+       if (++index >= mouse_speed_size) {
+               index = 0;
+               have_full_mouse_speed = true;
+       }
+       
+       mouse_speed[index] = speed;
+       mouse_speed_entries = index;
+}
+
+double
+Editor::compute_mouse_speed ()
+{
+       double total = 0;
+
+       if (!have_full_mouse_speed) {
+
+               /* partial speed buffer, just use whatever we have so far */
+
+               if (mouse_speed_entries == 0 ) {
+                       return 0.0;
+               }
+
+               for (size_t n = 0; n < mouse_speed_entries; ++n) {
+                       total += mouse_speed[n];
+               }
+               
+               return mouse_direction * total/mouse_speed_entries;
+       }
+
+       /* compute the average (effectively low-pass filtering) mouse speed
+          across the entire buffer.
+       */
+
+       for (size_t n = 0; n < mouse_speed_size; ++n) {
+               total += mouse_speed[n];
+       }
+
+
+       return mouse_direction * total/mouse_speed_size;
+}
+
+bool
+Editor::update_mouse_speed ()
+{
+       double speed;
+
+       if (!_scrubbing) {
+               session->request_transport_speed (0.0);
+               mouse_speed_update = -1;
+               return false;
+       }
+
+       speed = compute_mouse_speed ();
+
+       struct timeval tmnow;
+       
+       gettimeofday (&tmnow, 0);
+       double now = (tmnow.tv_sec * 1000000.0) + tmnow.tv_usec;
+
+       if (now - last_scrub_time > 250000) {
+           
+               // 0.25 seconds since last mouse motion, start to brake
+
+               if (fabs (speed) < 0.1) {
+                       /* don't asymptotically approach zero */
+                       memset (mouse_speed, 0, sizeof (double) * mouse_speed_size);
+                       speed = 0.0;
+               } else if (fabs (speed) < 0.25) {
+                       add_mouse_speed (fabs (speed * 0.2), mouse_direction);
+               } else {
+                       add_mouse_speed (fabs (speed * 0.6), mouse_direction);
+               }
+       } 
+
+       session->request_transport_speed (speed);
+       return _scrubbing;
+}
index 89068370312783e3f001d1f96b594853c5b1ed7e..ca2d7039add2db3289f5708f974506082c426bbf 100644 (file)
@@ -119,7 +119,22 @@ Editor::split_regions_at (nframes_t where, RegionSelection& regions)
 {
        begin_reversible_command (_("split"));
 
-       snap_to (where);
+       // if splitting a single region, and snap-to is using
+       // region boundaries, don't pay attention to them
+
+       if (regions.size() == 1) {
+               switch (snap_type) {
+               case SnapToRegionStart:
+               case SnapToRegionSync:
+               case SnapToRegionEnd:
+                       break;
+               default:
+                       snap_to (where);
+               }
+       } else {
+               snap_to (where);
+       }
+
        for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
 
                RegionSelection::iterator tmp;
@@ -178,16 +193,17 @@ Editor::remove_selected_regions ()
        /* XXX: should be called remove regions if we're removing more than one */
        begin_reversible_command (_("remove region"));
        
+
        while (!selection->regions.empty()) {
                boost::shared_ptr<Region> region = selection->regions.front()->region ();
                boost::shared_ptr<Playlist> playlist = region->playlist ();
-       
+
                XMLNode &before = playlist->get_state();
                playlist->remove_region (region);
                XMLNode &after = playlist->get_state();
                session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
        }
-       
+
        commit_reversible_command ();
 }
 
@@ -497,12 +513,13 @@ Editor::build_region_boundary_cache ()
                for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
 
                        if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
-                               at_end = true;
+                               if (*p == interesting_points.back()) {
+                                       at_end = true;
+                               }
                                /* move to next point type */
                                continue;
                        }
 
-                       
                        switch (*p) {
                        case Start:
                                rpos = r->first_frame();
@@ -3423,73 +3440,94 @@ Editor::reset_region_gain_envelopes ()
        session->commit_reversible_command ();
 }
 
-/** Set whether or not gain envelopes are visible for the selected regions.
- * @param yn true to make visible, false to make invisible.
- */
 void
-Editor::set_gain_envelope_visibility (bool yn)
+Editor::toggle_gain_envelope_visibility ()
 {
        for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                if (arv) {
-                       if (arv->envelope_visible() != yn) {
-                               arv->set_envelope_visible (yn);
+                       bool x = region_envelope_visible_item->get_active();
+                       if (x != arv->envelope_visible()) {
+                               arv->set_envelope_visible (x);
                        }
                }
        }
 }
 
-/** Set whether or not gain envelopes are active for the selected regions.
- * @param yn true to make active, false to make inactive.
- */
 void
-Editor::set_gain_envelope_active (bool yn)
+Editor::toggle_gain_envelope_active ()
 {
        for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
                AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                if (arv) {
-                       if (arv->audio_region()->envelope_active() != yn) {
-                               arv->audio_region()->set_envelope_active (yn);
+                       bool x = region_envelope_active_item->get_active();
+                       if (x != arv->audio_region()->envelope_active()) {
+                               arv->audio_region()->set_envelope_active (x);
                        }
                }
        }
 }
 
-/** Set the locked state of all selected regions to a particular value.
+/** Set the position-locked state of all selected regions to a particular value.
  * @param yn true to make locked, false to make unlocked.
  */
 void
-Editor::set_region_lock (bool yn)
+Editor::toggle_region_position_lock ()
 {
+       bool x = region_lock_position_item->get_active();
+
        for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
-               (*i)->region()->set_locked (yn);
+               AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+               if (arv) {
+                       if (x != arv->audio_region()->locked()) {
+                               arv->audio_region()->set_position_locked (x);
+                       }
+               }
        }
 }
 
-/** Set the position-locked state of all selected regions to a particular value.
- * @param yn true to make locked, false to make unlocked.
- */
 void
-Editor::set_region_position_lock (bool yn)
+Editor::toggle_region_lock ()
 {
+       bool x = region_lock_item->get_active();
+
        for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
-               (*i)->region()->set_position_locked (yn);
+               AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+               if (arv) {
+                       if (x != arv->audio_region()->locked()) {
+                               arv->audio_region()->set_locked (x);
+                       }
+               }
        }
 }
 
 void
-Editor::set_region_mute (bool yn)
+Editor::toggle_region_mute ()
 {
+       bool x = region_mute_item->get_active();
+
        for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
-               (*i)->region()->set_muted (yn);
+               AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+               if (arv) {
+                       if (x != arv->audio_region()->muted()) {
+                               arv->audio_region()->set_muted (x);
+                       }
+               }
        }
 }
 
 void
-Editor::set_region_opaque (bool yn)
+Editor::toggle_region_opaque ()
 {
+       bool x = region_opaque_item->get_active();
+
        for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
-               (*i)->region()->set_opaque (yn);
+               AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+               if (arv) {
+                       if (x != arv->audio_region()->opaque()) {
+                               arv->audio_region()->set_opaque (x);
+                       }
+               }
        }
 }
 
index a9df9282220c8fabd5c118a0311beec4bc53b6b6..f1001cb8e44e478ce81663e4855f7cf7c84c42bf 100644 (file)
@@ -626,8 +626,8 @@ Editor::region_list_display_drag_data_received (const RefPtr<Gdk::DragContext>&
        vector<ustring> paths;
 
        if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
-               nframes_t pos = 0;
-               do_embed (paths, false, ImportAsRegion, 0, pos, true);
+               nframes64_t pos = 0;
+               do_embed (paths, Editing::ImportDistinctFiles, ImportAsRegion, pos);
                context->drag_finish (true, false, time);
        }
 }
index e11738f65b3c0eae0cf5c126f0c300ec06f87917..5e10a578f55e899fcc8bc8663f348b441632dfca 100644 (file)
@@ -53,6 +53,10 @@ Editor::handle_new_route (Session::RouteList& routes)
        TreeModel::Row parent;
        TreeModel::Row row;
 
+       ignore_route_list_reorder = true;
+       ignore_route_order_sync = true;
+       no_route_list_redisplay = true;
+
        for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
 
@@ -100,6 +104,7 @@ Editor::handle_new_route (Session::RouteList& routes)
                row[route_display_columns.text] = route->name();
                row[route_display_columns.visible] = tv->marked_for_display();
                row[route_display_columns.tv] = tv;
+               row[route_display_columns.route] = route;
                
                track_views.push_back (tv);
                
@@ -114,11 +119,18 @@ Editor::handle_new_route (Session::RouteList& routes)
                
                ignore_route_list_reorder = false;
                
+               tv->set_old_order_key (route_display_model->children().size() - 1);
                route->gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes));
                
                tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
        }
 
+       ignore_route_list_reorder = false;
+       ignore_route_order_sync = false;
+       no_route_list_redisplay = false;
+
+       redisplay_route_list ();
+
        if (show_editor_mixer_when_tracks_arrive) {
                show_editor_mixer (true);
        }
@@ -234,6 +246,33 @@ Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::itera
        redisplay_route_list ();
 }
 
+
+void
+Editor::sync_order_keys ()
+{
+       vector<int> neworder;
+       TreeModel::Children rows = route_display_model->children();
+       TreeModel::Children::iterator ri;
+
+       if (ignore_route_order_sync || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
+               return;
+       }
+
+       for (ri = rows.begin(); ri != rows.end(); ++ri) {
+               neworder.push_back (0);
+       }
+
+       for (ri = rows.begin(); ri != rows.end(); ++ri) {
+               TimeAxisView* tv = (*ri)[route_display_columns.tv];
+               boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
+               neworder[route->order_key (X_("editor"))] = tv->old_order_key ();
+       }
+
+       ignore_route_list_reorder = true;
+       route_display_model->reorder (neworder);
+       ignore_route_list_reorder = false;
+}
+
 void
 Editor::redisplay_route_list ()
 {
@@ -288,6 +327,13 @@ Editor::redisplay_route_list ()
        cursor_group->raise_to_top ();
 
        reset_scrolling_region ();
+
+       if (Config->get_sync_all_route_ordering() && !ignore_route_list_reorder) {
+               ignore_route_order_sync = true;
+               Route::SyncOrderKeys (); // EMIT SIGNAL
+               ignore_route_order_sync = false;
+       }
+
 }
 
 void
@@ -523,6 +569,13 @@ Editor::initial_route_list_display ()
        redisplay_route_list ();
 }
 
+void
+Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
+{
+       session->set_remote_control_ids();
+       redisplay_route_list ();
+}
+
 void
 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
 {
index cfc71575104bb0a2e0c6d416834f82a925d75edf..88ff3a0c1e9452b7c991e3da4ffe5248352a388e 100644 (file)
@@ -152,14 +152,14 @@ Editor::ruler_button_press (GdkEventButton* ev)
 
        switch (ev->button) {
        case 1:
-               // Since we are about to move the playhead, cancel any running
+               // Since we will locate the playhead on button release, cancel any running
                // auditions.
                if (session->is_auditioning()) {
                        session->cancel_audition ();
                }
-               /* transport playhead */
+               /* playhead cursor */
                snap_to (where);
-               session->request_locate (where);
+               playhead_cursor->set_position (where);
                _dragging_playhead = true;
                break;
 
diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc
new file mode 100644 (file)
index 0000000..5be28e9
--- /dev/null
@@ -0,0 +1,1126 @@
+#include <vector>
+#include <cmath>
+#include <fstream>
+
+#include <glibmm.h>
+#include <pbd/xml++.h>
+
+#ifdef __APPLE__
+#include <CoreAudio/CoreAudio.h>
+#include <CoreFoundation/CFString.h>
+#include <sys/param.h>
+#include <mach-o/dyld.h>
+#else
+#include <alsa/asoundlib.h>
+#endif
+
+#include <ardour/profile.h>
+#include <jack/jack.h>
+
+#include <gtkmm/stock.h>
+#include <gtkmm2ext/utils.h>
+
+#include <pbd/convert.h>
+#include <pbd/error.h>
+
+#ifdef __APPLE
+#include <CFBundle.h>
+#endif
+
+#include "engine_dialog.h"
+#include "i18n.h"
+
+using namespace std;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+using namespace PBD;
+using namespace Glib;
+
+EngineControl::EngineControl ()
+       : periods_adjustment (2, 2, 16, 1, 2),
+         periods_spinner (periods_adjustment),
+         priority_adjustment (60, 10, 90, 1, 10),
+         priority_spinner (priority_adjustment),
+         ports_adjustment (128, 8, 1024, 1, 16),
+         ports_spinner (ports_adjustment),
+         realtime_button (_("Realtime")),
+         no_memory_lock_button (_("Do not lock memory")),
+         unlock_memory_button (_("Unlock memory")),
+         soft_mode_button (_("No zombies")),
+         monitor_button (_("Provide monitor ports")),
+         force16bit_button (_("Force 16 bit")),
+         hw_monitor_button (_("H/W monitoring")),
+         hw_meter_button (_("H/W metering")),
+         verbose_output_button (_("Verbose output")),
+         start_button (_("Start")),
+         stop_button (_("Stop")),
+#ifdef __APPLE__
+         basic_packer (5, 2),
+         options_packer (4, 2),
+         device_packer (4, 2)
+#else
+         basic_packer (8, 2),
+         options_packer (14, 2),
+         device_packer (6, 2)
+#endif   
+{
+       using namespace Notebook_Helpers;
+       Label* label;
+       vector<string> strings;
+       int row = 0;
+
+       _used = false;
+
+       strings.push_back (_("8000Hz"));
+       strings.push_back (_("22050Hz"));
+       strings.push_back (_("44100Hz"));
+       strings.push_back (_("48000Hz"));
+       strings.push_back (_("88200Hz"));
+       strings.push_back (_("96000Hz"));
+       strings.push_back (_("192000Hz"));
+       set_popdown_strings (sample_rate_combo, strings);
+       sample_rate_combo.set_active_text ("48000Hz");
+
+       strings.clear ();
+       strings.push_back ("32");
+       strings.push_back ("64");
+       strings.push_back ("128");
+       strings.push_back ("256");
+       strings.push_back ("512");
+       strings.push_back ("1024");
+       strings.push_back ("2048");
+       strings.push_back ("4096");
+       strings.push_back ("8192");
+       set_popdown_strings (period_size_combo, strings);
+       period_size_combo.set_active_text ("1024");
+
+       strings.clear ();
+       strings.push_back (_("None"));
+       strings.push_back (_("Triangular"));
+       strings.push_back (_("Rectangular"));
+       strings.push_back (_("Shaped"));
+       set_popdown_strings (dither_mode_combo, strings);
+       dither_mode_combo.set_active_text (_("None"));
+
+       /* basic parameters */
+
+       basic_packer.set_spacings (6);
+
+       strings.clear ();
+#ifdef __APPLE__
+       strings.push_back (X_("CoreAudio"));
+#else
+       strings.push_back (X_("ALSA"));
+       strings.push_back (X_("OSS"));
+       strings.push_back (X_("FFADO"));
+#endif
+       strings.push_back (X_("NetJACK"));
+       strings.push_back (X_("Dummy"));
+       set_popdown_strings (driver_combo, strings);
+       driver_combo.set_active_text (strings.front());
+
+       /* figure out available devices and set up interface_combo */
+
+       enumerate_devices ();
+       driver_combo.signal_changed().connect (mem_fun (*this, &EngineControl::driver_changed));
+       driver_changed ();
+
+       strings.clear ();
+       strings.push_back (_("Playback/Recording on 1 Device"));
+       strings.push_back (_("Playback/Recording on 2 Devices"));
+       strings.push_back (_("Playback only"));
+       strings.push_back (_("Recording only"));
+       set_popdown_strings (audio_mode_combo, strings);
+       audio_mode_combo.set_active_text (strings.front());
+
+       audio_mode_combo.signal_changed().connect (mem_fun (*this, &EngineControl::audio_mode_changed));
+       audio_mode_changed ();
+
+       row = 0;
+
+       label = manage (new Label (_("Driver")));
+       basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       row++;
+
+       label = manage (new Label (_("Interface")));
+       basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       basic_packer.attach (interface_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       row++;
+
+       label = manage (new Label (_("Sample Rate")));
+       basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       basic_packer.attach (sample_rate_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       row++;
+
+       label = manage (new Label (_("Buffer size")));
+       basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       basic_packer.attach (period_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       row++;
+
+#ifndef __APPLE__
+       label = manage (new Label (_("Number of buffers")));
+       basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       basic_packer.attach (periods_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       periods_spinner.set_value (2);
+       row++;
+#endif
+
+       label = manage (new Label (_("Approximate latency")));
+       label->set_alignment (0.0, 0.5);
+       basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       basic_packer.attach (latency_label, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       row++;
+
+       sample_rate_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
+       periods_adjustment.signal_value_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
+       period_size_combo.signal_changed().connect (mem_fun (*this, &EngineControl::redisplay_latency));
+       redisplay_latency();
+       row++;
+       /* no audio mode with CoreAudio, its duplex or nuthin' */
+
+#ifndef __APPLE__
+       label = manage (new Label (_("Audio Mode")));
+       basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       basic_packer.attach (audio_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       row++;
+#endif
+
+       interface_combo.set_size_request (125, -1);
+       input_device_combo.set_size_request (125, -1);
+       output_device_combo.set_size_request (125, -1);
+
+       /*
+
+       if (engine_running()) {
+               start_button.set_sensitive (false);
+       } else {
+               stop_button.set_sensitive (false);
+       }
+
+       start_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
+       stop_button.signal_clicked().connect (mem_fun (*this, &EngineControl::start_engine));
+       */
+
+       button_box.pack_start (start_button, false, false);
+       button_box.pack_start (stop_button, false, false);
+
+       // basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0);
+
+       /* options */
+
+       options_packer.set_spacings (6);
+       row = 0;
+
+       options_packer.attach (realtime_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+
+       realtime_button.signal_toggled().connect (mem_fun (*this, &EngineControl::realtime_changed));
+       realtime_changed ();
+
+#ifndef __APPLE__
+       label = manage (new Label (_("Realtime Priority")));
+       label->set_alignment (1.0, 0.5);
+       options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       options_packer.attach (priority_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       priority_spinner.set_value (60);
+
+       options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       options_packer.attach (hw_meter_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+#else 
+       options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+#endif
+
+       strings.clear ();
+       strings.push_back (_("Ignore"));
+       strings.push_back ("500 msec");
+       strings.push_back ("1 sec");
+       strings.push_back ("2 sec");
+       strings.push_back ("10 sec");
+       set_popdown_strings (timeout_combo, strings);
+       timeout_combo.set_active_text (strings.front ());
+
+       label = manage (new Label (_("Client timeout")));
+       label->set_alignment (1.0, 0.5);
+       options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
+       options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+
+       label = manage (new Label (_("Number of ports")));
+       label->set_alignment (1.0, 0.5);
+       options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
+       options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+
+#ifndef __APPLE__
+       label = manage (new Label (_("Dither")));       
+       label->set_alignment (1.0, 0.5);
+       options_packer.attach (dither_mode_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
+       options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+#endif
+
+       find_jack_servers (server_strings);
+
+       if (server_strings.empty()) {
+               fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg;
+               /*NOTREACHED*/
+       }
+       
+       set_popdown_strings (serverpath_combo, server_strings);
+       serverpath_combo.set_active_text (server_strings.front());
+
+       if (server_strings.size() > 1) {
+               label = manage (new Label (_("Server:")));
+               options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+               label->set_alignment (0.0, 0.5);
+               options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
+               ++row;
+       }
+
+       /* device settings */
+
+       device_packer.set_spacings (6);
+       row = 0;
+
+#ifndef __APPLE__
+       label = manage (new Label (_("Input device")));
+       label->set_alignment (1.0, 0.5);
+       device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       device_packer.attach (input_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       label = manage (new Label (_("Output device")));
+       label->set_alignment (1.0, 0.5);
+       device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       device_packer.attach (output_device_combo, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);   
+       ++row;
+#endif
+       label = manage (new Label (_("Input channels")));
+       label->set_alignment (1.0, 0.5);
+       device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       device_packer.attach (input_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       label = manage (new Label (_("Output channels")));
+       label->set_alignment (1.0, 0.5);
+       device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       device_packer.attach (output_channels, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       label = manage (new Label (_("Hardware input latency (samples)")));
+       label->set_alignment (1.0, 0.5);
+       device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       device_packer.attach (input_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+       label = manage (new Label (_("Hardware output latency (samples)")));
+       label->set_alignment (1.0, 0.5);
+       device_packer.attach (*label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       device_packer.attach (output_latency, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0);
+       ++row;
+
+       basic_hbox.pack_start (basic_packer, false, false);
+       options_hbox.pack_start (options_packer, false, false);
+
+       device_packer.set_border_width (12);
+       options_packer.set_border_width (12);
+       basic_packer.set_border_width (12);
+
+       notebook.pages().push_back (TabElem (basic_hbox, _("Device")));
+       notebook.pages().push_back (TabElem (options_hbox, _("Options")));
+       notebook.pages().push_back (TabElem (device_packer, _("Advanced")));
+       notebook.set_border_width (12);
+
+       set_border_width (12);
+       pack_start (notebook);
+}
+
+EngineControl::~EngineControl ()
+{
+
+}
+
+void
+EngineControl::build_command_line (vector<string>& cmd)
+{
+       string str;
+       string driver;
+       bool using_oss = false;
+       bool using_alsa = false;
+       bool using_coreaudio = false;
+       bool using_netjack = false;
+       bool using_ffado = false;
+
+       /* first, path to jackd */
+
+       cmd.push_back (serverpath_combo.get_active_text ());
+       
+       /* now jackd arguments */
+
+       str = timeout_combo.get_active_text ();
+       if (str != _("Ignore")) {
+               double secs;
+               uint32_t msecs;
+               atof (str);
+               msecs = (uint32_t) floor (secs * 1000.0);
+               cmd.push_back ("-t");
+               cmd.push_back (to_string (msecs, std::dec));
+       }
+
+       if (no_memory_lock_button.get_active()) {
+               cmd.push_back ("-m"); /* no munlock */
+       }
+       
+       cmd.push_back ("-p"); /* port max */
+       cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec));
+
+       if (realtime_button.get_active()) {
+               cmd.push_back ("-R");
+               cmd.push_back ("-P");
+               cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
+       }
+
+       if (unlock_memory_button.get_active()) {
+               cmd.push_back ("-u");
+       }
+
+       if (verbose_output_button.get_active()) {
+               cmd.push_back ("-v");
+       }
+       
+       /* now add fixed arguments (not user-selectable) */
+
+       cmd.push_back ("-T"); // temporary */
+
+       /* next the driver */
+
+       cmd.push_back ("-d");
+
+       driver = driver_combo.get_active_text ();
+       if (driver == X_("ALSA")) {
+               using_alsa = true;
+               cmd.push_back ("alsa");
+       } else if (driver == X_("OSS")) {
+               using_oss = true;
+               cmd.push_back ("oss");
+       } else if (driver == X_("CoreAudio")) {
+               using_coreaudio = true;
+               cmd.push_back ("coreaudio");
+       } else if (driver == X_("NetJACK")) {
+               using_netjack = true;
+               cmd.push_back ("netjack");
+       } else if (driver == X_("FFADO")) {
+               using_ffado = true;
+               cmd.push_back ("ffado");
+       }
+
+       /* driver arguments */
+
+       if (!using_coreaudio) {
+               str = audio_mode_combo.get_active_text();
+               
+               if (str == _("Playback/Recording on 1 Device")) {
+                       
+                       /* relax */
+                       
+               } else if (str == _("Playback/Recording on 2 Devices")) {
+                       
+                       cmd.push_back ("-C");
+                       cmd.push_back (get_device_name (driver, input_device_combo.get_active_text()));
+                       cmd.push_back ("-P");
+                       cmd.push_back (get_device_name (driver, output_device_combo.get_active_text()));
+                       
+               } else if (str == _("Playback only")) {
+                       cmd.push_back ("-P");
+               } else if (str == _("Recording only")) {
+                       cmd.push_back ("-C");
+               }
+
+               cmd.push_back ("-n");
+               cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
+       }
+
+       cmd.push_back ("-r");
+       cmd.push_back (to_string (get_rate(), std::dec));
+       
+       cmd.push_back ("-p");
+       cmd.push_back (period_size_combo.get_active_text());
+
+       if (using_alsa) {
+               
+               if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) {
+                       cmd.push_back ("-d");
+                       cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
+               } 
+
+               if (hw_meter_button.get_active()) {
+                       cmd.push_back ("-M");
+               }
+               
+               if (hw_monitor_button.get_active()) {
+                       cmd.push_back ("-H");
+               }
+
+               str = dither_mode_combo.get_active_text();
+
+               if (str == _("None")) {
+               } else if (str == _("Triangular")) {
+                       cmd.push_back ("-z triangular");
+               } else if (str == _("Rectangular")) {
+                       cmd.push_back ("-z rectangular");
+               } else if (str == _("Shaped")) {
+                       cmd.push_back ("-z shaped");
+               }
+
+               if (force16bit_button.get_active()) {
+                       cmd.push_back ("-S");
+               }
+               
+               if (soft_mode_button.get_active()) {
+                       cmd.push_back ("-s");
+               }
+
+       } else if (using_coreaudio) {
+
+#ifdef __APPLE__
+               // note: older versions of the CoreAudio JACK backend use -n instead of -d here
+               cmd.push_back ("-d");
+               cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
+#endif
+
+       } else if (using_oss) {
+
+       } else if (using_netjack) {
+
+       }
+}
+
+bool
+EngineControl::engine_running ()
+{
+       jack_status_t status;
+       jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
+
+       if (status == 0) {
+               jack_client_close (c);
+               return true;
+       }
+       return false;
+}
+
+int
+EngineControl::setup_engine ()
+{
+       vector<string> args;
+       std::string cwd = "/tmp";
+
+       build_command_line (args);
+
+       Glib::ustring jackdrc_path = Glib::get_home_dir();
+       jackdrc_path += "/.jackdrc";
+
+       ofstream jackdrc (jackdrc_path.c_str());
+       if (!jackdrc) {
+               error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
+               return -1;
+       }
+
+       for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
+               jackdrc << (*i) << ' ';
+       }
+       jackdrc << endl;
+       jackdrc.close ();
+
+       _used = true;
+
+       return 0;
+}
+
+void
+EngineControl::realtime_changed ()
+{
+#ifndef __APPLE__
+       priority_spinner.set_sensitive (realtime_button.get_active());
+#endif
+}
+
+void
+EngineControl::enumerate_devices ()
+{
+       /* note: case matters for the map keys */
+
+#ifdef __APPLE__
+       devices["CoreAudio"] = enumerate_coreaudio_devices ();
+#else
+       devices["ALSA"] = enumerate_alsa_devices ();
+       devices["FFADO"] = enumerate_ffado_devices ();
+       devices["OSS"] = enumerate_oss_devices ();
+       devices["Dummy"] = enumerate_dummy_devices ();
+       devices["NetJACK"] = enumerate_netjack_devices ();
+#endif
+}
+
+#ifdef __APPLE__
+static OSStatus 
+getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
+{
+       UInt32 size = sizeof(CFStringRef);
+       CFStringRef UI;
+       OSStatus res = AudioDeviceGetProperty(id, 0, false,
+               kAudioDevicePropertyDeviceUID, &size, &UI);
+       if (res == noErr) 
+               CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
+       CFRelease(UI);
+       return res;
+}
+
+vector<string>
+EngineControl::enumerate_coreaudio_devices ()
+{
+       vector<string> devs;
+       
+       // Find out how many Core Audio devices are there, if any...
+       // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
+       OSStatus err;
+       Boolean isWritable;
+       size_t outSize = sizeof(isWritable);
+
+       backend_devs.clear ();
+
+       err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
+                                          &outSize, &isWritable);
+       if (err == noErr) {
+               // Calculate the number of device available...
+               int numCoreDevices = outSize / sizeof(AudioDeviceID);
+               // Make space for the devices we are about to get...
+               AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
+               err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
+                                              &outSize, (void *) coreDeviceIDs);
+               if (err == noErr) {
+                       // Look for the CoreAudio device name...
+                       char coreDeviceName[256];
+                       size_t nameSize;
+                       for (int i = 0; i < numCoreDevices; i++) {
+
+                               nameSize = sizeof (coreDeviceName);
+
+                               err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
+                                                                0, true, kAudioDevicePropertyDeviceName,
+                                                                &outSize, &isWritable);
+                               if (err == noErr) {
+                                       err = AudioDeviceGetProperty(coreDeviceIDs[i],
+                                                                    0, true, kAudioDevicePropertyDeviceName,
+                                                                    &nameSize, (void *) coreDeviceName);
+                                       if (err == noErr) {
+                                               char drivername[128];
+
+                                               // this returns the unique id for the device
+                                               // that must be used on the commandline for jack
+                                               
+                                               if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
+                                                       devs.push_back (coreDeviceName);
+                                                       backend_devs.push_back (drivername);
+                                               } 
+                                       }
+                               }
+                       }
+               }
+               delete [] coreDeviceIDs;
+       }
+
+       return devs;
+}
+#else
+vector<string>
+EngineControl::enumerate_alsa_devices ()
+{
+       vector<string> devs;
+
+       snd_ctl_t *handle;
+       snd_ctl_card_info_t *info;
+       snd_pcm_info_t *pcminfo;
+       snd_ctl_card_info_alloca(&info);
+       snd_pcm_info_alloca(&pcminfo);
+       string devname;
+       int cardnum = -1;
+       int device = -1;
+
+       backend_devs.clear ();
+
+       while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
+
+               devname = "hw:";
+               devname += to_string (cardnum, std::dec);
+
+               if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
+
+                       while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
+
+                               bool have_playback = false;
+                               bool have_capture = false;
+
+                               /* find duplex devices only */
+
+                               snd_pcm_info_set_device (pcminfo, device);
+                               snd_pcm_info_set_subdevice (pcminfo, 0);
+                               snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
+
+                               if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
+                                       have_capture = true;
+                               }
+
+                               snd_pcm_info_set_device (pcminfo, device);
+                               snd_pcm_info_set_subdevice (pcminfo, 0);
+                               snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
+
+                               if (snd_ctl_pcm_info (handle, pcminfo) >= 0) {
+                                       have_playback = true;
+                               }
+
+                               if (have_capture && have_playback) {
+                                       devs.push_back (snd_pcm_info_get_name (pcminfo));
+                                       devname += ',';
+                                       devname += to_string (device, std::dec);
+                                       backend_devs.push_back (devname);
+                               }
+                       }
+
+                       snd_ctl_close(handle);
+               }
+       }
+
+       return devs;
+}
+
+vector<string>
+EngineControl::enumerate_ffado_devices ()
+{
+       vector<string> devs;
+       return devs;
+}
+vector<string>
+EngineControl::enumerate_oss_devices ()
+{
+       vector<string> devs;
+       return devs;
+}
+vector<string>
+EngineControl::enumerate_dummy_devices ()
+{
+       vector<string> devs;
+       return devs;
+}
+vector<string>
+EngineControl::enumerate_netjack_devices ()
+{
+       vector<string> devs;
+       return devs;
+}
+#endif
+
+void
+EngineControl::driver_changed ()
+{
+       string driver = driver_combo.get_active_text();
+       vector<string>& strings = devices[driver];
+       string::size_type maxlen = 0;
+       int maxindex = -1;
+       int n = 0;
+
+       for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
+               if ((*i).length() > maxlen) {
+                       maxlen = (*i).length();
+                       maxindex = n;
+               }
+       }
+
+       set_popdown_strings (interface_combo, strings);
+       set_popdown_strings (input_device_combo, strings);
+       set_popdown_strings (output_device_combo, strings);
+
+       if (!strings.empty()) {
+               interface_combo.set_active_text (strings.front());
+               input_device_combo.set_active_text (strings.front());
+               output_device_combo.set_active_text (strings.front());
+       }
+       
+       if (driver == "ALSA") {
+               soft_mode_button.set_sensitive (true);
+               force16bit_button.set_sensitive (true);
+               hw_monitor_button.set_sensitive (true);
+               hw_meter_button.set_sensitive (true);
+               monitor_button.set_sensitive (true);
+       } else {
+               soft_mode_button.set_sensitive (false);
+               force16bit_button.set_sensitive (false);
+               hw_monitor_button.set_sensitive (false);
+               hw_meter_button.set_sensitive (false);
+               monitor_button.set_sensitive (false);
+       }
+}
+
+uint32_t
+EngineControl::get_rate ()
+{
+       return atoi (sample_rate_combo.get_active_text ());
+}
+
+void
+EngineControl::redisplay_latency ()
+{
+       uint32_t rate = get_rate();
+#ifdef __APPLE_
+       float periods = 2;
+#else
+       float periods = periods_adjustment.get_value();
+#endif
+       float period_size = atof (period_size_combo.get_active_text());
+
+       char buf[32];
+       snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0));
+
+       latency_label.set_text (buf);
+}
+
+void
+EngineControl::audio_mode_changed ()
+{
+       Glib::ustring str = audio_mode_combo.get_active_text();
+
+       if (str == _("Playback/Recording on 1 Device")) {
+               input_device_combo.set_sensitive (false);
+               output_device_combo.set_sensitive (false);
+       } else if (str == _("Playback/Recording on 2 Devices")) {
+               input_device_combo.set_sensitive (true);
+               output_device_combo.set_sensitive (true);
+       } else if (str == _("Playback only")) {
+               output_device_combo.set_sensitive (true);
+       } else if (str == _("Recording only")) {
+               input_device_combo.set_sensitive (true);
+       }
+}
+
+void
+EngineControl::find_jack_servers (vector<string>& strings)
+{
+#ifdef __APPLE__
+       /* this magic lets us finds the path to the OSX bundle, and then
+          we infer JACK's location from there
+       */
+       
+       char execpath[MAXPATHLEN+1];
+       uint32_t pathsz = sizeof (execpath);
+
+       _NSGetExecutablePath (execpath, &pathsz);
+       
+       cerr << " execpath = " << execpath << endl;
+
+       Glib::ustring path (Glib::path_get_dirname (execpath));
+       path += "/jackd";
+
+       if (Glib::file_test (path, FILE_TEST_EXISTS)) {
+               strings.push_back (path);
+               cerr << "Found jack in " << path << endl;
+       } 
+
+       if (getenv ("ARDOUR_WITH_JACK")) {
+               /* no other options - only use the JACK we supply */
+               if (strings.empty()) {
+                       fatal << _("JACK appears to be missing from the Ardour bundle") << endmsg;
+                       /*NOTREACHED*/
+               }
+               return;
+       }
+#endif
+       
+       if (Glib::file_test ("/usr/bin/jackd", FILE_TEST_EXISTS)) {
+               strings.push_back ("/usr/bin/jackd");
+       }
+       if (Glib::file_test ("/usr/local/bin/jackd", FILE_TEST_EXISTS)) {
+               strings.push_back ("/usr/local/bin/jackd");
+       }
+       if (Glib::file_test ("/opt/bin/jackd", FILE_TEST_EXISTS)) {
+               strings.push_back ("/opt/bin/jackd");
+       }
+       if (Glib::file_test ("/usr/bin/jackdmp", FILE_TEST_EXISTS)) {
+               strings.push_back ("/usr/bin/jackd");
+       }
+       if (Glib::file_test ("/usr/local/bin/jackdmp", FILE_TEST_EXISTS)) {
+               strings.push_back ("/usr/local/bin/jackd");
+       }
+       if (Glib::file_test ("/opt/bin/jackdmp", FILE_TEST_EXISTS)) {
+               strings.push_back ("/opt/bin/jackd");
+       }
+
+}
+
+string
+EngineControl::get_device_name (const string& driver, const string& human_readable)
+{
+       vector<string>::iterator n;
+       vector<string>::iterator i;
+
+       if (backend_devs.empty()) {
+               return human_readable;
+       }
+       
+       for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) {
+               if (human_readable == (*i)) {
+                       return (*n);
+               }
+       }
+       
+       if (i == devices[driver].end()) {
+               fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
+               /*NOTREACHED*/
+       }
+
+       /* keep gcc happy */
+
+       return string();
+}
+
+XMLNode&
+EngineControl::get_state ()
+{
+       XMLNode* root = new XMLNode ("AudioSetup");
+       XMLNode* child;
+       Glib::ustring path;
+
+       child = new XMLNode ("periods");
+       child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("priority");
+       child->add_property ("val", to_string (priority_adjustment.get_value(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("ports");
+       child->add_property ("val", to_string (ports_adjustment.get_value(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("inchannels");
+       child->add_property ("val", to_string (input_channels.get_value(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("outchannels");
+       child->add_property ("val", to_string (output_channels.get_value(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("inlatency");
+       child->add_property ("val", to_string (input_latency.get_value(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("outlatency");
+       child->add_property ("val", to_string (output_latency.get_value(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("realtime");
+       child->add_property ("val", to_string (realtime_button.get_active(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("nomemorylock");
+       child->add_property ("val", to_string (no_memory_lock_button.get_active(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("unlockmemory");
+       child->add_property ("val", to_string (unlock_memory_button.get_active(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("softmode");
+       child->add_property ("val", to_string (soft_mode_button.get_active(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("force16bit");
+       child->add_property ("val", to_string (force16bit_button.get_active(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("hwmonitor");
+       child->add_property ("val", to_string (hw_monitor_button.get_active(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("hwmeter");
+       child->add_property ("val", to_string (hw_meter_button.get_active(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("verbose");
+       child->add_property ("val", to_string (verbose_output_button.get_active(), std::dec));
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("samplerate");
+       child->add_property ("val", sample_rate_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("periodsize");
+       child->add_property ("val", period_size_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("serverpath");
+       child->add_property ("val", serverpath_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("driver");
+       child->add_property ("val", driver_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("interface");
+       child->add_property ("val", interface_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("timeout");
+       child->add_property ("val", timeout_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("dither");
+       child->add_property ("val", dither_mode_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("audiomode");
+       child->add_property ("val", audio_mode_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("inputdevice");
+       child->add_property ("val", input_device_combo.get_active_text());
+       root->add_child_nocopy (*child);
+
+       child = new XMLNode ("outputdevice");
+       child->add_property ("val", output_device_combo.get_active_text());
+       root->add_child_nocopy (*child);
+       
+       return *root;
+}
+
+void
+EngineControl::set_state (const XMLNode& root)
+{
+       XMLNodeList          clist;
+       XMLNodeConstIterator citer;
+       XMLNode* child;
+       XMLProperty* prop;
+
+       int val;
+       string strval;
+
+       clist = root.children();
+
+       for (citer = clist.begin(); citer != clist.end(); ++citer) {
+
+               child = *citer;
+
+               prop = child->property ("val");
+
+               if (!prop || prop->value().empty()) {
+                       error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
+                       continue;
+               }
+               
+               strval = prop->value();
+
+               /* adjustments/spinners */
+
+               if (child->name() == "periods") {
+                       val = atoi (strval);
+                       periods_adjustment.set_value(val);
+               } else if (child->name() == "priority") {
+                       val = atoi (strval);
+                       priority_adjustment.set_value(val);
+               } else if (child->name() == "ports") {
+                       val = atoi (strval);
+                       ports_adjustment.set_value(val);
+               } else if (child->name() == "inchannels") {
+                       val = atoi (strval);
+                       input_channels.set_value(val);
+               } else if (child->name() == "outchannels") {
+                       val = atoi (strval);
+                       output_channels.set_value(val);
+               } else if (child->name() == "inlatency") {
+                       val = atoi (strval);
+                       input_latency.set_value(val);
+               } else if (child->name() == "outlatency") {
+                       val = atoi (strval);
+                       output_latency.set_value(val);
+               }
+
+               /* buttons */
+
+               else if (child->name() == "realtime") {
+                       val = atoi (strval);
+                       realtime_button.set_active(val);
+               } else if (child->name() == "nomemorylock") {
+                       val = atoi (strval);
+                       no_memory_lock_button.set_active(val);
+               } else if (child->name() == "unlockmemory") {
+                       val = atoi (strval);
+                       unlock_memory_button.set_active(val);
+               } else if (child->name() == "softmode") {
+                       val = atoi (strval);
+                       soft_mode_button.set_active(val);
+               } else if (child->name() == "force16bit") {
+                       val = atoi (strval);
+                       force16bit_button.set_active(val);
+               } else if (child->name() == "hwmonitor") {
+                       val = atoi (strval);
+                       hw_monitor_button.set_active(val);
+               } else if (child->name() == "hwmeter") {
+                       val = atoi (strval);
+                       hw_meter_button.set_active(val);
+               } else if (child->name() == "verbose") {
+                       val = atoi (strval);
+                       verbose_output_button.set_active(val);
+               }
+
+               /* combos */
+
+               else if (child->name() == "samplerate") {
+                       sample_rate_combo.set_active_text(strval);
+               } else if (child->name() == "periodsize") {
+                       period_size_combo.set_active_text(strval);
+               } else if (child->name() == "serverpath") {
+                       /* do not allow us to use a server path that doesn't
+                          exist on this system. this handles cases where
+                          the user has an RC file listing a serverpath
+                          from some other machine.
+                       */
+                       vector<string>::iterator x;
+                       for (x = server_strings.begin(); x != server_strings.end(); ++x) {
+                               if (*x == strval) {
+                                       break;
+                               }
+                       }
+                       if (x != server_strings.end()) {
+                               serverpath_combo.set_active_text (strval);
+                       } else {
+                               warning << string_compose (_("configuration files contain a JACK server path that doesn't exist (%1)"),
+                                                            strval)
+                                       << endmsg;
+                       }
+               } else if (child->name() == "driver") {
+                       driver_combo.set_active_text(strval);
+               } else if (child->name() == "interface") {
+                       interface_combo.set_active_text(strval);
+               } else if (child->name() == "timeout") {
+                       timeout_combo.set_active_text(strval);
+               } else if (child->name() == "dither") {
+                       dither_mode_combo.set_active_text(strval);
+               } else if (child->name() == "audiomode") {
+                       audio_mode_combo.set_active_text(strval);
+               } else if (child->name() == "inputdevice") {
+                       input_device_combo.set_active_text(strval);
+               } else if (child->name() == "outputdevice") {
+                       output_device_combo.set_active_text(strval);
+               }
+       }
+}
diff --git a/gtk2_ardour/engine_dialog.h b/gtk2_ardour/engine_dialog.h
new file mode 100644 (file)
index 0000000..925d12a
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef __gtk2_ardour_engine_dialog_h__
+#define __gtk2_ardour_engine_dialog_h__
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include <gtkmm/checkbutton.h>
+#include <gtkmm/spinbutton.h>
+#include <gtkmm/notebook.h>
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/table.h>
+#include <gtkmm/expander.h>
+#include <gtkmm/box.h>
+#include <gtkmm/buttonbox.h>
+#include <gtkmm/button.h>
+
+class EngineControl : public Gtk::VBox {
+  public:
+       EngineControl ();
+       ~EngineControl ();
+
+       static bool engine_running ();
+       int setup_engine ();
+
+       bool was_used() const { return _used; }
+       XMLNode& get_state ();
+       void set_state (const XMLNode&);
+
+  private:
+       Gtk::Adjustment periods_adjustment;
+       Gtk::SpinButton periods_spinner;
+       Gtk::Adjustment priority_adjustment;
+       Gtk::SpinButton priority_spinner;
+       Gtk::Adjustment ports_adjustment;
+       Gtk::SpinButton ports_spinner;
+       Gtk::SpinButton input_channels;
+       Gtk::SpinButton output_channels;
+       Gtk::SpinButton input_latency;
+       Gtk::SpinButton output_latency;
+       Gtk::Label latency_label;
+
+       Gtk::CheckButton realtime_button;
+       Gtk::CheckButton no_memory_lock_button;
+       Gtk::CheckButton unlock_memory_button;
+       Gtk::CheckButton soft_mode_button;
+       Gtk::CheckButton monitor_button;
+       Gtk::CheckButton force16bit_button;
+       Gtk::CheckButton hw_monitor_button;
+       Gtk::CheckButton hw_meter_button;
+       Gtk::CheckButton verbose_output_button;
+       
+       Gtk::Button start_button;
+       Gtk::Button stop_button;
+       Gtk::HButtonBox button_box;
+
+       Gtk::ComboBoxText sample_rate_combo;
+       Gtk::ComboBoxText period_size_combo;
+
+       Gtk::ComboBoxText preset_combo;
+       Gtk::ComboBoxText serverpath_combo;
+       Gtk::ComboBoxText driver_combo;
+       Gtk::ComboBoxText interface_combo;
+       Gtk::ComboBoxText timeout_combo;
+       Gtk::ComboBoxText dither_mode_combo;
+       Gtk::ComboBoxText audio_mode_combo;
+       Gtk::ComboBoxText input_device_combo;
+       Gtk::ComboBoxText output_device_combo;
+
+       Gtk::Table basic_packer;
+       Gtk::Table options_packer;
+       Gtk::Table device_packer;
+       Gtk::HBox basic_hbox;
+       Gtk::HBox options_hbox;
+       Gtk::HBox device_hbox;
+       Gtk::Notebook notebook;
+       
+       bool _used;
+
+       void realtime_changed ();
+       void driver_changed ();
+       void build_command_line (std::vector<std::string>&);
+
+       std::map<std::string,std::vector<std::string> > devices;
+       std::vector<std::string> backend_devs;
+       void enumerate_devices ();
+
+#ifdef __APPLE__
+       std::vector<std::string> enumerate_coreaudio_devices ();
+#else
+       std::vector<std::string> enumerate_alsa_devices ();
+       std::vector<std::string> enumerate_oss_devices ();
+       std::vector<std::string> enumerate_netjack_devices ();
+       std::vector<std::string> enumerate_ffado_devices ();
+       std::vector<std::string> enumerate_dummy_devices ();
+#endif 
+
+       void redisplay_latency ();
+       uint32_t get_rate();
+       void audio_mode_changed ();
+       std::vector<std::string> server_strings;
+       void find_jack_servers (std::vector<std::string>&);
+       std::string get_device_name (const std::string& driver, const std::string& human_readable_name);
+};
+
+#endif /* __gtk2_ardour_engine_dialog_h__ */
index e6c81598fb905aa68d3f69b53dcf0b3aa0f3a1b9..c33b2965c37f92022ddc162211ee6c3871c51ff9 100644 (file)
 #include <pbd/enumwriter.h>
 
 #include "audio_clock.h"
+#include "editing.h"
 #include "enums.h"
 
 using namespace std;
 using namespace PBD;
 using namespace ARDOUR;
+using namespace Editing;
 
 void
 setup_gtk_ardour_enums ()
@@ -35,6 +37,7 @@ setup_gtk_ardour_enums ()
 
        AudioClock::Mode clock_mode;
        Width width;
+       ImportMode import_mode;
 
 #define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
 #define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
@@ -51,4 +54,10 @@ setup_gtk_ardour_enums ()
        REGISTER_ENUM (Wide);
        REGISTER_ENUM (Narrow);
        REGISTER (width);
+
+       REGISTER_ENUM (ImportAsTrack);
+       REGISTER_ENUM (ImportToTrack);
+       REGISTER_ENUM (ImportAsRegion);
+       REGISTER_ENUM (ImportAsTapeTrack);
+       REGISTER (import_mode);
 }
index 90fea321de89320a5500bcacbfa12c6662182088..e6eaffefcbfd0e1fc6807410802991bd9a027418 100644 (file)
@@ -48,14 +48,14 @@ uint32_t Keyboard::Shift = GDK_SHIFT_MASK;
 uint32_t Keyboard::Alt = GDK_MOD1_MASK;
 uint32_t Keyboard::Meta;
 
-Keyboard* Keyboard::_the_keyboard = 0;
+Keyboard*    Keyboard::_the_keyboard = 0;
+Gtk::Window* Keyboard::current_window = 0;
+bool         Keyboard::_some_magic_widget_has_focus = false;
 
 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
 
 GdkModifierType Keyboard::RelevantModifierKeyMask;
 
-bool Keyboard::_some_magic_widget_has_focus = false;
-
 void
 Keyboard::magic_widget_grab_focus () 
 {
@@ -199,6 +199,13 @@ Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
 
        }
 
+       if (event->type == GDK_KEY_RELEASE && event->keyval == GDK_w && modifier_state_equals (event->state, Control)) {
+               if (current_window) {
+                       current_window->hide ();
+                       current_window = 0;
+               }
+       }
+
        return false;
 }
 
@@ -211,6 +218,7 @@ Keyboard::key_is_down (uint32_t keyval)
 bool
 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
 {
+       current_window = win;
        return false;
 }
 
@@ -236,6 +244,7 @@ Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
                        cerr << "clearing current target\n";
                }
                state.clear ();
+               current_window = 0;
        }
 
        return false;
index 3d9e1c9f41e254091033de37d3b56500185b713e..fb22f2eca9d9bef1868ee893ba876f483948d489 100644 (file)
@@ -105,6 +105,7 @@ class Keyboard : public sigc::trackable, PBD::Stateful
        static guint     delete_but;
        static guint     delete_mod;
        static guint     snap_mod;
+       static Gtk::Window* current_window;
 
        static gint _snooper (GtkWidget*, GdkEventKey*, gpointer);
        gint snooper (GtkWidget*, GdkEventKey*);
index 67e59d4b80749336bc35bd1b3303598b46cc245e..1e9b27d8a7eac1178f3c829120529cf131b7e719 100644 (file)
@@ -47,7 +47,7 @@
 #include "i18n.h"
 
 using namespace Gtk;
-using namespace GTK_ARDOUR;
+using namespace ARDOUR_COMMAND_LINE;
 using namespace ARDOUR;
 using namespace PBD;
 using namespace sigc;
@@ -57,6 +57,7 @@ TextReceiver text_receiver ("ardour");
 extern int curvetest (string);
 
 static ARDOUR_UI  *ui = 0;
+static char* localedir = LOCALEDIR;
 
 gint
 show_ui_callback (void *arg)
@@ -98,65 +99,129 @@ Please consider the possibilities, and perhaps (re)start JACK."));
        win.run ();
 }
 
-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()) {
-                       if (!ui->new_session ()) {
-                               return false;
-                       }
-               }
 
-               return true;
+#ifdef __APPLE__
+
+#include <mach-o/dyld.h>
+#include <sys/param.h>
+#include <fstream>
+
+void
+fixup_bundle_environment ()
+{
+       if (!getenv ("ARDOUR_BUNDLED")) {
+               return;
        }
 
-       /* Load session or start the new session dialog */
-       string name, path;
+       char execpath[MAXPATHLEN+1];
+       uint32_t pathsz = sizeof (execpath);
 
-       bool isnew;
+       _NSGetExecutablePath (execpath, &pathsz);
 
-       if (find_session (session_name, path, name, isnew)) {
-               error << string_compose(_("could not load command line session \"%1\""), session_name) << endmsg;
-               return false;
+       Glib::ustring exec_path (execpath);
+       Glib::ustring dir_path = Glib::path_get_dirname (exec_path);
+       Glib::ustring path;
+       const char *cstr = getenv ("PATH");
+
+       /* ensure that we find any bundled executables (e.g. JACK) */
+
+       path = dir_path;
+       if (cstr) {
+               path += ':';
+               path += cstr;
        }
+       setenv ("PATH", path.c_str(), 1);
+
+       path = dir_path;
+       path += "/../Resources";
+       path += dir_path;
+       path += "/../Resources/Surfaces";
+       path += dir_path;
+       path += "/../Resources/Panners";
+
+       setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
+
+       path = dir_path;
+       path += "/../Resources/icons:";
+       path += dir_path;
+       path += "/../Resources/pixmaps:";
+       path += dir_path;
+       path += "/../Resources/share:";
+       path += dir_path;
+       path += "/../Resources";
+
+       setenv ("ARDOUR_PATH", path.c_str(), 1);
+       setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
+       setenv ("ARDOUR_DATA_PATH", path.c_str(), 1);
+
+       cstr = getenv ("LADSPA_PATH");
+       if (cstr) {
+               path = cstr;
+               path += ':';
+       }
+       path = dir_path;
+       path += "/../Plugins";
+       
+       setenv ("LADSPA_PATH", path.c_str(), 1);
 
-       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;
-               }
+       path = dir_path;
+       path += "/../Frameworks/clearlooks";
 
-               if (ui->load_session (path, name)) {
-                       /* it failed */
-                       return false;
-               }
+       setenv ("GTK_PATH", path.c_str(), 1);
 
-       } else {
+       path = dir_path;
+       path += "/../Resources/locale";
+       
+       localedir = strdup (path.c_str());
+
+       /* write a pango.rc file and tell pango to use it */
 
-               /*  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); 
-               */
+       path = dir_path;
+       path += "/../Resources/pango.rc";
+
+       std::ofstream pangorc (path.c_str());
+       if (!pangorc) {
+               error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
+       } else {
+               pangorc << "[Pango]\nModuleFiles=";
+               Glib::ustring mpath = dir_path;
+               mpath += "/../Resources/pango.modules";
+               pangorc << mpath << endl;
                
-               /* Show the NSD */
-               ui->hide_splash ();
-               if (!Config->get_no_new_session_dialog()) {
-                       if (!ui->new_session ()) {
-                               return false;
-                       }
-               }
+               pangorc.close ();
+               setenv ("PANGO_RC_FILE", path.c_str(), 1);
        }
 
-       return true;
+       // gettext charset aliases
+
+       setenv ("CHARSETALIASDIR", path.c_str(), 1);
+
+       // font config
+       
+       path = dir_path;
+       path += "/../Resources/fonts.conf";
+
+       setenv ("FONTCONFIG_FILE", path.c_str(), 1);
+
+       // GDK Pixbuf loader module file
+
+       path = dir_path;
+       path += "/../Resources/gdk-pixbuf.loaders";
+
+       setenv ("GDK_PIXBUF_MODULE_FILE", path.c_str(), 1);
+
+       if (getenv ("ARDOUR_WITH_JACK")) {
+               // JACK driver dir
+               
+               path = dir_path;
+               path += "/../Frameworks";
+               
+               setenv ("JACK_DRIVER_DIR", path.c_str(), 1);
+       }
 }
 
+#endif
+
 #ifdef VST_SUPPORT
 /* this is called from the entry point of a wine-compiled
    executable that is linked against gtk2_ardour built
@@ -167,15 +232,17 @@ int ardour_main (int argc, char *argv[])
 #else
 int main (int argc, char *argv[])
 #endif
-
 {
-       ARDOUR::AudioEngine *engine = NULL;
        vector<Glib::ustring> null_file_list;
 
-       Glib::thread_init();
+#ifdef __APPLE__
+       fixup_bundle_environment ();
+#endif
+
+        Glib::thread_init();
        gtk_set_locale ();
 
-       (void) bindtextdomain (PACKAGE, LOCALEDIR);
+       (void) bindtextdomain (PACKAGE, localedir);
        /* our i18n translations are all in UTF-8, so make sure
           that even if the user locale doesn't specify UTF-8,
           we use that when handling them.
@@ -229,17 +296,13 @@ int main (int argc, char *argv[])
 
        PBD::ID::init ();
 
-       try { 
+        try { 
                ui = new ARDOUR_UI (&argc, &argv);
        } catch (failed_constructor& err) {
                error << _("could not create ARDOUR GUI") << endmsg;
                exit (1);
        }
 
-       if (!keybindings_path.empty()) {
-               ui->set_keybindings_path (keybindings_path);
-       }
-
        if (!no_splash) {
                ui->show_splash ();
                if (session_name.length()) {  
@@ -247,50 +310,17 @@ int main (int argc, char *argv[])
                }
        }
 
-    try {
-               ARDOUR::init (use_vst, try_hw_optimization);
-               setup_gtk_ardour_enums ();
-               Config->set_current_owner (ConfigVariableBase::Interface);
-               ui->setup_profile ();
-
-               try { 
-                       engine = new ARDOUR::AudioEngine (jack_client_name);
-               } catch (AudioEngine::NoBackendAvailable& err) {
-                       gui_jack_error ();
-                       error << string_compose (_("Could not connect to JACK server as  \"%1\""), jack_client_name) <<  endmsg;
-                       return -1;
-               }
-
-               ARDOUR::setup_midi(*engine);
-               
-               ui->set_engine (*engine);
-
-       } catch (failed_constructor& err) {
-               error << _("could not initialize Ardour.") << endmsg;
-               return -1;
-       } 
-
-       ui->start_engine ();
-
-       if (maybe_load_session ()) {
-               ui->run (text_receiver);
-               ui = 0;
+       if (!keybindings_path.empty()) {
+               ui->set_keybindings_path (keybindings_path);
        }
 
-       delete engine;
-       ARDOUR::cleanup ();
+       ui->run (text_receiver);
+       ui = 0;
 
-       if (ui) {
-               ui->kill();
-       }
-               
+       ARDOUR::cleanup ();
        pthread_cancel_all ();
-
-       exit (0);
-
        return 0;
 }
 #ifdef VST_SUPPORT
 } // end of extern C block
 #endif
-
index dfe5a268fa0080e47e466120d72297b8cbbe7c8c..f791314d7519fa0b94288948a39d84e98681479e 100644 (file)
@@ -1227,19 +1227,19 @@ MixerStrip::route_active_changed ()
        } else if (is_audio_track()) {
                if (_route->active()) {
                        set_name ("AudioTrackStripBase");
-                       gpm.set_meter_strip_name ("AudioTrackStripBase");
+                       gpm.set_meter_strip_name ("AudioTrackMetrics");
                } else {
                        set_name ("AudioTrackStripBaseInactive");
-                       gpm.set_meter_strip_name ("AudioTrackStripBaseInactive");
+                       gpm.set_meter_strip_name ("AudioTrackMetricsInactive");
                }
                gpm.set_fader_name ("AudioTrackFader");
        } else {
                if (_route->active()) {
                        set_name ("AudioBusStripBase");
-                       gpm.set_meter_strip_name ("AudioBusStripBase");
+                       gpm.set_meter_strip_name ("AudioBusMetrics");
                } else {
                        set_name ("AudioBusStripBaseInactive");
-                       gpm.set_meter_strip_name ("AudioBusStripBaseInactive");
+                       gpm.set_meter_strip_name ("AudioBusMetricsInactive");
                }
                gpm.set_fader_name ("AudioBusFader");
                
index 89d7ef5cc4558f860944088ccdfbaa5c5f8b286e..e3f6cae6ac8b4165abb5698c735123997d9f1f9d 100644 (file)
@@ -61,12 +61,17 @@ using PBD::atoi;
 Mixer_UI::Mixer_UI ()
        : Window (Gtk::WINDOW_TOPLEVEL)
 {
+       session = 0;
        _strip_width = Wide;
        track_menu = 0;
        mix_group_context_menu = 0;
        no_track_list_redisplay = false;
        in_group_row_change = false;
        _visible = false;
+       ignore_route_reorder = false;
+       ignore_sync = false;
+
+       Route::SyncOrderKeys.connect (mem_fun (*this, &Mixer_UI::sync_order_keys));
 
        scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
        scroller_base.set_name ("MixerWindow");
@@ -92,6 +97,7 @@ Mixer_UI::Mixer_UI ()
 
        track_model->signal_row_deleted().connect (mem_fun (*this, &Mixer_UI::track_list_delete));
        track_model->signal_row_changed().connect (mem_fun (*this, &Mixer_UI::track_list_change));
+       track_model->signal_rows_reordered().connect (mem_fun (*this, &Mixer_UI::track_list_reorder));
 
        CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
        track_list_visible_cell->property_activatable() = true;
@@ -318,6 +324,8 @@ Mixer_UI::add_strip (Session::RouteList& routes)
                row[track_columns.route] = route;
                row[track_columns.strip] = strip;
                
+               strip->set_old_order_key (track_model->children().size() - 1);
+
                no_track_list_redisplay = false;
                redisplay_track_list ();
                
@@ -349,6 +357,42 @@ Mixer_UI::remove_strip (MixerStrip* strip)
        }
 }
 
+const char*
+Mixer_UI::get_order_key() 
+{
+       if (Config->get_sync_all_route_ordering()) {
+               return X_("editor");
+       } else {
+               return X_("signal");
+       }
+}
+
+void
+Mixer_UI::sync_order_keys ()
+{
+       vector<int> neworder;
+       TreeModel::Children rows = track_model->children();
+       TreeModel::Children::iterator ri;
+
+       if (ignore_sync || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
+               return;
+       }
+
+       for (ri = rows.begin(); ri != rows.end(); ++ri) {
+               neworder.push_back (0);
+       }
+
+       for (ri = rows.begin(); ri != rows.end(); ++ri) {
+               boost::shared_ptr<Route> route = (*ri)[track_columns.route];
+               MixerStrip* strip = (*ri)[track_columns.strip];
+               neworder[route->order_key (get_order_key())] = strip->old_order_key ();
+       }
+
+       ignore_route_reorder = true;
+       track_model->reorder (neworder);
+       ignore_route_reorder = false;
+}
+
 void
 Mixer_UI::follow_strip_selection ()
 {
@@ -593,6 +637,13 @@ Mixer_UI::hide_all_audiotracks ()
        set_all_audio_visibility (1, false);
 }
 
+void
+Mixer_UI::track_list_reorder (const TreeModel::Path& path, const TreeModel::iterator& iter, int* new_order)
+{
+       session->set_remote_control_ids();
+       redisplay_track_list ();
+}
+
 void
 Mixer_UI::track_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
 {
@@ -632,6 +683,10 @@ Mixer_UI::redisplay_track_list ()
                        strip->set_marked_for_display (true);
                        strip->route()->set_order_key (N_("signal"), order);
 
+                       if (!ignore_route_reorder) {
+                               strip->route()->set_order_key (get_order_key(), order);
+                       } 
+
                        if (strip->packed()) {
 
                                if (strip->route()->is_master() || strip->route()->is_control()) {
@@ -663,12 +718,18 @@ Mixer_UI::redisplay_track_list ()
                        }
                }
        }
+       
+       if (Config->get_sync_all_route_ordering() && !ignore_route_reorder) {
+               ignore_sync = true;
+               Route::SyncOrderKeys (); // EMIT SIGNAL
+               ignore_sync = false;
+       }
 }
 
 struct SignalOrderRouteSorter {
     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
            /* use of ">" forces the correct sort order */
-           return a->order_key ("signal") < b->order_key ("signal");
+           return a->order_key (Mixer_UI::get_order_key()) < b->order_key (Mixer_UI::get_order_key());
     }
 };
 
index 3c9355efb775b37393b11015581ee97622e3ac5c..5d00acff5b3cf11553dceaa8f8e8fc8a89a392ba 100644 (file)
@@ -77,6 +77,8 @@ class Mixer_UI : public Gtk::Window
        void ensure_float (Gtk::Window&);
 
        RouteRedirectSelection& selection() { return _selection; }
+
+       static const char* get_order_key();
        
   private:
        ARDOUR::Session         *session;
@@ -148,6 +150,7 @@ class Mixer_UI : public Gtk::Window
        
        void track_list_change (const Gtk::TreeModel::Path&,const Gtk::TreeModel::iterator&);
        void track_list_delete (const Gtk::TreeModel::Path&);
+       void track_list_reorder (const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter, int* new_order);
 
        void initial_track_display ();
        void show_track_list_menu ();
@@ -234,6 +237,10 @@ class Mixer_UI : public Gtk::Window
 
        Width _strip_width;
 
+       void sync_order_keys ();
+       bool ignore_route_reorder;
+       bool ignore_sync;
+
        static const int32_t default_width = 478;
        static const int32_t default_height = 765;
 };
index 132af4a86c1b277c950a4aa059b0f45dacd1fe9d..ebf520fba74f8aa9901ed6991f2fa1c6b1c6255f 100644 (file)
@@ -23,6 +23,8 @@
 #include <ardour/recent_sessions.h>
 #include <ardour/session_state_utils.h>
 #include <ardour/template_utils.h>
+#include <ardour/session.h>
+#include <ardour/profile.h>
 
 #include <gtkmm/entry.h>
 #include <gtkmm/filechooserbutton.h>
@@ -44,9 +46,10 @@ using namespace PBD;
 NewSessionDialog::NewSessionDialog()
        : ArdourDialog ("session control")
 {
+       in_destructor = false;
        session_name_label = Gtk::manage(new class Gtk::Label(_("Name :")));
        m_name = Gtk::manage(new class Gtk::Entry());
-       m_name->set_text(GTK_ARDOUR::session_name);
+       m_name->set_text(ARDOUR_COMMAND_LINE::session_name);
 
        chan_count_label_1 = Gtk::manage(new class Gtk::Label(_("channels")));
        chan_count_label_2 = Gtk::manage(new class Gtk::Label(_("channels")));
@@ -308,8 +311,11 @@ NewSessionDialog::NewSessionDialog()
        new_session_table->attach(*m_folder, 1, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0);
        new_session_table->attach(*session_template_label, 0, 1, 2, 3, Gtk::FILL, Gtk::FILL, 0, 0);
        new_session_table->attach(*m_template, 1, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0);
-       new_session_table->attach(*advanced_expander, 0, 2, 3, 4, Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 6);
 
+       if (!ARDOUR::Profile->get_sae()) {
+               new_session_table->attach(*advanced_expander, 0, 2, 3, 4, Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 6);
+       }
+       
        open_session_hbox->pack_start(*open_session_file_label, false, false, 12);
        open_session_hbox->pack_start(*m_open_filechooser, true, true, 12);
        m_treeview->set_flags(Gtk::CAN_FOCUS);
@@ -358,7 +364,7 @@ NewSessionDialog::NewSessionDialog()
        // add_button(Gtk::Stock::HELP, Gtk::RESPONSE_HELP);
        add_button(Gtk::Stock::QUIT, Gtk::RESPONSE_CANCEL);
        add_button(Gtk::Stock::CLEAR, Gtk::RESPONSE_NONE);
-       m_okbutton = add_button(Gtk::Stock::NEW, Gtk::RESPONSE_OK);
+       m_okbutton = add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
 
        recent_model = Gtk::TreeStore::create (recent_columns);
        m_treeview->set_model (recent_model);
@@ -401,7 +407,7 @@ NewSessionDialog::NewSessionDialog()
 
 
        set_default_response (Gtk::RESPONSE_OK);
-       if (!GTK_ARDOUR::session_name.length()) {
+       if (!ARDOUR_COMMAND_LINE::session_name.length()) {
                set_response_sensitive (Gtk::RESPONSE_OK, false);
                set_response_sensitive (Gtk::RESPONSE_NONE, false);
        } else {
@@ -426,12 +432,39 @@ NewSessionDialog::NewSessionDialog()
        m_name->grab_focus();
 }
 
+NewSessionDialog::~NewSessionDialog()
+{
+       in_destructor = true;
+}
+
+void
+NewSessionDialog::set_have_engine (bool yn)
+{
+       if (yn) {
+               m_notebook->remove_page (engine_control);
+       } else {
+               // XXX this is a bit of crude hack. if we ever add or remove
+               // pages from the notebook, this is going to break.
+               if (m_notebook->get_n_pages () != 3) {
+                       m_notebook->append_page (engine_control, _("Audio Setup"));
+                       m_notebook->show_all_children();
+               }
+       }
+}
+
+
 void
 NewSessionDialog::set_session_name(const Glib::ustring& name)
 {
        m_name->set_text(name);
 }
 
+void
+NewSessionDialog::set_session_folder(const Glib::ustring& dir)
+{
+       // XXX DO SOMETHING
+}
+
 std::string
 NewSessionDialog::session_name() const
 {
@@ -450,7 +483,7 @@ NewSessionDialog::session_name() const
        }         
        */
 
-       if (on_new_session_page ()) {
+       if (on_newable_page()) {
                return Glib::filename_from_utf8(m_name->get_text());
        } else {
                if (m_treeview->get_selection()->count_selected_rows() == 0) {
@@ -464,10 +497,9 @@ NewSessionDialog::session_name() const
 std::string
 NewSessionDialog::session_folder() const
 {
-       if (on_new_session_page ()) {
+       if (on_newable_page()) {
                return Glib::filename_from_utf8(m_folder->get_filename());
        } else {
-              
                if (m_treeview->get_selection()->count_selected_rows() == 0) {
                        std::string str = Glib::filename_from_utf8(m_open_filechooser->get_filename());
                        return Glib::path_get_dirname(str);
@@ -563,9 +595,16 @@ NewSessionDialog::connect_outs_to_physical() const
 }
 
 bool
-NewSessionDialog::on_new_session_page() const
+NewSessionDialog::on_newable_page() const
 {
-       return (m_notebook->get_current_page() == 0);
+       return (m_notebook->get_current_page() == 0 ||
+               m_notebook->get_current_page() == 2);
+}
+
+int
+NewSessionDialog::get_current_page() const
+{
+       return m_notebook->get_current_page();
 }
 
 void
@@ -595,7 +634,11 @@ NewSessionDialog::on_new_session_name_entry_changed ()
 void
 NewSessionDialog::notebook_page_changed (GtkNotebookPage* np, uint pagenum)
 {
-       if (!on_new_session_page ()) {
+       if (in_destructor) {
+               return;
+       }
+
+       if (!on_newable_page ()) {
                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)));
@@ -635,7 +678,7 @@ NewSessionDialog::treeview_selection_changed ()
 void
 NewSessionDialog::file_chosen ()
 {
-       if (on_new_session_page ()) return;
+       if (on_newable_page ()) return;
 
        m_treeview->get_selection()->unselect_all();
 
index 2a2081e56a5d58cd21257b593561932906d48f39..53ec3eabf2b3019fb98b6998884de38b4d36c6b9 100644 (file)
@@ -38,6 +38,7 @@
 #include <glibmm/refptr.h>
 
 #include "ardour_dialog.h"
+#include "engine_dialog.h"
 
 namespace Gtk {
        class Entry;
@@ -54,8 +55,10 @@ class NewSessionDialog : public ArdourDialog
 public:
                
        NewSessionDialog();
+       ~NewSessionDialog ();
 
        void set_session_name(const Glib::ustring& name);
+       void set_session_folder(const Glib::ustring& folder);
 
        std::string session_name() const;
        std::string session_folder() const;
@@ -82,14 +85,17 @@ public:
        bool connect_outs_to_master() const;
        bool connect_outs_to_physical() const ;
 
-       bool on_new_session_page () const;
-       
+       bool on_newable_page() const;
+       int  get_current_page () const;
        void set_current_page (int);
        void reset_recent();
 
        // reset everything to default values.
        void reset();
 
+       EngineControl engine_control;
+       void set_have_engine (bool yn);
+
 protected:
 
        void reset_name();
@@ -173,6 +179,8 @@ protected:
        RecentSessionModelColumns    recent_columns;
        Glib::RefPtr<Gtk::TreeStore> recent_model;
 
+       bool in_destructor;
+
        void recent_session_selection_changed ();
        void nsd_redisplay_recent_sessions();
        void nsd_recent_session_row_activated (const Gtk::TreePath& path, Gtk::TreeViewColumn* col);
@@ -194,6 +202,7 @@ protected:
        void master_bus_button_clicked ();
        void monitor_bus_button_clicked ();
 
+       bool have_engine;
 };
 
 #endif // NEW_SESSION_DIALOG_H
index 513e46448e1d80c7575b47a7b2e109eb95755b73..e49b410668ecfc3dc8b6fb7c5e88cb5b6ccea5f1 100644 (file)
@@ -27,7 +27,6 @@
 #include <ardour/crossfade.h>
 #include <midi++/manager.h>
 #include <midi++/factory.h>
-#include <midi++/port_request.h>
 #include <gtkmm2ext/stop_signal.h>
 #include <gtkmm2ext/utils.h>
 #include <gtkmm2ext/window_title.h>
@@ -43,6 +42,7 @@
 #include "editing.h"
 #include "option_editor.h"
 #include "midi_port_dialog.h"
+#include "gui_thread.h"
 
 #include "i18n.h"
 
@@ -56,7 +56,7 @@ using namespace std;
 static vector<string> positional_sync_strings;
 
 OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui)
-       : Dialog ("options editor"),
+       : ArdourDialog ("options editor", false),
          ui (uip),
          editor (ed),
          mixer (mixui),
@@ -64,24 +64,33 @@ OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui)
          /* Paths */
          path_table (11, 2),
 
-         /* Fades */
+         /* misc */
 
          short_xfade_adjustment (0, 1.0, 500.0, 5.0, 100.0),
          short_xfade_slider (short_xfade_adjustment),
          destructo_xfade_adjustment (1.0, 1.0, 500.0, 1.0, 100.0),
          destructo_xfade_slider (destructo_xfade_adjustment),
+         history_depth (20, -1, 100, 1.0, 10.0),
+         saved_history_depth (20, 0, 100, 1.0, 10.0),
+         history_depth_spinner (history_depth),
+         saved_history_depth_spinner (saved_history_depth),
+         limit_history_button (_("Limit undo history")),
+         save_history_button (_("Save undo history")),
 
          /* Sync */
 
          smpte_offset_clock (X_("smpteoffset"), false, X_("SMPTEOffsetClock"), true, true),
          smpte_offset_negative_button (_("SMPTE offset is negative")),
+         synced_timecode_button (_("Timecode source is sample-clock synced")),
 
          /* MIDI */
 
+         midi_port_table (4, 11),
          mmc_receive_device_id_adjustment (0.0, 0.0, (double) 0x7f, 1.0, 16.0),
          mmc_receive_device_id_spinner (mmc_receive_device_id_adjustment),
          mmc_send_device_id_adjustment (0.0, 0.0, (double) 0x7f, 1.0, 16.0),
          mmc_send_device_id_spinner (mmc_send_device_id_adjustment),
+         add_midi_port_button (_("Add new MIDI port")),
 
          /* Click */
 
@@ -105,13 +114,13 @@ OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui)
        session = 0;
        
        WindowTitle title(Glib::get_application_name());
-       title += _("Options Editor");
+       title += _("Preferences");
        set_title(title.get_string());
 
        set_default_size (300, 300);
-       set_wmclass (X_("ardour_option_editor"), "Ardour");
+       set_wmclass (X_("ardour_preferences"), "Ardour");
 
-       set_name ("OptionsWindow");
+       set_name ("Preferences");
        add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
        
        VBox *vbox = get_vbox();
@@ -128,7 +137,7 @@ OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui)
 
        setup_sync_options();
        setup_path_options();
-       setup_fade_options ();
+       setup_misc_options ();
        setup_keyboard_options ();
        setup_auditioner_editor ();
 
@@ -137,15 +146,16 @@ OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui)
        notebook.pages().push_back (TabElem (keyboard_mouse_table, _("Kbd/Mouse")));
        notebook.pages().push_back (TabElem (click_packer, _("Click")));
        notebook.pages().push_back (TabElem (audition_packer, _("Audition")));
-       notebook.pages().push_back (TabElem (fade_packer, _("Layers & Fades")));
+       notebook.pages().push_back (TabElem (misc_packer, _("Misc")));
 
-       if (!MIDI::Manager::instance()->get_midi_ports().empty()) {
-               setup_midi_options ();
-               notebook.pages().push_back (TabElem (midi_packer, _("MIDI")));
-       }
+       setup_midi_options ();
+       notebook.pages().push_back (TabElem (midi_packer, _("MIDI")));
 
        set_session (0);
        show_all_children();
+
+       Config->map_parameters (mem_fun (*this, &OptionEditor::parameter_changed));
+       Config->ParameterChanged.connect (mem_fun (*this, &OptionEditor::parameter_changed));
 }
 
 void
@@ -182,27 +192,7 @@ OptionEditor::set_session (Session *s)
 
        smpte_offset_negative_button.set_active (session->smpte_offset_negative());
 
-       /* set up port assignments */
-
-       std::map<MIDI::Port*,vector<RadioButton*> >::iterator res;
-
-       if (session->mtc_port()) {
-               if ((res = port_toggle_buttons.find (session->mtc_port())) != port_toggle_buttons.end()) {
-                       (*res).second[MtcIndex]->set_active (true);
-               }
-       } 
-
-       if (session->mmc_port ()) {
-               if ((res = port_toggle_buttons.find (session->mmc_port())) != port_toggle_buttons.end()) {
-                       (*res).second[MmcIndex]->set_active (true);
-               } 
-       }
-
-       if (session->midi_port()) {
-               if ((res = port_toggle_buttons.find (session->midi_port())) != port_toggle_buttons.end()) {
-                       (*res).second[MidiIndex]->set_active (true);
-               }
-       }
+       redisplay_midi_ports ();
 
        setup_click_editor ();
        connect_audition_editor ();
@@ -260,7 +250,7 @@ OptionEditor::add_session_paths ()
 }
 
 void
-OptionEditor::setup_fade_options ()
+OptionEditor::setup_misc_options ()
 {
        Gtk::HBox* hbox;
        
@@ -272,7 +262,7 @@ OptionEditor::setup_fade_options ()
        hbox->set_spacing (10);
        hbox->pack_start (*label, false, false);
        hbox->pack_start (short_xfade_slider, true, true);
-       fade_packer.pack_start (*hbox, false, false);
+       misc_packer.pack_start (*hbox, false, false);
 
        short_xfade_adjustment.signal_value_changed().connect (mem_fun(*this, &OptionEditor::short_xfade_adjustment_changed));
 
@@ -284,16 +274,94 @@ OptionEditor::setup_fade_options ()
        hbox->set_spacing (10);
        hbox->pack_start (*label, false, false);
        hbox->pack_start (destructo_xfade_slider, true, true);
-       fade_packer.pack_start (*hbox, false, false);
+       misc_packer.pack_start (*hbox, false, false);
        
+
        destructo_xfade_adjustment.signal_value_changed().connect (mem_fun(*this, &OptionEditor::destructo_xfade_adjustment_changed));
 
+       hbox = manage (new HBox);
+       hbox->set_border_width (5);
+       hbox->set_spacing (10);
+       hbox->pack_start (limit_history_button, false, false);
+       misc_packer.pack_start (*hbox, false, false);
+
+       label = manage (new Label (_("History depth (commands)")));
+       label->set_name ("OptionsLabel");
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (5);
+       hbox->set_spacing (10);
+       hbox->pack_start (*label, false, false);
+       hbox->pack_start (history_depth_spinner, false, false);
+       misc_packer.pack_start (*hbox, false, false);
+
+       history_depth.signal_value_changed().connect (mem_fun (*this, &OptionEditor::history_depth_changed));
+       saved_history_depth.signal_value_changed().connect (mem_fun (*this, &OptionEditor::saved_history_depth_changed));
+       save_history_button.signal_toggled().connect (mem_fun (*this, &OptionEditor::save_history_toggled));
+       limit_history_button.signal_toggled().connect (mem_fun (*this, &OptionEditor::limit_history_toggled));
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (5);
+       hbox->set_spacing (10);
+       hbox->pack_start (save_history_button, false, false);
+       misc_packer.pack_start (*hbox, false, false);
+
+       label = manage (new Label (_("Saved history depth (commands)")));
+       label->set_name ("OptionsLabel");
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (5);
+       hbox->set_spacing (10);
+       hbox->pack_start (*label, false, false);
+       hbox->pack_start (saved_history_depth_spinner, false, false);
+       misc_packer.pack_start (*hbox, false, false);
+       
        short_xfade_slider.set_update_policy (UPDATE_DISCONTINUOUS);
        destructo_xfade_slider.set_update_policy (UPDATE_DISCONTINUOUS);
 
        destructo_xfade_adjustment.set_value (Config->get_destructive_xfade_msecs());
 
-       fade_packer.show_all ();
+       misc_packer.show_all ();
+}
+
+void
+OptionEditor::limit_history_toggled ()
+{
+       bool x = limit_history_button.get_active();
+       
+       if (!x) {
+               Config->set_history_depth (0);
+               history_depth_spinner.set_sensitive (false);
+       } else {
+               if (Config->get_history_depth() == 0) {
+                       /* get back to a sane default */
+                       Config->set_history_depth (20);
+               }
+               history_depth_spinner.set_sensitive (true);
+       }
+}
+
+void
+OptionEditor::save_history_toggled ()
+{
+       bool x = save_history_button.get_active();
+
+       if (x != Config->get_save_history()) {
+               Config->set_save_history (x);
+               saved_history_depth_spinner.set_sensitive (x);
+       }
+}
+
+void
+OptionEditor::history_depth_changed()
+{
+       Config->set_history_depth ((int32_t) floor (history_depth.get_value()));
+}
+
+void
+OptionEditor::saved_history_depth_changed()
+{
+       Config->set_saved_history_depth ((int32_t) floor (saved_history_depth.get_value()));
 }
 
 void
@@ -347,8 +415,10 @@ OptionEditor::setup_sync_options ()
        hbox->pack_start (smpte_offset_negative_button, false, false);
 
        sync_packer.pack_start (*hbox, false, false);
+       sync_packer.pack_start (synced_timecode_button, false, false);
 
        smpte_offset_negative_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::smpte_offset_negative_clicked));
+       synced_timecode_button.signal_toggled().connect (mem_fun(*this, &OptionEditor::synced_timecode_toggled));
 }
 
 void
@@ -359,6 +429,17 @@ OptionEditor::smpte_offset_negative_clicked ()
        }
 }
 
+void
+OptionEditor::synced_timecode_toggled ()
+{
+       bool x;
+
+       if ((x = synced_timecode_button.get_active()) != Config->get_timecode_source_is_synced()) {
+               Config->set_timecode_source_is_synced (x);
+               Config->save_state();
+       }
+}
+
 void
 OptionEditor::smpte_offset_chosen()
 {
@@ -368,6 +449,7 @@ OptionEditor::smpte_offset_chosen()
        }
 }
 
+
 void
 OptionEditor::setup_midi_options ()
 {
@@ -379,6 +461,9 @@ OptionEditor::setup_midi_options ()
 
        redisplay_midi_ports ();
 
+       mmc_receive_device_id_adjustment.set_value (Config->get_mmc_receive_device_id());
+       mmc_send_device_id_adjustment.set_value (Config->get_mmc_send_device_id());
+
        mmc_receive_device_id_adjustment.signal_value_changed().connect (mem_fun (*this, &OptionEditor::mmc_receive_device_id_adjusted));
        mmc_send_device_id_adjustment.signal_value_changed().connect (mem_fun (*this, &OptionEditor::mmc_send_device_id_adjusted));
 
@@ -396,7 +481,9 @@ OptionEditor::setup_midi_options ()
        label = (manage (new Label (_("Inbound MMC Device ID")))); 
        hbox->pack_start (mmc_receive_device_id_spinner, false, false);
        hbox->pack_start (*label, false, false);
-       midi_packer.pack_start (*hbox, false, false);
+       midi_packer.pack_start (*hbox, false, false); 
+
+       mmc_receive_device_id_spinner.set_value(Config->get_mmc_receive_device_id ());
 
        hbox = manage (new HBox);
        hbox->set_border_width (6);
@@ -406,6 +493,8 @@ OptionEditor::setup_midi_options ()
        hbox->pack_start (*label, false, false);
        midi_packer.pack_start (*hbox, false, false);
 
+       mmc_send_device_id_spinner.set_value(Config->get_mmc_send_device_id ());
+
        add_midi_port_button.signal_clicked().connect (mem_fun (*this, &OptionEditor::add_midi_port));
 }
 
@@ -624,12 +713,15 @@ OptionEditor::add_midi_port ()
                smod = "duplex";
        }
 
-       MIDI::PortRequest req (X_("ardour"),
-                              dialog.port_name.get_text(),
-                              smod,
-                              MIDI::PortFactory::default_port_type());
 
-       if (MIDI::Manager::instance()->add_port (req) != 0) {
+       XMLNode node (X_("MIDI-port"));
+
+       node.add_property ("tag", dialog.port_name.get_text());
+       node.add_property ("device", X_("ardour")); // XXX this can't be right for all types
+       node.add_property ("type", MIDI::PortFactory::default_port_type());
+       node.add_property ("mode", smod);
+
+       if (MIDI::Manager::instance()->add_port (node) != 0) {
                redisplay_midi_ports ();
        }
 }
@@ -696,23 +788,27 @@ OptionEditor::port_online_toggled (MIDI::Port* port, ToggleButton* tb)
 {
        bool wanted = tb->get_active();
 
-       if (wanted != port->input()->offline()) {
-               port->input()->set_offline (wanted);
-       } 
+       if (port->input()) {
+               if (wanted != port->input()->offline()) {
+                       port->input()->set_offline (wanted);
+               } 
+       }
 }
 
 void
 OptionEditor::map_port_online (MIDI::Port* port, ToggleButton* tb)
 {
        bool bstate = tb->get_active ();
-
-       if (bstate != port->input()->offline()) {
-               if (port->input()->offline()) {
-                       tb->set_label (_("offline"));
-                       tb->set_active (false);
-               } else {
-                       tb->set_label (_("online"));
-                       tb->set_active (true);
+       
+       if (port->input()) {
+               if (bstate != port->input()->offline()) {
+                       if (port->input()->offline()) {
+                               tb->set_label (_("offline"));
+                               tb->set_active (false);
+                       } else {
+                               tb->set_label (_("online"));
+                               tb->set_active (true);
+                       }
                }
        }
 }
@@ -721,20 +817,14 @@ void
 OptionEditor::mmc_receive_device_id_adjusted ()
 {
        uint8_t id = (uint8_t) mmc_receive_device_id_spinner.get_value();
-
-       if (id != Config->get_mmc_receive_device_id()) {
-               Config->set_mmc_receive_device_id (id);
-       }
+       Config->set_mmc_receive_device_id (id);
 }
 
 void
 OptionEditor::mmc_send_device_id_adjusted ()
 {
        uint8_t id = (uint8_t) mmc_send_device_id_spinner.get_value();
-
-       if (id != Config->get_mmc_send_device_id()) {
-               Config->set_mmc_send_device_id (id);
-       }
+       Config->set_mmc_send_device_id (id);
 }
 
 void
@@ -742,8 +832,10 @@ OptionEditor::port_trace_in_toggled (MIDI::Port* port, ToggleButton* tb)
 {
        bool trace = tb->get_active();
 
-       if (port->input()->tracing() != trace) {
-               port->input()->trace (trace, &cerr, string (port->name()) + string (" input: "));
+       if (port->input()) {
+               if (port->input()->tracing() != trace) {
+                       port->input()->trace (trace, &cerr, string (port->name()) + string (" input: "));
+               }
        }
 }
 
@@ -752,8 +844,10 @@ OptionEditor::port_trace_out_toggled (MIDI::Port* port, ToggleButton* tb)
 {
        bool trace = tb->get_active();
 
-       if (port->output()->tracing() != trace) {
-               port->output()->trace (trace, &cerr, string (port->name()) + string (" output: "));
+       if (port->output()) {
+               if (port->output()->tracing() != trace) {
+                       port->output()->trace (trace, &cerr, string (port->name()) + string (" output: "));
+               }
        }
 }
 
@@ -784,10 +878,13 @@ OptionEditor::raid_path_changed ()
 void
 OptionEditor::click_browse_clicked ()
 {
-       SoundFileChooser sfdb (_("Choose Click"), session);
+       SoundFileChooser sfdb (*this, _("Choose Click"), session);
        
-       int result = sfdb.run ();
+       sfdb.show_all ();
+       sfdb.present ();
 
+       int result = sfdb.run ();
        if (result == Gtk::RESPONSE_OK) {
                click_chosen(sfdb.get_filename());
        }
@@ -803,7 +900,10 @@ OptionEditor::click_chosen (const string & path)
 void
 OptionEditor::click_emphasis_browse_clicked ()
 {
-       SoundFileChooser sfdb (_("Choose Click Emphasis"), session);
+       SoundFileChooser sfdb (*this, _("Choose Click Emphasis"), session);
+
+       sfdb.show_all ();
+       sfdb.present ();
 
        int result = sfdb.run ();
 
@@ -1167,3 +1267,31 @@ OptionEditor::fixup_combo_size (Gtk::ComboBoxText& combo, vector<string>& string
        set_size_request_to_display_given_text (combo, maxstring.c_str(), 10 + FUDGE, 10);
 }
 
+void
+OptionEditor::parameter_changed (const char* parameter_name)
+{
+       ENSURE_GUI_THREAD (bind (mem_fun (*this, &OptionEditor::parameter_changed), parameter_name));
+
+#define PARAM_IS(x) (!strcmp (parameter_name, (x)))
+       
+       if (PARAM_IS ("timecode-source-is-synced")) {
+               synced_timecode_button.set_active (Config->get_timecode_source_is_synced());
+       } else if (PARAM_IS ("history-depth")) {
+               int32_t depth = Config->get_history_depth();
+               
+               history_depth.set_value (depth);
+               history_depth_spinner.set_sensitive (depth != 0);
+               limit_history_button.set_active (depth != 0);
+
+       } else if (PARAM_IS ("saved-history-depth")) {
+
+               saved_history_depth.set_value (Config->get_saved_history_depth());
+
+       } else if (PARAM_IS ("save-history")) {
+
+               bool x = Config->get_save_history();
+
+               save_history_button.set_active (x);
+               saved_history_depth_spinner.set_sensitive (x);
+       }
+}
index a234f1d7522be2a5fe2d204ef4ee54dc465a4649..82bb4db79b048703d4939f4bb4f9347685e6e820 100644 (file)
@@ -45,7 +45,7 @@ class IOSelector;
 class GainMeter;
 class PannerUI;
 
-class OptionEditor : public Gtk::Dialog
+class OptionEditor : public ArdourDialog
 {
   public:
        OptionEditor (ARDOUR_UI&, PublicEditor&, Mixer_UI&);
@@ -66,6 +66,7 @@ class OptionEditor : public Gtk::Dialog
 
        gint wm_close (GdkEventAny *);
        bool focus_out_event_handler (GdkEventFocus*, void (OptionEditor::*pmf)());
+       void parameter_changed (const char* name);
 
        /* paths */
 
@@ -77,18 +78,32 @@ class OptionEditor : public Gtk::Dialog
        void remove_session_paths ();
        void raid_path_changed ();
 
-       /* fades */
+       /* misc */
+
+       Gtk::VBox        misc_packer;
 
-       Gtk::VBox        fade_packer;
        Gtk::Adjustment  short_xfade_adjustment;
        Gtk::HScale      short_xfade_slider;
        Gtk::Adjustment  destructo_xfade_adjustment;
        Gtk::HScale      destructo_xfade_slider;
 
-       void setup_fade_options();
+       void setup_misc_options();
+
        void short_xfade_adjustment_changed ();
        void destructo_xfade_adjustment_changed ();
 
+       Gtk::Adjustment history_depth;
+       Gtk::Adjustment saved_history_depth;
+       Gtk::SpinButton     history_depth_spinner;
+       Gtk::SpinButton     saved_history_depth_spinner;
+       Gtk::CheckButton    limit_history_button;
+       Gtk::CheckButton    save_history_button;
+
+       void history_depth_changed();
+       void saved_history_depth_changed();
+       void save_history_toggled ();
+       void limit_history_toggled ();
+
        /* Sync */
 
        Gtk::VBox sync_packer;
@@ -96,11 +111,13 @@ class OptionEditor : public Gtk::Dialog
        Gtk::ComboBoxText slave_type_combo;
        AudioClock smpte_offset_clock;
        Gtk::CheckButton smpte_offset_negative_button;
+       Gtk::CheckButton synced_timecode_button;
 
        void setup_sync_options ();
 
        void smpte_offset_chosen ();
        void smpte_offset_negative_clicked ();
+       void synced_timecode_toggled ();
 
        /* MIDI */
 
index 608f684fc9f41ef587cfa42862b17c57b65afab7..8da0fb9ca115ced40f8ac217dce800006938f041 100644 (file)
 
 using namespace std;
 
-string GTK_ARDOUR::session_name = "";
-string GTK_ARDOUR::jack_client_name = "ardour";
-bool  GTK_ARDOUR::show_key_actions = false;
-bool GTK_ARDOUR::no_splash = true;
-bool GTK_ARDOUR::just_version = false;
-bool GTK_ARDOUR::use_vst = true;
-bool GTK_ARDOUR::new_session = false;
-char* GTK_ARDOUR::curvetest_file = 0;
-bool GTK_ARDOUR::try_hw_optimization = true;
-string GTK_ARDOUR::keybindings_path = ""; /* empty means use builtin default */
-
-using namespace GTK_ARDOUR;
+string ARDOUR_COMMAND_LINE::session_name = "";
+string ARDOUR_COMMAND_LINE::jack_client_name = "ardour";
+bool  ARDOUR_COMMAND_LINE::show_key_actions = false;
+bool ARDOUR_COMMAND_LINE::no_splash = true;
+bool ARDOUR_COMMAND_LINE::just_version = false;
+bool ARDOUR_COMMAND_LINE::use_vst = true;
+bool ARDOUR_COMMAND_LINE::new_session = false;
+char* ARDOUR_COMMAND_LINE::curvetest_file = 0;
+bool ARDOUR_COMMAND_LINE::try_hw_optimization = true;
+string ARDOUR_COMMAND_LINE::keybindings_path = ""; /* empty means use builtin default */
+Glib::ustring ARDOUR_COMMAND_LINE::menus_file = "ardour.menus";
+
+using namespace ARDOUR_COMMAND_LINE;
 
 int
 print_help (const char *execname)
@@ -49,9 +50,10 @@ print_help (const char *execname)
             << _("  -b, --bindings                   Print all possible keyboard binding names\n")
             << _("  -n, --show-splash                Show splash screen\n")
             << _("  -c, --name  name                 Use a specific jack client name, default is ardour\n")
+            << _("  -m, --menus file                 Use \"file\" for Ardour menus\n")                       
             << _("  -N, --new session-name           Create a new session from the command line\n")                       
             << _("  -O, --no-hw-optimizations        Disable h/w specific optimizations\n")
-            << _("  -S, --sync                    Draw the gui synchronously \n")
+            << _("  -S, --sync                       Draw the gui synchronously \n")
 #ifdef VST_SUPPORT
             << _("  -V, --novst                      Do not use VST support\n")
 #endif
@@ -64,12 +66,16 @@ print_help (const char *execname)
 }
 
 int
-GTK_ARDOUR::parse_opts (int argc, char *argv[])
+ARDOUR_COMMAND_LINE::parse_opts (int argc, char *argv[])
 
 {
-       const char *optstring = "U:hSbvVnOc:C:N:k:";
+       const char *optstring = "U:hSbvVnOc:C:m:N:k:";
        const char *execname = strrchr (argv[0], '/');
 
+       if (getenv ("ARDOUR_SAE")) {
+               menus_file = "ardour-sae.menus";
+       }
+
        if (execname == 0) {
                execname = argv[0];
        } else {
@@ -81,11 +87,12 @@ GTK_ARDOUR::parse_opts (int argc, char *argv[])
                { "help", 0, 0, 'h' },
                { "bindings", 0, 0, 'b' },
                { "show-splash", 0, 0, 'n' },
+               { "menus", 1, 0, 'm' },
                { "name", 1, 0, 'c' },
                { "novst", 0, 0, 'V' },
                { "new", 1, 0, 'N' },
                { "no-hw-optimizations", 0, 0, 'O' },
-               { "sync", 0, 0, 'O' },
+               { "sync", 0, 0, 'S' },
                { "curvetest", 1, 0, 'C' },
                { 0, 0, 0, 0 }
        };
@@ -116,6 +123,11 @@ GTK_ARDOUR::parse_opts (int argc, char *argv[])
                        show_key_actions = true;
                        break;
 
+                case 'm':
+                        menus_file = optarg;
+                        break;
+
                case 'n':
                        no_splash = false;
                        break;
@@ -133,6 +145,11 @@ GTK_ARDOUR::parse_opts (int argc, char *argv[])
                        try_hw_optimization = false;
                        break;
 
+
+               case 'p':
+                       //undocumented OS X finder -psn_XXXXX argument
+                       break;
+               
                case 'V':
 #ifdef VST_SUPPORT
                        use_vst = false;
index fb780fc8aa3457db18aa2f0ceae6c4724682653f..c1b3f062d407030e12e33b71a400276f9c768456 100644 (file)
 #define __ardour_opts_h__
 
 #include <string>
+#include <glibmm/ustring.h>
 
 using std::string;
 
-namespace GTK_ARDOUR {
+namespace ARDOUR_COMMAND_LINE {
 
 extern string session_name;
 extern bool   show_key_actions;
@@ -37,6 +38,7 @@ extern char*  curvetest_file;
 extern bool   try_hw_optimization;
 extern bool   use_gtk_theme;
 extern string keybindings_path;
+extern Glib::ustring menus_file;
 
 extern int32_t parse_opts (int argc, char *argv[]);
 
index d093fda99f974dc62acba932ba0546b09c36903e..12e30e59c0b4668d16cab982a6648375a0e86e9c 100644 (file)
@@ -338,7 +338,7 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
                show_processor_menu(ev->time);
                ret = true;
 
-       } else if (processor && (ev->button == 2) && (ev->state == Gdk::BUTTON2_MASK)) {
+       } else if (processor && (ev->button == 2) && (Keyboard::no_modifier_keys_pressed (ev) && ((ev->state & Gdk::BUTTON2_MASK) == Gdk::BUTTON2_MASK))) {
                
                processor->set_active (!processor->active());
                ret = true;
@@ -394,13 +394,13 @@ ProcessorBox::processor_plugin_chosen (boost::shared_ptr<Plugin> plugin)
 
                boost::shared_ptr<Processor> processor (new PluginInsert (_session, plugin, _placement));
                
-               processor->ActiveChanged.connect (bind (mem_fun (*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
-
                Route::ProcessorStreams err;
 
                if (_route->add_processor (processor, &err)) {
                        weird_plugin_dialog (*plugin, err, _route);
                        // XXX SHAREDPTR delete plugin here .. do we even need to care? 
+               } else {
+                       processor->ActiveChanged.connect (bind (mem_fun (*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
                }
        }
 }
@@ -482,36 +482,39 @@ ProcessorBox::choose_send ()
        boost::shared_ptr<Send> send (new Send (_session, _placement));
        //send->set_default_type(_route->default_type());
 
-       /* XXX need redirect lock on route */
+       ChanCount outs;
+
+       /* make an educated guess at the initial number of outputs for the send */
+
+       if (_session.master_out()) {
+               outs = _session.master_out()->n_outputs();
+       } else {
+               outs = _route->n_outputs();
+       }
+
+       send->io()->ensure_io (ChanCount::ZERO, outs, false, this);
 
-       // This will be set properly in route->add_processor
-       send->configure_io (_route->max_processor_outs(), _route->max_processor_outs());
+       SendUIWindow* gui = new SendUIWindow (send, _session);
        
-       IOSelectorWindow *ios = new IOSelectorWindow (_session, send->io(), false, true);
+       /* let the user adjust the output setup (number and connections) before passing
+          it along to the Route
+       */
        
-       ios->show_all ();
+       gui->show_all ();
+       gui->present ();
 
-       ios->selector().Finished.connect (bind (mem_fun(*this, &ProcessorBox::send_io_finished), send, ios));
+       /* pass shared_ptr, it will go out of scope when the GUI is deleted */
+       /* also, connect it *before* existing handlers so that its definitely executed */
+
+       gui->signal_delete_event().connect (bind (mem_fun(*this, &ProcessorBox::send_io_finished), send, gui), false);
 }
 
-void
-ProcessorBox::send_io_finished (IOSelector::Result r, boost::shared_ptr<Send> send, IOSelectorWindow* ios)
+bool
+ProcessorBox::send_io_finished (GdkEventAny* ev, boost::shared_ptr<Send> send, SendUIWindow* sui)
 {
-       if (!send) {
-               return;
-       }
-
-       switch (r) {
-       case IOSelector::Cancelled:
-               // send will go away when all shared_ptrs to it vanish
-               break;
-
-       case IOSelector::Accepted:
-               _route->add_processor (send);
-               break;
-       }
-
-       delete_when_idle (ios);
+       _route->add_processor (send);
+       delete sui;
+       return false;
 }
 
 void
index 1ed0bcb39efd190f942a68235f22ee5138981530..b6bb3ae3d781bd856b72b0005fd9bf23be1a494a 100644 (file)
@@ -50,6 +50,7 @@ class MotionController;
 class PluginSelector;
 class PluginUIWindow;
 class RouteRedirectSelection;
+class SendUIWindow;
 
 namespace ARDOUR {
        class Bundle;
@@ -142,7 +143,7 @@ class ProcessorBox : public Gtk::HBox
        void show_processor_menu (gint arg);
 
        void choose_send ();
-       void send_io_finished (IOSelector::Result, boost::shared_ptr<ARDOUR::Send>, IOSelectorWindow*);
+       bool send_io_finished (GdkEventAny*,boost::shared_ptr<ARDOUR::Send>, SendUIWindow*);
        void choose_processor ();
        void choose_plugin ();
        void processor_plugin_chosen (boost::shared_ptr<ARDOUR::Plugin>);
index 7dda653894ee1868fb1ddaafcab635d942d1a7c9..c91068f97c27bf37d4b6aae839d411ba9301a687 100644 (file)
@@ -54,7 +54,7 @@ SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
 
        _send->set_metering (true);
 
-       _send->io()->output_changed.connect (mem_fun (*this, &SendUI::ins_changed));
+       _send->io()->input_changed.connect (mem_fun (*this, &SendUI::ins_changed));
        _send->io()->output_changed.connect (mem_fun (*this, &SendUI::outs_changed));
        
        panners.set_width (Wide);
index 5415cd70cb3b29c359523bfa43218f843e26c4b8..67bedb6182ef33d6ecb139c8fcba13425940326e 100644 (file)
 #include <cerrno>
 #include <sstream>
 
+#include <unistd.h>
 #include <sys/stat.h>
+#include <sys/param.h>
 
 #include <gtkmm/box.h>
 #include <gtkmm/stock.h>
+#include <glibmm/fileutils.h>
 
 #include <pbd/convert.h>
 #include <pbd/tokenizer.h>
+#include <pbd/enumwriter.h>
 
 #include <gtkmm2ext/utils.h>
 
 #include <ardour/audio_library.h>
+#include <ardour/auditioner.h>
 #include <ardour/audioregion.h>
 #include <ardour/audiofilesource.h>
 #include <ardour/region_factory.h>
 #include <ardour/source_factory.h>
+#include <ardour/session.h>
+#include <ardour/session_directory.h>
+#include <ardour/profile.h>
 
 #include "ardour_ui.h"
 #include "editing.h"
 #include "gui_thread.h"
 #include "prompter.h"
 #include "sfdb_ui.h"
+#include "editing.h"
 #include "utils.h"
+#include "gain_meter.h"
 
 #include "i18n.h"
 
 using namespace ARDOUR;
 using namespace PBD;
 using namespace std;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+using namespace Editing;
+
+using Glib::ustring;
 
-Glib::ustring SoundFileBrowser::persistent_folder;
+ustring SoundFileBrowser::persistent_folder;
 
-SoundFileBox::SoundFileBox ()
-       :
-       _session(0),
-       current_pid(0),
-       main_box (false, 3),
-       bottom_box (true, 4),
-       play_btn(_("Play")),
-       stop_btn(_("Stop")),
-       apply_btn(_("Apply"))
+static ImportMode
+string2importmode (string str)
 {
-       set_name (X_("SoundFileBox"));
+       if (str == "as new tracks") {
+               return ImportAsTrack;
+       } else if (str == "to selected tracks") {
+               return ImportToTrack;
+       } else if (str == "to region list") {
+               return ImportAsRegion;
+       } else if (str == "as new tape tracks") {
+               return ImportAsTapeTrack;
+       }
+
+       warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
        
-       set_size_request (250, 500);
+       return ImportAsTrack;
+}
+
+static string
+importmode2string (ImportMode mode)
+{
+       switch (mode) {
+       case ImportAsTrack:
+               return _("as new tracks");
+       case ImportToTrack:
+               return _("to selected tracks");
+       case ImportAsRegion:
+               return _("to region list");
+       case ImportAsTapeTrack:
+               return _("as new tape tracks");
+       }
+       /*NOTREACHED*/
+       return _("as new tracks");
+}
+
+SoundFileBox::SoundFileBox (bool persistent)
+       : _session(0),
+         table (6, 2),
+         length_clock ("sfboxLengthClock", !persistent, "EditCursorClock", false, true, false),
+         timecode_clock ("sfboxTimecodeClock", !persistent, "EditCursorClock", false, false, false),
+         main_box (false, 6),
+         autoplay_btn (_("Auto-play"))
        
-       border_frame.set_label (_("Soundfile Info"));
+{
+       HBox* hbox;
+       VBox* vbox;
+
+       set_name (X_("SoundFileBox"));
+       set_size_request (300, -1);
+
+       preview_label.set_markup (_("<b>Soundfile Info</b>"));
+
+       border_frame.set_label_widget (preview_label);
        border_frame.add (main_box);
 
-       Gtk::Label* tag_label = manage(new Gtk::Label(_("comma seperated tags")));
+       pack_start (border_frame, true, true);
+       set_border_width (6);
 
-       pack_start (border_frame);
-       set_border_width (4);
+       main_box.set_border_width (6);
+       main_box.set_spacing (12);
 
-       main_box.set_border_width (4);
+       length.set_text (_("Length:"));
+       timecode.set_text (_("Timestamp:"));
+       format.set_text (_("Format:"));
+       channels.set_text (_("Channels:"));
+       samplerate.set_text (_("Sample rate:"));
 
-       main_box.pack_start(length, false, false);
-       main_box.pack_start(format, false, false);
-       main_box.pack_start(channels, false, false);
-       main_box.pack_start(samplerate, false, false);
-       main_box.pack_start(timecode, false, false);
-       main_box.pack_start(*tag_label, false, false);
-       main_box.pack_start(tags_entry, false, false);
-       main_box.pack_start(apply_btn, false, false);
-       main_box.pack_start(bottom_box, false, false);
+       table.set_col_spacings (6);
+       table.set_homogeneous (false);
+       table.set_row_spacings (6);
+
+       table.attach (channels, 0, 1, 0, 1, FILL|EXPAND, (AttachOptions) 0);
+       table.attach (samplerate, 0, 1, 1, 2, FILL|EXPAND, (AttachOptions) 0);
+       table.attach (format, 0, 1, 2, 4, FILL|EXPAND, (AttachOptions) 0);
+       table.attach (length, 0, 1, 4, 5, FILL|EXPAND, (AttachOptions) 0);
+       table.attach (timecode, 0, 1, 5, 6, FILL|EXPAND, (AttachOptions) 0);
+
+       table.attach (channels_value, 1, 2, 0, 1, FILL, (AttachOptions) 0);
+       table.attach (samplerate_value, 1, 2, 1, 2, FILL, (AttachOptions) 0);
+       table.attach (format_text, 1, 2, 2, 4, FILL, AttachOptions (0));
+       table.attach (length_clock, 1, 2, 4, 5, FILL, (AttachOptions) 0);
+       table.attach (timecode_clock, 1, 2, 5, 6, FILL, (AttachOptions) 0);
+
+       length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock.mode());
+       timecode_clock.set_mode (AudioClock::SMPTE);
+
+       hbox = manage (new HBox);
+       hbox->pack_start (table, false, false);
+       main_box.pack_start (*hbox, false, false);
 
-       bottom_box.set_homogeneous(true);
-       bottom_box.pack_start(play_btn);
-       bottom_box.pack_start(stop_btn);
+       tags_entry.set_editable (true);
+       tags_entry.signal_focus_out_event().connect (mem_fun (*this, &SoundFileBox::tags_entry_left));
+       hbox = manage (new HBox);
+       hbox->pack_start (tags_entry, true, true);
 
-       play_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::play_btn_clicked));
-       stop_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_btn_clicked));
-       apply_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::apply_btn_clicked));
-       tags_entry.signal_activate().connect (mem_fun (*this, &SoundFileBox::apply_btn_clicked));
+       vbox = manage (new VBox);
 
-       length.set_alignment (0.0f, 0.0f);
-       format.set_alignment (0.0f, 0.0f);
-       channels.set_alignment (0.0f, 0.0f);
-       samplerate.set_alignment (0.0f, 0.0f);
-       timecode.set_alignment (0.0f, 0.0f);
+       Label* label = manage (new Label (_("Tags:")));
+       label->set_alignment (0.0f, 0.5f);
+       vbox->set_spacing (6);
+       vbox->pack_start(*label, false, false);
+       vbox->pack_start(*hbox, true, true);
 
-       stop_btn.set_no_show_all (true);
-       stop_btn.hide();
+       main_box.pack_start(*vbox, true, true);
+       main_box.pack_start(bottom_box, false, false);
+       
+       play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
+       play_btn.set_label (_("Play (double click)"));
+
+       stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
+       stop_btn.set_label (_("Stop"));
        
-       show_all();
+       bottom_box.set_homogeneous (false);
+       bottom_box.set_spacing (6);
+       bottom_box.pack_start(play_btn, true, true);
+       bottom_box.pack_start(stop_btn, true, true);
+       bottom_box.pack_start(autoplay_btn, false, false);
+
+       play_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::audition));
+       stop_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_audition));
+
+       length.set_alignment (0.0f, 0.5f);
+       format.set_alignment (0.0f, 0.5f);
+       channels.set_alignment (0.0f, 0.5f);
+       samplerate.set_alignment (0.0f, 0.5f);
+       timecode.set_alignment (0.0f, 0.5f);
+
+       channels_value.set_alignment (0.0f, 0.5f);
+       samplerate_value.set_alignment (0.0f, 0.5f);
 }
 
 void
@@ -113,41 +204,66 @@ SoundFileBox::set_session(Session* s)
        _session = s;
 
        if (!_session) {
-               play_btn.set_sensitive(false);
-       } else {
-               _session->AuditionActive.connect(mem_fun (*this, &SoundFileBox::audition_status_changed));
-       }
+               play_btn.set_sensitive (false);
+               stop_btn.set_sensitive (false);
+       } 
+
+
+       length_clock.set_session (s);
+       timecode_clock.set_session (s);
 }
 
 bool
-SoundFileBox::setup_labels (string filename) 
+SoundFileBox::setup_labels (const ustring& filename) 
 {
+       if (!path.empty()) {
+               // save existing tags
+               tags_changed ();
+       }
+
        path = filename;
 
        string error_msg;
 
        if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
-               length.set_text (_("Length: n/a"));
-               format.set_text (_("Format: n/a"));
-               channels.set_text (_("Channels: n/a"));
-               samplerate.set_text (_("Samplerate: n/a"));
-               timecode.set_text (_("Timecode: n/a"));
-               tags_entry.set_text ("");
+
+               preview_label.set_markup (_("<b>Soundfile Info</b>"));
+               format_text.set_text (_("n/a"));
+               channels_value.set_text (_("n/a"));
+               samplerate_value.set_text (_("n/a"));
+               tags_entry.get_buffer()->set_text ("");
+
+               length_clock.set (0);
+               timecode_clock.set (0);
                
                tags_entry.set_sensitive (false);
                play_btn.set_sensitive (false);
-               apply_btn.set_sensitive (false);
                
                return false;
        }
 
-       length.set_text (string_compose(_("Length: %1"), length2string(sf_info.length, sf_info.samplerate)));
-       format.set_text (sf_info.format_name);
-       channels.set_text (string_compose(_("Channels: %1"), sf_info.channels));
-       samplerate.set_text (string_compose(_("Samplerate: %1"), sf_info.samplerate));
-       timecode.set_text (string_compose (_("Timecode: %1"), length2string(sf_info.timecode, sf_info.samplerate)));
+       preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
+       format_text.set_text (sf_info.format_name);
+       channels_value.set_text (to_string (sf_info.channels, std::dec));
+
+       if (_session && sf_info.samplerate != _session->frame_rate()) {
+               samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
+               samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
+               samplerate_value.set_name ("NewSessionSR1Label");
+               samplerate.set_name ("NewSessionSR1Label");
+       } else {
+               samplerate.set_text (_("Sample rate:"));
+               samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
+               samplerate_value.set_name ("NewSessionSR2Label");
+               samplerate.set_name ("NewSessionSR2Label");
+       }
+
+       length_clock.set (sf_info.length, true);
+       timecode_clock.set (sf_info.timecode, true);
+
+       // this is a hack that is fixed in trunk, i think (august 26th, 2007)
 
-       vector<string> tags = Library->get_tags (filename);
+       vector<string> tags = Library->get_tags (string ("//") + filename);
        
        stringstream tag_string;
        for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
@@ -156,158 +272,164 @@ SoundFileBox::setup_labels (string filename)
                }
                tag_string << *i;
        }
-       tags_entry.set_text (tag_string.str());
+       tags_entry.get_buffer()->set_text (tag_string.str());
        
        tags_entry.set_sensitive (true);
        if (_session) {
                play_btn.set_sensitive (true);
        }
-       apply_btn.set_sensitive (true);
        
        return true;
 }
 
 bool
-SoundFileBox::tags_entry_left (GdkEventFocus* event)
-{      
-       apply_btn_clicked ();
-       
-       return true;
+SoundFileBox::autoplay() const
+{
+       return autoplay_btn.get_active();
+}
+
+bool
+SoundFileBox::audition_oneshot()
+{
+       audition ();
+       return false;
 }
 
 void
-SoundFileBox::play_btn_clicked ()
+SoundFileBox::audition ()
 {
        if (!_session) {
                return;
        }
-
+       
        _session->cancel_audition();
 
-       if (access(path.c_str(), R_OK)) {
+       if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
                warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
                return;
        }
 
-       typedef std::map<string, boost::shared_ptr<AudioRegion> > RegionCache; 
-       static  RegionCache region_cache;
-       RegionCache::iterator the_region;
+       boost::shared_ptr<Region> r;
+       SourceList srclist;
+       boost::shared_ptr<AudioFileSource> afs;
+       bool old_sbp = AudioSource::get_build_peakfiles ();
 
-       if ((the_region = region_cache.find (path)) == region_cache.end()) {
-               SourceList srclist;
-               boost::shared_ptr<AudioFileSource> afs;
-               
-               for (int n = 0; n < sf_info.channels; ++n) {
-                       try {
-                               afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, *_session, path, n, AudioFileSource::Flag (0)));
-                               srclist.push_back(afs);
-
-                       } catch (failed_constructor& err) {
-                               error << _("Could not access soundfile: ") << path << endmsg;
-                               return;
-                       }
-               }
+       /* don't even think of building peakfiles for these files */
+
+       AudioSource::set_build_peakfiles (false);
 
-               if (srclist.empty()) {
+       for (int n = 0; n < sf_info.channels; ++n) {
+               try {
+                       afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, *_session, path, 
+                                                                                                          n, AudioFileSource::Flag (0), false));
+                       
+                       srclist.push_back(afs);
+                       
+               } catch (failed_constructor& err) {
+                       error << _("Could not access soundfile: ") << path << endmsg;
+                       AudioSource::set_build_peakfiles (old_sbp);
                        return;
                }
-
-               string rname;
-
-               _session->region_name (rname, Glib::path_get_basename(srclist[0]->name()), false);
-
-               pair<string,boost::shared_ptr<AudioRegion> > newpair;
-               pair<RegionCache::iterator,bool> res;
-
-               newpair.first = path;
-               newpair.second = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0, srclist[0]->length(), rname, 0, Region::DefaultFlags, false));
-
-               res = region_cache.insert (newpair);
-               the_region = res.first;
        }
 
-       play_btn.hide();
-       stop_btn.show();
-
-       boost::shared_ptr<Region> r = boost::static_pointer_cast<Region> (the_region->second);
+       AudioSource::set_build_peakfiles (old_sbp);
+                       
+       if (srclist.empty()) {
+               return;
+       }
+       
+       afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
+       string rname = region_name_from_path (afs->path(), false);
+       r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0, srclist[0]->length(), rname, 0, Region::DefaultFlags, false));
 
        _session->audition_region(r);
 }
 
 void
-SoundFileBox::stop_btn_clicked ()
+SoundFileBox::stop_audition ()
 {
        if (_session) {
                _session->cancel_audition();
-               play_btn.show();
-               stop_btn.hide();
        }
 }
 
+bool
+SoundFileBox::tags_entry_left (GdkEventFocus *ev)
+{
+       tags_changed ();
+       return false;
+}
+
 void
-SoundFileBox::apply_btn_clicked ()
+SoundFileBox::tags_changed ()
 {
-       string tag_string = tags_entry.get_text ();
+       string tag_string = tags_entry.get_buffer()->get_text ();
+
+       if (tag_string.empty()) {
+               return;
+       }
 
        vector<string> tags;
 
-    if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
+       if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
                warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
                return;
        }
-       
-       Library->set_tags (path, tags);
-       Library->save_changes ();
+
+       save_tags (tags);
 }
 
 void
-SoundFileBox::audition_status_changed (bool active)
+SoundFileBox::save_tags (const vector<string>& tags)
 {
-       ENSURE_GUI_THREAD(bind (mem_fun (*this, &SoundFileBox::audition_status_changed), active));
-       
-       if (!active) {
-               stop_btn_clicked ();
-       }
+       Library->set_tags (string ("//") + path, tags);
+       Library->save_changes ();
 }
 
-// this needs to be kept in sync with the ImportMode enum defined in editing.h and editing_syms.h.
-static const char *import_mode_strings[] = {
-       N_("Add to Region list"),
-       N_("Add to selected Track(s)"),
-       N_("Add as new Track(s)"),
-       N_("Add as new Tape Track(s)"),
-       0
-};
-
-SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s)
-       : ArdourDialog (title, false),
-         chooser (Gtk::FILE_CHOOSER_ACTION_OPEN),
-         found_list (Gtk::ListStore::create(found_list_columns)),
+SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
+       : ArdourDialog (parent, title, false, false),
+         found_list (ListStore::create(found_list_columns)),
+         chooser (FILE_CHOOSER_ACTION_OPEN),
          found_list_view (found_list),
+         preview (persistent),
          found_search_btn (_("Search"))
+
 {
-       set_default_size (700, 500);
-       Gtk::HBox* hbox = manage(new Gtk::HBox);
-       hbox->pack_start(notebook);
-       hbox->pack_start(preview, Gtk::PACK_SHRINK);
-       get_vbox()->pack_start(*hbox);
+       VBox* vbox;
+       HBox* hbox;
+
+       gm = 0;
+
+       set_session (s);
+       resetting_ourselves = false;
+       
+       hpacker.set_spacing (6);
+       hpacker.pack_start (notebook, true, true);
+       hpacker.pack_start (preview, false, false);
+
+       get_vbox()->pack_start (hpacker, true, true);
 
-       hbox = manage(new Gtk::HBox);
+       hbox = manage(new HBox);
        hbox->pack_start (found_entry);
        hbox->pack_start (found_search_btn);
        
-       Gtk::VBox* vbox = manage(new Gtk::VBox);
-       vbox->pack_start (*hbox, Gtk::PACK_SHRINK);
+       vbox = manage(new VBox);
+       vbox->pack_start (*hbox, PACK_SHRINK);
        vbox->pack_start (found_list_view);
        found_list_view.append_column(_("Paths"), found_list_columns.pathname);
        
-       notebook.append_page (chooser, _("Files"));
-       notebook.append_page (*vbox, _("Tags"));
+       chooser.set_border_width (12);
+
+       notebook.append_page (chooser, _("Browse Files"));
+       notebook.append_page (*vbox, _("Search Tags"));
 
-       found_list_view.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
+       notebook.set_size_request (500, -1);
 
-       custom_filter.add_custom (Gtk::FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_custom));
-       custom_filter.set_name (_("Probable audio files"));
+       found_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
+       found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
+
+       custom_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_custom));
+       custom_filter.set_name (_("Audio files"));
 
        matchall_filter.add_pattern ("*.*");
        matchall_filter.set_name (_("All files"));
@@ -316,6 +438,7 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s)
        chooser.add_filter (matchall_filter);
        chooser.set_select_multiple (true);
        chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
+       chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
 
        if (!persistent_folder.empty()) {
                chooser.set_current_folder (persistent_folder);
@@ -325,10 +448,11 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s)
        
        found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
        found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
+
+       add_button (Stock::CANCEL, RESPONSE_CANCEL);
+       add_button (Stock::APPLY, RESPONSE_APPLY);
+       add_button (Stock::OK, RESPONSE_OK);
        
-       show_all ();
-       
-       set_session (s);
 }
 
 SoundFileBrowser::~SoundFileBrowser ()
@@ -336,37 +460,129 @@ SoundFileBrowser::~SoundFileBrowser ()
        persistent_folder = chooser.get_current_folder();
 }
 
+
+void
+SoundFileBrowser::on_show ()
+{
+       ArdourDialog::on_show ();
+       start_metering ();
+}
+
+void
+SoundFileBrowser::clear_selection ()
+{
+       chooser.unselect_all ();
+       found_list_view.get_selection()->unselect_all ();
+}
+
+void
+SoundFileBrowser::chooser_file_activated ()
+{
+       preview.audition ();
+}
+
+void
+SoundFileBrowser::found_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
+{
+       preview.audition ();
+}
+
 void
 SoundFileBrowser::set_session (Session* s)
 {
-       preview.set_session(s);
+       ArdourDialog::set_session (s);
+       preview.set_session (s);
+       if (s) {
+               add_gain_meter ();
+       } else {
+               remove_gain_meter ();
+       }
+}
+
+void
+SoundFileBrowser::add_gain_meter ()
+{
+       if (gm) {
+               delete gm;
+       }
+
+       gm = new GainMeter (session->the_auditioner(), *session);
+
+       meter_packer.set_border_width (12);
+       meter_packer.pack_start (*gm, false, true);
+       hpacker.pack_end (meter_packer, false, false);
+       meter_packer.show_all ();
+       start_metering ();
+}
+
+void
+SoundFileBrowser::remove_gain_meter ()
+{
+       if (gm) {
+               meter_packer.remove (*gm);
+               hpacker.remove (meter_packer);
+               delete gm;
+               gm = 0;
+       }
+}
+
+void
+SoundFileBrowser::start_metering ()
+{
+       metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &SoundFileBrowser::meter));
+}
+
+void
+SoundFileBrowser::stop_metering ()
+{
+       metering_connection.disconnect();
+}
+
+void
+SoundFileBrowser::meter ()
+{
+       if (is_mapped () && session && gm) {
+               gm->update_meters ();
+       }
 }
 
 bool
-SoundFileBrowser::on_custom (const Gtk::FileFilter::Info& filter_info)
+SoundFileBrowser::on_custom (const FileFilter::Info& filter_info)
 {
-       return AudioFileSource::safe_file_extension(filter_info.filename);
+       return AudioFileSource::safe_file_extension (filter_info.filename);
 }
 
 void
 SoundFileBrowser::update_preview ()
 {
-       preview.setup_labels(chooser.get_filename());
+       preview.setup_labels (chooser.get_filename());
+
+       if (preview.autoplay()) {
+               Glib::signal_idle().connect (mem_fun (preview, &SoundFileBox::audition_oneshot));
+       }
 }
 
 void
 SoundFileBrowser::found_list_view_selected ()
 {
-       string file;
-       
-       Gtk::TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
-       
-       if (!rows.empty()) {
-               Gtk::TreeIter iter = found_list->get_iter(*rows.begin());
-               file = (*iter)[found_list_columns.pathname];
-               chooser.set_filename (file);
+       if (!reset_options ()) {
+               set_response_sensitive (RESPONSE_OK, false);
+       } else {
+               ustring file;
+
+               TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
+               
+               if (!rows.empty()) {
+                       TreeIter iter = found_list->get_iter(*rows.begin());
+                       file = (*iter)[found_list_columns.pathname];
+                       chooser.set_filename (file);
+                       set_response_sensitive (RESPONSE_OK, true);
+               } else {
+                       set_response_sensitive (RESPONSE_OK, false);
+               }
+               
+               preview.setup_labels (file);
        }
-       preview.setup_labels (file);
 }
 
 void
@@ -376,194 +592,608 @@ SoundFileBrowser::found_search_clicked ()
 
        vector<string> tags;
 
-    if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
+       if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
                warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
                return;
        }
-
+       
        vector<string> results;
        Library->search_members_and (results, tags);
        
        found_list->clear();
        for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
-               Gtk::TreeModel::iterator new_row = found_list->append();
-               Gtk::TreeModel::Row row = *new_row;
-               row[found_list_columns.pathname] = *i;
+               TreeModel::iterator new_row = found_list->append();
+               TreeModel::Row row = *new_row;
+               string path = Glib::filename_from_uri (string ("file:") + *i);
+               row[found_list_columns.pathname] = path;
        }
 }
 
-SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
-       :
-       SoundFileBrowser(title, s)
+vector<ustring>
+SoundFileBrowser::get_paths ()
 {
-       add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
-       add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+       vector<ustring> results;
        
-       chooser.set_select_multiple (false);
-       found_list_view.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
-       show_all ();
+       int n = notebook.get_current_page ();
+       
+       if (n == 0) {
+               vector<ustring> filenames = chooser.get_filenames();
+               vector<ustring>::iterator i;
+
+               for (i = filenames.begin(); i != filenames.end(); ++i) {
+                       struct stat buf;
+                       if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
+                               results.push_back (*i);
+                       }
+               }
+               
+       } else {
+               
+               typedef TreeView::Selection::ListHandle_Path ListPath;
+               
+               ListPath rows = found_list_view.get_selection()->get_selected_rows ();
+               for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
+                       TreeIter iter = found_list->get_iter(*i);
+                       ustring str = (*iter)[found_list_columns.pathname];
+                       
+                       results.push_back (str);
+               }
+       }
+
+       return results;
 }
 
-string
-SoundFileChooser::get_filename ()
+void
+SoundFileOmega::reset_options_noret ()
 {
-       Gtk::TreeModel::iterator iter;
-       Gtk::TreeModel::Row row;
-       
-       string filename;
-       switch (notebook.get_current_page()) {
-               case 0:
-                       filename = chooser.get_filename();
-               case 1:
-                       iter = found_list_view.get_selection()->get_selected();
-                       row = *iter;
-                       filename = row[found_list_columns.pathname];
-               default:
-                       /* NOT REACHED */
-                       return "";
+       if (!resetting_ourselves) {
+               (void) reset_options ();
        }
-       
-       struct stat buf;
-       if (stat (filename.c_str(), &buf) || !S_ISREG(buf.st_mode)) {
-               return "";
-       }
-       
-       return filename;
 }
 
-vector<string> SoundFileOmega::mode_strings;
-
-SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s)
-       : SoundFileBrowser (title, s),
-         split_check (_("Split Channels"))
+bool
+SoundFileOmega::reset_options ()
 {
-       ARDOUR_UI::instance()->tooltips().set_tip(split_check, 
-                       _("Create a region for each channel"));
+       vector<ustring> paths = get_paths ();
 
-       Gtk::Button* btn = add_button (_("Embed"), ResponseEmbed);
-       ARDOUR_UI::instance()->tooltips().set_tip(*btn, 
-                       _("Link to an external file"));
+       if (paths.empty()) {
 
-       btn = add_button (_("Import"), ResponseImport);
-       ARDOUR_UI::instance()->tooltips().set_tip(*btn, 
-                       _("Copy a file to the session folder"));
+               channel_combo.set_sensitive (false);
+               action_combo.set_sensitive (false);
+               where_combo.set_sensitive (false);
+               copy_files_btn.set_sensitive (false);
 
-       add_button (Gtk::Stock::CLOSE, Gtk::RESPONSE_CLOSE);
+               return false;
+
+       } else {
+
+               channel_combo.set_sensitive (true);
+               action_combo.set_sensitive (true);
+               where_combo.set_sensitive (true);
+
+               /* if we get through this function successfully, this may be
+                  reset at the end, once we know if we can use hard links
+                  to do embedding
+               */
+
+               if (Config->get_only_copy_imported_files()) {
+                       copy_files_btn.set_sensitive (false);
+               } else {
+                       copy_files_btn.set_sensitive (false);
+               }
+       }
+
+       bool same_size;
+       bool src_needed;
+       bool selection_includes_multichannel;
+       bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
+       ImportMode mode;
+
+       if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
+               Glib::signal_idle().connect (mem_fun (*this, &SoundFileOmega::bad_file_message));
+               return false;
+       }
+
+       ustring existing_choice;
+       vector<string> action_strings;
+
+       if (selected_track_cnt > 0) {
+               if (channel_combo.get_active_text().length()) {
+                       ImportDisposition id = get_channel_disposition();
+                       
+                       switch (id) {
+                       case Editing::ImportDistinctFiles:
+                               if (selected_track_cnt == paths.size()) {
+                                       action_strings.push_back (importmode2string (ImportToTrack));
+                               }
+                               break;
+                               
+                       case Editing::ImportDistinctChannels:
+                               /* XXX it would be nice to allow channel-per-selected track
+                                  but its too hard we don't want to deal with all the 
+                                  different per-file + per-track channel configurations.
+                               */
+                               break;
+                               
+                       default:
+                               action_strings.push_back (importmode2string (ImportToTrack));
+                               break;
+                       }
+               } 
+       }
+
+       action_strings.push_back (importmode2string (ImportAsTrack));
+       action_strings.push_back (importmode2string (ImportAsRegion));
+       action_strings.push_back (importmode2string (ImportAsTapeTrack));
+
+       resetting_ourselves = true;
+
+       existing_choice = action_combo.get_active_text();
+
+       set_popdown_strings (action_combo, action_strings);
+
+       /* preserve any existing choice, if possible */
+
+
+       if (existing_choice.length()) {
+               vector<string>::iterator x;
+               for (x = action_strings.begin(); x != action_strings.end(); ++x) {
+                       if (*x == existing_choice) {
+                               action_combo.set_active_text (existing_choice);
+                               break;
+                       }
+               }
+               if (x == action_strings.end()) {
+                       action_combo.set_active_text (action_strings.front());
+               }
+       } else {
+               action_combo.set_active_text (action_strings.front());
+       }
+
+       resetting_ourselves = false;
+
+       if ((mode = get_mode()) == ImportAsRegion) {
+               where_combo.set_sensitive (false);
+       } else {
+               where_combo.set_sensitive (true);
+       }
+
+       vector<string> channel_strings;
        
-       if (mode_strings.empty()) {
-               mode_strings = I18N (import_mode_strings);
+       if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
+               channel_strings.push_back (_("one track per file"));
+
+               if (selection_includes_multichannel) {
+                       channel_strings.push_back (_("one track per channel"));
+               }
+
+               if (paths.size() > 1) {
+                       /* tape tracks are a single region per track, so we cannot
+                          sequence multiple files.
+                       */
+                       if (mode != ImportAsTapeTrack) {
+                               channel_strings.push_back (_("sequence files"));
+                       }
+                       if (same_size) {
+                               channel_strings.push_back (_("all files in one region"));
+                       }
+                       
+               }
+
+       } else {
+               channel_strings.push_back (_("one region per file"));
+
+               if (selection_includes_multichannel) {
+                       channel_strings.push_back (_("one region per channel"));
+               }
+
+               if (paths.size() > 1) {
+                       if (same_size) {
+                               channel_strings.push_back (_("all files in one region"));
+                       }
+               }
+       }
+
+       existing_choice = channel_combo.get_active_text();
+
+       set_popdown_strings (channel_combo, channel_strings);
+
+       /* preserve any existing choice, if possible */
+
+       if (existing_choice.length()) {
+               vector<string>::iterator x;
+               for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
+                       if (*x == existing_choice) {
+                               channel_combo.set_active_text (existing_choice);
+                               break;
+                       }
+               }
+               if (x == channel_strings.end()) {
+                       channel_combo.set_active_text (channel_strings.front());
+               }
+       } else {
+               channel_combo.set_active_text (channel_strings.front());
        }
-       Gtkmm2ext::set_popdown_strings (mode_combo, mode_strings);
 
-       set_mode (Editing::ImportAsRegion);
+       if (src_needed) {
+               src_combo.set_sensitive (true);
+       } else {
+               src_combo.set_sensitive (false);
+       }
+       
+       if (Config->get_only_copy_imported_files()) {
 
-       get_action_area()->pack_start (split_check);
-       get_action_area()->pack_start (mode_combo);
+               if (selection_can_be_embedded_with_links) {
+                       copy_files_btn.set_sensitive (true);
+               } else {
+                       copy_files_btn.set_sensitive (false);
+               }
 
-       mode_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::mode_changed));
+       }  else {
+
+               copy_files_btn.set_sensitive (true);
+       }
        
-       show_all ();
+       return true;
+}      
+
+
+bool
+SoundFileOmega::bad_file_message()
+{
+       MessageDialog msg (*this, 
+                          _("One or more of the selected files\ncannot be used by Ardour"),
+                          true,
+                          Gtk::MESSAGE_INFO,
+                          Gtk::BUTTONS_OK);
+       msg.run ();
+       resetting_ourselves = true;
+       chooser.unselect_uri (chooser.get_preview_uri());
+       resetting_ourselves = false;
+
+       return false;
 }
 
 bool
-SoundFileOmega::get_split ()
+SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
 {
-       return split_check.get_active();
+       SNDFILE* sf;
+       SF_INFO info;
+       nframes64_t sz = 0;
+       bool err = false;
+
+       same_size = true;
+       src_needed = false;
+       multichannel = false;
+
+       for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+
+               info.format = 0; // libsndfile says to clear this before sf_open().
+               
+               if ((sf = sf_open ((char*) (*i).c_str(), SFM_READ, &info)) != 0) { 
+                       sf_close (sf);
+
+                       if (info.channels > 1) {
+                               multichannel = true;
+                       }
+
+                       if (sz == 0) {
+                               sz = info.frames;
+                       } else {
+                               if (sz != info.frames) {
+                                       same_size = false;
+                               }
+                       }
+
+                       if ((nframes_t) info.samplerate != session->frame_rate()) {
+                               src_needed = true;
+                       }
+
+               } else {
+                       err = true;
+               }
+       }
+
+       return err;
 }
 
-vector<Glib::ustring>
-SoundFileOmega::get_paths ()
+
+bool
+SoundFileOmega::check_link_status (const Session& s, const vector<ustring>& paths)
 {
-       vector<Glib::ustring> results;
-       
-       int n = notebook.get_current_page ();
+       sys::path path = s.session_directory().sound_path() / "linktest";
+       string tmpdir = path.to_string();
+       bool ret = false;
+
+       if (mkdir (tmpdir.c_str(), 0744)) {
+               if (errno != EEXIST) {
+                       return false;
+               }
+       }
        
-       if (n == 0) {
-               vector<Glib::ustring> filenames = chooser.get_filenames();
-               vector<Glib::ustring>::iterator i;
-               for (i = filenames.begin(); i != filenames.end(); ++i) {
-                       struct stat buf;
-                       if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
-                               results.push_back (*i);
-                       }
+       for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+
+               char tmpc[MAXPATHLEN+1];
+
+               snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
+
+               /* can we link ? */
+
+               if (link ((*i).c_str(), tmpc)) {
+                       goto out;
                }
-               return results;
-               
-       } else {
                
-               typedef Gtk::TreeView::Selection::ListHandle_Path ListPath;
-               
-               ListPath rows = found_list_view.get_selection()->get_selected_rows ();
-               for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
-                       Gtk::TreeIter iter = found_list->get_iter(*i);
-                       string str = (*iter)[found_list_columns.pathname];
-                       
-                       results.push_back (str);
-               }
-               return results;
+               unlink (tmpc);
        }
+
+       ret = true;
+
+  out:
+       rmdir (tmpdir.c_str());
+       return ret;
+}
+
+SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
+       : SoundFileBrowser (parent, title, s, false)
+{
+       set_size_request (780, 300);
+       chooser.set_select_multiple (false);
+       found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
 }
 
 void
-SoundFileOmega::set_mode (Editing::ImportMode mode)
+SoundFileChooser::on_hide ()
 {
-       mode_combo.set_active_text (mode_strings[(int)mode]);
+       ArdourDialog::on_hide();
+       stop_metering ();
 
-       switch (mode) {
-       case Editing::ImportAsRegion:
-               split_check.set_sensitive (true);
-               break;
-       case Editing::ImportAsTrack:
-               split_check.set_sensitive (true);
-               break;
-       case Editing::ImportToTrack:
-               split_check.set_sensitive (false);
-               break;
-       case Editing::ImportAsTapeTrack:
-               split_check.set_sensitive (true);
-               break;
-       }
-}
-
-Editing::ImportMode
-SoundFileOmega::get_mode ()
-{
-       vector<string>::iterator i;
-       uint32_t n;
-       string str = mode_combo.get_active_text ();
-
-       for (n = 0, i = mode_strings.begin (); i != mode_strings.end(); ++i, ++n) {
-               if (str == (*i)) {
-                       break;
-               }
+       if (session) {
+               session->cancel_audition();
+       }
+}
+
+ustring
+SoundFileChooser::get_filename ()
+{
+       vector<ustring> paths;
+
+       paths = get_paths ();
+
+       if (paths.empty()) {
+               return ustring ();
+       }
+       
+       if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
+               return ustring();
        }
 
-       if (i == mode_strings.end()) {
-               fatal << string_compose (_("programming error: %1"), X_("unknown import mode string")) << endmsg;
+       return paths.front();
+}
+
+SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
+                               Editing::ImportMode mode_hint)
+       : SoundFileBrowser (parent, title, s, persistent),
+         copy_files_btn ( _("Copy files to session")),
+         selected_track_cnt (selected_tracks)
+{
+       VBox* vbox;
+       HBox* hbox;
+       vector<string> str;
+
+       set_size_request (-1, 450);
+       
+       block_two.set_border_width (12);
+       block_three.set_border_width (12);
+       block_four.set_border_width (12);
+       
+       options.set_spacing (12);
+
+       str.clear ();
+       str.push_back (_("use file timestamp"));
+       str.push_back (_("at edit cursor"));
+       str.push_back (_("at playhead"));
+       str.push_back (_("at session start"));
+       set_popdown_strings (where_combo, str);
+       where_combo.set_active_text (str.front());
+
+       Label* l = manage (new Label);
+       l->set_text (_("Add files:"));
+       
+       hbox = manage (new HBox);
+       hbox->set_border_width (12);
+       hbox->set_spacing (6);
+       hbox->pack_start (*l, false, false);
+       hbox->pack_start (action_combo, false, false);
+       vbox = manage (new VBox);
+       vbox->pack_start (*hbox, false, false);
+       options.pack_start (*vbox, false, false);
+
+       /* dummy entry for action combo so that it doesn't look odd if we 
+          come up with no tracks selected.
+       */
+
+       str.clear ();
+       str.push_back (importmode2string (mode_hint));
+       set_popdown_strings (action_combo, str);
+       action_combo.set_active_text (str.front());
+       action_combo.set_sensitive (false);
+
+       l = manage (new Label);
+       l->set_text (_("Insert:"));
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (12);
+       hbox->set_spacing (6);
+       hbox->pack_start (*l, false, false);
+       hbox->pack_start (where_combo, false, false);
+       vbox = manage (new VBox);
+       vbox->pack_start (*hbox, false, false);
+       options.pack_start (*vbox, false, false);
+
+
+       l = manage (new Label);
+       l->set_text (_("Mapping:"));
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (12);
+       hbox->set_spacing (6);
+       hbox->pack_start (*l, false, false);
+       hbox->pack_start (channel_combo, false, false);
+       vbox = manage (new VBox);
+       vbox->pack_start (*hbox, false, false);
+       options.pack_start (*vbox, false, false);
+
+       str.clear ();
+       str.push_back (_("one track per file"));
+       set_popdown_strings (channel_combo, str);
+       channel_combo.set_active_text (str.front());
+       channel_combo.set_sensitive (false);
+
+       l = manage (new Label);
+       l->set_text (_("Conversion Quality:"));
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (12);
+       hbox->set_spacing (6);
+       hbox->pack_start (*l, false, false);
+       hbox->pack_start (src_combo, false, false);
+       vbox = manage (new VBox);
+       vbox->pack_start (*hbox, false, false);
+       options.pack_start (*vbox, false, false);
+
+       str.clear ();
+       str.push_back (_("Best"));
+       str.push_back (_("Good"));
+       str.push_back (_("Quick"));
+       str.push_back (_("Fast"));
+       str.push_back (_("Fastest"));
+
+       set_popdown_strings (src_combo, str);
+       src_combo.set_active_text (str.front());
+       src_combo.set_sensitive (false);
+
+       reset_options ();
+
+       action_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret));
+       
+       copy_files_btn.set_active (true);
+
+       block_four.pack_start (copy_files_btn, false, false);
+
+       options.pack_start (block_four, false, false);
+
+       get_vbox()->pack_start (options, false, false);
+
+       /* setup disposition map */
+
+       disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
+       disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
+       disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
+       disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
+
+       disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
+       disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
+       disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
+
+       chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed));
+}
+
+void
+SoundFileOmega::set_mode (ImportMode mode)
+{
+       action_combo.set_active_text (importmode2string (mode));
+}
+
+ImportMode
+SoundFileOmega::get_mode () const
+{
+       return string2importmode (action_combo.get_active_text());
+}
+
+void
+SoundFileOmega::on_hide ()
+{
+       ArdourDialog::on_hide();
+       if (session) {
+               session->cancel_audition();
+       }
+}
+
+ImportPosition
+SoundFileOmega::get_position() const
+{
+       ustring str = where_combo.get_active_text();
+
+       if (str == _("use file timestamp")) {
+               return ImportAtTimestamp;
+       } else if (str == _("at edit cursor")) {
+               return ImportAtEditCursor;
+       } else if (str == _("at playhead")) {
+               return ImportAtPlayhead;
+       } else {
+               return ImportAtStart;
+       }
+}
+
+SrcQuality
+SoundFileOmega::get_src_quality() const
+{
+       ustring str = where_combo.get_active_text();
+
+       if (str == _("Best")) {
+               return SrcBest;
+       } else if (str == _("Good")) {
+               return SrcGood;
+       } else if (str == _("Quick")) {
+               return SrcQuick;
+       } else if (str == _("Fast")) {
+               return SrcFast;
+       } else {
+               return SrcFastest;
+       }
+}
+
+ImportDisposition
+SoundFileOmega::get_channel_disposition () const
+{
+       /* we use a map here because the channel combo can contain different strings
+          depending on the state of the other combos. the map contains all possible strings
+          and the ImportDisposition enum that corresponds to it.
+       */
+
+       ustring str = channel_combo.get_active_text();
+       DispositionMap::const_iterator x = disposition_map.find (str);
+
+       if (x == disposition_map.end()) {
+               fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
                /*NOTREACHED*/
        }
 
-       return (Editing::ImportMode) (n);
+       return x->second;
 }
 
 void
-SoundFileOmega::mode_changed ()
+SoundFileOmega::reset (int selected_tracks)
 {
-       Editing::ImportMode mode = get_mode();
+       selected_track_cnt = selected_tracks;
+       reset_options ();
+}      
 
-       switch (mode) {
-       case Editing::ImportAsRegion:
-               split_check.set_sensitive (true);
-               break;
-       case Editing::ImportAsTrack:
-               split_check.set_sensitive (true);
-               break;
-       case Editing::ImportToTrack:
-               split_check.set_sensitive (false);
-               break;
-       case Editing::ImportAsTapeTrack:
-               split_check.set_sensitive (true);
-               break;
+void
+SoundFileOmega::file_selection_changed ()
+{
+       if (resetting_ourselves) {
+               return;
+       }
+
+       if (!reset_options ()) {
+               set_response_sensitive (RESPONSE_OK, false);
+       } else {
+               if (chooser.get_filenames().size() > 0) {
+                       set_response_sensitive (RESPONSE_OK, true);
+               } else {
+                       set_response_sensitive (RESPONSE_OK, false);
+               }
        }
 }
 
index 34c3f558bbd8cd245ce98e746df6964fbdf75d67..43f76a9ea24402028eee6785ff3d139c9dba90d6 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <string>
 #include <vector>
+#include <map>
+#include <glibmm/ustring.h>
 
 #include <sigc++/signal.h>
 
 #include "ardour_dialog.h"
 #include "editing.h"
 
+namespace ARDOUR {
+       class Session;
+};
+
+class GainMeter;
+
 class SoundFileBox : public Gtk::VBox
 {
   public:
-       SoundFileBox ();
+       SoundFileBox (bool persistent);
        virtual ~SoundFileBox () {};
        
        void set_session (ARDOUR::Session* s);
-       bool setup_labels (std::string filename);
+       bool setup_labels (const Glib::ustring& filename);
+
+       void audition();
+       bool audition_oneshot();
+       bool autoplay () const;
 
   protected:
        ARDOUR::Session* _session;
-       std::string path;
+       Glib::ustring path;
        
        ARDOUR::SoundFileInfo sf_info;
        
-       pid_t current_pid;
+       Gtk::Table table;
        
        Gtk::Label length;
        Gtk::Label format;
        Gtk::Label channels;
        Gtk::Label samplerate;
        Gtk::Label timecode;
+
+       Gtk::Label channels_value;
+       Gtk::Label samplerate_value;
        
+       Gtk::Label format_text;
+       AudioClock length_clock;
+       AudioClock timecode_clock;
+
        Gtk::Frame border_frame;
-       
-       Gtk::Entry tags_entry;
+       Gtk::Label preview_label;
+
+       Gtk::TextView tags_entry;
        
        Gtk::VBox main_box;
        Gtk::VBox path_box;
@@ -74,91 +94,137 @@ class SoundFileBox : public Gtk::VBox
        
        Gtk::Button play_btn;
        Gtk::Button stop_btn;
+       Gtk::CheckButton autoplay_btn;
        Gtk::Button apply_btn;
-       
+
        bool tags_entry_left (GdkEventFocus* event);
-       void play_btn_clicked ();
-       void stop_btn_clicked ();
-       void apply_btn_clicked ();
-       
-       void audition_status_changed (bool state);
+       void tags_changed ();
+       void save_tags (const std::vector<std::string>&);
+       void stop_audition ();
 };
 
 class SoundFileBrowser : public ArdourDialog
 {
+  private:
+       class FoundTagColumns : public Gtk::TreeModel::ColumnRecord
+       {
+         public:
+               Gtk::TreeModelColumn<Glib::ustring> pathname;
+               
+               FoundTagColumns() { add(pathname); }
+       };
+       
+       FoundTagColumns found_list_columns;
+       Glib::RefPtr<Gtk::ListStore> found_list;
+
   public:
-       SoundFileBrowser (std::string title, ARDOUR::Session* _s = 0);
+       SoundFileBrowser (Gtk::Window& parent, std::string title, ARDOUR::Session* _s, bool persistent);
        virtual ~SoundFileBrowser ();
        
        virtual void set_session (ARDOUR::Session*);
+       std::vector<Glib::ustring> get_paths ();
+       
+       void clear_selection ();
 
-  protected:
        Gtk::FileChooserWidget chooser;
+       Gtk::TreeView found_list_view;
+
+  protected:
+       bool resetting_ourselves;
+       
        Gtk::FileFilter custom_filter;
        Gtk::FileFilter matchall_filter;
        SoundFileBox preview;
+       Gtk::HBox hpacker;
 
        static Glib::ustring persistent_folder;
 
-       class FoundTagColumns : public Gtk::TreeModel::ColumnRecord
-       {
-         public:
-               Gtk::TreeModelColumn<string> pathname;
-               
-               FoundTagColumns() { add(pathname); }
-       };
-       
-       FoundTagColumns found_list_columns;
-       Glib::RefPtr<Gtk::ListStore> found_list;
-       Gtk::TreeView found_list_view;
        Gtk::Entry found_entry;
        Gtk::Button found_search_btn;
-
        Gtk::Notebook notebook;
-       
+
+       GainMeter* gm;
+       Gtk::VBox meter_packer;
+       void add_gain_meter ();
+       void remove_gain_meter ();
+       void meter ();
+       void start_metering ();
+       void stop_metering ();
+       sigc::connection metering_connection;
+
        void update_preview ();
        void found_list_view_selected ();
+       void found_list_view_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*);
        void found_search_clicked ();
+
+       void chooser_file_activated ();
        
        bool on_custom (const Gtk::FileFilter::Info& filter_info);
+
+       virtual bool reset_options() { return true; }
+
+  protected:
+       void on_show();
+
 };
 
 class SoundFileChooser : public SoundFileBrowser
 {
   public:
-       SoundFileChooser (std::string title, ARDOUR::Session* _s = 0);
+       SoundFileChooser (Gtk::Window& parent, std::string title, ARDOUR::Session* _s = 0);
        virtual ~SoundFileChooser () {};
        
-       std::string get_filename ();
+       Glib::ustring get_filename ();
+
+  protected:
+       void on_hide();
 };
 
 class SoundFileOmega : public SoundFileBrowser
 {
+
   public:
-       SoundFileOmega (std::string title, ARDOUR::Session* _s);
-       virtual ~SoundFileOmega () {};
-       
-       /* these are returned by the Dialog::run() method. note
-          that builtin GTK responses are all negative, leaving
-          positive values for application-defined responses.
-       */
-       
-       const static int ResponseImport = 1;
-       const static int ResponseEmbed = 2;
+       SoundFileOmega (Gtk::Window& parent, std::string title, ARDOUR::Session* _s, int selected_tracks, bool persistent, 
+                       Editing::ImportMode mode_hint = Editing::ImportAsTrack);
        
-       std::vector<Glib::ustring> get_paths ();
-       bool get_split ();
+       void reset (int selected_tracks);
        
+       Gtk::ComboBoxText action_combo;
+       Gtk::ComboBoxText where_combo;
+       Gtk::ComboBoxText channel_combo;
+       Gtk::ComboBoxText src_combo;
+
+       Gtk::CheckButton copy_files_btn;
+
        void set_mode (Editing::ImportMode);
-       Editing::ImportMode get_mode ();
+       Editing::ImportMode get_mode() const;
+       Editing::ImportPosition get_position() const;
+       Editing::ImportDisposition get_channel_disposition() const;
+       ARDOUR::SrcQuality get_src_quality() const;
 
   protected:
-       Gtk::CheckButton  split_check;
-       Gtk::ComboBoxText mode_combo;
-       
-       void mode_changed ();
-       
-       static std::vector<std::string> mode_strings;
+       void on_hide();
+
+  private:
+       uint32_t selected_track_cnt;
+
+       typedef std::map<Glib::ustring,Editing::ImportDisposition> DispositionMap;
+       DispositionMap disposition_map;
+
+       Gtk::HBox options;
+       Gtk::VBox block_two;
+       Gtk::VBox block_three;
+       Gtk::VBox block_four;
+
+       bool check_info (const std::vector<Glib::ustring>& paths, 
+                        bool& same_size, bool& src_needed, bool& multichannel);
+
+       static bool check_link_status (const ARDOUR::Session&, const std::vector<Glib::ustring>& paths);
+
+       void file_selection_changed ();
+       bool reset_options ();
+       void reset_options_noret ();
+       bool bad_file_message ();
 };
 
 #endif // __ardour_sfdb_ui_h__
index 560dcd503f565f14d8960f99d20fca38b33cbf17..1a3fb9a0842ce3a39f6b74ceca16433ceb7ee802 100644 (file)
@@ -153,6 +153,8 @@ StreamView::set_samples_per_unit (gdouble spp)
 void
 StreamView::add_region_view (boost::shared_ptr<Region> r)
 {
+       // ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_region_view), r));
+
        add_region_view_internal (r, true);
 }
 
index 83a95fb71f0257fd0dca10c18bb70b2e172bac81..570a481c11036116abf945c0cc2fc5b2d971cc24 100644 (file)
@@ -337,6 +337,12 @@ set_color (Gdk::Color& c, int rgb)
        c.set_rgb((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256);
 }
 
+#ifdef GTKOSX
+extern "C" {
+       gboolean gdk_quartz_possibly_forward (GdkEvent*);
+}
+#endif
+
 bool
 key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
 {
@@ -348,7 +354,6 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
 #ifdef  DEBUG_ACCELERATOR_HANDLING
        bool debug = (getenv ("ARDOUR_DEBUG_ACCELERATOR_HANDLING") != 0);
 #endif
-
        if (focus) {
                if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
                        special_handling_of_unmodified_accelerators = true;
@@ -443,6 +448,11 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
                if (debug) {
                        cerr << "\tactivate, then propagate\n";
                }
+#endif
+#ifdef GTKOSX
+               if (gdk_quartz_possibly_forward ((GdkEvent*) ev)) {
+                       return true;
+               }
 #endif
                if (!gtk_window_activate_key (win, ev)) {
                        return gtk_window_propagate_key_event (win, ev);
@@ -468,6 +478,11 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
                if (debug) {
                        cerr << "\tpropagation didn't handle, so activate\n";
                }
+#endif
+#ifdef GTKOSX
+               if (gdk_quartz_possibly_forward ((GdkEvent*) ev)) {
+                       return true;
+               }
 #endif
                return gtk_window_activate_key (win, ev);
        } else {
@@ -490,23 +505,18 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
 Glib::RefPtr<Gdk::Pixbuf>      
 get_xpm (std::string name)
 {
-       if (!xpm_map[name]) {
-
-               SearchPath spath(ARDOUR::ardour_search_path());
-               spath += ARDOUR::system_data_search_path();
-
-               spath.add_subdirectory_to_paths("pixmaps");
+       SearchPath spath(ARDOUR::ardour_search_path());
+       spath += ARDOUR::system_data_search_path();
 
-               sys::path data_file_path;
+       spath.add_subdirectory_to_paths("pixmaps");
 
-               if(!find_file_in_search_path (spath, name, data_file_path)) {
-                       fatal << string_compose (_("cannot find pixmap %1"), name) << endmsg;
-               }
+       sys::path data_file_path;
 
-               xpm_map[name] = Gdk::Pixbuf::create_from_file (data_file_path.to_string());
+       if(!find_file_in_search_path (spath, name, data_file_path)) {
+               fatal << string_compose (_("cannot find XPM file for %1"), name) << endmsg;
        }
-               
-       return (xpm_map[name]);
+
+       return Gdk::Pixbuf::create_from_file (data_file_path.to_string());
 }
 
 Glib::RefPtr<Gdk::Pixbuf>      
index 3892af6e9bfaa1337b1e9273227b853c20553d89..465138d90d2f62a357cd610695c9a6feced11220 100644 (file)
@@ -12,7 +12,7 @@ ardour = env.Copy()
 # this defines the version number of libardour
 # 
 
-domain = 'libardour'
+domain = 'libardour2'
 
 ardour.Append(DOMAIN = domain, MAJOR = 2, MINOR = 0, MICRO = 0)
 ardour.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
@@ -101,6 +101,7 @@ recent_sessions.cc
 region.cc
 region_factory.cc
 reverse.cc
+resampled_source.cc
 quantize.cc
 route.cc
 route_group.cc
index 1b9725a04cc577ba57c988e5cc4b2c76a96ad85e..6e7b494441b260319774111e67185de29989ac3a 100644 (file)
@@ -47,8 +47,6 @@ namespace ARDOUR {
        int init (bool with_vst, bool try_optimization);
        int cleanup ();
 
-       int setup_midi(AudioEngine& engine);
-       
        std::string get_ardour_revision ();
 
        microseconds_t get_microseconds ();
index 78d10f9d64eb919d259bad50772f6915bbe23d46..4d80c8ddf558fa625ccce6ff35c73f1eb46c86a4 100644 (file)
@@ -61,7 +61,8 @@ class AudioFileSource : public AudioSource {
        
        Glib::ustring path() const { return _path; }
        Glib::ustring peak_path (Glib::ustring audio_path);
-       Glib::ustring old_peak_path (Glib::ustring audio_path);
+       Glib::ustring find_broken_peakfile (Glib::ustring missing_peak_path,
+                                            Glib::ustring audio_path);
 
        uint16_t channel() const { return _channel; }
 
@@ -122,7 +123,7 @@ class AudioFileSource : public AudioSource {
           to cause issues.
        */
 
-       virtual void handle_header_position_change ();
+       virtual void handle_header_position_change () {}
 
   protected:
        
@@ -166,6 +167,10 @@ class AudioFileSource : public AudioSource {
        bool find (Glib::ustring& path, bool must_exist, bool& is_new, uint16_t& chan);
        bool removable() const;
        bool writable() const { return _flags & Writable; }
+
+  private:
+       Glib::ustring old_peak_path (Glib::ustring audio_path);
+       Glib::ustring broken_peak_path (Glib::ustring audio_path);
 };
 
 } // namespace ARDOUR
index 812c30e8c297ebfc18f2520316d8cba5fe03e82d..7b22528bd17756defee57e2fa248ab0ab9f6caac 100644 (file)
@@ -40,7 +40,6 @@
 
 using std::list;
 using std::vector;
-using Glib::ustring;
 
 namespace ARDOUR {
 
@@ -49,10 +48,23 @@ const nframes_t frames_per_peak = 256;
  class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR::AudioSource>
 {
   public:
-       AudioSource (Session&, ustring name);
+       AudioSource (Session&, Glib::ustring name);
        AudioSource (Session&, const XMLNode&);
        virtual ~AudioSource ();
+
+       /* one could argue that this should belong to Source, but other data types
+          generally do not come with a model of "offset along an audio timeline"
+          so its here in AudioSource for now.
+       */
+
+       virtual nframes_t natural_position() const { return 0; }
        
+       /* returns the number of items in this `audio_source' */
+
+       virtual nframes_t length() const {
+               return _length;
+       }
+
        virtual nframes_t available_peaks (double zoom) const;
 
        virtual nframes_t read (Sample *dst, nframes_t start, nframes_t cnt) const;
@@ -65,8 +77,8 @@ const nframes_t frames_per_peak = 256;
 
        virtual bool can_truncate_peaks() const { return true; }
 
-       void set_captured_for (ustring str) { _captured_for = str; }
-       ustring captured_for() const { return _captured_for; }
+       void set_captured_for (Glib::ustring str) { _captured_for = str; }
+       Glib::ustring captured_for() const { return _captured_for; }
 
        uint32_t read_data_count() const { return _read_data_count; }
        uint32_t write_data_count() const { return _write_data_count; }
@@ -81,7 +93,7 @@ const nframes_t frames_per_peak = 256;
        XMLNode& get_state ();
        int set_state (const XMLNode&);
 
-       int rename_peakfile (ustring newpath);
+       int rename_peakfile (Glib::ustring newpath);
        void touch_peakfile ();
 
        static void set_build_missing_peakfiles (bool yn) {
@@ -92,35 +104,43 @@ const nframes_t frames_per_peak = 256;
                _build_peakfiles = yn;
        }
 
+       static bool get_build_peakfiles () {
+               return _build_peakfiles;
+       }
+
        virtual int setup_peakfile () { return 0; }
 
        int prepare_for_peakfile_writes ();
-       void done_with_peakfile_writes ();
+       void done_with_peakfile_writes (bool done = true);
 
   protected:
        static bool _build_missing_peakfiles;
        static bool _build_peakfiles;
 
-       bool                _peaks_built;
-       mutable Glib::Mutex _lock;
-       ustring               peakpath;
-       ustring              _captured_for;
+       bool                 _peaks_built;
+       mutable Glib::Mutex  _lock;
+       mutable Glib::Mutex  _peaks_ready_lock;
+       nframes_t            _length;
+       Glib::ustring               peakpath;
+       Glib::ustring              _captured_for;
 
        mutable uint32_t _read_data_count;  // modified in read()
        mutable uint32_t _write_data_count; // modified in write()
 
-       int initialize_peakfile (bool newfile, ustring path);
+       int initialize_peakfile (bool newfile, Glib::ustring path);
        int build_peaks_from_scratch ();
-       int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force);
+       int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force, bool intermediate_peaks_ready_signal);
        void truncate_peakfile();
 
        mutable off_t _peak_byte_max; // modified in compute_and_write_peak()
 
        virtual nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const = 0;
        virtual nframes_t write_unlocked (Sample *dst, nframes_t cnt) = 0;
-       virtual ustring peak_path(ustring audio_path) = 0;
-       virtual ustring old_peak_path(ustring audio_path) = 0;
+       virtual Glib::ustring peak_path(Glib::ustring audio_path) = 0;
+       virtual Glib::ustring find_broken_peakfile (Glib::ustring missing_peak_path, Glib::ustring audio_path) = 0;
        
+       void update_length (nframes_t pos, nframes_t cnt);
+
   private:
        int peakfile;
        nframes_t peak_leftover_cnt;
@@ -128,7 +148,7 @@ const nframes_t frames_per_peak = 256;
        Sample* peak_leftovers;
        nframes_t peak_leftover_frame;
 
-       bool file_changed (ustring path);
+       bool file_changed (Glib::ustring path);
 };
 
 }
index fe47614a1f6eecf693bfb9d473774adc08c7c334..f96ecc0bd139150aea0bf9b74b6582573b67e3d0 100644 (file)
@@ -83,6 +83,14 @@ public:
        
        Glib::Mutex& automation_lock() const { return _automation_lock; }
 
+       static void set_automation_interval (jack_nframes_t frames) {
+               _automation_interval = frames;
+       }
+
+       static jack_nframes_t automation_interval() { 
+               return _automation_interval;
+       }
+
 protected:
 
        void can_automate(Parameter);
@@ -102,6 +110,7 @@ protected:
        std::set<Parameter> _can_automate_list;
        
        nframes_t _last_automation_snapshot;
+       static nframes_t _automation_interval;
 };
 
 } // namespace ARDOUR
index 70b7e166c155754986a01dff670566430d06a833..7b890500d8fc375f84db7fd9f5bb90f5a089c995 100644 (file)
@@ -42,17 +42,7 @@ class Configuration : public PBD::Stateful
        Configuration();
        virtual ~Configuration();
 
-       struct MidiPortDescriptor {
-               std::string tag;
-               std::string device;
-               std::string type;
-               std::string mode;
-
-               MidiPortDescriptor (const XMLNode&);
-               XMLNode& get_state();
-       };
-
-       std::map<std::string,MidiPortDescriptor *> midi_ports;
+       std::map<std::string,XMLNode> midi_ports;
 
        void map_parameters (sigc::slot<void,const char*> theSlot);
 
index 4d5579a9a08b0ad6d12d6dad9915b348de4c2d55..b592a9f721f232a673935c63ef671fd60315f555 100644 (file)
@@ -138,11 +138,15 @@ CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture",
 CONFIG_VARIABLE (bool, no_new_session_dialog, "no-new-session-dialog", false)
 CONFIG_VARIABLE (bool, use_vst, "use-vst", true)
 CONFIG_VARIABLE (uint32_t, subframes_per_frame, "subframes-per-frame", 100)
-CONFIG_VARIABLE (uint32_t, saved_history_depth, "save-history-depth", 100)
+CONFIG_VARIABLE (bool, save_history, "save-history", true)
+CONFIG_VARIABLE (int32_t, saved_history_depth, "save-history-depth", 20)
+CONFIG_VARIABLE (int32_t, history_depth, "history-depth", 20)
 CONFIG_VARIABLE (bool, use_overlap_equivalency, "use-overlap-equivalency", false)
 CONFIG_VARIABLE (bool, periodic_safety_backups, "periodic-safety-backups", true)
 CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-backup-interval", 120)
-CONFIG_VARIABLE (string, possible_audio_file_regexp, "possible-audio-file-regexp", "\\.(wav|aiff|caf|w64|L|R)$")
+CONFIG_VARIABLE (float, automation_interval, "automation-interval", 50)
+CONFIG_VARIABLE (bool, sync_all_route_ordering, "sync-all-route-ordering", true)
+CONFIG_VARIABLE (bool, only_copy_imported_files, "only-copy-imported-files", true)
 
 /* denormal management */
 
index 6c040be63e220e02d482a50c9b6075943c52edc8..6e68c01d8c2039463dc92c93ef6f8138ee0bfe8b 100644 (file)
@@ -219,7 +219,7 @@ class IO : public Automatable, public Latent
   public:
 
        /* automation */
-       
+
        struct GainControl : public AutomationControl {
            GainControl (std::string name, IO& i, boost::shared_ptr<AutomationList> al)
                        : AutomationControl (i._session, al, name)
index 33474479154c42681fb28e48d106c4a1177345e1..b016063c4d3820b1aa63f6d2d36434375c0194c5 100644 (file)
@@ -29,6 +29,8 @@ class RuntimeProfile {
   public:
     enum Element {
            SmallScreen,
+           SAE,
+           SinglePackage,
            LastElement
     };
     
@@ -38,6 +40,12 @@ class RuntimeProfile {
     void set_small_screen() { bits[SmallScreen] = true; }
     bool get_small_screen() const { return bits[SmallScreen]; }
 
+    void set_sae () { bits[SAE] = true; }
+    bool get_sae () const { return bits[SAE]; }
+
+    void set_single_package () { bits[SinglePackage] = true; }
+    bool get_single_package () const { return bits[SinglePackage]; }
+
   private:
     boost::dynamic_bitset<uint64_t> bits;
     
diff --git a/libs/ardour/ardour/resampled_source.h b/libs/ardour/ardour/resampled_source.h
new file mode 100644 (file)
index 0000000..9a88ca9
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+    Copyright (C) 2007 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.
+
+*/
+
+#ifndef __ardour_resampled_source_h__
+#define __ardour_resampled_source_h__
+
+#include <samplerate.h>
+
+#include <ardour/types.h>
+#include <ardour/importable_source.h>
+
+namespace ARDOUR {
+
+class ResampledImportableSource : public ImportableSource 
+{
+  public:
+       ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate, SrcQuality);
+       ~ResampledImportableSource ();
+       
+       nframes_t read (Sample* buffer, nframes_t nframes);
+               
+       float ratio() const { return src_data.src_ratio; }
+       
+       static const uint32_t blocksize;
+       
+   private:
+        float* input;
+       SRC_STATE*      src_state;
+       SRC_DATA        src_data;
+};
+
+}
+
+#endif /* __ardour_resampled_source_h__ */
index 1fd6eff0f8917e34c4a04ba00691e57de2ce6f6e..fc17af06eedf4c4f476c0829a4a394a7f457acfb 100644 (file)
@@ -258,6 +258,9 @@ class Route : public IO
        uint32_t remote_control_id () const;
        sigc::signal<void> RemoteControlIDChanged;
 
+       void sync_order_keys ();
+       static sigc::signal<void> SyncOrderKeys;
+
   protected:
        friend class Session;
 
index 94caf8a242b40ee73441ca097e5437abcd001d31..bbcae6e91d3d0ddeaec99bea8021618d50c63dab 100644 (file)
@@ -261,6 +261,8 @@ class Session : public PBD::StatefulDestructible
 
        std::string automation_dir () const;
 
+       Glib::ustring peak_path (Glib::ustring) const;
+
        static string change_audio_path_by_name (string oldpath, string oldname, string newname, bool destructive);
        static string change_midi_path_by_name (string oldpath, string oldname, string newname, bool destructive);
        
@@ -422,6 +424,7 @@ class Session : public PBD::StatefulDestructible
        int restore_history (string snapshot_name);
        void remove_state (string snapshot_name);
        void rename_state (string old_name, string new_name);
+       void remove_pending_capture_state ();
        
        sigc::signal<void,string> StateSaved;
        sigc::signal<void> StateReady;
@@ -568,13 +571,14 @@ class Session : public PBD::StatefulDestructible
            string doing_what;
            
            /* control info */
-           bool multichan;
            bool sample_convert;
+           SrcQuality quality;
            volatile bool freeze;
            std::vector<Glib::ustring> paths;
            
            /* result */
-           std::vector<boost::shared_ptr<Region> > new_regions;
+           SourceList sources;
+           
        };
 
        int import_audiofile (import_status&);
@@ -650,8 +654,6 @@ class Session : public PBD::StatefulDestructible
        void add_curve(Curve*);
        void add_automation_list(AutomationList*);
        
-       nframes_t automation_interval () const { return _automation_interval; }
-
        /* fade curves */
 
        float get_default_fade_length () const { return default_fade_msecs; }
@@ -1650,8 +1652,6 @@ class Session : public PBD::StatefulDestructible
        void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force);
        uint32_t _npan_buffers;
 
-       nframes_t _automation_interval;
-
        /* VST support */
 
        long _vst_callback (VSTPlugin*,
@@ -1668,7 +1668,6 @@ class Session : public PBD::StatefulDestructible
        uint32_t n_physical_outputs;
        uint32_t n_physical_inputs;
 
-       void remove_pending_capture_state ();
 
        int find_all_sources (std::string path, std::set<std::string>& result);
        int find_all_sources_across_snapshots (std::set<std::string>& result, bool exclude_this_snapshot);
@@ -1688,6 +1687,8 @@ class Session : public PBD::StatefulDestructible
 
        XMLNode& get_control_protocol_state ();
        
+       void set_history_depth (uint32_t depth);
+       void sync_order_keys ();
 };
 
 } // namespace ARDOUR
index 916e9da49ec15f6b5d4ed7c8cecd705180b4dc90..4fd71a4c96285ead1251942434fd2e20c922dea8 100644 (file)
@@ -76,9 +76,6 @@ class SndFileSource : public AudioFileSource {
        SF_INFO _info;
        SF_BROADCAST_INFO *_broadcast_info;
 
-       mutable float *interleave_buf;
-       mutable nframes_t interleave_bufsize;
-
        void init ();
        int open();
        void close();
@@ -105,6 +102,7 @@ class SndFileSource : public AudioFileSource {
        void handle_header_position_change ();
 
        static int64_t get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists);
+       static Sample* get_interleave_buffer (nframes_t size);
 };
 
 } // namespace ARDOUR
index fb591216bfa91e465f9e348c76612c7ad8ab3b9d..01f50126a4b68cf2f9fea6ac1b0fb247bced07a3 100644 (file)
@@ -36,16 +36,23 @@ class Session;
 
 class SourceFactory {
   public:
+       static void init ();
+
        static sigc::signal<void,boost::shared_ptr<Source> > SourceCreated;
 
-       static boost::shared_ptr<Source> create (Session&, const XMLNode& node);
+       static boost::shared_ptr<Source> create (Session&, const XMLNode& node, bool async = false);
        static boost::shared_ptr<Source> createSilent (Session&, const XMLNode& node, nframes_t nframes, float sample_rate);
 
-       static boost::shared_ptr<Source> createReadable (DataType type, Session&, std::string path, int chn, AudioFileSource::Flag flags, bool announce = true);
-       static boost::shared_ptr<Source> createWritable (DataType type, Session&, std::string name, bool destructive, nframes_t rate, bool announce = true);
+       static boost::shared_ptr<Source> createReadable (DataType type, Session&, std::string path, int chn, AudioFileSource::Flag flags,
+                                                        bool announce = true, bool async = false);
+       static boost::shared_ptr<Source> createWritable (DataType type, Session&, std::string name, bool destructive, nframes_t rate, 
+                                                        bool announce = true, bool async = true);
+
+       static Glib::Cond*                              PeaksToBuild;
+       static Glib::StaticMutex                        peak_building_lock;
+       static std::list<boost::weak_ptr<AudioSource> > files_with_peaks;
 
-  private:
-       static int setup_peakfile (boost::shared_ptr<Source>);
+       static int setup_peakfile (boost::shared_ptr<Source>, bool async);
 };
 
 }
index e13bd09d83a9fe06cd58d8f8d0c3ab11bc7c0353..5b5071331352f9ed50e28e214fac0c4f5e6f0365 100644 (file)
@@ -370,6 +370,15 @@ namespace ARDOUR {
        };
 
        typedef std::vector<boost::shared_ptr<Source> > SourceList;
+
+       enum SrcQuality {
+               SrcBest,
+               SrcGood,
+               SrcQuick,
+               SrcFast,
+               SrcFastest
+       };
+
 } // namespace ARDOUR
 
 std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
index cde17d8b492cdd9aa7add37efcc9700887cf1cec..e52274eb1f1968664c45b5e6dd6ff53886acc4f3 100644 (file)
@@ -50,7 +50,7 @@ int cmp_nocase (const std::string& s, const std::string& s2);
 int touch_file(Glib::ustring path);
 
 Glib::ustring path_expand (Glib::ustring);
-Glib::ustring region_name_from_path (Glib::ustring path, bool strip_channels);
+Glib::ustring region_name_from_path (Glib::ustring path, bool strip_channels, bool add_channel_suffix = false, uint32_t total = 0, uint32_t this_one = 0);
 bool path_is_paired (Glib::ustring path, Glib::ustring& pair_base);
 
 void compute_equal_power_fades (nframes_t nframes, float* in, float* out);
index d28d88488ed651b853eb7b8d231142ec127a2f32..d5c6120946f3daffb873e3cced312bd3a0ad82ed 100644 (file)
@@ -379,7 +379,9 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                        bottom = region;
                }
 
-
+               if (!top->opaque()) {
+                       continue;
+               }
 
                OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
 
index a4ce5f291d48ffc1d9fc41d468164658ec929aa4..2a4b36f7d8cd9cb8d25e6cf5173deacb2418e14c 100644 (file)
@@ -156,7 +156,7 @@ AudioEngine::start ()
                        _has_run = true;
                        Running(); /* EMIT SIGNAL */
                } else {
-                       error << _("cannot activate JACK client") << endmsg;
+                       // error << _("cannot activate JACK client") << endmsg;
                }
        }
 
@@ -1078,7 +1078,7 @@ AudioEngine::connect_to_jack (string client_name)
                        error << _("Unable to connect to JACK server") << endmsg;
                }
                
-               error << string_compose (_("Could not connect to JACK server as  \"%1\""), jack_client_name) <<  endmsg;
+               // error message is not useful here
                return -1;
        }
 
index 1044dd10d2c4b521d23719b62a9b1a946a32d388..1284dd343bbe0fb127d5432ceb8115fc50d11989 100644 (file)
 
 #include <sys/time.h>
 #include <sys/stat.h>
+#include <stdio.h> // for rename(), sigh
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 
+#include <pbd/convert.h>
+#include <pbd/basename.h>
 #include <pbd/mountpoint.h>
 #include <pbd/stl_delete.h>
 #include <pbd/strsplit.h>
@@ -40,6 +43,7 @@
 #include <ardour/sndfile_helpers.h>
 #include <ardour/sndfilesource.h>
 #include <ardour/session.h>
+#include <ardour/session_directory.h>
 #include <ardour/source_factory.h>
 #include <ardour/filename_extensions.h>
 
@@ -153,7 +157,60 @@ AudioFileSource::init (ustring pathstr, bool must_exist)
 ustring
 AudioFileSource::peak_path (ustring audio_path)
 {
-       return _session.peak_path_from_audio_path (audio_path);
+       ustring base;
+
+       base = PBD::basename_nosuffix (audio_path);
+       base += '%';
+       base += (char) ('A' + _channel);
+
+       return _session.peak_path (base);
+}
+
+ustring
+AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
+{
+       ustring str;
+
+       /* check for the broken location in use by 2.0 for several months */
+       
+       str = broken_peak_path (audio_path);
+       
+       if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
+               
+               if (is_embedded()) {
+                       
+                       /* it would be nice to rename it but the nature of 
+                          the bug means that we can't reliably use it.
+                       */
+                       
+                       peak_path = str;
+                       
+               } else {
+                       /* all native files are mono, so we can just rename
+                          it.
+                       */
+                       ::rename (str.c_str(), peak_path.c_str());
+               }
+               
+       } else {
+               /* Nasty band-aid for older sessions that were created before we
+                  used libsndfile for all audio files.
+               */
+               
+               
+               str = old_peak_path (audio_path);       
+               if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
+                       peak_path = str;
+               }
+       }
+
+       return peak_path;
+}
+
+ustring
+AudioFileSource::broken_peak_path (ustring audio_path)
+{
+       return _session.peak_path (audio_path);
 }
 
 ustring
@@ -171,9 +228,9 @@ AudioFileSource::old_peak_path (ustring audio_path)
 
        char buf[32];
 #ifdef __APPLE__
-       snprintf (buf, sizeof (buf), "%u-%u-%d", stat_mount.st_ino, stat_file.st_ino, _channel);
+       snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
 #else
-       snprintf (buf, sizeof (buf), "%ld-%ld-%d", stat_mount.st_ino, stat_file.st_ino, _channel);
+       snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
 #endif
 
        ustring res = peak_dir;
@@ -227,7 +284,7 @@ AudioFileSource::set_state (const XMLNode& node)
        }
 
        if ((prop = node.property (X_("channel"))) != 0) {
-               _channel = atoi (prop->value().c_str());
+               _channel = atoi (prop->value());
        } else {
                _channel = 0;
        }
@@ -265,6 +322,10 @@ AudioFileSource::mark_streaming_write_completed ()
        if (!writable()) {
                return;
        }
+       
+       /* XXX notice that we're readers of _peaks_built
+          but we must hold a solid lock on PeaksReady.
+       */
 
        Glib::Mutex::Lock lm (_lock);
 
@@ -432,7 +493,7 @@ AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t&
                                                fullpath += shorter;
 
                                                if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
-                                                       chan = atoi (pathstr.substr (pos+1).c_str());
+                                                       chan = atoi (pathstr.substr (pos+1));
                                                        pathstr = shorter;
                                                        keeppath = fullpath;
                                                        ++cnt;
@@ -484,7 +545,7 @@ AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t&
                        ustring shorter = pathstr.substr (0, pos);
 
                        if (Glib::file_test (shorter, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
-                               chan = atoi (pathstr.substr (pos+1).c_str());
+                               chan = atoi (pathstr.substr (pos+1));
                                pathstr = shorter;
                        }
                }
@@ -542,15 +603,6 @@ AudioFileSource::set_header_position_offset (nframes_t offset)
        HeaderPositionOffsetChanged ();
 }
 
-void 
-AudioFileSource::handle_header_position_change ()
-{
-       if (writable()) {
-               set_header_timeline_position ();
-               flush_header ();
-       }
-}
-
 void
 AudioFileSource::set_timeline_position (int64_t pos)
 {
@@ -603,15 +655,15 @@ AudioFileSource::set_source_name (ustring newname, bool destructive)
 bool
 AudioFileSource::is_empty (Session& s, ustring path)
 {
-       bool ret = false;
+       SoundFileInfo info;
+       string err;
        
-       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, s, path, 0, NoPeakFile, false));
-
-       if (afs) {
-               ret = (afs->length() == 0);
+       if (!get_soundfile_info (path, info, err)) {
+               /* dangerous: we can't get info, so assume that its not empty */
+               return false; 
        }
 
-       return ret;
+       return info.length == 0;
 }
 
 int
index d09a9b29cd4f21fd1814a4c62dc60ac4e95df62a..a2ce7209f6f634e0802b71f69b4dd2d0e6cd8071 100644 (file)
@@ -20,6 +20,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <poll.h>
 #include <float.h>
 #include <utime.h>
 #include <cerrno>
 #include <algorithm>
 #include <vector>
 
+#include <glibmm/fileutils.h>
+
 #include <pbd/xml++.h>
 #include <pbd/pthread_utils.h>
 
 #include <ardour/audiosource.h>
 #include <ardour/cycle_timer.h>
-#include <ardour/runtime_functions.h>
+#include <ardour/session.h>
 
 #include "i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
+using Glib::ustring;
 
 bool AudioSource::_build_missing_peakfiles = false;
 bool AudioSource::_build_peakfiles = false;
@@ -126,12 +130,12 @@ bool
 AudioSource::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const
 {
        bool ret;
-       Glib::Mutex::Lock lm (_lock);
+       Glib::Mutex::Lock lm (_peaks_ready_lock);
 
        /* check to see if the peak data is ready. if not
           connect the slot while still holding the lock.
        */
-
+       
        if (!(ret = _peaks_built)) {
                conn = PeaksReady.connect (the_slot);
        }
@@ -182,15 +186,10 @@ AudioSource::initialize_peakfile (bool newfile, ustring audio_path)
 
        peakpath = peak_path (audio_path);
 
-       /* Nasty band-aid for older sessions that were created before we
-          used libsndfile for all audio files.
-       */
+       /* if the peak file should be there, but isn't .... */
        
-       if (!newfile && access (peakpath.c_str(), R_OK) != 0) {
-               ustring str = old_peak_path (audio_path);
-               if (access (str.c_str(), R_OK) == 0) {
-                       peakpath = str;
-               }
+       if (!newfile && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
+               peakpath = find_broken_peakfile (peakpath, audio_path);
        }
 
        if (newfile) {
@@ -332,7 +331,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
                /* open, read, close */
 
                if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
-                       error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+                       error << string_compose(_("AudioSource: cannot open peakpath (a) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
                        return -1;
                }
 
@@ -406,7 +405,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
                /* open ... close during out: handling */
 
                if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
-                       error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+                       error << string_compose(_("AudioSource: cannot open peakpath (b) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
                        return 0;
                }
 
@@ -581,9 +580,11 @@ AudioSource::build_peaks_from_scratch ()
 {
        nframes_t current_frame;
        nframes_t cnt;
-       Sample buf[frames_per_peak];
+       Sample* buf = 0;
        nframes_t frames_read;
        nframes_t frames_to_read;
+       const nframes_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
+
        int ret = -1;
 
        {
@@ -598,39 +599,41 @@ AudioSource::build_peaks_from_scratch ()
                current_frame = 0;
                cnt = _length;
                _peaks_built = false;
+               buf = new Sample[bufsize];
                
                while (cnt) {
                        
-                       frames_to_read = min (frames_per_peak, cnt);
+                       frames_to_read = min (bufsize, cnt);
 
                        if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
                                error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
-                               done_with_peakfile_writes ();
+                               done_with_peakfile_writes (false);
                                goto out;
                        }
 
-                       if (compute_and_write_peaks (buf, current_frame, frames_read, true)) {
+                       if (compute_and_write_peaks (buf, current_frame, frames_read, true, false)) {
                                break;
                        }
                        
                        current_frame += frames_read;
                        cnt -= frames_read;
                }
-               
+
                if (cnt == 0) {
                        /* success */
                        truncate_peakfile();
-                       _peaks_built = true;
                } 
 
-               done_with_peakfile_writes ();
+               done_with_peakfile_writes ((cnt == 0));
        }
-
-       /* lock no longer held, safe to signal */
-
-       if (_peaks_built) {
-               PeaksReady (); /* EMIT SIGNAL */
-               ret = 0;
+       
+       {
+               Glib::Mutex::Lock lm (_peaks_ready_lock);
+               
+               if (_peaks_built) {
+                       PeaksReady (); /* EMIT SIGNAL */
+                       ret = 0;
+               }
        }
 
   out:
@@ -638,6 +641,10 @@ AudioSource::build_peaks_from_scratch ()
                unlink (peakpath.c_str());
        }
 
+       if (buf) {
+               delete [] buf;
+       }
+
        return ret;
 }
 
@@ -645,17 +652,21 @@ int
 AudioSource::prepare_for_peakfile_writes ()
 {
        if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
-               error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+               error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
                return -1;
        }
        return 0;
 }
 
 void
-AudioSource::done_with_peakfile_writes ()
+AudioSource::done_with_peakfile_writes (bool done)
 {
        if (peak_leftover_cnt) {
-               compute_and_write_peaks (0, 0, 0, true);
+               compute_and_write_peaks (0, 0, 0, true, false);
+       }
+       
+       if (done) {
+               _peaks_built = true;
        }
 
        if (peakfile >= 0) {
@@ -665,7 +676,7 @@ AudioSource::done_with_peakfile_writes ()
 }
 
 int
-AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force)
+AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force, bool intermediate_peaks_ready)
 {
        Sample* buf2 = 0;
        nframes_t to_do;
@@ -695,7 +706,8 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
                        
                        x.min = peak_leftovers[0];
                        x.max = peak_leftovers[0];
-                       find_peaks (peak_leftovers + 1, peak_leftover_cnt - 1, &x.min, &x.max);
+
+                       ARDOUR::find_peaks (peak_leftovers + 1, peak_leftover_cnt - 1, &x.min, &x.max);
 
                        off_t byte = (peak_leftover_frame / frames_per_peak) * sizeof (PeakData);
 
@@ -706,8 +718,13 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
 
                        _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
 
-                       PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
-                       PeaksReady (); /* EMIT SIGNAL */
+                       { 
+                               Glib::Mutex::Lock lm (_peaks_ready_lock);
+                               PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
+                               if (intermediate_peaks_ready) {
+                                       PeaksReady (); /* EMIT SIGNAL */
+                               } 
+                       }
 
                        /* left overs are done */
 
@@ -778,7 +795,7 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
                peakbuf[peaks_computed].max = buf[0];
                peakbuf[peaks_computed].min = buf[0];
 
-               find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
+               ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
 
                peaks_computed++;
                buf += this_time;
@@ -814,8 +831,11 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
        _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));     
 
        if (frames_done) {
+               Glib::Mutex::Lock lm (_peaks_ready_lock);
                PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
-               PeaksReady (); /* EMIT SIGNAL */
+               if (intermediate_peaks_ready) {
+                       PeaksReady (); /* EMIT SIGNAL */
+               }
        }
 
        ret = 0;
@@ -882,3 +902,11 @@ AudioSource::available_peaks (double zoom_factor) const
        return (end/sizeof(PeakData)) * frames_per_peak;
 }
 
+void
+AudioSource::update_length (nframes_t pos, nframes_t cnt)
+{
+       if (pos + cnt > _length) {
+               _length = pos+cnt;
+       }
+}
+
index e344d5f2a64825895f44b583744814c34e9a10a7..c509997b2ef7e8a1f826c78619137720792b9b3a 100644 (file)
@@ -137,7 +137,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
        boost::shared_ptr<AudioRegion> the_region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
        the_region->set_position (0, this);
 
-       _diskstream->playlist()->clear ();
+       _diskstream->playlist()->drop_regions ();
        _diskstream->playlist()->add_region (the_region, 0, 1);
 
        if (_diskstream->n_channels().n_audio() < the_region->n_channels()) {
index 0609b8d38037bac67abbb8dbe2a7a5c220b66600..45b19d1997aea345f44bbba2bdbc9975f06e478b 100644 (file)
@@ -34,6 +34,8 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
+nframes_t Automatable::_automation_interval = 0;
+
 Automatable::Automatable(Session& _session, const string& name)
        : SessionObject(_session, name)
        , _last_automation_snapshot(0)
@@ -422,7 +424,7 @@ Automatable::protect_automation ()
 void
 Automatable::automation_snapshot (nframes_t now)
 {
-       if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
+       if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
 
                for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) {
                        if (i->second->list()->automation_write()) {
index 5faab7c0ab65535e4f88243c4611c2f38063885b..1460491180c51553d7b5e6a7c3ecfea352d887d5 100644 (file)
@@ -25,6 +25,9 @@
 #include <pbd/filesystem.h>
 #include <pbd/file_utils.h>
 
+#include <midi++/manager.h>
+
+#include <ardour/ardour.h>
 #include <ardour/configuration.h>
 #include <ardour/audio_diskstream.h>
 #include <ardour/control_protocol_manager.h>
@@ -195,9 +198,12 @@ Configuration::get_state ()
        LocaleGuard lg (X_("POSIX"));
 
        root = new XMLNode("Ardour");
-       typedef map<string, MidiPortDescriptor*>::const_iterator CI;
-       for(CI m = midi_ports.begin(); m != midi_ports.end(); ++m){
-               root->add_child_nocopy(m->second->get_state());
+
+       MIDI::Manager::PortMap::const_iterator i;
+       const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports();
+       
+       for (i = ports.begin(); i != ports.end(); ++i) {
+               root->add_child_nocopy(i->second->get_state());
        }
        
        root->add_child_nocopy (get_variables (sigc::mem_fun (*this, &Configuration::save_config_options_predicate), "Config"));
@@ -250,10 +256,13 @@ Configuration::set_state (const XMLNode& root)
                if (node->name() == "MIDI-port") {
 
                        try {
-                               pair<string,MidiPortDescriptor*> newpair;
-                               newpair.second = new MidiPortDescriptor (*node);
-                               newpair.first = newpair.second->tag;
-                               midi_ports.insert (newpair);
+
+                               MIDI::Port::Descriptor desc (*node);
+                               map<string,XMLNode>::iterator x;
+                               if ((x = midi_ports.find (desc.tag)) != midi_ports.end()) {
+                                       midi_ports.erase (x);
+                               }
+                               midi_ports.insert (pair<string,XMLNode>(desc.tag,*node));
                        }
 
                        catch (failed_constructor& err) {
@@ -296,53 +305,6 @@ Configuration::set_variables (const XMLNode& node, ConfigVariableBase::Owner own
 #undef  CONFIG_VARIABLE_SPECIAL
        
 }
-
-Configuration::MidiPortDescriptor::MidiPortDescriptor (const XMLNode& node)
-{
-       const XMLProperty *prop;
-       bool have_tag = false;
-       bool have_device = false;
-       bool have_type = false;
-       bool have_mode = false;
-
-       if ((prop = node.property ("tag")) != 0) {
-               tag = prop->value();
-               have_tag = true;
-       }
-
-       if ((prop = node.property ("device")) != 0) {
-               device = prop->value();
-               have_device = true;
-       }
-
-       if ((prop = node.property ("type")) != 0) {
-               type = prop->value();
-               have_type = true;
-       }
-
-       if ((prop = node.property ("mode")) != 0) {
-               mode = prop->value();
-               have_mode = true;
-       }
-
-       if (!have_tag || !have_device || !have_type || !have_mode) {
-               throw failed_constructor();
-       }
-}
-
-XMLNode&
-Configuration::MidiPortDescriptor::get_state()
-{
-       XMLNode* root = new XMLNode("MIDI-port");
-
-       root->add_property("tag", tag);
-       root->add_property("device", device);
-       root->add_property("type", type);
-       root->add_property("mode", mode);
-
-       return *root;
-}
-
 void
 Configuration::map_parameters (sigc::slot<void,const char*> theSlot)
 {
index 556f11125e6576d3347b1d6b455ba02523d2c498..d45d5efa9fb621d762e8957ee3137edae567c373 100644 (file)
@@ -294,6 +294,13 @@ Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
 
        offset = start - _position;
 
+       /* Prevent data from piling up inthe crossfade buffers when reading a transparent region */
+       if (!(_out->opaque())) {
+               memset (crossfade_buffer_out, 0, sizeof (Sample) * to_write);
+       } else if (!(_in->opaque())) {
+               memset (crossfade_buffer_in, 0, sizeof (Sample) * to_write);
+       }
+       
        _out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n);
        _in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n);
 
@@ -358,6 +365,13 @@ Crossfade::refresh ()
                return false;
        }
 
+       /* Top layer shouldn't be transparent */
+       
+       if (!((layer_relation > 0 ? _in : _out)->opaque())) {
+               Invalidated (shared_from_this());
+               return false;
+       }
+
        /* layer ordering cannot change */
 
        int32_t new_layer_relation = (int32_t) (_in->layer() - _out->layer());
index 52be946f1e59155ba02e6c5f2c336470e3b1c0d8..c3eae5ad86a9027ff251a917d30f34762a0e0fc3 100644 (file)
@@ -39,7 +39,6 @@
 #include <pbd/fpu.h>
 
 #include <midi++/port.h>
-#include <midi++/port_request.h>
 #include <midi++/manager.h>
 #include <midi++/mmc.h>
 
@@ -51,6 +50,7 @@
 #include <ardour/audiosource.h>
 #include <ardour/utils.h>
 #include <ardour/session.h>
+#include <ardour/source_factory.h>
 #include <ardour/control_protocol_manager.h>
 #include <ardour/audioengine.h>
 
@@ -114,47 +114,25 @@ setup_osc ()
 #endif
 
 int 
-ARDOUR::setup_midi (AudioEngine& engine)
+setup_midi ()
 {
-       std::map<string,Configuration::MidiPortDescriptor*>::iterator i;
-       int nports;
-
-       if ((nports = Config->midi_ports.size()) == 0) {
+       if (Config->midi_ports.size() == 0) {
                warning << _("no MIDI ports specified: no MMC or MTC control possible") << endmsg;
                return 0;
        }
 
-       MIDI::Manager::instance()->set_api_data(engine.jack());
-
-       for (i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
-               Configuration::MidiPortDescriptor* port_descriptor;
-
-               port_descriptor = (*i).second;
-
-               MIDI::PortRequest request (port_descriptor->device, 
-                                          port_descriptor->tag, 
-                                          port_descriptor->mode, 
-                                          port_descriptor->type);
-
-               if (request.status != MIDI::PortRequest::OK) {
-                       error << string_compose(_("MIDI port specifications for \"%1\" are not understandable."), port_descriptor->tag) << endmsg;
-                       continue;
-               }
-               
-               MIDI::Manager::instance()->add_port (request);
-
-               nports++;
+       for (std::map<string,XMLNode>::iterator i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
+               MIDI::Manager::instance()->add_port (i->second);
        }
 
        MIDI::Port* first;
        const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports();
-       first = ports.begin()->second;
 
-       if (nports > 1) {
+       if (ports.size() > 1) {
 
-               /* More than one port, so try using specific names for each port */
+               first = ports.begin()->second;
 
-               map<string,Configuration::MidiPortDescriptor *>::iterator i;
+               /* More than one port, so try using specific names for each port */
 
                if (Config->get_mmc_port_name() != N_("default")) {
                        default_mmc_port =  MIDI::Manager::instance()->port (Config->get_mmc_port_name());
@@ -182,11 +160,13 @@ ARDOUR::setup_midi (AudioEngine& engine)
                        default_midi_port = first;
                }
                
-       } else {
+       } else if (ports.size() == 1) {
+
+               first = ports.begin()->second;
 
                /* Only one port described, so use it for both MTC and MMC */
 
-               default_mmc_port = MIDI::Manager::instance()->port ("");
+               default_mmc_port = first;
                default_mtc_port = default_mmc_port;
                default_midi_port = default_mmc_port;
        }
@@ -209,15 +189,16 @@ ARDOUR::setup_midi (AudioEngine& engine)
 
        return 0;
 }
-       
+
 void
 setup_hardware_optimization (bool try_optimization)
 {
         bool generic_mix_functions = true;
-       FPU fpu;
 
        if (try_optimization) {
 
+               FPU fpu;
+
 #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
                
                if (fpu.has_sse()) {
@@ -253,6 +234,10 @@ setup_hardware_optimization (bool try_optimization)
                         info << "Apple VecLib H/W specific optimizations in use" << endmsg;
                 }
 #endif
+               
+               /* consider FPU denormal handling to be "h/w optimization" */
+               
+               setup_fpu ();
         }
 
         if (generic_mix_functions) {
@@ -265,9 +250,6 @@ setup_hardware_optimization (bool try_optimization)
                
                info << "No H/W specific optimizations in use" << endmsg;
        }
-
-       setup_fpu ();
-
 }
 
 int
@@ -306,6 +288,8 @@ ARDOUR::init (bool use_vst, bool try_optimization)
 
        setup_hardware_optimization (try_optimization);
 
+       SourceFactory::init ();
+
        /* singleton - first object is "it" */
        new PluginManager ();
        
@@ -387,6 +371,13 @@ ARDOUR::LocaleGuard::~LocaleGuard ()
 void
 ARDOUR::setup_fpu ()
 {
+
+       if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
+               // valgrind doesn't understand this assembler stuff
+               // September 10th, 2007
+               return;
+       }
+
 #if defined(ARCH_X86) && defined(USE_XMMINTRIN)
 
        int MXCSR;
index bc16cde1568a1de2af7e7274ca978f9f51baeb04..bd6351cf0558be969e3844a143a40a6de4d99b1f 100644 (file)
@@ -32,9 +32,9 @@
 #include <glibmm.h>
 
 #include <pbd/basename.h>
+#include <pbd/convert.h>
 
 #include <ardour/ardour.h>
-#include <ardour/types.h>
 #include <ardour/session.h>
 #include <ardour/session_directory.h>
 #include <ardour/audio_diskstream.h>
 #include <ardour/audioregion.h>
 #include <ardour/region_factory.h>
 #include <ardour/source_factory.h>
-
+#include <ardour/resampled_source.h>
 
 #include "i18n.h"
 
 using namespace ARDOUR;
 using namespace PBD;
 
-#define BLOCKSIZE 4096U
-
-class ImportableSource {
-   public:
-    ImportableSource (SNDFILE* sf, SF_INFO* info) : in (sf), sf_info (info) {}
-    virtual ~ImportableSource() {}
-
-    virtual nframes_t read (Sample* buffer, nframes_t nframes) {
-           nframes_t per_channel = nframes / sf_info->channels;
-           per_channel = sf_readf_float (in, buffer, per_channel);
-           return per_channel * sf_info->channels;
-    }
-
-    virtual float ratio() const { return 1.0f; }
-
-protected:
-       SNDFILE* in;
-       SF_INFO* sf_info;
-};
-
-class ResampledImportableSource : public ImportableSource {
-   public:
-    ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate) : ImportableSource (sf, info) {
-           int err;
-
-           sf_seek (in, 0, SEEK_SET) ;
-           
-           /* Initialize the sample rate converter. */
-           
-           if ((src_state = src_new (SRC_SINC_BEST_QUALITY, sf_info->channels, &err)) == 0) {  
-                   error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ;
-                   throw failed_constructor ();
-           }
-           
-           src_data.end_of_input = 0 ; /* Set this later. */
-           
-           /* Start with zero to force load in while loop. */
-           
-           src_data.input_frames = 0 ;
-           src_data.data_in = input ;
-           
-           src_data.src_ratio = ((float) rate) / sf_info->samplerate ;
-
-    }
-
-    ~ResampledImportableSource () { 
-       src_state = src_delete (src_state) ;
-    }
-
-    nframes_t read (Sample* buffer, nframes_t nframes);
-    
-    float ratio() const { return src_data.src_ratio; }
-
-   private:
-       float input[BLOCKSIZE];
-       SRC_STATE*      src_state;
-       SRC_DATA        src_data;
-};
-
 int
 Session::import_audiofile (import_status& status)
 {
        SNDFILE *in;
        vector<boost::shared_ptr<AudioFileSource> > newfiles;
-       SourceList sources;
        SF_INFO info;
        float *data = 0;
        Sample **channel_data = 0;
-       long nfiles = 0;
+       int nfiles = 0;
        string basepath;
        string sounds_dir;
        nframes_t so_far;
@@ -127,178 +67,166 @@ Session::import_audiofile (import_status& status)
        vector<string> new_paths;
        struct tm* now;
        ImportableSource* importable = 0;
-       const nframes_t nframes = BLOCKSIZE;
-
-       status.new_regions.clear ();
-
-       if ((in = sf_open (status.paths.front().c_str(), SFM_READ, &info)) == 0) {
-               error << string_compose(_("Import: cannot open input sound file \"%1\""), status.paths.front()) << endmsg;
-               status.done = 1;
-               status.cancel = 1;
-               return -1;
-       }
-
-       if ((nframes_t) info.samplerate != frame_rate()) {
-               importable = new ResampledImportableSource (in, &info, frame_rate());
-       } else {
-               importable = new ImportableSource (in, &info);
-       }
-
-       for (int n = 0; n < info.channels; ++n) {
-               newfiles.push_back (boost::shared_ptr<AudioFileSource>());
-       }
+       const nframes_t nframes = ResampledImportableSource::blocksize;
+       uint32_t cnt = 1;
 
-       SessionDirectory sdir(get_best_session_directory_for_new_source ());
-       sounds_dir = sdir.sound_path().to_string();
-
-       basepath = PBD::basename_nosuffix (status.paths.front());
+       status.sources.clear ();
+       
+       for (vector<Glib::ustring>::iterator p = status.paths.begin(); p != status.paths.end(); ++p, ++cnt) {
 
-       for (int n = 0; n < info.channels; ++n) {
+               if ((in = sf_open ((*p).c_str(), SFM_READ, &info)) == 0) {
+                       error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg;
+                       status.done = 1;
+                       status.cancel = 1;
+                       return -1;
+               }
+               
+               if ((nframes_t) info.samplerate != frame_rate()) {
+                       importable = new ResampledImportableSource (in, &info, frame_rate(), status.quality);
+               } else {
+                       importable = new ImportableSource (in, &info);
+               }
+               
+               newfiles.clear ();
 
-               bool goodfile = false;
+               for (int n = 0; n < info.channels; ++n) {
+                       newfiles.push_back (boost::shared_ptr<AudioFileSource>());
+               }
+               
+               SessionDirectory sdir(get_best_session_directory_for_new_source ());
+               sounds_dir = sdir.sound_path().to_string();
 
-               do {
-                       if (info.channels == 2) {
-                               if (n == 0) {
-                                       snprintf (buf, sizeof(buf), "%s/%s-L.wav", sounds_dir.c_str(), basepath.c_str());
+               basepath = PBD::basename_nosuffix ((*p));
+               
+               for (int n = 0; n < info.channels; ++n) {
+                       
+                       bool goodfile = false;
+                       
+                       do {
+                               if (info.channels == 2) {
+                                       if (n == 0) {
+                                               snprintf (buf, sizeof(buf), "%s/%s-L.wav", sounds_dir.c_str(), basepath.c_str());
+                                       } else {
+                                               snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str());
+                                       }
+                               } else if (info.channels > 1) {
+                                       snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
                                } else {
-                                       snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str());
+                                       snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str());
                                }
-                       } else if (info.channels > 1) {
-                               snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
-                       } else {
-                               snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str());
-                       }
 
-                       if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
+                               if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
 
-                               /* if the file already exists, we must come up with
-                                *  a new name for it.  for now we just keep appending
-                                *  _ to basepath
-                                */
+                                       /* if the file already exists, we must come up with
+                                        *  a new name for it.  for now we just keep appending
+                                        *  _ to basepath
+                                        */
                                
-                               basepath += "_";
+                                       basepath += "_";
 
-                       } else {
+                               } else {
 
-                               goodfile = true;
-                       }
+                                       goodfile = true;
+                               }
 
-               } while ( !goodfile);
+                       } while ( !goodfile);
 
-               try { 
-                       newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> (
-                               SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
-               }
+                       try { 
+                               newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
+                       }
 
-               catch (failed_constructor& err) {
-                       error << string_compose(_("Session::import_audiofile: cannot open new file source for channel %1"), n+1) << endmsg;
-                       goto out;
-               }
+                       catch (failed_constructor& err) {
+                               error << string_compose(_("Session::import_audiofile: cannot open new file source for channel %1"), n+1) << endmsg;
+                               goto out;
+                       }
 
-               new_paths.push_back (buf);
-               nfiles++;
-       }
+                       new_paths.push_back (buf);
+                       newfiles[n]->prepare_for_peakfile_writes ();
+                       nfiles++;
+               }
        
-       data = new float[nframes * info.channels];
-       channel_data = new Sample * [ info.channels ];
+               data = new float[nframes * info.channels];
+               channel_data = new Sample * [ info.channels ];
        
-       for (int n = 0; n < info.channels; ++n) {
-               channel_data[n] = new Sample[nframes];
-       }
+               for (int n = 0; n < info.channels; ++n) {
+                       channel_data[n] = new Sample[nframes];
+               }
 
-       so_far = 0;
+               so_far = 0;
 
-       status.doing_what = _("converting audio");
-       status.progress = 0.0;
+               if ((nframes_t) info.samplerate != frame_rate()) {
+                       status.doing_what = string_compose (_("converting %1\n(resample from %2KHz to %3KHz)\n(%4 of %5)"),
+                                                           basepath,
+                                                           info.samplerate/1000.0f,
+                                                           frame_rate()/1000.0f,
+                                                           cnt, status.paths.size());
+                                                           
+               } else {
+                       status.doing_what = string_compose (_("converting %1\n(%2 of %3)"), 
+                                                           basepath,
+                                                           cnt, status.paths.size());
 
-       while (!status.cancel) {
+               }
+
+               status.progress = 0.0;
+
+               while (!status.cancel) {
 
-               nframes_t nread, nfread;
-               long x;
-               long chn;
+                       nframes_t nread, nfread;
+                       long x;
+                       long chn;
                
-               if ((nread = importable->read (data, nframes)) == 0) {
-                       break;
-               }
-               nfread = nread / info.channels;
+                       if ((nread = importable->read (data, nframes)) == 0) {
+                               break;
+                       }
+                       nfread = nread / info.channels;
 
-               /* de-interleave */
+                       /* de-interleave */
                                
-               for (chn = 0; chn < info.channels; ++chn) {
+                       for (chn = 0; chn < info.channels; ++chn) {
 
-                       nframes_t n;
-                       for (x = chn, n = 0; n < nfread; x += info.channels, ++n) {
-                               channel_data[chn][n] = (Sample) data[x];
+                               nframes_t n;
+                               for (x = chn, n = 0; n < nfread; x += info.channels, ++n) {
+                                       channel_data[chn][n] = (Sample) data[x];
+                               }
                        }
-               }
 
-               /* flush to disk */
+                       /* flush to disk */
 
-               for (chn = 0; chn < info.channels; ++chn) {
-                       newfiles[chn]->write (channel_data[chn], nfread);
-               }
+                       for (chn = 0; chn < info.channels; ++chn) {
+                               newfiles[chn]->write (channel_data[chn], nfread);
+                       }
 
-               so_far += nread;
-               status.progress = so_far / (importable->ratio () * info.frames * info.channels);
-       }
+                       so_far += nread;
+                       status.progress = so_far / (importable->ratio () * info.frames * info.channels);
+               }
 
-       if (status.cancel) {
-               goto out;
-       }
+               if (status.cancel) {
+                       goto out;
+               }
+               
+               for (int n = 0; n < info.channels; ++n) {
+                       status.sources.push_back (newfiles[n]);
+               }
 
-       if (status.multichan) {
-               status.doing_what = _("building region");
-       } else {
-               status.doing_what = _("building regions");
+               if (status.cancel) {
+                       goto out;
+               }
        }
-
+       
        status.freeze = true;
 
        time_t xnow;
        time (&xnow);
        now = localtime (&xnow);
 
-       if (status.multichan) {
-               /* all sources are used in a single multichannel region */
+       /* flush the final length(s) to the header(s) */
 
-               for (int n = 0; n < nfiles && !status.cancel; ++n) {
-                       /* flush the final length to the header */
-                       newfiles[n]->update_header(0, *now, xnow);
-                       sources.push_back(newfiles[n]);
-               }
-
-               bool strip_paired_suffixes = (newfiles.size() > 1);
-
-               boost::shared_ptr<AudioRegion> r (boost::dynamic_pointer_cast<AudioRegion> 
-                                                 (RegionFactory::create (sources, 0, 
-                                                                         newfiles[0]->length(), 
-                                                                         region_name_from_path (basepath, strip_paired_suffixes),
-                                                                         0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile))));
-               
-               status.new_regions.push_back (r);
-
-       } else {
-               for (int n = 0; n < nfiles && !status.cancel; ++n) {
-
-                       /* flush the final length to the header */
-
-                       newfiles[n]->update_header(0, *now, xnow);
-
-                       /* The sources had zero-length when created, which means that the Session
-                          did not bother to create whole-file AudioRegions for them. Do it now.
-
-                          Note: leave any trailing paired indicators from the file names as part
-                          of the region name.
-                       */
-               
-                       status.new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> 
-                                                     (RegionFactory::create (boost::static_pointer_cast<Source> (newfiles[n]), 0, newfiles[n]->length(), 
-                                                                             region_name_from_path (newfiles[n]->name(), false),
-                                                                             0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile | AudioRegion::Import))));
-               }
+       for (SourceList::iterator x = status.sources.begin(); x != status.sources.end() && !status.cancel; ++x) {
+               boost::dynamic_pointer_cast<AudioFileSource>(*x)->update_header(0, *now, xnow);
+               boost::dynamic_pointer_cast<AudioSource>(*x)->done_with_peakfile_writes ();
        }
-       
+
        /* save state so that we don't lose these new Sources */
 
        if (!status.cancel) {
@@ -321,7 +249,8 @@ Session::import_audiofile (import_status& status)
        }
 
        if (status.cancel) {
-               status.new_regions.clear ();
+
+               status.sources.clear ();
 
                for (vector<string>::iterator i = new_paths.begin(); i != new_paths.end(); ++i) {
                        unlink ((*i).c_str());
@@ -337,50 +266,3 @@ Session::import_audiofile (import_status& status)
 
        return ret;
 }
-
-nframes_t 
-ResampledImportableSource::read (Sample* output, nframes_t nframes)
-{
-       int err;
-
-       /* If the input buffer is empty, refill it. */
-       
-       if (src_data.input_frames == 0) {       
-
-               src_data.input_frames = ImportableSource::read (input, BLOCKSIZE);
-
-               /* The last read will not be a full buffer, so set end_of_input. */
-
-               if ((nframes_t) src_data.input_frames < BLOCKSIZE) {
-                       src_data.end_of_input = SF_TRUE ;
-               }               
-
-               src_data.input_frames /= sf_info->channels;
-               src_data.data_in = input ;
-       } 
-       
-       src_data.data_out = output;
-
-       if (!src_data.end_of_input) {
-               src_data.output_frames = nframes / sf_info->channels ;
-       } else {
-               src_data.output_frames = src_data.input_frames;
-       }
-
-       if ((err = src_process (src_state, &src_data))) {
-               error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ;
-               return 0 ;
-       } 
-       
-       /* Terminate if at end */
-       
-       if (src_data.end_of_input && src_data.output_frames_gen == 0) {
-               return 0;
-       }
-       
-       src_data.data_in += src_data.input_frames_used * sf_info->channels ;
-       src_data.input_frames -= src_data.input_frames_used ;
-
-       return src_data.output_frames_gen * sf_info->channels;
-}
-
index a708821c20fe27f7c3ee6df01d163e053eb93eb0..bff8c18bc9a374d82f9fcb828c2fd6e1dac6d9a8 100644 (file)
@@ -1307,7 +1307,7 @@ IO::state (bool full_state)
        int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
        int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
 
-       snprintf (buf, sizeof(buf)-1, "%zd,%d,%zd,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
+       snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
 
        node->add_property ("iolimits", buf);
 
@@ -2335,7 +2335,7 @@ IO::automation_snapshot (nframes_t now)
 {
        Automatable::automation_snapshot (now);
 
-       if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
+       if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
                _panner->snapshot (now);
        }
 }
index 4af7e2b907febb489496a3199acaf9e9e8cf3c81..09b54000d8a07b93829d1a82d5d556fe4ae968bb 100644 (file)
@@ -1176,8 +1176,8 @@ Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
                        save = !(_splicing || _nudging);
                }
                
-               if ((what_changed & Region::MuteChanged) && 
-                   !(what_changed &  Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
+               if ((what_changed & our_interests) && 
+                   !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
                        check_dependents (region, false);
                }
                
diff --git a/libs/ardour/resampled_source.cc b/libs/ardour/resampled_source.cc
new file mode 100644 (file)
index 0000000..38aa383
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+    Copyright (C) 2007 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.
+
+*/
+
+#include <pbd/error.h>
+#include <ardour/resampled_source.h>
+#include <pbd/failed_constructor.h>
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+
+const uint32_t ResampledImportableSource::blocksize = 4096U;
+
+ResampledImportableSource::ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate, SrcQuality srcq)
+       : ImportableSource (sf, info) 
+{
+       int err;
+       
+       sf_seek (in, 0, SEEK_SET) ;
+       
+       /* Initialize the sample rate converter. */
+       
+       int src_type;
+
+       switch (srcq) {
+       case SrcBest:
+               src_type = SRC_SINC_BEST_QUALITY;
+               break;
+       case SrcGood:
+               src_type = SRC_SINC_MEDIUM_QUALITY;
+               break;
+       case SrcQuick:
+               src_type = SRC_SINC_FASTEST;
+               break;
+       case SrcFast:
+               src_type = SRC_ZERO_ORDER_HOLD;
+               break;
+       case SrcFastest:
+               src_type = SRC_LINEAR;
+               break;
+       }
+       
+       if ((src_state = src_new (src_type, sf_info->channels, &err)) == 0) {   
+               error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ;
+               throw failed_constructor ();
+       }
+       
+       src_data.end_of_input = 0 ; /* Set this later. */
+       
+       /* Start with zero to force load in while loop. */
+       
+       src_data.input_frames = 0 ;
+       src_data.data_in = input ;
+       
+       src_data.src_ratio = ((float) rate) / sf_info->samplerate ;
+       
+       input = new float[blocksize];
+}
+
+ResampledImportableSource::~ResampledImportableSource ()
+{
+       src_state = src_delete (src_state) ;
+       delete [] input;
+}
+
+nframes_t 
+ResampledImportableSource::read (Sample* output, nframes_t nframes)
+{
+       int err;
+
+       /* If the input buffer is empty, refill it. */
+       
+       if (src_data.input_frames == 0) {       
+
+               src_data.input_frames = ImportableSource::read (input, blocksize);
+
+               /* The last read will not be a full buffer, so set end_of_input. */
+
+               if ((nframes_t) src_data.input_frames < blocksize) {
+                       src_data.end_of_input = SF_TRUE ;
+               }               
+
+               src_data.input_frames /= sf_info->channels;
+               src_data.data_in = input ;
+       } 
+       
+       src_data.data_out = output;
+
+       if (!src_data.end_of_input) {
+               src_data.output_frames = nframes / sf_info->channels ;
+       } else {
+               src_data.output_frames = src_data.input_frames;
+       }
+
+       if ((err = src_process (src_state, &src_data))) {
+               error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ;
+               return 0 ;
+       } 
+       
+       /* Terminate if at end */
+       
+       if (src_data.end_of_input && src_data.output_frames_gen == 0) {
+               return 0;
+       }
+       
+       src_data.data_in += src_data.input_frames_used * sf_info->channels ;
+       src_data.input_frames -= src_data.input_frames_used ;
+
+       return src_data.output_frames_gen * sf_info->channels;
+}
+
index 19095425f276a2cc8015b445765918ca611d8a25..be7dfb846973aa67c1c49016d84e8d4f3e420d0d 100644 (file)
@@ -53,7 +53,7 @@ using namespace ARDOUR;
 using namespace PBD;
 
 uint32_t Route::order_key_cnt = 0;
-
+sigc::signal<void> Route::SyncOrderKeys;
 
 Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type)
        : IO (sess, name, input_min, input_max, output_min, output_max, default_type),
@@ -161,9 +161,34 @@ void
 Route::set_order_key (const char* name, long n)
 {
        order_keys[strdup(name)] = n;
+
+       if (Config->get_sync_all_route_ordering()) {
+               for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) {
+                       x->second = n;
+               }
+       } 
+
        _session.set_dirty ();
 }
 
+void
+Route::sync_order_keys ()
+{
+       uint32_t key;
+       
+       if (order_keys.empty()) {
+               return;
+       }
+       
+       OrderKeys::iterator x = order_keys.begin();
+       key = x->second;
+       ++x;
+
+       for (; x != order_keys.end(); ++x) {
+               x->second = key;
+       }
+}
+
 void
 Route::inc_gain (gain_t fraction, void *src)
 {
@@ -460,13 +485,9 @@ Route::process_output_buffers (BufferSet& bufs,
                
            // OR recording 
                
-               // h/w monitoring not in use 
-               
-               (!Config->get_monitoring_model() == HardwareMonitoring && 
-
                 // AND software monitoring required
 
-                Config->get_monitoring_model() == SoftwareMonitoring)) { 
+               Config->get_monitoring_model() == SoftwareMonitoring) { 
                
                if (apply_gain_automation) {
                        
index 742b17af2c0faeac356d30f6277ae77af535daa1..e7f2c542e65eaed272b5100d3fd90b34cb0e3886 100644 (file)
@@ -124,8 +124,7 @@ Session::Session (AudioEngine &eng,
          routes (new RouteList),
          auditioner ((Auditioner*) 0),
          _click_io ((IO*) 0),
-         main_outs (0),
-         _automation_interval (0)
+         main_outs (0)
 {
        if (!eng.connected()) {
                throw failed_constructor();
@@ -224,8 +223,7 @@ Session::Session (AudioEngine &eng,
          _send_smpte_update (false),
          diskstreams (new DiskstreamList),
          routes (new RouteList),
-         main_outs (0),
-         _automation_interval (0)
+         main_outs (0)
 
 {
        if (!eng.connected()) {
@@ -1257,8 +1255,10 @@ Session::set_frame_rate (nframes_t frames_per_second)
 
        sync_time_vars();
 
-       _automation_interval = ((nframes_t) ceil ((double) frames_per_second * 0.25));
+       Automatable::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval())));
 
+       clear_clicks ();
+       
        // XXX we need some equivalent to this, somehow
        // SndFileSource::setup_standard_crossfades (frames_per_second);
 
@@ -2755,13 +2755,11 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
        return boost::shared_ptr<Source>();
 }
 
-string
-Session::peak_path_from_audio_path (string audio_path) const
+Glib::ustring
+Session::peak_path (Glib::ustring base) const
 {
        sys::path peakfile_path(_session_dir->peak_path());
-
-       peakfile_path /= basename_nosuffix (audio_path) + peakfile_suffix;
-
+       peakfile_path /= basename_nosuffix (base) + peakfile_suffix;
        return peakfile_path.to_string();
 }
 
@@ -3387,8 +3385,8 @@ Session::remove_empty_sounds ()
                        try
                        {
                                sys::remove (audio_file_path);
-                               const string peak_path = peak_path_from_audio_path (audio_file_path.to_string());
-                               sys::remove (peak_path);
+                               const string peakfile = peak_path (audio_file_path.to_string());
+                               sys::remove (peakfile);
                        }
                        catch (const sys::filesystem_error& err)
                        {
@@ -4123,6 +4121,23 @@ Session::compute_initial_length ()
        return _engine.frame_rate() * 60 * 5;
 }
 
+void
+Session::sync_order_keys ()
+{
+       if (!Config->get_sync_all_route_ordering()) {
+               /* leave order keys as they are */
+               return;
+       }
+
+       boost::shared_ptr<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               (*i)->sync_order_keys ();
+       }
+
+       Route::SyncOrderKeys (); // EMIT SIGNAL
+}
+
 void
 Session::foreach_bundle (sigc::slot<void, boost::shared_ptr<Bundle> > sl)
 {
index 35c1019c0e43cb11ce6906b8be920a34b2e2216f..aa5a1b87d4e5f6fab7302cdb800539715ddbc8a7 100644 (file)
@@ -410,6 +410,8 @@ Session::process_event (Event* ev)
 
        case Event::Audition:
                set_audition (ev->region);
+               // drop reference to region
+               ev->region.reset ();
                break;
 
        case Event::InputConfigurationChange:
index f2f396cbeec1bab2a5864d2d6a4b1f358af526fc..0534da6c89dc364a631f5906ce0ec93d91924378 100644 (file)
@@ -138,10 +138,14 @@ Session::first_stage_init (string fullpath, string snapshot_name)
 
        _name = _current_snapshot_name = snapshot_name;
 
+       set_history_depth (Config->get_history_depth());
+
        _current_frame_rate = _engine.frame_rate ();
        _tempo_map = new TempoMap (_current_frame_rate);
        _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
 
+
+
        g_atomic_int_set (&processing_prohibited, 0);
        insert_cnt = 0;
        _transport_speed = 0;
@@ -501,7 +505,7 @@ void
 Session::remove_pending_capture_state ()
 {
        sys::path pending_state_file_path(_session_dir->root_path());
-
+       
        pending_state_file_path /= _current_snapshot_name + pending_suffix;
 
        try
@@ -2668,8 +2672,6 @@ Session::save_history (string snapshot_name)
 {
        XMLTree tree;
        
-       tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
-
        if (snapshot_name.empty()) {
                snapshot_name = _current_snapshot_name;
        }
@@ -2691,6 +2693,13 @@ Session::save_history (string snapshot_name)
                }
        }
 
+
+       if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) {
+               return 0;
+       }
+
+       tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
+
        if (!tree.write (xml_path.to_string()))
        {
                error << string_compose (_("history could not be saved to %1"), xml_path.to_string()) << endmsg;
@@ -2977,6 +2986,10 @@ Session::config_changed (const char* parameter_name)
                set_remote_control_ids ();
        }  else if (PARAM_IS ("denormal-model")) {
                setup_fpu ();
+       } else if (PARAM_IS ("history-depth")) {
+               set_history_depth (Config->get_history_depth());
+       } else if (PARAM_IS ("sync-all-route-ordering")) {
+               sync_order_keys ();
        }
 
        set_dirty ();
@@ -2984,3 +2997,9 @@ Session::config_changed (const char* parameter_name)
 #undef PARAM_IS
 
 }
+
+void
+Session::set_history_depth (uint32_t d)
+{
+       _history.set_depth (d);
+}
index 6977eef6bda738b792b72605a85af4c3ca83c59c..7c4859aa55a06a1bee9d8569365e62102ffd8013 100644 (file)
@@ -25,7 +25,7 @@
 #include <sys/stat.h>
 
 #include <glibmm/miscutils.h>
-
+#include <glibmm/thread.h>
 #include <ardour/sndfilesource.h>
 #include <ardour/sndfile_helpers.h>
 #include <ardour/utils.h>
@@ -45,6 +45,21 @@ const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSou
                                                                                           AudioFileSource::RemovableIfEmpty|
                                                                                           AudioFileSource::CanRename);
 
+struct SizedSampleBuffer {
+    nframes_t size;
+    Sample* buf;
+
+    SizedSampleBuffer (nframes_t sz) : size (sz) { 
+           buf = new Sample[size];
+    }
+
+    ~SizedSampleBuffer() {
+           delete [] buf;
+    }
+};
+
+Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
+
 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
        : AudioFileSource (s, node)
 {
@@ -186,8 +201,6 @@ SndFileSource::init ()
 
        // lets try to keep the object initalizations here at the top
        xfade_buf = 0;
-       interleave_buf = 0;
-       interleave_bufsize = 0;
        sf = 0;
        _broadcast_info = 0;
 
@@ -272,10 +285,6 @@ SndFileSource::~SndFileSource ()
                touch_peakfile ();
        }
 
-       if (interleave_buf) {
-               delete [] interleave_buf;
-       }
-
        if (_broadcast_info) {
                delete _broadcast_info;
        }
@@ -341,14 +350,7 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
 
        real_cnt = cnt * _info.channels;
 
-       if (interleave_bufsize < real_cnt) {
-               
-               if (interleave_buf) {
-                       delete [] interleave_buf;
-               }
-               interleave_bufsize = real_cnt;
-               interleave_buf = new float[interleave_bufsize];
-       }
+       Sample* interleave_buf = get_interleave_buffer (real_cnt);
        
        nread = sf_read_float (sf, interleave_buf, real_cnt);
        ptr = interleave_buf + _channel;
@@ -401,7 +403,7 @@ SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
        update_length (oldlen, cnt);
 
        if (_build_peakfiles) {
-               compute_and_write_peaks (data, frame_pos, cnt, false);
+               compute_and_write_peaks (data, frame_pos, cnt, false, true);
        }
 
        _write_data_count = cnt;
@@ -493,7 +495,7 @@ SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
        update_length (file_pos, cnt);
 
        if (_build_peakfiles) {
-               compute_and_write_peaks (data, file_pos, cnt, false);
+               compute_and_write_peaks (data, file_pos, cnt, false, true);
        }
 
        file_pos += cnt;
@@ -904,3 +906,21 @@ SndFileSource::one_of_several_channels () const
 {
        return _info.channels > 1;
 }
+
+Sample*
+SndFileSource::get_interleave_buffer (nframes_t size)
+{
+       SizedSampleBuffer* ssb;
+
+       if ((ssb = thread_interleave_buffer.get()) == 0) {
+               ssb = new SizedSampleBuffer (size);
+               thread_interleave_buffer.set (ssb);
+       }
+
+       if (ssb->size < size) {
+               ssb = new SizedSampleBuffer (size);
+               thread_interleave_buffer.set (ssb);
+       }
+
+       return ssb->buf;
+}
index 148f737551c760f8193442dd4acb711635e49a50..c6b19c860030523156b83f0e865b581ba480df23 100644 (file)
@@ -19,6 +19,8 @@
 */
 
 #include <pbd/error.h>
+#include <pbd/convert.h>
+#include <pbd/pthread_utils.h>
 
 #include <ardour/source_factory.h>
 #include <ardour/sndfilesource.h>
@@ -37,15 +39,69 @@ using namespace std;
 using namespace PBD;
 
 sigc::signal<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated;
+Glib::Cond* SourceFactory::PeaksToBuild;
+Glib::StaticMutex SourceFactory::peak_building_lock;
+std::list<boost::weak_ptr<AudioSource> > SourceFactory::files_with_peaks;
+
+static void 
+peak_thread_work ()
+{
+       PBD::ThreadCreated (pthread_self(), string ("peakbuilder-") + to_string (pthread_self(), std::dec));
+
+       while (true) {
+
+               SourceFactory::peak_building_lock.lock ();
+               
+         wait:
+               if (SourceFactory::files_with_peaks.empty()) {
+                       SourceFactory::PeaksToBuild->wait (SourceFactory::peak_building_lock);
+               }
+
+               if (SourceFactory::files_with_peaks.empty()) {
+                       goto wait;
+               }
+               
+               boost::shared_ptr<AudioSource> as (SourceFactory::files_with_peaks.front().lock());
+               SourceFactory::files_with_peaks.pop_front ();
+               SourceFactory::peak_building_lock.unlock ();
+               
+               if (!as) {
+                       continue;
+               }
+
+               as->setup_peakfile ();
+       }
+}
+
+void
+SourceFactory::init ()
+{
+       PeaksToBuild = new Glib::Cond();
+
+       for (int n = 0; n < 2; ++n) {
+               Glib::Thread::create (sigc::ptr_fun (::peak_thread_work), false);
+       }
+}
 
 int
-SourceFactory::setup_peakfile (boost::shared_ptr<Source> s)
+SourceFactory::setup_peakfile (boost::shared_ptr<Source> s, bool async)
 {
        boost::shared_ptr<AudioSource> as (boost::dynamic_pointer_cast<AudioSource> (s));
+
        if (as) {
-               if (as->setup_peakfile ()) {
-                       error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg;
-                       return -1;
+
+               if (async) {
+
+                       Glib::Mutex::Lock lm (peak_building_lock);
+                       files_with_peaks.push_back (boost::weak_ptr<AudioSource> (as));
+                       PeaksToBuild->broadcast ();
+
+               } else {
+
+                       if (as->setup_peakfile ()) {
+                               error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg;
+                               return -1;
+                       }
                }
        }
 
@@ -60,84 +116,85 @@ SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes,
        return ret;
 }
 
+#ifdef USE_COREAUDIO_FOR_FILES
 boost::shared_ptr<Source>
-SourceFactory::create (Session& s, const XMLNode& node)
+SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
 {
-       /* this is allowed to throw */
-
-       DataType type = DataType::AUDIO;
-       const XMLProperty* prop = node.property("type");
-       if (prop) {
-               type = DataType(prop->value());
-       }
-       
-       if (type == DataType::AUDIO) {
-               
-#ifdef HAVE_COREAUDIO
-               try {
-                       boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
-                       if (setup_peakfile (ret)) {
+       try {
+               boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
+               if (!defer_peaks) {
+                       if (setup_peakfile (ret, false)) {
                                return boost::shared_ptr<Source>();
                        }
-                       SourceCreated (ret);
-                       return ret;
-               } 
+               }
+               SourceCreated (ret);
+               return ret;
+       } 
 
-               catch (failed_constructor& err) {
-               
-                       /* this is allowed to throw */
-                       
-                       boost::shared_ptr<Source> ret (new SndFileSource (s, node));
-                       if (setup_peakfile (ret)) {
+
+       catch (failed_constructor& err) {       
+
+               /* this is allowed to throw */
+
+               boost::shared_ptr<Source> ret (new SndFileSource (s, node));
+               if (!defer_peaks) {
+                       if (setup_peakfile (ret, false)) {
                                return boost::shared_ptr<Source>();
                        }
-                       SourceCreated (ret);
-                       return ret;
                }
-#else
-               boost::shared_ptr<Source> ret (new SndFileSource (s, node));
-
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
-               }
-               
                SourceCreated (ret);
                return ret;
-#endif
+       }
 
-       } else if (type == DataType::MIDI) {
+       return boost::shared_ptr<Source>();
+}
 
-               boost::shared_ptr<Source> ret (new SMFSource (s, node));
-               
-               SourceCreated (ret);
-               return ret;
+#else
+
+boost::shared_ptr<Source>
+SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
+{
+       /* this is allowed to throw */
 
+       boost::shared_ptr<Source> ret (new SndFileSource (s, node));
+       
+       if (!defer_peaks) {
+               if (setup_peakfile (ret, false)) {
+                       return boost::shared_ptr<Source>();
+               }
        }
        
-       return boost::shared_ptr<Source> ();
+       SourceCreated (ret);
+       return ret;
 }
 
+#endif // USE_COREAUDIO_FOR_FILES
+
 boost::shared_ptr<Source>
-SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce)
+SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce, bool defer_peaks)
 {
        if (type == DataType::AUDIO) {
        
 #ifdef HAVE_COREAUDIO
                try {
                        boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags));
-                       if (setup_peakfile (ret)) {
-                               return boost::shared_ptr<Source>();
+                       if (!defer_peaks) {
+                               if (setup_peakfile (ret, false)) {
+                                       return boost::shared_ptr<Source>();
+                               }
                        }
                        if (announce) {
                                SourceCreated (ret);
                        }
                        return ret;
                }
-
+               
                catch (failed_constructor& err) {
                        boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
-                       if (setup_peakfile (ret)) {
-                               return boost::shared_ptr<Source>();
+                       if (!defer_peaks) {
+                               if (setup_peakfile (ret, false)) {
+                                       return boost::shared_ptr<Source>();
+                               }
                        }
                        if (announce) {
                                SourceCreated (ret);
@@ -147,8 +204,10 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
 #else
                boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
 
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
+               if (!defer_peaks) {
+                       if (setup_peakfile (ret, false)) {
+                               return boost::shared_ptr<Source>();
+                       }
                }
 
                if (announce) {
@@ -157,7 +216,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
 
                return ret;
 #endif
-
+               
        } else if (type == DataType::MIDI) {
 
                // FIXME: flags?
@@ -174,21 +233,23 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
 }
 
 boost::shared_ptr<Source>
-SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce)
+SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce, bool defer_peaks)
 {
        /* this might throw failed_constructor(), which is OK */
-
+       
        if (type == DataType::AUDIO) {
                boost::shared_ptr<Source> ret (new SndFileSource 
-                               (s, path, 
-                                Config->get_native_file_data_format(),
-                                Config->get_native_file_header_format(),
-                                rate,
-                                (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) :
-                                 SndFileSource::default_writable_flags)));     
-
-               if (setup_peakfile (ret)) {
-                       return boost::shared_ptr<Source>();
+                                              (s, path, 
+                                               Config->get_native_file_data_format(),
+                                               Config->get_native_file_header_format(),
+                                               rate,
+                                               (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) :
+                                                SndFileSource::default_writable_flags)));      
+
+               if (!defer_peaks) {
+                       if (setup_peakfile (ret, false)) {
+                               return boost::shared_ptr<Source>();
+                       }
                }
                if (announce) {
                        SourceCreated (ret);
index 01e070e9202bd7b9ed198ee51ef5443fcd956fb9..cfd38c5099d7f451ef4e05f17b9b9c741d03ce24 100644 (file)
@@ -143,7 +143,7 @@ touch_file (ustring path)
 }
 
 ustring
-region_name_from_path (ustring path, bool strip_channels)
+region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffix, uint32_t total, uint32_t this_one)
 {
        path = PBD::basename_nosuffix (path);
 
@@ -160,6 +160,17 @@ region_name_from_path (ustring path, bool strip_channels)
                }
        }
 
+       if (add_channel_suffix) {
+
+               path += '%';
+               
+               if (total > 2) {
+                       path += (char) ('a' + this_one);
+               } else {
+                       path += (char) (this_one == 0 ? 'L' : 'R');
+               }
+       }
+
        return path;
 }      
 
index 110bfe41bef5884095afe8fb29e7b494f61dfc6c..2676f630220d79963f824c4a9089a0b90ae73ef6 100644 (file)
@@ -17,6 +17,9 @@ clearlooks = env.Copy()
 clearlooks.Replace(CCFLAGS = ' `pkg-config --cflags gtk+-2.0` ',
                    LINKFLAGS = ' `pkg-config --libs gtk+-2.0` ')
 
+if env['GTKOSX']:
+    clearlooks.Append (CCFLAGS = '-DGTKOSX')
+
 libclearlooks = clearlooks.SharedLibrary('clearlooks', libclearlooks_files) 
 
 usable_libclearlooks = clearlooks.Install ('engines', libclearlooks)
index 241f14c6e4c1c75fc03434d7e339b7e1ddc7a1e5..074f1604b1a36081c1413b00b8f130b080ce3bb5 100644 (file)
@@ -1677,14 +1677,18 @@ draw_option (DRAW_ARGS)
        x += (width - RADIO_SIZE)/2;
        y += (height - RADIO_SIZE)/2;
        
+#ifndef GTKOSX
        gdk_gc_set_clip_mask (gc, clearlooks_style->radio_pixmap_mask);
        gdk_gc_set_clip_origin (gc, x, y);
+#endif
        
        gdk_draw_drawable (window, gc, pixmap, 0, 0, x, y,
                           RADIO_SIZE, RADIO_SIZE);
        
+#ifndef GTKOSX
        gdk_gc_set_clip_origin (gc, 0, 0);
        gdk_gc_set_clip_mask (gc, NULL);
+#endif
        
        if (area)
                gdk_gc_set_clip_rectangle (gc, NULL);
index a8d10a7dde27abd4894fe2d58bb44f9bf354f104..8e51d70501f9307264b7e4c0f1a9c031b8bdc8e7 100644 (file)
@@ -30,7 +30,7 @@
 //but the GtkToolbar compatibility system is particularly unpleasant, so we just removed it in gtkmm 2.4. murrayc.
 //In future, this GTK_DISABLE_DEPRECATED might be inappropriate because it might cover extra GTK+ API. Just remove it then.
 
-#define GTK_DISABLE_DEPRECATED
+// #define GTK_DISABLE_DEPRECATED
 
 #include <glib.h>
 #include <gtkmm/button.h>
index 04b027b6a381b3821e782d690672db9418c569aa..769d8889032cbe759dd61c66ed76f14fe7e9e904 100644 (file)
@@ -7,7 +7,7 @@ import glob
 Import('env libraries install_prefix')
 
 midi2 = env.Copy()
-midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glib2'], libraries['pbd'], libraries['jack'] ])
+midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glibmm2'], libraries['glib2'], libraries['pbd'], libraries['jack'] ])
 
 domain = 'midipp'
 
@@ -24,7 +24,6 @@ midiparser.cc
 midiport.cc
 mmc.cc
 mtc.cc
-port_request.cc
 version.cc
 """)
 
index bf891108c6c97e24a1d3afc172cb870fffc6cd15..bae8aff2abd269e63f97d76fee49822482ba58e3 100644 (file)
 
 #include <pbd/failed_constructor.h>
 #include <pbd/error.h>
+#include <pbd/xml++.h>
 
 #include <midi++/types.h>
 #include <midi++/alsa_sequencer.h>
-#include <midi++/port_request.h>
+
+#include "i18n.h"
 
 //#define DOTRACE 1
 
@@ -44,31 +46,31 @@ using namespace PBD;
 
 snd_seq_t* ALSA_SequencerMidiPort::seq = 0;
 
-ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (PortRequest &req)
-       : Port (req)
+ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (const XMLNode& node)
+       : Port (node)
        , decoder (0) 
        , encoder (0) 
        , port_id (-1)
 {
        TR_FN();
        int err;
+       Descriptor desc (node);
 
-       if (!seq && init_client (req.devname) < 0) {
+       if (!seq && init_client (desc.device) < 0) {
                _ok = false; 
 
        } else {
                
-               if (0 <= (err = CreatePorts (req)) &&
+               if (0 <= (err = create_ports (desc)) &&
                    0 <= (err = snd_midi_event_new (1024, &decoder)) && // Length taken from ARDOUR::Session::midi_read ()
                    0 <= (err = snd_midi_event_new (64, &encoder))) {   // Length taken from ARDOUR::Session::mmc_buffer
                        snd_midi_event_init (decoder);
                        snd_midi_event_init (encoder);
                        _ok = true;
-                       req.status = PortRequest::OK;
-               } else {
-                       req.status = PortRequest::Unknown;
-               }
+               } 
        }
+
+       set_state (node);
 }
 
 ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort ()
@@ -94,7 +96,8 @@ ALSA_SequencerMidiPort::selectable () const
        return -1;
 }
 
-int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp)    
+int 
+ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t ignored)  
 {
        TR_FN ();
        int R;
@@ -133,7 +136,8 @@ int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t timesta
        return totwritten;
 }
 
-int ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t timestamp)
+int 
+ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t ignored)
 {
        TR_FN();
        int err;
@@ -158,17 +162,20 @@ int ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t timestamp)
 }
 
 int 
-ALSA_SequencerMidiPort::CreatePorts (PortRequest &req)
+ALSA_SequencerMidiPort::create_ports (const Port::Descriptor& desc)
 {
        int err;
        unsigned int caps = 0;
 
-       if (req.mode == O_WRONLY  ||  req.mode == O_RDWR)
+       if (desc.mode == O_WRONLY  ||  desc.mode == O_RDWR)
                caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
-       if (req.mode == O_RDONLY  ||  req.mode == O_RDWR)
+       if (desc.mode == O_RDONLY  ||  desc.mode == O_RDWR)
                caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
        
-       if (0 <= (err = snd_seq_create_simple_port (seq, req.tagname, caps, SND_SEQ_PORT_TYPE_MIDI_GENERIC))) {
+       if (0 <= (err = snd_seq_create_simple_port (seq, desc.tag.c_str(), caps, 
+                                                   (SND_SEQ_PORT_TYPE_MIDI_GENERIC|
+                                                    SND_SEQ_PORT_TYPE_SOFTWARE|
+                                                    SND_SEQ_PORT_TYPE_APPLICATION)))) {
                
                port_id = err;
 
@@ -203,3 +210,216 @@ ALSA_SequencerMidiPort::init_client (std::string name)
                return -1;
        }
 }
+
+int
+ALSA_SequencerMidiPort::discover (vector<PortSet>& ports)
+{
+        int n = 0;
+
+        snd_seq_client_info_t *client_info;
+        snd_seq_port_info_t   *port_info;
+
+        snd_seq_client_info_alloca (&client_info);
+        snd_seq_port_info_alloca (&port_info);
+        snd_seq_client_info_set_client (client_info, -1);
+
+        while (snd_seq_query_next_client(seq, client_info) >= 0) {
+
+                int alsa_client;
+
+                if ((alsa_client = snd_seq_client_info_get_client(client_info)) <= 0) {
+                        break;
+                }
+
+                snd_seq_port_info_set_client(port_info, alsa_client);
+                snd_seq_port_info_set_port(port_info, -1);
+
+                char client[256];
+                snprintf (client, sizeof (client), "%d:%s", alsa_client, snd_seq_client_info_get_name(client_info));
+
+                ports.push_back (PortSet (client));
+
+                while (snd_seq_query_next_port(seq, port_info) >= 0) {
+
+#if 0
+                        int type = snd_seq_port_info_get_type(pinfo);
+                        if (!(type & SND_SEQ_PORT_TYPE_PORT)) {
+                                continue;
+                        }
+#endif
+
+                        unsigned int port_capability = snd_seq_port_info_get_capability(port_info);
+
+                        if ((port_capability & SND_SEQ_PORT_CAP_NO_EXPORT) == 0) {
+
+                                int alsa_port = snd_seq_port_info_get_port(port_info);
+
+                                char port[256];
+                                snprintf (port, sizeof (port), "%d:%s", alsa_port, snd_seq_port_info_get_name(port_info));
+
+                                std::string mode;
+
+                                if (port_capability & SND_SEQ_PORT_CAP_READ) {
+                                        if (port_capability & SND_SEQ_PORT_CAP_WRITE) {
+                                                mode = "duplex";
+                                        } else {
+                                                mode = "output";
+                                        } 
+                                } else if (port_capability & SND_SEQ_PORT_CAP_WRITE) {
+                                        if (port_capability & SND_SEQ_PORT_CAP_READ) {
+                                                mode = "duplex";
+                                        } else {
+                                                mode = "input";
+                                        } 
+                                }
+
+                                XMLNode node (X_("MIDI-port"));
+                                node.add_property ("device", client);
+                                node.add_property ("tag", port);
+                                node.add_property ("mode", mode);
+                                node.add_property ("type", "alsa/sequencer");
+                                
+                                ports.back().ports.push_back (node);
+                                ++n;
+                        }
+                }
+        }
+        
+        return n;
+}
+
+void
+ALSA_SequencerMidiPort::get_connections (vector<SequencerPortAddress>& connections, int dir) const
+{
+       snd_seq_query_subscribe_t *subs;
+       snd_seq_addr_t seq_addr;
+
+       snd_seq_query_subscribe_alloca (&subs);
+
+       // Get port connections...
+       
+       if (dir) {
+               snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_WRITE);
+       } else {
+               snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_READ);
+       }
+
+       snd_seq_query_subscribe_set_index(subs, 0);
+       seq_addr.client = snd_seq_client_id (seq);
+       seq_addr.port   = port_id;
+       snd_seq_query_subscribe_set_root(subs, &seq_addr);
+       
+       while (snd_seq_query_port_subscribers(seq, subs) >= 0) {
+
+               seq_addr = *snd_seq_query_subscribe_get_addr (subs);
+               
+               connections.push_back (SequencerPortAddress (seq_addr.client,
+                                                            seq_addr.port));
+
+               snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1);
+       }
+}
+
+XMLNode&
+ALSA_SequencerMidiPort::get_state () const
+{
+       XMLNode& root (Port::get_state ());
+       vector<SequencerPortAddress> connections;
+       XMLNode* sub = 0;
+       char buf[256];
+
+       get_connections (connections, 1);
+
+       if (!connections.empty()) {
+               if (!sub) {
+                       sub = new XMLNode (X_("connections"));
+               }
+               for (vector<SequencerPortAddress>::iterator i = connections.begin(); i != connections.end(); ++i) {
+                       XMLNode* cnode = new XMLNode (X_("read"));
+                       snprintf (buf, sizeof (buf), "%d:%d", i->first, i->second);
+                       cnode->add_property ("dest", buf);
+                       sub->add_child_nocopy (*cnode);
+               }
+       }
+       
+       connections.clear ();
+       get_connections (connections, 0);
+
+       if (!connections.empty()) {
+               if (!sub) {
+                       sub = new XMLNode (X_("connections"));
+               }
+               for (vector<SequencerPortAddress>::iterator i = connections.begin(); i != connections.end(); ++i) {
+                       XMLNode* cnode = new XMLNode (X_("write"));
+                       snprintf (buf, sizeof (buf), "%d:%d", i->first, i->second);
+                       cnode->add_property ("dest", buf);
+                       sub->add_child_nocopy (*cnode);
+               }
+       }
+
+       if (sub) {
+               root.add_child_nocopy (*sub);
+       }
+
+       return root;
+}
+
+void
+ALSA_SequencerMidiPort::set_state (const XMLNode& node)
+{
+       Port::set_state (node);
+
+       XMLNodeList children (node.children());
+       XMLNodeIterator iter;
+
+       for (iter = children.begin(); iter != children.end(); ++iter) {
+
+               if ((*iter)->name() == X_("connections")) {
+
+                       XMLNodeList gchildren ((*iter)->children());
+                       XMLNodeIterator gciter;
+
+                       for (gciter = gchildren.begin(); gciter != gchildren.end(); ++gciter) {
+                               XMLProperty* prop;
+
+                               if ((prop = (*gciter)->property ("dest")) != 0) {
+                                       int client;
+                                       int port;
+
+                                       if (sscanf (prop->value().c_str(), "%d:%d", &client, &port) == 2) {
+
+                                               snd_seq_port_subscribe_t *sub;
+                                               snd_seq_addr_t seq_addr;
+                                               
+                                               snd_seq_port_subscribe_alloca(&sub);
+
+                                               if ((*gciter)->name() == X_("write")) {
+                                                       
+                                                       seq_addr.client = snd_seq_client_id (seq);
+                                                       seq_addr.port   = port_id;
+                                                       snd_seq_port_subscribe_set_sender(sub, &seq_addr);
+                                                       
+                                                       seq_addr.client = client;
+                                                       seq_addr.port   = port;
+                                                       snd_seq_port_subscribe_set_dest(sub, &seq_addr);
+
+                                               } else {
+                                                       
+                                                       seq_addr.client = snd_seq_client_id (seq);
+                                                       seq_addr.port   = port_id;
+                                                       snd_seq_port_subscribe_set_dest(sub, &seq_addr);
+                                                       
+                                                       seq_addr.client = client;
+                                                       seq_addr.port   = port;
+                                                       snd_seq_port_subscribe_set_sender(sub, &seq_addr);
+                                               }
+
+                                               snd_seq_subscribe_port (seq, sub);
+                                       }
+                               }
+                       }
+
+                       break;
+               }
+       }
+}
index 2cd98239ece74b4edb2aae7ec5e81f6c26c93d35..14020a6f359f5b3e118ffbd216d77fa12080b031 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <midi++/coremidi_midiport.h>
 #include <midi++/types.h>
-#include <midi++/port_request.h>
 #include <mach/mach_time.h>
 
 #include <pbd/pthread_utils.h>
@@ -36,15 +35,15 @@ MIDITimeStamp CoreMidi_MidiPort::MIDIGetCurrentHostTime()
        return mach_absolute_time();
 }
 
-CoreMidi_MidiPort::CoreMidi_MidiPort (PortRequest &req) : Port (req)
+CoreMidi_MidiPort::CoreMidi_MidiPort (const XMLNode& node) : Port (node)
 {
+       Descriptor desc (node);
+
        firstrecv = true;
        int err;
-       if (0 == (err = Open(req))) {
+       if (0 == (err = Open(desc))) {
                _ok = true;
-               req.status = PortRequest::OK;
-       } else
-               req.status = PortRequest::Unknown;
+       }
 }
 
 CoreMidi_MidiPort::~CoreMidi_MidiPort () {Close();}
@@ -56,10 +55,10 @@ void CoreMidi_MidiPort::Close ()
        if (midi_client) MIDIClientDispose(midi_client);
 }
 
-int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp) 
+int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t ignored)   
 {
        OSStatus err;
-    MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer;
+       MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer;
        MIDIPacket* packet = MIDIPacketListInit(pktlist);
        packet = MIDIPacketListAdd(pktlist,sizeof(midi_buffer),packet,MIDIGetCurrentHostTime(),msglen,msg);
        
@@ -77,21 +76,21 @@ int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp)
        }
 }
 
-int CoreMidi_MidiPort::Open (PortRequest &req)
+int CoreMidi_MidiPort::Open (const Descriptor& desc)
 {
        OSStatus err;
        CFStringRef coutputStr;
        string str;
-
-       coutputStr = CFStringCreateWithCString(0, req.devname, CFStringGetSystemEncoding());
+       
+       coutputStr = CFStringCreateWithCString(0, desc.device.c_str(), CFStringGetSystemEncoding());
        err = MIDIClientCreate(coutputStr, 0, 0, &midi_client);
        CFRelease(coutputStr);
-    if (!midi_client) {
+       if (!midi_client) {
                //error << "Cannot open CoreMidi client : " << err << endmsg.
-        goto error;
-    }
+               goto error;
+       }
        
-       str = req.tagname + string("_in");
+       str = desc.tag + string("_in");
        coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
        err = MIDIDestinationCreate(midi_client, coutputStr, read_proc, this, &midi_destination);
        CFRelease(coutputStr);
@@ -100,7 +99,7 @@ int CoreMidi_MidiPort::Open (PortRequest &req)
                goto error;
        }
        
-       str = req.tagname + string("_out");
+       str = desc.tag + string("_out");
        coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
        err = MIDISourceCreate(midi_client, coutputStr, &midi_source);
        CFRelease(coutputStr);
@@ -142,3 +141,10 @@ void CoreMidi_MidiPort::read_proc (const MIDIPacketList *pktlist, void *refCon,
     }
 }
 
+int
+CoreMidi_MidiPort::discover (vector<PortSet>& ports)
+{
+       /* XXX do dynamic port discovery here */
+
+       return 0;
+}
index 81d81c8558cffe83c0343dde69ea158582b8fbd6..17a7eff367dac1f6f9eb2175ab2b4a2ca9d3ad74 100644 (file)
@@ -34,40 +34,38 @@ using namespace PBD;
 string *FD_MidiPort::midi_dirpath = 0;
 string *FD_MidiPort::midi_filename_pattern = 0;
 
-FD_MidiPort::FD_MidiPort (PortRequest &req, 
+FD_MidiPort::FD_MidiPort (const XMLNode& node,
                          const string &dirpath,
                          const string &pattern) 
-       : Port (req)
+       : Port (node)
 {      
-       open (req);
+       Descriptor desc (node);
+
+       open (desc);
 
        if (_fd < 0) {
                switch (errno) {
                case EBUSY:
                        error << "MIDI: port device in use" << endmsg;
-                       req.status = PortRequest::Busy;
                        break;
                case ENOENT:
                        error << "MIDI: no such port device" << endmsg;
-                       req.status = PortRequest::NoSuchFile;
                        break;
                case EACCES:
                        error << "MIDI: access to port denied" << endmsg;
-                       req.status = PortRequest::NotAllowed;
                        break;
                default:
-                       req.status = PortRequest::Unknown;
+                       break;
                } 
        } else {
                _ok = true;
-               req.status = PortRequest::OK;
 
                if (midi_dirpath == 0) {
                        midi_dirpath = new string (dirpath);
                        midi_filename_pattern = new string (pattern);
                }
 
-               if (req.mode & O_NONBLOCK == 0) {
+               if (desc.mode & O_NONBLOCK == 0) {
                        /* we unconditionally set O_NONBLOCK during
                           open, but the request didn't ask for it,
                           so remove it.
@@ -80,11 +78,11 @@ FD_MidiPort::FD_MidiPort (PortRequest &req,
 }
 
 void
-FD_MidiPort::open (PortRequest &req)
+FD_MidiPort::open (const Descriptor& desc)
 
 {
-       int mode = req.mode | O_NONBLOCK;
-       _fd = ::open (req.devname, mode);
+       int mode = desc.mode | O_NONBLOCK;
+       _fd = ::open (desc.device.c_str(), mode);
 }
 
 vector<string *> *
@@ -152,7 +150,7 @@ FD_MidiPort::do_slow_write (byte *msg, unsigned int msglen)
 }
 
 int
-FD_MidiPort::read (byte* buf, size_t max, timestamp_t timestamp)
+FD_MidiPort::read (byte* buf, size_t max, timestamp_t ignored)
 {
        int nread;
        
index 7bb126ddebec2231edaa53fe5fe5658da581382c..a81520bb9532f134d1f5523fa8a330cae2be038a 100644 (file)
 
 using namespace MIDI;
 
-FIFO_MidiPort::FIFO_MidiPort (PortRequest &req
-       : FD_MidiPort (req, ".", "midi")
+FIFO_MidiPort::FIFO_MidiPort (const XMLNode& node
+       : FD_MidiPort (node, ".", "midi")
 
 {
 }
 
 void
-FIFO_MidiPort::open (PortRequest &req)
+FIFO_MidiPort::open (const Port::Descriptor& desc)
 
 {
        /* This is a placeholder for the fun-and-games I think we will
           need to do with FIFO's.
        */
 
-       _fd = ::open (req.devname, req.mode|O_NDELAY);
+       _fd = ::open (desc.device.c_str(), desc.mode|O_NDELAY);
 }
index 4b2808a6986a431cff0f2940d22d2406b653d85c..11cd70a0513a78db25e8c7c1d5c1116ad42b9e82 100644 (file)
 
 #include <midi++/types.h>
 #include <midi++/jack.h>
-#include <midi++/port_request.h>
 
 using namespace std;
 using namespace MIDI;
 
-JACK_MidiPort::JACK_MidiPort(PortRequest & req, jack_client_t* jack_client)
-       : Port(req)
+JACK_MidiPort::JACK_MidiPort(const XMLNode& node, jack_client_t* jack_client)
+       : Port(node)
        , _jack_client(jack_client)
        , _jack_input_port(NULL)
        , _jack_output_port(NULL)
        , _last_read_index(0)
 {
-       int err = create_ports(req);
+       int err = create_ports (node);
 
        if (!err) {
-               req.status = PortRequest::OK;
                _ok = true;
-       } else {
-               req.status = PortRequest::Unknown;
-       }
+       } 
 }
 
 JACK_MidiPort::~JACK_MidiPort()
@@ -94,8 +90,10 @@ JACK_MidiPort::read(byte * buf, size_t max, timestamp_t timestamp)
 }
 
 int
-JACK_MidiPort::create_ports(PortRequest & req)
+JACK_MidiPort::create_ports(const XMLNode& node)
 {
+       Descriptor desc (node);
+
        assert(!_jack_input_port);
        assert(!_jack_output_port);
        
@@ -103,24 +101,33 @@ JACK_MidiPort::create_ports(PortRequest & req)
 
        bool ret = true;
 
-       if (req.mode == O_RDWR || req.mode == O_WRONLY) {
+       if (desc.mode == O_RDWR || desc.mode == O_WRONLY) {
                _jack_output_port = jack_port_register(_jack_client,
-                       string(req.tagname).append("_out").c_str(),
-                       JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
-               jack_midi_clear_buffer(
-                       jack_port_get_buffer(_jack_output_port, nframes));
+                                                      string(desc.tag).append("_out").c_str(),
+                                                      JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
+               jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes));
                ret = ret && (_jack_output_port != NULL);
        }
-
-       if (req.mode == O_RDWR || req.mode == O_RDONLY) {
+       
+       if (desc.mode == O_RDWR || desc.mode == O_RDONLY) {
                _jack_input_port = jack_port_register(_jack_client,
-                       string(req.tagname).append("_in").c_str(),
-                       JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
-               jack_midi_clear_buffer(
-                       jack_port_get_buffer(_jack_input_port, nframes));
+                                                     string(desc.tag).append("_in").c_str(),
+                                                     JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
+               jack_midi_clear_buffer(jack_port_get_buffer(_jack_input_port, nframes));
                ret = ret && (_jack_input_port != NULL);
        }
 
        return ret ? 0 : -1;
 }
 
+XMLNode& 
+JACK_MidiPort::get_state () const
+{
+       XMLNode& root (Port::get_state ());
+       return root;
+}
+
+void
+JACK_MidiPort::set_state (const XMLNode& node)
+{
+}
index 54b86edd70e5f77de73b1882e16e84aad70f9bd7..e5abc2832f9ecd8bf5292d565b84ddcc4fa9f1bc 100644 (file)
@@ -34,8 +34,8 @@ class ALSA_RawMidiPort : public MIDI::FD_MidiPort
 
 {
   public:
-       ALSA_RawMidiPort (MIDI::PortRequest &req) 
-               : FD_MidiPort (req, "/dev/snd", "midi") {}
+       ALSA_RawMidiPort (const XMLNode& node)
+               : FD_MidiPort (node, "/dev/snd", "midi") {}
        virtual ~ALSA_RawMidiPort () {}
 
        static std::string typestring;
@@ -46,7 +46,7 @@ class ALSA_RawMidiPort : public MIDI::FD_MidiPort
        }
 };
 
-} // namespace MIDI
+}
 
 #endif // __alsa_rawmidi_h__
 
index b54486416a6e63dbffd783d0be525c4715900563..a95f9c476fe2fa07e9c4c24c67aea28d8017dcc8 100644 (file)
 
 namespace MIDI {
 
-class PortRequest;
-
 class ALSA_SequencerMidiPort : public Port
+
 {
   public:
-       ALSA_SequencerMidiPort (PortRequest &req);
+       ALSA_SequencerMidiPort (const XMLNode&);
        virtual ~ALSA_SequencerMidiPort ();
 
        /* select(2)/poll(2)-based I/O */
 
        virtual int selectable() const;
-
+       
+       static int discover (std::vector<PortSet>&);
        static std::string typestring;
 
-  protected:
-       std::string get_typestring () const {
-               return typestring;
-       }
+       XMLNode& get_state() const;
+       void set_state (const XMLNode&);
 
   protected:
        /* Direct I/O */
+       
        int write (byte *msg, size_t msglen, timestamp_t timestamp);    
        int read (byte *buf, size_t max, timestamp_t timestamp);
 
+       std::string get_typestring () const {
+               return typestring;
+       }
+
   private:
        snd_midi_event_t *decoder, *encoder;
        int port_id;
        snd_seq_event_t SEv;
 
-       int CreatePorts(PortRequest &req);
+       int create_ports (const Port::Descriptor&);
 
        static int init_client (std::string name);
        static snd_seq_t* seq;
+
+       typedef std::pair<int,int> SequencerPortAddress;
+       void get_connections (std::vector<SequencerPortAddress>&, int dir) const;
 };
 
 }; /* namespace MIDI */
index 91eccea4a55bdaa50ff0ce2ea2997961d4fc2738..d5d3c23edef6da63b0c76bfe801057ee99c6a493 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <list>
 #include <string>
+#include <vector>
 
 #include <fcntl.h>
 #include <unistd.h>
 
 namespace MIDI {
 
-namespace PortRequest;
+    class CoreMidi_MidiPort:public Port {
+      public:
+       CoreMidi_MidiPort(const XMLNode& node);
+       virtual ~ CoreMidi_MidiPort();
 
-class CoreMidi_MidiPort:public Port 
-{
-  public:
-       CoreMidi_MidiPort(PortRequest & req);
-       virtual ~ CoreMidi_MidiPort();
-    
-       virtual int selectable() const {
-              return -1;
-       }
-       static std::string typestring;
+       virtual int selectable() const {
+           return -1;
+       }
+
+       static int discover (std::vector<PortSet>&);
+       static std::string typestring;
+
+      protected:
+       /* Direct I/O */
+       int write (byte * msg, size_t msglen, timestamp_t timestamp);
 
-  protected:
+       int read (byte * buf, size_t max, timestamp_t timestamp) {
+           return 0;
+       } 
+
+        /* CoreMidi callback */
+       static void read_proc(const MIDIPacketList * pktlist,
+                             void *refCon, void *connRefCon);
+       
        std::string get_typestring () const {
                return typestring;
        }
 
-       protected:
-               /* Direct I/O */
-               int write (byte *msg, size_t msglen, timestamp_t timestamp);    
-               int read (byte *buf, size_t max, timestamp_t timestamp);
-
-               /* CoreMidi callback */
-               static void read_proc(const MIDIPacketList * pktlist,
-                               void *refCon, void *connRefCon);
-
-       private:
-               byte midi_buffer[1024];
-               MIDIClientRef midi_client;
-               MIDIEndpointRef midi_destination;
-               MIDIEndpointRef midi_source;
+      private:
+       byte midi_buffer[1024];
+       MIDIClientRef midi_client;
+       MIDIEndpointRef midi_destination;
+       MIDIEndpointRef midi_source;
 
-               int Open(PortRequest & req);
-               void Close();
-               static MIDITimeStamp MIDIGetCurrentHostTime();
+       int Open(const Port::Descriptor&);
+       void Close();
+       static MIDITimeStamp MIDIGetCurrentHostTime();
 
-               bool firstrecv;
-};
+       bool firstrecv;
+       
+    };
 
 } // namespace MIDI
 
index 9954ea72fec7b98c49a5140511cbab9b20caa209..f3402546e9504875a7e859f171d7c12872aafb4f 100644 (file)
 #include <string>
 
 #include <midi++/port.h>
-#include <midi++/port_request.h>
 
 namespace MIDI {
 
 class PortFactory {
   public:
-       Port *create_port (PortRequest &req, void* data);
+       Port *create_port (const XMLNode&, void* data);
 
        static bool ignore_duplicate_devices (Port::Type);
        static int get_known_ports (std::vector<PortSet>&);
index 34e2e27a1a40b85e5f16feffb6a524bf8d7e8922..ec5a9f8af4ccf4ab54fcd8a186f4195f5c18803a 100644 (file)
@@ -29,7 +29,6 @@
 #include <unistd.h>
 
 #include <midi++/port.h>
-#include <midi++/port_request.h>
 
 namespace MIDI {
 
@@ -37,7 +36,7 @@ class FD_MidiPort : public Port
 
 {
   public:
-       FD_MidiPort (PortRequest &req, 
+       FD_MidiPort (const XMLNode& node,
                     const std::string &dirpath,
                     const std::string &pattern);
 
@@ -46,23 +45,14 @@ class FD_MidiPort : public Port
        }
 
        virtual int selectable() const;
-       static std::vector<std::string *> *list_devices ();
-
-       static std::string typestring;
 
-  protected:
-       std::string get_typestring () const {
-               return typestring;
-       }
+       static std::vector<std::string *> *list_devices ();
 
   protected:
        int _fd;
-       virtual void open (PortRequest &req);
+       virtual void open (const Port::Descriptor&);
 
-       /* Direct I/O */
-       
-       virtual int write (byte *msg, size_t msglen,
-                          timestamp_t timestamp) {
+       virtual int write (byte *msg, size_t msglen, timestamp_t ignored) {
                int nwritten;
                
                if ((_mode & O_ACCMODE) == O_RDONLY) {
@@ -89,8 +79,7 @@ class FD_MidiPort : public Port
                return nwritten;
        }
 
-       virtual int read (byte *buf, size_t max,
-                         timestamp_t timestamp);
+       virtual int read (byte *buf, size_t max, timestamp_t ignored);
 
   private:
        static std::string *midi_dirpath;
index ea644dde06be59f0e448dfb59c7deccbefc82d32..3439c27dcfb64cace2cfe46ee5004c6105de45f6 100644 (file)
@@ -25,7 +25,6 @@
 #include <unistd.h>
 
 #include <midi++/port.h>
-#include <midi++/port_request.h>
 #include <midi++/fd_midiport.h>
 
 namespace MIDI {
@@ -34,7 +33,7 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort
 
 {
   public:
-       FIFO_MidiPort (PortRequest &req);
+       FIFO_MidiPort (const XMLNode&);
        ~FIFO_MidiPort () {};
 
        static std::string typestring;
@@ -45,7 +44,7 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort
        }
 
   private:
-       void open (PortRequest &req);
+       void open (const Port::Descriptor&);
 };
 
 } // namespace MIDI
index 1f25609aacbaca3e46ceea9041d4f7a0cf9ed78a..845dd0c229c1e4e3d44db44672c152ee8e62c293 100644 (file)
@@ -39,7 +39,7 @@ namespace MIDI
 class JACK_MidiPort : public Port
 {
 public:
-       JACK_MidiPort (PortRequest &req, jack_client_t* jack_client);
+       JACK_MidiPort (const XMLNode& node, jack_client_t* jack_client);
        virtual ~JACK_MidiPort ();
 
        /* No select(2)/poll(2)-based I/O */
@@ -49,6 +49,9 @@ public:
 
        static std::string typestring;
 
+       virtual XMLNode& get_state () const;
+       virtual void set_state (const XMLNode&);
+
   protected:
        std::string get_typestring () const {
                return typestring;
@@ -60,7 +63,7 @@ protected:
        int read(byte *buf, size_t max, timestamp_t timestamp);
 
 private:
-       int create_ports(PortRequest &req);
+       int create_ports(const XMLNode&);
 
        jack_client_t* _jack_client;
        jack_port_t*   _jack_input_port;
index eef52abe521664e79f2f3dcd2b3d8eb64a432bed..bb3bf9b99967f328cc9675698ed6aa90e66e765d 100644 (file)
@@ -21,6 +21,8 @@
 #define __midi_manager_h__
 
 #include <map>
+#include <vector>
+
 #include <string>
 
 #include <midi++/types.h>
 
 namespace MIDI {
 
-/** Creates, stores, and manages system MIDI ports.
- */
 class Manager {
   public:
        ~Manager ();
        
        void set_api_data(void* data) { api_data = data; }
-
+       
        /** Signal the start of an audio cycle.
         * This MUST be called before any reading/writing for this cycle.
         * Realtime safe.
         */
        void cycle_start(nframes_t nframes);
-
+       
        /** Signal the end of an audio cycle.
         * This signifies that the cycle began with @ref cycle_start has ended.
         * This MUST be called at the end of each cycle.
@@ -49,13 +49,25 @@ class Manager {
         */
        void cycle_end();
 
-       Port *add_port (PortRequest &);
+       Port *add_port (const XMLNode& node);
        int   remove_port (Port*);
 
        Port *port (std::string name);
 
        size_t    nports () { return ports_by_device.size(); }
 
+       /* defaults for clients who are not picky */
+       
+       Port *inputPort;
+       Port *outputPort;
+       channel_t inputChannelNumber;
+       channel_t outputChannelNumber;
+
+       int set_input_port (std::string);
+       int set_output_port (std::string);
+       int set_input_channel (channel_t);
+       int set_output_channel (channel_t);
+
        int foreach_port (int (*func)(const Port &, size_t n, void *), 
                          void *arg);
 
@@ -70,7 +82,7 @@ class Manager {
                return theManager;
        }
 
-       static int parse_port_request (std::string str, Port::Type type);
+       int get_known_ports (std::vector<PortSet>&);
 
   private:
        /* This is a SINGLETON pattern */
@@ -81,7 +93,7 @@ class Manager {
        PortMap         ports_by_device; /* canonical */
        PortMap         ports_by_tag;    /* may contain duplicate Ports */
 
-       void *api_data;
+       voidapi_data;
 
        void close_ports ();
 };
index 6ed94db71cc41f64907c8a0ddbbb70ba2371b430..8f36e6aed812efb741311a55936bb9187c18bc7d 100644 (file)
@@ -24,7 +24,6 @@
 #include <string>
 
 #include <midi++/port.h>
-#include <midi++/port_request.h>
 
 namespace MIDI {
 
index e4338cf95226fceb940e398de10795f15c3394c4..dcae446c422d62d343b89fd5bee0d920b09c29dd 100644 (file)
 #define  __libmidi_port_h__
 
 #include <string>
+#include <iostream>
 
 #include <sigc++/sigc++.h>
+#include <pbd/xml++.h>
 
-#include <pbd/selectable.h>
 #include <midi++/types.h>
 #include <midi++/parser.h>
 
@@ -44,64 +45,82 @@ class Port : public sigc::trackable {
                FIFO
        };
 
-       Port (PortRequest &);
+
+       Port (const XMLNode&);
        virtual ~Port ();
 
+       virtual XMLNode& get_state () const;
+       virtual void set_state (const XMLNode&);
+
        // FIXME: make Manager a friend of port so these can be hidden?
-       
+
        /* Only for use by MidiManager.  Don't ever call this. */
        virtual void cycle_start(nframes_t nframes);
-
        /* Only for use by MidiManager.  Don't ever call this. */
        virtual void cycle_end();
 
-       /* Direct I/O */
-       
-       /** Read a message from port.
-        * @param buf Raw MIDI message to send
-        * @param max Max size to write to @a buf
-        * @param timestamp Time stamp in frames of this message (relative to cycle start)
-        * @return number of bytes successfully written to \a buf
-        */
-       virtual int read(byte *buf, size_t max, timestamp_t timestamp) = 0;
-       
        /** Write a message to port.
         * @param msg Raw MIDI message to send
         * @param msglen Size of @a msg
         * @param timestamp Time stamp in frames of this message (relative to cycle start)
         * @return number of bytes successfully written
         */
-       virtual int write(byte *msg, size_t msglen, timestamp_t timestamp) = 0; 
+       virtual int write (byte *msg, size_t msglen, timestamp_t timestamp) = 0;        
+
+       /** Read a message from port.
+        * @param buf Raw MIDI message to send
+        * @param max Max size to write to @a buf
+        * @param timestamp Time stamp in frames of this message (relative to cycle start)
+        * @return number of bytes successfully written to \a buf
+        */
+       virtual int read (byte *buf, size_t max, timestamp_t timestamp) = 0;
 
        /** Write a message to port.
         * @return true on success.
         * FIXME: describe semantics here
         */
-       bool midimsg (byte *msg, size_t len, timestamp_t timestamp) {
+       int midimsg (byte *msg, size_t len, timestamp_t timestamp) {
                return !(write (msg, len, timestamp) == (int) len);
-       }
+       } 
+
+       int three_byte_msg (byte a, byte b, byte c, timestamp_t timestamp) {
+               byte msg[3];
 
+               msg[0] = a;
+               msg[1] = b;
+               msg[2] = c;
+
+               return !(write (msg, 3, timestamp) == 3);
+       } 
+       
        bool clock (timestamp_t timestamp);
+       
+       /* slowdown i/o to a loop of single byte emissions
+          interspersed with a busy loop of 10000 * this value.
+
+          This may be ignored by a particular instance
+          of this virtual class. See FD_MidiPort for an 
+          example of where it used.  
+       */
 
-       /** Slow down I/O to a loop of single byte emissions
-         * interspersed with a busy loop of 10000 * this value.
-         *
-         * This may be ignored by a particular instance of this virtual
-         * class. See FD_MidiPort for an example of where it used. */
        void set_slowdown (size_t n) { slowdown = n; }
 
        /* select(2)/poll(2)-based I/O */
 
        /** Get the file descriptor for port.
-        * @return File descriptor, or -1 if not selectable. */
+        * @return File descriptor, or -1 if not selectable. 
+        */
        virtual int selectable() const = 0;
 
+       static void gtk_read_callback (void *ptr, int fd, int cond);
+       static void write_callback (byte *msg, unsigned int len, void *);
+       
        Channel *channel (channel_t chn) { 
                return _channel[chn&0x7F];
        }
        
-       Parser *input()  { return input_parser; }
-       Parser *output() { return output_parser; }
+       Parser *input()     { return input_parser; }
+       Parser *output()    { return output_parser; }
 
        void iostat (int *written, int *read, 
                     const size_t **in_counts,
@@ -121,14 +140,21 @@ class Port : public sigc::trackable {
                }
        }
        
-       bool clock ();
-       
        const char *device () const { return _devname.c_str(); }
-       const char *name ()   const { return _tagname.c_str(); }
-       Type        type ()   const { return _type; }
-       int         mode ()   const { return _mode; }
-       bool        ok ()     const { return _ok; }
-       size_t      number () const { return _number; }
+       const char *name () const   { return _tagname.c_str(); }
+       Type   type () const        { return _type; }
+       int    mode () const        { return _mode; }
+       bool   ok ()   const        { return _ok; }
+
+       struct Descriptor {
+           std::string tag;
+           std::string device;
+           int mode;
+           Port::Type type;
+
+           Descriptor (const XMLNode&);
+           XMLNode& get_state();
+       };
 
   protected:
        bool             _ok;
@@ -147,10 +173,21 @@ class Port : public sigc::trackable {
        Parser           *output_parser;
        size_t           slowdown;
 
+       virtual std::string get_typestring () const = 0;
+
   private:
        static size_t nports;
 };
 
+struct PortSet {
+    PortSet (std::string str) : owner (str) { }
+    
+    std::string owner;
+    std::list<XMLNode> ports;
+};
+
+std::ostream & operator << ( std::ostream & os, const Port & port );
+
 } // namespace MIDI
 
 #endif // __libmidi_port_h__
diff --git a/libs/midi++2/midi++/port_request.h b/libs/midi++2/midi++/port_request.h
deleted file mode 100644 (file)
index dfde87a..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-    Copyright (C) 1999 Paul Barton-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.
-
-*/
-
-#ifndef __midi_port_request_h__
-#define __midi_port_request_h__
-
-#include <string>
-
-namespace MIDI {
-
-struct PortRequest {
-    enum Status {
-           Unknown,
-           OK,
-           Busy,
-           NoSuchFile,
-           TypeUnsupported,
-           NotAllowed
-    };
-    const char *devname;
-    const char *tagname;
-    int mode;
-    Port::Type type;
-    Status status;
-    
-    PortRequest () {
-           devname = 0;
-           tagname = 0;
-           mode = 0;
-           type = Port::Unknown;
-           status = Unknown;
-    }
-
-    PortRequest (const std::string &xdev, 
-                const std::string &xtag, 
-                const std::string &xmode,
-                const std::string &xtype);
-};
-
-struct PortSet {
-    PortSet (std::string str) : owner (str) { }
-    
-    std::string owner;
-    std::list<PortRequest> ports;
-};
-
-} // namespace MIDI
-
-#endif // __midi_port_request_h__
-
index 9d98d9f6a7d0260f2bdd097a009f2fee0c50330b..d893cc9f474cf19880389034a2371af9bccfc24b 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <midi++/types.h>
 #include <midi++/factory.h>
-#include <midi++/nullmidi.h>
 #include <midi++/fifomidi.h>
 
 #ifdef WITH_JACK_MIDI
@@ -33,7 +32,6 @@
 std::string MIDI::JACK_MidiPort::typestring = "jack";
 #endif // WITH_JACK_MIDI
 
-std::string MIDI::Null_MidiPort::typestring = "null";
 std::string MIDI::FIFO_MidiPort::typestring = "fifo";
 
 #ifdef WITH_ALSA
@@ -58,50 +56,44 @@ using namespace PBD;
 
 // FIXME: void* data pointer, filthy
 Port *
-PortFactory::create_port (PortRequest &req, void* data)
+PortFactory::create_port (const XMLNode& node, void* data)
 
 {
+       Port::Descriptor desc (node);
        Port *port;
        
-       switch (req.type) {
+       switch (desc.type) {
 #ifdef WITH_JACK_MIDI
        case Port::JACK_Midi:
                assert(data != NULL);
-               port = new JACK_MidiPort (req, (jack_client_t*)data);
+               port = new JACK_MidiPort (node, (jack_client_t*) data);
                break;
 #endif // WITH_JACK_MIDI
        
 #ifdef WITH_ALSA
        case Port::ALSA_RawMidi:
-               port = new ALSA_RawMidiPort (req);
+               port = new ALSA_RawMidiPort (node);
                break;
 
        case Port::ALSA_Sequencer:
-               port = new ALSA_SequencerMidiPort (req);
+               port = new ALSA_SequencerMidiPort (node);
                break;
 #endif // WITH_ALSA
 
 #if WITH_COREMIDI
        case Port::CoreMidi_MidiPort:
-               port = new CoreMidi_MidiPort (req);
+               port = new CoreMidi_MidiPort (node);
                break;
 #endif // WITH_COREMIDI
 
-       case Port::Null:
-               port = new Null_MidiPort (req);
-               break;
-
        case Port::FIFO:
-               port = new FIFO_MidiPort (req);
+               port = new FIFO_MidiPort (node);
                break;
 
        default:
-               req.status = PortRequest::TypeUnsupported;
                return 0;
        }
 
-       req.status = PortRequest::OK;
-
        return port;
 }
 
@@ -179,8 +171,6 @@ PortFactory::string_to_type (const string& xtype)
        } else if (strings_equal_ignore_case (xtype, CoreMidi_MidiPort::typestring)) {
                return Port::CoreMidi_MidiPort;
 #endif
-       } else if (strings_equal_ignore_case (xtype, Null_MidiPort::typestring)) {
-               return Port::Null;
        } else if (strings_equal_ignore_case (xtype, FIFO_MidiPort::typestring)) {
                return Port::FIFO;
 #ifdef WITH_JACK_MIDI
index ee73bdad868da206f90749d7b0692f4d30a3b2a9..8a358c318370b50c168ec6a028cac06fb63d44de 100644 (file)
 #include <midi++/manager.h>
 #include <midi++/factory.h>
 #include <midi++/channel.h>
-#include <midi++/port_request.h>
 
 using namespace std;
 using namespace MIDI;
 using namespace PBD;
 
+/* XXX check for strdup leaks */
+
 Manager *Manager::theManager = 0;
 
 Manager::Manager () 
-       : api_data(NULL)
 {
+       inputPort = 0;
+       outputPort = 0;
+       inputChannelNumber = 0;
+       outputChannelNumber = 0;
+       api_data = 0;
 }
 
 Manager::~Manager ()
-
 {
        PortMap::iterator i;
 
@@ -58,27 +62,27 @@ Manager::~Manager ()
 }
 
 Port *
-Manager::add_port (PortRequest &req)
-
+Manager::add_port (const XMLNode& node)
 {
+       Port::Descriptor desc (node);
        PortFactory factory;
        Port *port;
        PortMap::iterator existing;
        pair<string, Port *> newpair;
 
-       if (!PortFactory::ignore_duplicate_devices (req.type)) {
+       if (!PortFactory::ignore_duplicate_devices (desc.type)) {
 
-               if ((existing = ports_by_device.find (req.devname)) != ports_by_device.end()) {
+               if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
                        
                        port = (*existing).second;
                        
-                       if (port->mode() == req.mode) {
+                       if (port->mode() == desc.mode) {
                                
                                /* Same mode - reuse the port, and just
                                   create a new tag entry.
                                */
                                
-                               newpair.first = req.tagname;
+                               newpair.first = desc.tag;
                                newpair.second = port;
                                
                                ports_by_tag.insert (newpair);
@@ -91,10 +95,10 @@ Manager::add_port (PortRequest &req)
                           operation.
                        */
                        
-                       if ((req.mode == O_RDWR && port->mode() != O_RDWR) ||
-                           (req.mode != O_RDWR && port->mode() == O_RDWR)) {
+                       if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
+                           (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
                                error << "MIDIManager: port tagged \""
-                                     << req.tagname
+                                     << desc.tag
                                      << "\" cannot be opened duplex and non-duplex"
                                      << endmsg;
                                return 0;
@@ -103,7 +107,8 @@ Manager::add_port (PortRequest &req)
                        /* modes must be different or complementary */
                }
        }
-       port = factory.create_port (req, api_data);
+       
+       port = factory.create_port (node, api_data);
        
        if (port == 0) {
                return 0;
@@ -122,6 +127,18 @@ Manager::add_port (PortRequest &req)
        newpair.second = port;
        ports_by_device.insert (newpair);
 
+       /* first port added becomes the default input
+          port.
+       */
+
+       if (inputPort == 0) {
+               inputPort = port;
+       } 
+
+       if (outputPort == 0) {
+               outputPort = port;
+       }
+
        return port;
 }
 
@@ -156,119 +173,88 @@ Manager::remove_port (Port* port)
        return 0;
 }
 
-Port *
-Manager::port (string name)
+int
+Manager::set_input_port (string tag)
 {
        PortMap::iterator res;
+       bool found = false;
 
        for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
-               if (name == (*res).first) {
-                       return (*res).second;
+               if (tag == (*res).first) {
+                       found = true;
+                       break;
                }
        }
+       
+       if (!found) {
+               return -1;
+       }
+
+       inputPort = (*res).second;
 
        return 0;
 }
 
 int
-Manager::foreach_port (int (*func)(const Port &, size_t, void *),
-                          void *arg)
+Manager::set_output_port (string tag)
 
 {
-       PortMap::const_iterator i;
-       int retval;
-       int n;
-               
-       for (n = 0, i = ports_by_device.begin(); 
-                   i != ports_by_device.end(); i++, n++) {
+       PortMap::iterator res;
+       bool found = false;
 
-               if ((retval = func (*((*i).second), n, arg)) != 0) {
-                       return retval;
+       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
+               if (tag == (*res).first) {
+                       found = true;
+                       break;
                }
        }
-
-       return 0;
-}
-
-int
-Manager::parse_port_request (string str, Port::Type type)
-{
-       PortRequest *req;
-       string::size_type colon;
-       string tag;
-
-       if (str.length() == 0) {
-               error << "MIDI: missing port specification" << endmsg;
+       
+       if (!found) {
                return -1;
        }
 
-       /* Port specifications look like:
+       // XXX send a signal to say we're about to change output ports
 
-          devicename
-          devicename:tagname
-          devicename:tagname:mode
+       if (outputPort) {
+               for (channel_t chan = 0; chan < 16; chan++) {
+                       outputPort->channel (chan)->all_notes_off (0);
+               }
+       }
+       outputPort = (*res).second;
 
-          where 
+       // XXX send a signal to say we've changed output ports
 
-          "devicename" is the full path to the requested file
-          
-          "tagname" (optional) is the name used to refer to the
-                        port. If not given, g_path_get_basename (devicename)
-                        will be used.
+       return 0;
+}
 
-          "mode" (optional) is either "r" or "w" or something else.
-                       if it is "r", the port will be opened
-                       read-only, if "w", the port will be opened
-                       write-only. Any other value, or no mode
-                       specification at all, will cause the port to
-                       be opened for reading and writing.
-       */
-                       
-       req = new PortRequest;
-       colon = str.find_first_of (':');
+Port *
+Manager::port (string name)
+{
+       PortMap::iterator res;
 
-       if (colon != string::npos) {
-               req->devname = strdup (str.substr (0, colon).c_str());
-       } else {
-               req->devname = strdup (str.c_str());
+       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
+               if (name == (*res).first) {
+                       return (*res).second;
+               }
        }
 
-       if (colon < str.length()) {
-
-               tag = str.substr (colon+1);
+       return 0;
+}
 
-               /* see if there is a mode specification in the tag part */
+int
+Manager::foreach_port (int (*func)(const Port &, size_t, void *),
+                          void *arg)
+{
+       PortMap::const_iterator i;
+       int retval;
+       int n;
                
-               colon = tag.find_first_of (':');
-
-               if (colon != string::npos) {
-                       string modestr;
-
-                       req->tagname = strdup (tag.substr (0, colon).c_str());
-
-                       modestr = tag.substr (colon+1);
-                       if (modestr == "r") {
-                               req->mode = O_RDONLY;
-                       } else if (modestr == "w") {
-                               req->mode = O_WRONLY;
-                       } else {
-                               req->mode = O_RDWR;
-                       }
+       for (n = 0, i = ports_by_device.begin(); 
+                   i != ports_by_device.end(); i++, n++) {
 
-               } else {
-                       req->tagname = strdup (tag.c_str());
-                       req->mode = O_RDWR;
+               if ((retval = func (*((*i).second), n, arg)) != 0) {
+                       return retval;
                }
-
-       } else {
-               req->tagname = g_path_get_basename (req->devname);
-               req->mode = O_RDWR;
-       }
-
-       req->type = type;
-
-       if (MIDI::Manager::instance()->add_port (*req) == 0) {
-               return -1;
        }
 
        return 0;
@@ -277,16 +263,22 @@ Manager::parse_port_request (string str, Port::Type type)
 void
 Manager::cycle_start(nframes_t nframes)
 {
-       for (PortMap::iterator i = ports_by_device.begin(); 
-                   i != ports_by_device.end(); i++)
-               (*i).second->cycle_start(nframes);
+       for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
+               (*i).second->cycle_start (nframes);
+       }
 }
 
 void
 Manager::cycle_end()
 {
-       for (PortMap::iterator i = ports_by_device.begin(); 
-                   i != ports_by_device.end(); i++)
-               (*i).second->cycle_end();
+       for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
+               (*i).second->cycle_end ();
+       }
 }
 
+
+int
+Manager::get_known_ports (vector<PortSet>& ports)
+{
+       return PortFactory::get_known_ports (ports);
+}
index 7f31b909d377f985b71471e03abc1cf195040847..2e3d36c19c728531e34326d9d7f50cc0703c84b9 100644 (file)
 
     $Id$
 */
-
+#include <iostream>
 #include <cstdio>
 #include <fcntl.h>
 
+#include <pbd/xml++.h>
+#include <pbd/failed_constructor.h>
+
 #include <midi++/types.h>
 #include <midi++/port.h>
 #include <midi++/channel.h>
-#include <midi++/port_request.h>
+#include <midi++/factory.h>
 
-using namespace Select;
 using namespace MIDI;
+using namespace std;
 
 size_t Port::nports = 0;
 
-Port::Port (PortRequest &req)
+Port::Port (const XMLNode& node)
        : _currently_in_cycle(false)
        , _nframes_this_cycle(0)
 {
+       Descriptor desc (node);
+
        _ok = false;  /* derived class must set to true if constructor
                         succeeds.
                      */
@@ -45,10 +50,9 @@ Port::Port (PortRequest &req)
        output_parser = 0;
        slowdown = 0;
 
-       _devname = req.devname;
-       _tagname = req.tagname;
-       _mode = req.mode;
-       _number = nports++;
+       _devname = desc.device;
+       _tagname = desc.tag;
+       _mode = desc.mode;
 
        if (_mode == O_RDONLY || _mode == O_RDWR) {
                input_parser = new Parser (*this);
@@ -77,7 +81,6 @@ Port::Port (PortRequest &req)
 
 
 Port::~Port ()
-       
 {
        for (int i = 0; i < 16; i++) {
                delete _channel[i];
@@ -113,3 +116,87 @@ Port::cycle_end ()
        _nframes_this_cycle = 0;
 }
 
+XMLNode&
+Port::get_state () const
+{
+       XMLNode* node = new XMLNode ("MIDI-port");
+       node->add_property ("tag", _tagname);
+       node->add_property ("device", _devname);
+       node->add_property ("mode", PortFactory::mode_to_string (_mode));
+       node->add_property ("type", get_typestring());
+
+       return *node;
+}
+
+void
+Port::set_state (const XMLNode& node)
+{
+       // relax
+}
+
+void
+Port::gtk_read_callback (void *ptr, int fd, int cond)
+{
+       byte buf[64];
+       
+       ((Port *)ptr)->read (buf, sizeof (buf), 0);
+}
+
+void
+Port::write_callback (byte *msg, unsigned int len, void *ptr)
+       
+{
+       ((Port *)ptr)->write (msg, len, 0);
+}
+
+std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port )
+{
+       using namespace std;
+       os << "MIDI::Port { ";
+       os << "device: " << port.device();
+       os << "; ";
+       os << "name: " << port.name();
+       os << "; ";
+       os << "type: " << port.type();
+       os << "; ";
+       os << "mode: " << port.mode();
+       os << "; ";
+       os << "ok: " << port.ok();
+       os << "; ";
+       os << " }";
+       return os;
+}
+
+Port::Descriptor::Descriptor (const XMLNode& node)
+{
+       const XMLProperty *prop;
+       bool have_tag = false;
+       bool have_device = false;
+       bool have_type = false;
+       bool have_mode = false;
+
+       if ((prop = node.property ("tag")) != 0) {
+               tag = prop->value();
+               have_tag = true;
+       }
+
+       if ((prop = node.property ("device")) != 0) {
+               device = prop->value();
+               have_device = true;
+       }
+
+       if ((prop = node.property ("type")) != 0) {
+               type = PortFactory::string_to_type (prop->value());
+               have_type = true;
+       }
+
+       if ((prop = node.property ("mode")) != 0) {
+               mode = PortFactory::string_to_mode (prop->value());
+               have_mode = true;
+       }
+
+       if (!have_tag || !have_device || !have_type || !have_mode) {
+               throw failed_constructor();
+       }
+}
+
index d7c65d9f29b78daf0f142eae4fe4203616c1df32..fafe822f8231ab5c35b841b5788149309ac29297 100644 (file)
@@ -11,7 +11,6 @@ Transmitter fatal (Transmitter::Fatal);
 TextReceiver text_receiver ("mmctest");
 
 #include "midi++/port.h"
-#include "midi++/port_request.h"
 #include "midi++/manager.h"
 
 using namespace MIDI;
index 36fbd61124d9e1321e6205fe754378a954f29ca2..062f6e8d3258d93d4555bfd2ccfcc9cc905217e3 100644 (file)
@@ -11,7 +11,6 @@ Transmitter fatal (Transmitter::Fatal);
 TextReceiver text_receiver ("mmctest");
 
 #include "midi++/port.h"
-#include "midi++/port_request.h"
 #include "midi++/manager.h"
 #include "midi++/mmc.h"
 
diff --git a/libs/midi++2/port_request.cc b/libs/midi++2/port_request.cc
deleted file mode 100644 (file)
index d209f02..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
-    Copyright (C) 2000 Paul Barton-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$
-*/
-
-#include <fcntl.h>
-#include <string.h>
-#include <midi++/port.h>
-#include <midi++/port_request.h>
-
-using namespace std;
-using namespace MIDI;
-
-PortRequest::PortRequest (const string &xdev, 
-                         const string &xtag, 
-                         const string &xmode,
-                         const string &xtype)
-
-{
-       status = OK;
-       
-       devname = strdup (xdev.c_str());
-       tagname = strdup (xtag.c_str());
-       
-       if (xmode == "output" ||
-           xmode == "out" || 
-           xmode == "OUTPUT" ||
-           xmode == "OUT") {
-               mode = O_WRONLY;
-
-       } else if (xmode == "input" ||
-                  xmode == "in" ||
-                  xmode == "INPUT" ||
-                  xmode == "IN") {
-               mode = O_RDONLY;
-
-       } else if (xmode == "duplex" ||
-                  xmode == "DUPLEX" ||
-                  xmode == "inout" || 
-                  xmode == "INOUT") {
-               mode = O_RDWR;
-       } else {
-               status = Unknown;
-       }
-
-       if (xtype == "JACK" ||
-                  xtype == "jack") {
-               type = Port::JACK_Midi;
-       } else if (xtype == "ALSA/RAW" ||
-                  xtype == "alsa/raw") {
-               type = Port::ALSA_RawMidi;
-       } else if (xtype == "ALSA/SEQUENCER" ||
-                  xtype == "alsa/sequencer") {
-               type = Port::ALSA_Sequencer;
-       } else if (xtype == "COREMIDI" ||
-                  xtype == "coremidi") {
-               type = Port::CoreMidi_MidiPort;
-       } else if (xtype == "NULL" ||
-                  xtype == "null") {
-               type = Port::Null;
-       } else if (xtype == "FIFO" ||
-                  xtype == "fifo") {
-               type = Port::FIFO;
-       } else {
-               status = Unknown;
-       }
-}
-
index 303ac8455277808d5873f64076ca0b8202b500c8..d513dfc7625ac298b8dcb34208d2d32de86c7833 100644 (file)
@@ -31,6 +31,7 @@ filesystem_paths.cc
 file_utils.cc
 fpu.cc
 id.cc
+misc.c
 mountpoint.cc
 pathscanner.cc
 pool.cc
index 07fcc09acefc61c3d5c265065cd98b98ee5e90af..2ce99ba631c864413442b0c121c1ce6da505e91a 100644 (file)
@@ -30,6 +30,7 @@
 
 using std::string;
 using std::vector;
+using Glib::ustring;
 
 namespace PBD {
 
@@ -194,6 +195,52 @@ url_decode (string& url)
        }
 }
 
+void
+url_decode (ustring& url)
+{
+       ustring::iterator last;
+       ustring::iterator next;
+
+       for (ustring::iterator i = url.begin(); i != url.end(); ++i) {
+               if ((*i) == '+') {
+                       next = i;
+                       ++next;
+                       url.replace (i, next, 1, ' ');
+               }
+       }
+
+       if (url.length() <= 3) {
+               return;
+       }
+
+       last = url.end();
+
+       --last; /* points at last char */
+       --last; /* points at last char - 1 */
+
+       for (ustring::iterator i = url.begin(); i != last; ) {
+
+               if (*i == '%') {
+
+                       next = i;
+
+                       url.erase (i);
+                       
+                       i = next;
+                       ++next;
+                       
+                       if (isxdigit (*i) && isxdigit (*next)) {
+                               /* replace first digit with char */
+                               url.replace (i, next, 1, (gunichar) int_from_hex (*i,*next));
+                               ++i; /* points at 2nd of 2 digits */
+                               url.erase (i);
+                       }
+               } else {
+                       ++i;
+               }
+       }
+}
+
 #if 0
 string
 length2string (const int32_t frames, const float sample_rate)
index efb065fbd4e3d19b28ac72f0a03b172b3216893c..f8dfe269c503b55e55bf9269ce495be22b47e11f 100644 (file)
@@ -102,14 +102,6 @@ find_file_in_search_path(const SearchPath& search_path,
 
        if (tmp.size() == 0)
        {
-               info << string_compose
-                       (
-                        "Found no file named %1 in search path %2",
-                        filename,
-                        search_path.to_string ()
-                       )
-                       << endmsg;
-
                return false;
        }
 
diff --git a/libs/pbd/misc.c b/libs/pbd/misc.c
new file mode 100644 (file)
index 0000000..797be5d
--- /dev/null
@@ -0,0 +1,21 @@
+#include <pbd/misc.h>
+
+#ifdef GTKOSX
+#include <AppKit/AppKit.h>
+#endif
+
+void
+disable_screen_updates ()
+{
+#ifdef GTKOSX
+       NSDisableScreenUpdates ();
+#endif
+}
+
+void
+enable_screen_updates ()
+{
+#ifdef GTKOSX
+       NSEnableScreenUpdates();
+#endif
+}
index 00176659cf61b805dcc52fe9e3979f8e1e591d02..83cd28509822270c77658792fcd8ab05caa00f29 100644 (file)
@@ -22,6 +22,9 @@
 
 #include <string>
 #include <vector>
+#include <sstream>
+#include <iostream>
+#include <glibmm/ustring.h>
 
 namespace PBD {
 
@@ -30,6 +33,7 @@ std::string short_version (std::string, std::string::size_type target_length);
 int    atoi (const std::string&);
 double atof (const std::string&);
 void   url_decode (std::string&);
+void   url_decode (Glib::ustring&);
 
 // std::string length2string (const int32_t frames, const float sample_rate);
 std::string length2string (const int64_t frames, const double sample_rate);
@@ -37,6 +41,14 @@ std::string length2string (const int64_t frames, const double sample_rate);
 std::vector<std::string> internationalize (const char *, const char **);
 bool strings_equal_ignore_case (const std::string& a, const std::string& b);
 
+template <class T> std::string 
+to_string (T t, std::ios_base & (*f)(std::ios_base&))
+{
+       std::ostringstream oss;
+       oss << f << t;
+       return oss.str();
+}
+
 } //namespace PBD
 
 #endif /* __pbd_convert_h__ */
diff --git a/libs/pbd/pbd/functor_command.h b/libs/pbd/pbd/functor_command.h
new file mode 100644 (file)
index 0000000..e335f44
--- /dev/null
@@ -0,0 +1,121 @@
+/* 
+   Copyright (C) 2007 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.
+
+*/
+
+#ifndef __lib_pbd_functor_command_h__
+#define __lib_pbd_functor_command_h__
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <map>
+
+#include <pbd/xml++.h>
+#include <pbd/shiva.h>
+#include <pbd/command.h>
+#include <pbd/failed_constructor.h>
+
+/** This command class is initialized 
+ */
+
+namespace PBD {
+
+template <class obj_type, class arg_type>
+class FunctorCommand : public Command
+{
+       private:
+       typedef void (obj_type::*functor_type)(arg_type);
+       typedef std::map< std::string, functor_type > FunctorMap;
+       typedef typename FunctorMap::iterator FunctorMapIterator;
+
+       public:
+       FunctorCommand(
+               std::string functor,
+               obj_type object,
+               arg_type b,
+               arg_type a
+       ) : functor_name(functor), 
+               object(object),
+               before(b),
+               after(a) 
+       {
+               method = find_functor(functor);
+
+               /* catch destruction of the object */
+               new PBD::Shiva< obj_type, FunctorCommand<obj_type, arg_type> > (object, *this);
+       }
+
+       ~FunctorCommand() {
+               GoingAway();
+       }
+
+       void operator() () {
+               (object.*method) (after);
+       }
+
+       void undo() { 
+               (object.*method) (before);
+       }
+
+       virtual XMLNode &get_state() {
+               std::stringstream ss;
+               
+               XMLNode *node = new XMLNode("FunctorCommand");
+               node->add_property("functor", functor_name);
+               ss << before;
+               node->add_property("before", ss.str());
+               ss.clear ();
+               ss << after;
+               node->add_property("after", ss.str());
+
+               return *node;
+       }
+
+       static void register_functor(std::string name, functor_type f) {
+               functor_map[name] = f;
+       }
+
+       private:
+       static functor_type find_functor(std::string name) {
+               FunctorMapIterator iter;
+
+               if((iter = functor_map.find(name)) == functor_map.end()) {
+                       throw failed_constructor();
+               }
+
+               return iter->second;
+       }
+
+       protected:
+       std::string functor_name;
+       obj_type &object;
+       arg_type before;
+       arg_type after;
+       functor_type method;
+       static FunctorMap functor_map;
+};
+
+// static initialization of functor_map... 
+template <class obj_type, class arg_type>
+typename FunctorCommand<obj_type, arg_type>::FunctorMap
+FunctorCommand<obj_type, arg_type>::functor_map;
+
+};
+
+#endif // __lib_pbd_functor_command_h__
+
diff --git a/libs/pbd/pbd/misc.h b/libs/pbd/pbd/misc.h
new file mode 100644 (file)
index 0000000..306c006
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __pbd_misc_h__
+#define __pbd_misc_h__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+       void disable_screen_updates ();
+       void enable_screen_updates ();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __pbd_misc_h__ */
index 5bfccf5a062fdf9bdfac4e625eb0ba9b6e001280..8f1716d09f45e0fe517d2b64eecb2c90b726b7c0 100644 (file)
@@ -80,20 +80,24 @@ class UndoHistory : public sigc::trackable
        unsigned long undo_depth() const { return UndoList.size(); }
        unsigned long redo_depth() const { return RedoList.size(); }
        
-       std::string next_undo() const { return (UndoList.empty() ? std::string("") : UndoList.back()->name()); }
-       std::string next_redo() const { return (RedoList.empty() ? std::string("") : RedoList.back()->name()); }
+       std::string next_undo() const { return (UndoList.empty() ? std::string() : UndoList.back()->name()); }
+       std::string next_redo() const { return (RedoList.empty() ? std::string() : RedoList.back()->name()); }
 
        void clear ();
        void clear_undo ();
        void clear_redo ();
 
-       XMLNode &get_state(uint32_t depth = 0);
-       void save_state();
+        XMLNode &get_state(int32_t depth = 0);
+        void save_state();
 
-       sigc::signal<void> Changed;
+       void set_depth (int32_t);
+       int32_t get_depth() const { return _depth; }
 
+       sigc::signal<void> Changed;
+       
   private:
        bool _clearing;
+       int32_t _depth;
        std::list<UndoTransaction*> UndoList;
        std::list<UndoTransaction*> RedoList;
 
index 6db85e6ab34d21518ce5d6c91943dacaf7698232..aeff37cce72e3f6dc70a9136b97e8df8a1f218fe 100644 (file)
@@ -148,12 +148,28 @@ XMLNode &UndoTransaction::get_state()
 UndoHistory::UndoHistory ()
 {
        _clearing = false;
+       _depth = 0;
+}
+
+void
+UndoHistory::set_depth (int32_t d)
+{
+       _depth = d;
+
+       while (_depth > 0 && UndoList.size() > (uint32_t) _depth) {
+               UndoList.pop_front ();
+       }
 }
 
 void
 UndoHistory::add (UndoTransaction* const ut)
 {
        ut->GoingAway.connect (bind (mem_fun (*this, &UndoHistory::remove), ut));
+
+       while (_depth > 0 && UndoList.size() > (uint32_t) _depth) {
+               UndoList.pop_front ();
+       }
+
        UndoList.push_back (ut);
 
        /* we are now owners of the transaction */
@@ -240,17 +256,22 @@ UndoHistory::clear ()
 }
 
 XMLNode& 
-UndoHistory::get_state (uint32_t depth)
+UndoHistory::get_state (int32_t depth)
 {
     XMLNode *node = new XMLNode ("UndoHistory");
 
     if (depth == 0) {
+
+           return (*node);
+
+    } else if (depth < 0) {
+
            /* everything */
 
            for (list<UndoTransaction*>::iterator it = UndoList.begin(); it != UndoList.end(); ++it) {
                    node->add_child_nocopy((*it)->get_state());
            }
-           
+
     } else {
 
            /* just the last "depth" transactions */
@@ -268,3 +289,5 @@ UndoHistory::get_state (uint32_t depth)
 
     return *node;
 }
+
+
index 3906b53e366cdde03a5fa17193180ac3bf59c855..93cbf088c7ceff74d47ab84f2e62441f3112619a 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <midi++/port.h>
 #include <midi++/manager.h>
-#include <midi++/port_request.h>
 
 #include <ardour/route.h>
 #include <ardour/session.h>
index 05681c0c250d6532585f9b4cac5e798f6e8a3c3e..fa7134fa952e26975c5bb17225f299920318d8c2 100644 (file)
@@ -9,7 +9,6 @@
 #include <midi++/types.h>
 #include <midi++/port.h>
 #include <midi++/manager.h>
-#include <midi++/port_request.h>
 #include "i18n.h"
 
 #include <unistd.h>
index 139313f3f8a7cea3e12915299f085473e3021dcb..8b3051af20b7e93ea2555298a58594267605602f 100644 (file)
 
 #include <i18n.h>
 #include <pbd/xml++.h>
+#include <pbd/error.h>
+#include <glibmm.h>
 
 #include "powermate.h"
 
 using namespace ARDOUR;
 using namespace std;
 using namespace sigc;
+using namespace PBD;
 
 #define NUM_VALID_PREFIXES 2
 
@@ -32,17 +35,22 @@ static const char *valid_prefix[NUM_VALID_PREFIXES] = {
 
 int open_powermate(const char *dev, int mode)
 {
-  int fd = open(dev, mode);
-  int i;
-  char name[255];
-
-  if(fd < 0){
-    fprintf(stderr, "Unable to open \"%s\": %s\n", dev, strerror(errno));
-    return -1;
-  }
+       if (!Glib::file_test (dev, Glib::FILE_TEST_EXISTS)) {
+               return -1;
+       }
+       int fd = open(dev, mode);
+       int i;
+       char name[255];
+       
+       if(fd < 0){
+               if (errno != EACCES) {
+                       error << string_compose ("Unable to open \"%1\": %2", dev, strerror(errno)) << endmsg;
+               }
+               return -1;
+       }
 
   if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0){
-    fprintf(stderr, "\"%s\": EVIOCGNAME failed: %s\n", dev, strerror(errno));
+    error << string_compose ("\"%1\": EVIOCGNAME failed: %2", dev, strerror(errno)) << endmsg;
     close(fd);
     return -1;
   }