summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2007-10-11 22:07:47 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2007-10-11 22:07:47 +0000
commitf7f9d6fdc40248b190ec9c6e1a886261d55777ae (patch)
tree080723e9dc35a66013b37acbafc67a6afa929302
parentaa1f736a651376534acaa2268b65d42a3786fff7 (diff)
merge from 2.0-ongoing by hand, minus key binding editor
git-svn-id: svn://localhost/ardour2/trunk@2539 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--SConstruct33
-rw-r--r--gtk2_ardour/SConscript93
-rwxr-xr-xgtk2_ardour/ardbg2
-rwxr-xr-xgtk2_ardour/ardev2
-rw-r--r--gtk2_ardour/ardour.menus22
-rw-r--r--gtk2_ardour/ardour.sh.in2
-rw-r--r--gtk2_ardour/ardour2_ui_dark.rc.in144
-rw-r--r--gtk2_ardour/ardour2_ui_default.conf37
-rw-r--r--gtk2_ardour/ardour2_ui_light.rc.in111
-rw-r--r--gtk2_ardour/ardour_dialog.cc9
-rw-r--r--gtk2_ardour/ardour_dialog.h1
-rw-r--r--gtk2_ardour/ardour_ui.cc628
-rw-r--r--gtk2_ardour/ardour_ui.h43
-rw-r--r--gtk2_ardour/ardour_ui2.cc44
-rw-r--r--gtk2_ardour/ardour_ui_dependents.cc5
-rw-r--r--gtk2_ardour/ardour_ui_dialogs.cc19
-rw-r--r--gtk2_ardour/ardour_ui_ed.cc89
-rw-r--r--gtk2_ardour/ardour_ui_options.cc50
-rwxr-xr-xgtk2_ardour/arprof2
-rwxr-xr-xgtk2_ardour/arval2
-rw-r--r--gtk2_ardour/audio_region_view.cc8
-rw-r--r--gtk2_ardour/audio_streamview.cc1
-rw-r--r--gtk2_ardour/axis_view.h6
-rw-r--r--gtk2_ardour/editing.h27
-rw-r--r--gtk2_ardour/editing_syms.h12
-rw-r--r--gtk2_ardour/editor.cc353
-rw-r--r--gtk2_ardour/editor.h90
-rw-r--r--gtk2_ardour/editor_actions.cc32
-rw-r--r--gtk2_ardour/editor_audio_import.cc534
-rw-r--r--gtk2_ardour/editor_audiotrack.cc28
-rw-r--r--gtk2_ardour/editor_canvas.cc39
-rw-r--r--gtk2_ardour/editor_keyboard.cc8
-rw-r--r--gtk2_ardour/editor_markers.cc47
-rw-r--r--gtk2_ardour/editor_mouse.cc219
-rw-r--r--gtk2_ardour/editor_ops.cc96
-rw-r--r--gtk2_ardour/editor_region_list.cc4
-rw-r--r--gtk2_ardour/editor_route_list.cc53
-rw-r--r--gtk2_ardour/editor_rulers.cc6
-rw-r--r--gtk2_ardour/engine_dialog.cc1126
-rw-r--r--gtk2_ardour/engine_dialog.h106
-rw-r--r--gtk2_ardour/enums.cc9
-rw-r--r--gtk2_ardour/keyboard.cc15
-rw-r--r--gtk2_ardour/keyboard.h1
-rw-r--r--gtk2_ardour/main.cc214
-rw-r--r--gtk2_ardour/mixer_strip.cc8
-rw-r--r--gtk2_ardour/mixer_ui.cc63
-rw-r--r--gtk2_ardour/mixer_ui.h7
-rw-r--r--gtk2_ardour/new_session_dialog.cc65
-rw-r--r--gtk2_ardour/new_session_dialog.h13
-rw-r--r--gtk2_ardour/option_editor.cc266
-rw-r--r--gtk2_ardour/option_editor.h25
-rw-r--r--gtk2_ardour/opts.cc49
-rw-r--r--gtk2_ardour/opts.h4
-rw-r--r--gtk2_ardour/processor_box.cc55
-rw-r--r--gtk2_ardour/processor_box.h3
-rw-r--r--gtk2_ardour/send_ui.cc2
-rw-r--r--gtk2_ardour/sfdb_ui.cc1218
-rw-r--r--gtk2_ardour/sfdb_ui.h162
-rw-r--r--gtk2_ardour/streamview.cc2
-rw-r--r--gtk2_ardour/utils.cc38
-rw-r--r--libs/ardour/SConscript3
-rw-r--r--libs/ardour/ardour/ardour.h2
-rw-r--r--libs/ardour/ardour/audiofilesource.h9
-rw-r--r--libs/ardour/ardour/audiosource.h50
-rw-r--r--libs/ardour/ardour/automatable.h9
-rw-r--r--libs/ardour/ardour/configuration.h12
-rw-r--r--libs/ardour/ardour/configuration_vars.h8
-rw-r--r--libs/ardour/ardour/io.h2
-rw-r--r--libs/ardour/ardour/profile.h8
-rw-r--r--libs/ardour/ardour/resampled_source.h50
-rw-r--r--libs/ardour/ardour/route.h3
-rw-r--r--libs/ardour/ardour/session.h15
-rw-r--r--libs/ardour/ardour/sndfilesource.h4
-rw-r--r--libs/ardour/ardour/source_factory.h17
-rw-r--r--libs/ardour/ardour/types.h9
-rw-r--r--libs/ardour/ardour/utils.h2
-rw-r--r--libs/ardour/audio_playlist.cc4
-rw-r--r--libs/ardour/audioengine.cc4
-rw-r--r--libs/ardour/audiofilesource.cc94
-rw-r--r--libs/ardour/audiosource.cc98
-rw-r--r--libs/ardour/auditioner.cc2
-rw-r--r--libs/ardour/automatable.cc4
-rw-r--r--libs/ardour/configuration.cc70
-rw-r--r--libs/ardour/crossfade.cc14
-rw-r--r--libs/ardour/globals.cc65
-rw-r--r--libs/ardour/import.cc368
-rw-r--r--libs/ardour/io.cc4
-rw-r--r--libs/ardour/playlist.cc4
-rw-r--r--libs/ardour/resampled_source.cc128
-rw-r--r--libs/ardour/route.cc33
-rw-r--r--libs/ardour/session.cc39
-rw-r--r--libs/ardour/session_events.cc2
-rw-r--r--libs/ardour/session_state.cc25
-rw-r--r--libs/ardour/sndfilesource.cc54
-rw-r--r--libs/ardour/source_factory.cc189
-rw-r--r--libs/ardour/utils.cc13
-rw-r--r--libs/clearlooks/SConscript3
-rw-r--r--libs/clearlooks/clearlooks_style.c4
-rw-r--r--libs/gtkmm2/gtk/gtkmm/toolbar.cc2
-rw-r--r--libs/midi++2/SConscript3
-rw-r--r--libs/midi++2/alsa_sequencer_midiport.cc250
-rw-r--r--libs/midi++2/coremidi_midiport.cc38
-rw-r--r--libs/midi++2/fd_midiport.cc24
-rw-r--r--libs/midi++2/fifomidi.cc8
-rw-r--r--libs/midi++2/jack_midiport.cc47
-rw-r--r--libs/midi++2/midi++/alsa_rawmidi.h6
-rw-r--r--libs/midi++2/midi++/alsa_sequencer.h24
-rw-r--r--libs/midi++2/midi++/coremidi_midiport.h65
-rw-r--r--libs/midi++2/midi++/factory.h3
-rw-r--r--libs/midi++2/midi++/fd_midiport.h21
-rw-r--r--libs/midi++2/midi++/fifomidi.h5
-rw-r--r--libs/midi++2/midi++/jack.h7
-rw-r--r--libs/midi++2/midi++/manager.h26
-rw-r--r--libs/midi++2/midi++/nullmidi.h1
-rw-r--r--libs/midi++2/midi++/port.h101
-rw-r--r--libs/midi++2/midi++/port_request.h66
-rw-r--r--libs/midi++2/midifactory.cc26
-rw-r--r--libs/midi++2/midimanager.cc196
-rw-r--r--libs/midi++2/midiport.cc105
-rw-r--r--libs/midi++2/miditrace.cc1
-rw-r--r--libs/midi++2/mmctest.cc1
-rw-r--r--libs/midi++2/port_request.cc83
-rw-r--r--libs/pbd/SConscript1
-rw-r--r--libs/pbd/convert.cc47
-rw-r--r--libs/pbd/file_utils.cc8
-rw-r--r--libs/pbd/misc.c21
-rw-r--r--libs/pbd/pbd/convert.h12
-rw-r--r--libs/pbd/pbd/functor_command.h121
-rw-r--r--libs/pbd/pbd/misc.h15
-rw-r--r--libs/pbd/pbd/undo.h14
-rw-r--r--libs/pbd/undo.cc27
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc1
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol_poll.cc1
-rw-r--r--libs/surfaces/powermate/powermate.cc26
134 files changed, 6835 insertions, 2344 deletions
diff --git a/SConstruct b/SConstruct
index cddc7384c8..5f6bde5103 100644
--- a/SConstruct
+++ b/SConstruct
@@ -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)
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript
index b96498602e..12e3225f89 100644
--- a/gtk2_ardour/SConscript
+++ b/gtk2_ardour/SConscript
@@ -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')))
diff --git a/gtk2_ardour/ardbg b/gtk2_ardour/ardbg
index ab99296f45..063b2b1b6d 100755
--- a/gtk2_ardour/ardbg
+++ b/gtk2_ardour/ardbg
@@ -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 "$@"
diff --git a/gtk2_ardour/ardev b/gtk2_ardour/ardev
index 5dd8fc9d13..7980c43d93 100755
--- a/gtk2_ardour/ardev
+++ b/gtk2_ardour/ardev
@@ -1,4 +1,4 @@
#!/bin/sh
. `dirname "$0"`/ardev_common.sh
LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
-exec $EXECUTABLE $*
+exec $EXECUTABLE "$@"
diff --git a/gtk2_ardour/ardour.menus b/gtk2_ardour/ardour.menus
index 24adba9f7f..128ca81c27 100644
--- a/gtk2_ardour/ardour.menus
+++ b/gtk2_ardour/ardour.menus
@@ -13,13 +13,7 @@
<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'/>
@@ -140,7 +134,6 @@
<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'>
@@ -215,7 +208,7 @@
<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'/>
@@ -304,10 +297,6 @@
<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='MeterFalloffOff'/>
@@ -370,13 +359,15 @@
<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'/>
@@ -399,9 +390,6 @@
<menuitem action='activate_all'/>
<menuitem action='deactivate_all'/>
<separator/>
- <menuitem action='deactivate_plugins'/>
- <menuitem action='a_b_plugins'/>
- <separator/>
<menuitem action='edit'/>
</popup>
diff --git a/gtk2_ardour/ardour.sh.in b/gtk2_ardour/ardour.sh.in
index beed436cbe..2f1092c3fe 100644
--- a/gtk2_ardour/ardour.sh.in
+++ b/gtk2_ardour/ardour.sh.in
@@ -15,6 +15,6 @@ fi
ulimit -c unlimited
-exec %INSTALL_PREFIX%/%LIBDIR%/ardour2/ardour-%VERSION% $*
+exec %INSTALL_PREFIX%/%LIBDIR%/ardour2/ardour-%VERSION% "$@"
diff --git a/gtk2_ardour/ardour2_ui_dark.rc.in b/gtk2_ardour/ardour2_ui_dark.rc.in
index 1420fc8660..ba8e5fe1e1 100644
--- a/gtk2_ardour/ardour2_ui_dark.rc.in
+++ b/gtk2_ardour/ardour2_ui_dark.rc.in
@@ -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"
diff --git a/gtk2_ardour/ardour2_ui_default.conf b/gtk2_ardour/ardour2_ui_default.conf
index e0d6ea2773..034dd75b0f 100644
--- a/gtk2_ardour/ardour2_ui_default.conf
+++ b/gtk2_ardour/ardour2_ui_default.conf
@@ -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"/>
@@ -83,15 +83,6 @@
<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>
diff --git a/gtk2_ardour/ardour2_ui_light.rc.in b/gtk2_ardour/ardour2_ui_light.rc.in
index 4172b73a5b..b8c3683e91 100644
--- a/gtk2_ardour/ardour2_ui_light.rc.in
+++ b/gtk2_ardour/ardour2_ui_light.rc.in
@@ -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"
diff --git a/gtk2_ardour/ardour_dialog.cc b/gtk2_ardour/ardour_dialog.cc
index c5162919d4..795b924075 100644
--- a/gtk2_ardour/ardour_dialog.cc
+++ b/gtk2_ardour/ardour_dialog.cc
@@ -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 ()
{
}
diff --git a/gtk2_ardour/ardour_dialog.h b/gtk2_ardour/ardour_dialog.h
index 069768c143..13248e14de 100644
--- a/gtk2_ardour/ardour_dialog.h
+++ b/gtk2_ardour/ardour_dialog.h
@@ -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*);
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index cac63dc752..962ada5035 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -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);
@@ -479,9 +550,151 @@ 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
diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h
index 39bd8db4a6..427d40dffe 100644
--- a/gtk2_ardour/ardour_ui.h
+++ b/gtk2_ardour/ardour_ui.h
@@ -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__ */
diff --git a/gtk2_ardour/ardour_ui2.cc b/gtk2_ardour/ardour_ui2.cc
index 489728286c..8f755a3d93 100644
--- a/gtk2_ardour/ardour_ui2.cc
+++ b/gtk2_ardour/ardour_ui2.cc
@@ -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 ()
{
diff --git a/gtk2_ardour/ardour_ui_dependents.cc b/gtk2_ardour/ardour_ui_dependents.cc
index 725180e0ab..6464c52967 100644
--- a/gtk2_ardour/ardour_ui_dependents.cc
+++ b/gtk2_ardour/ardour_ui_dependents.cc
@@ -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
diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc
index c6353df782..9a71443489 100644
--- a/gtk2_ardour/ardour_ui_dialogs.cc
+++ b/gtk2_ardour/ardour_ui_dialogs.cc
@@ -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
diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc
index a043128700..c850d72048 100644
--- a/gtk2_ardour/ardour_ui_ed.cc
+++ b/gtk2_ardour/ardour_ui_ed.cc
@@ -34,8 +34,10 @@
#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);
@@ -745,12 +781,23 @@ ARDOUR_UI::build_menu_bar ()
}
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 ()
{
ARDOUR_UI::Clock.connect (bind (mem_fun (big_clock, &AudioClock::set), false));
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);
}
diff --git a/gtk2_ardour/ardour_ui_options.cc b/gtk2_ardour/ardour_ui_options.cc
index 4a6bef6b5f..d013f98e5b 100644
--- a/gtk2_ardour/ardour_ui_options.cc
+++ b/gtk2_ardour/ardour_ui_options.cc
@@ -82,6 +82,13 @@ ARDOUR_UI::toggle_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)
{
const char *action = 0;
@@ -459,6 +466,12 @@ ARDOUR_UI::toggle_StopRecordingOnXrun()
}
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()
{
ActionManager::toggle_config_state ("options", "StopTransportAtEndOfSession", &Configuration::set_stop_at_session_end, &Configuration::get_stop_at_session_end);
@@ -577,6 +590,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 ()
{
const char* on = 0;
@@ -762,6 +788,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 ()
{
const char* action = X_("MeterFalloffMedium");
@@ -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
}
diff --git a/gtk2_ardour/arprof b/gtk2_ardour/arprof
index 05a469cb17..47c11cdb99 100755
--- a/gtk2_ardour/arprof
+++ b/gtk2_ardour/arprof
@@ -6,4 +6,4 @@ if [ gprofhelper.c -nt gprofhelper.so ] ; then
fi
. ardev_common.sh
-LDPRELOAD=./gprofhelper.so $EXECUTABLE $*
+LDPRELOAD=./gprofhelper.so $EXECUTABLE "$@"
diff --git a/gtk2_ardour/arval b/gtk2_ardour/arval
index 920e7cb1a8..5661b4cd11 100755
--- a/gtk2_ardour/arval
+++ b/gtk2_ardour/arval
@@ -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 "$@"
diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc
index dc6de8d0f6..4bc10e93ec 100644
--- a/gtk2_ardour/audio_region_view.cc
+++ b/gtk2_ardour/audio_region_view.cc
@@ -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);
diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc
index bbe573dab2..22f8fa6239 100644
--- a/gtk2_ardour/audio_streamview.cc
+++ b/gtk2_ardour/audio_streamview.cc
@@ -74,6 +74,7 @@ AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
use_rec_regions = tv.editor.show_waveforms_recording ();
+
}
AudioStreamView::~AudioStreamView ()
diff --git a/gtk2_ardour/axis_view.h b/gtk2_ardour/axis_view.h
index 51f744c4e5..e64ef99b16 100644
--- a/gtk2_ardour/axis_view.h
+++ b/gtk2_ardour/axis_view.h
@@ -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__ */
diff --git a/gtk2_ardour/editing.h b/gtk2_ardour/editing.h
index d7f8f6ece8..93bbb603ee 100644
--- a/gtk2_ardour/editing.h
+++ b/gtk2_ardour/editing.h
@@ -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 {
diff --git a/gtk2_ardour/editing_syms.h b/gtk2_ardour/editing_syms.h
index a057f6dd64..a520b0d318 100644
--- a/gtk2_ardour/editing_syms.h
+++ b/gtk2_ardour/editing_syms.h
@@ -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)
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index 031262c41e..f0a2bfa809 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -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 ();
+}
+
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 976ad68188..63cbc042ac 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -26,9 +26,14 @@
#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__ */
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index 7fe0de9aae..051af2c898 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -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));
@@ -474,6 +471,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)
{
RefPtr<Action> act;
diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc
index 263ac0c31f..0dc0d707c0 100644
--- a/gtk2_ardour/editor_audio_import.cc
+++ b/gtk2_ardour/editor_audio_import.cc
@@ -19,9 +19,12 @@
#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;
}
diff --git a/gtk2_ardour/editor_audiotrack.cc b/gtk2_ardour/editor_audiotrack.cc
index cdcbb43f76..87fa8a06b8 100644
--- a/gtk2_ardour/editor_audiotrack.cc
+++ b/gtk2_ardour/editor_audiotrack.cc
@@ -26,11 +26,13 @@
#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
diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc
index c5a8695158..86beec387e 100644
--- a/gtk2_ardour/editor_canvas.cc
+++ b/gtk2_ardour/editor_canvas.cc
@@ -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);
diff --git a/gtk2_ardour/editor_keyboard.cc b/gtk2_ardour/editor_keyboard.cc
index 4b0088f075..28b86f53fc 100644
--- a/gtk2_ardour/editor_keyboard.cc
+++ b/gtk2_ardour/editor_keyboard.cc
@@ -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) {
diff --git a/gtk2_ardour/editor_markers.cc b/gtk2_ardour/editor_markers.cc
index 29a212f2f5..724ff2c31a 100644
--- a/gtk2_ardour/editor_markers.cc
+++ b/gtk2_ardour/editor_markers.cc
@@ -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
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc
index e8bc98a73c..da95d50d95 100644
--- a/gtk2_ardour/editor_mouse.cc
+++ b/gtk2_ardour/editor_mouse.cc
@@ -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;
+}
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index 8906837031..ca2d7039ad 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -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);
+ }
+ }
}
}
diff --git a/gtk2_ardour/editor_region_list.cc b/gtk2_ardour/editor_region_list.cc
index a9df928222..f1001cb8e4 100644
--- a/gtk2_ardour/editor_region_list.cc
+++ b/gtk2_ardour/editor_region_list.cc
@@ -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);
}
}
diff --git a/gtk2_ardour/editor_route_list.cc b/gtk2_ardour/editor_route_list.cc
index e11738f65b..5e10a578f5 100644
--- a/gtk2_ardour/editor_route_list.cc
+++ b/gtk2_ardour/editor_route_list.cc
@@ -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
@@ -524,6 +570,13 @@ Editor::initial_route_list_display ()
}
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)
{
session->set_remote_control_ids();
diff --git a/gtk2_ardour/editor_rulers.cc b/gtk2_ardour/editor_rulers.cc
index cfc7157510..88ff3a0c1e 100644
--- a/gtk2_ardour/editor_rulers.cc
+++ b/gtk2_ardour/editor_rulers.cc
@@ -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
index 0000000000..5be28e9226
--- /dev/null
+++ b/gtk2_ardour/engine_dialog.cc
@@ -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
index 0000000000..925d12acbb
--- /dev/null
+++ b/gtk2_ardour/engine_dialog.h
@@ -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__ */
diff --git a/gtk2_ardour/enums.cc b/gtk2_ardour/enums.cc
index e6c81598fb..c33b2965c3 100644
--- a/gtk2_ardour/enums.cc
+++ b/gtk2_ardour/enums.cc
@@ -20,11 +20,13 @@
#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);
}
diff --git a/gtk2_ardour/keyboard.cc b/gtk2_ardour/keyboard.cc
index 90fea321de..e6eaffefcb 100644
--- a/gtk2_ardour/keyboard.cc
+++ b/gtk2_ardour/keyboard.cc
@@ -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;
diff --git a/gtk2_ardour/keyboard.h b/gtk2_ardour/keyboard.h
index 3d9e1c9f41..fb22f2eca9 100644
--- a/gtk2_ardour/keyboard.h
+++ b/gtk2_ardour/keyboard.h
@@ -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*);
diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc
index 67e59d4b80..1e9b27d8a7 100644
--- a/gtk2_ardour/main.cc
+++ b/gtk2_ardour/main.cc
@@ -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
-
diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc
index dfe5a268fa..f791314d75 100644
--- a/gtk2_ardour/mixer_strip.cc
+++ b/gtk2_ardour/mixer_strip.cc
@@ -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");
diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc
index 89d7ef5cc4..e3f6cae6ac 100644
--- a/gtk2_ardour/mixer_ui.cc
+++ b/gtk2_ardour/mixer_ui.cc
@@ -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 ()
{
@@ -594,6 +638,13 @@ Mixer_UI::hide_all_audiotracks ()
}
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)
{
session->set_remote_control_ids();
@@ -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());
}
};
diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h
index 3c9355efb7..5d00acff5b 100644
--- a/gtk2_ardour/mixer_ui.h
+++ b/gtk2_ardour/mixer_ui.h
@@ -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;
};
diff --git a/gtk2_ardour/new_session_dialog.cc b/gtk2_ardour/new_session_dialog.cc
index 132af4a86c..ebf520fba7 100644
--- a/gtk2_ardour/new_session_dialog.cc
+++ b/gtk2_ardour/new_session_dialog.cc
@@ -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();
diff --git a/gtk2_ardour/new_session_dialog.h b/gtk2_ardour/new_session_dialog.h
index 2a2081e56a..53ec3eabf2 100644
--- a/gtk2_ardour/new_session_dialog.h
+++ b/gtk2_ardour/new_session_dialog.h
@@ -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
diff --git a/gtk2_ardour/option_editor.cc b/gtk2_ardour/option_editor.cc
index 513e46448e..e49b410668 100644
--- a/gtk2_ardour/option_editor.cc
+++ b/gtk2_ardour/option_editor.cc
@@ -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
@@ -360,6 +430,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()
{
if (session) {
@@ -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);
+ }
+}
diff --git a/gtk2_ardour/option_editor.h b/gtk2_ardour/option_editor.h
index a234f1d752..82bb4db79b 100644
--- a/gtk2_ardour/option_editor.h
+++ b/gtk2_ardour/option_editor.h
@@ -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 */
diff --git a/gtk2_ardour/opts.cc b/gtk2_ardour/opts.cc
index 608f684fc9..8da0fb9ca1 100644
--- a/gtk2_ardour/opts.cc
+++ b/gtk2_ardour/opts.cc
@@ -27,18 +27,19 @@
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;
diff --git a/gtk2_ardour/opts.h b/gtk2_ardour/opts.h
index fb780fc8aa..c1b3f062d4 100644
--- a/gtk2_ardour/opts.h
+++ b/gtk2_ardour/opts.h
@@ -21,10 +21,11 @@
#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[]);
diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc
index d093fda99f..12e30e59c0 100644
--- a/gtk2_ardour/processor_box.cc
+++ b/gtk2_ardour/processor_box.cc
@@ -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
diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h
index 1ed0bcb39e..b6bb3ae3d7 100644
--- a/gtk2_ardour/processor_box.h
+++ b/gtk2_ardour/processor_box.h
@@ -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>);
diff --git a/gtk2_ardour/send_ui.cc b/gtk2_ardour/send_ui.cc
index 7dda653894..c91068f97c 100644
--- a/gtk2_ardour/send_ui.cc
+++ b/gtk2_ardour/send_ui.cc
@@ -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);
diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc
index 5415cd70cb..67bedb6182 100644
--- a/gtk2_ardour/sfdb_ui.cc
+++ b/gtk2_ardour/sfdb_ui.cc
@@ -21,90 +21,181 @@
#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);
+ }
}
}
diff --git a/gtk2_ardour/sfdb_ui.h b/gtk2_ardour/sfdb_ui.h
index 34c3f558bb..43f76a9ea2 100644
--- a/gtk2_ardour/sfdb_ui.h
+++ b/gtk2_ardour/sfdb_ui.h
@@ -22,6 +22,8 @@
#include <string>
#include <vector>
+#include <map>
+#include <glibmm/ustring.h>
#include <sigc++/signal.h>
@@ -41,32 +43,50 @@
#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__
diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc
index 560dcd503f..1a3fb9a084 100644
--- a/gtk2_ardour/streamview.cc
+++ b/gtk2_ardour/streamview.cc
@@ -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);
}
diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc
index 83a95fb71f..570a481c11 100644
--- a/gtk2_ardour/utils.cc
+++ b/gtk2_ardour/utils.cc
@@ -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;
@@ -444,6 +449,11 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
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);
} else {
@@ -469,6 +479,11 @@ key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
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 {
#ifdef DEBUG_ACCELERATOR_HANDLING
@@ -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>
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 3892af6e9b..465138d90d 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -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
diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h
index 1b9725a04c..6e7b494441 100644
--- a/libs/ardour/ardour/ardour.h
+++ b/libs/ardour/ardour/ardour.h
@@ -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 ();
diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h
index 78d10f9d64..4d80c8ddf5 100644
--- a/libs/ardour/ardour/audiofilesource.h
+++ b/libs/ardour/ardour/audiofilesource.h
@@ -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
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 812c30e8c2..7b22528bd1 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -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);
};
}
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index fe47614a1f..f96ecc0bd1 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -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
diff --git a/libs/ardour/ardour/configuration.h b/libs/ardour/ardour/configuration.h
index 70b7e166c1..7b890500d8 100644
--- a/libs/ardour/ardour/configuration.h
+++ b/libs/ardour/ardour/configuration.h
@@ -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);
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 4d5579a9a0..b592a9f721 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -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 */
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index 6c040be63e..6e68c01d8c 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -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)
diff --git a/libs/ardour/ardour/profile.h b/libs/ardour/ardour/profile.h
index 3347447915..b016063c4d 100644
--- a/libs/ardour/ardour/profile.h
+++ b/libs/ardour/ardour/profile.h
@@ -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
index 0000000000..9a88ca9644
--- /dev/null
+++ b/libs/ardour/ardour/resampled_source.h
@@ -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__ */
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 1fd6eff0f8..fc17af06ee 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -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;
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 94caf8a242..bbcae6e91d 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -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
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index 916e9da49e..4fd71a4c96 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -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
diff --git a/libs/ardour/ardour/source_factory.h b/libs/ardour/ardour/source_factory.h
index fb591216bf..01f50126a4 100644
--- a/libs/ardour/ardour/source_factory.h
+++ b/libs/ardour/ardour/source_factory.h
@@ -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);
};
}
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index e13bd09d83..5b50713313 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -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);
diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h
index cde17d8b49..e52274eb1f 100644
--- a/libs/ardour/ardour/utils.h
+++ b/libs/ardour/ardour/utils.h
@@ -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);
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index d28d88488e..d5c6120946 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -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());
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index a4ce5f291d..2a4b36f7d8 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -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;
}
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 1044dd10d2..1284dd343b 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -21,10 +21,13 @@
#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
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index d09a9b29cd..a2ce7209f6 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -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>
@@ -29,18 +30,21 @@
#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;
+ }
+}
+
diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc
index e344d5f2a6..c509997b2e 100644
--- a/libs/ardour/auditioner.cc
+++ b/libs/ardour/auditioner.cc
@@ -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()) {
diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc
index 0609b8d380..45b19d1997 100644
--- a/libs/ardour/automatable.cc
+++ b/libs/ardour/automatable.cc
@@ -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()) {
diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc
index 5faab7c0ab..1460491180 100644
--- a/libs/ardour/configuration.cc
+++ b/libs/ardour/configuration.cc
@@ -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)
{
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index 556f11125e..d45d5efa9f 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -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());
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 52be946f1e..c3eae5ad86 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -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;
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index bc16cde156..bd6351cf05 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -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>
@@ -43,82 +43,22 @@
#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;
-}
-
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index a708821c20..bff8c18bc9 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -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);
}
}
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index 4af7e2b907..09b54000d8 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -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
index 0000000000..38aa3832b9
--- /dev/null
+++ b/libs/ardour/resampled_source.cc
@@ -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;
+}
+
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 19095425f2..be7dfb8469 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -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,10 +161,35 @@ 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)
{
IO::inc_gain (fraction, 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) {
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 742b17af2c..e7f2c542e6 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -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)
{
@@ -4124,6 +4122,23 @@ Session::compute_initial_length ()
}
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)
{
Glib::Mutex::Lock lm (bundle_lock);
diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc
index 35c1019c0e..aa5a1b87d4 100644
--- a/libs/ardour/session_events.cc
+++ b/libs/ardour/session_events.cc
@@ -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:
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index f2f396cbee..0534da6c89 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -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);
+}
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index 6977eef6bd..7c4859aa55 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -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;
+}
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 148f737551..c6b19c8600 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -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);
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 01e070e920..cfd38c5099 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -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;
}
diff --git a/libs/clearlooks/SConscript b/libs/clearlooks/SConscript
index 110bfe41be..2676f63022 100644
--- a/libs/clearlooks/SConscript
+++ b/libs/clearlooks/SConscript
@@ -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)
diff --git a/libs/clearlooks/clearlooks_style.c b/libs/clearlooks/clearlooks_style.c
index 241f14c6e4..074f1604b1 100644
--- a/libs/clearlooks/clearlooks_style.c
+++ b/libs/clearlooks/clearlooks_style.c
@@ -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);
diff --git a/libs/gtkmm2/gtk/gtkmm/toolbar.cc b/libs/gtkmm2/gtk/gtkmm/toolbar.cc
index a8d10a7dde..8e51d70501 100644
--- a/libs/gtkmm2/gtk/gtkmm/toolbar.cc
+++ b/libs/gtkmm2/gtk/gtkmm/toolbar.cc
@@ -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>
diff --git a/libs/midi++2/SConscript b/libs/midi++2/SConscript
index 04b027b6a3..769d888903 100644
--- a/libs/midi++2/SConscript
+++ b/libs/midi++2/SConscript
@@ -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
""")
diff --git a/libs/midi++2/alsa_sequencer_midiport.cc b/libs/midi++2/alsa_sequencer_midiport.cc
index bf891108c6..bae8aff2ab 100644
--- a/libs/midi++2/alsa_sequencer_midiport.cc
+++ b/libs/midi++2/alsa_sequencer_midiport.cc
@@ -23,10 +23,12 @@
#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;
+ }
+ }
+}
diff --git a/libs/midi++2/coremidi_midiport.cc b/libs/midi++2/coremidi_midiport.cc
index 2cd98239ec..14020a6f35 100644
--- a/libs/midi++2/coremidi_midiport.cc
+++ b/libs/midi++2/coremidi_midiport.cc
@@ -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;
+}
diff --git a/libs/midi++2/fd_midiport.cc b/libs/midi++2/fd_midiport.cc
index 81d81c8558..17a7eff367 100644
--- a/libs/midi++2/fd_midiport.cc
+++ b/libs/midi++2/fd_midiport.cc
@@ -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;
diff --git a/libs/midi++2/fifomidi.cc b/libs/midi++2/fifomidi.cc
index 7bb126ddeb..a81520bb95 100644
--- a/libs/midi++2/fifomidi.cc
+++ b/libs/midi++2/fifomidi.cc
@@ -26,19 +26,19 @@
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);
}
diff --git a/libs/midi++2/jack_midiport.cc b/libs/midi++2/jack_midiport.cc
index 4b2808a698..11cd70a051 100644
--- a/libs/midi++2/jack_midiport.cc
+++ b/libs/midi++2/jack_midiport.cc
@@ -23,26 +23,22 @@
#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)
+{
+}
diff --git a/libs/midi++2/midi++/alsa_rawmidi.h b/libs/midi++2/midi++/alsa_rawmidi.h
index 54b86edd70..e5abc2832f 100644
--- a/libs/midi++2/midi++/alsa_rawmidi.h
+++ b/libs/midi++2/midi++/alsa_rawmidi.h
@@ -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__
diff --git a/libs/midi++2/midi++/alsa_sequencer.h b/libs/midi++2/midi++/alsa_sequencer.h
index b54486416a..a95f9c476f 100644
--- a/libs/midi++2/midi++/alsa_sequencer.h
+++ b/libs/midi++2/midi++/alsa_sequencer.h
@@ -30,39 +30,45 @@
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 */
diff --git a/libs/midi++2/midi++/coremidi_midiport.h b/libs/midi++2/midi++/coremidi_midiport.h
index 91eccea4a5..d5d3c23ede 100644
--- a/libs/midi++2/midi++/coremidi_midiport.h
+++ b/libs/midi++2/midi++/coremidi_midiport.h
@@ -22,6 +22,7 @@
#include <list>
#include <string>
+#include <vector>
#include <fcntl.h>
#include <unistd.h>
@@ -32,45 +33,47 @@
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
diff --git a/libs/midi++2/midi++/factory.h b/libs/midi++2/midi++/factory.h
index 9954ea72fe..f3402546e9 100644
--- a/libs/midi++2/midi++/factory.h
+++ b/libs/midi++2/midi++/factory.h
@@ -23,13 +23,12 @@
#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>&);
diff --git a/libs/midi++2/midi++/fd_midiport.h b/libs/midi++2/midi++/fd_midiport.h
index 34e2e27a1a..ec5a9f8af4 100644
--- a/libs/midi++2/midi++/fd_midiport.h
+++ b/libs/midi++2/midi++/fd_midiport.h
@@ -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;
diff --git a/libs/midi++2/midi++/fifomidi.h b/libs/midi++2/midi++/fifomidi.h
index ea644dde06..3439c27dcf 100644
--- a/libs/midi++2/midi++/fifomidi.h
+++ b/libs/midi++2/midi++/fifomidi.h
@@ -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
diff --git a/libs/midi++2/midi++/jack.h b/libs/midi++2/midi++/jack.h
index 1f25609aac..845dd0c229 100644
--- a/libs/midi++2/midi++/jack.h
+++ b/libs/midi++2/midi++/jack.h
@@ -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;
diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h
index eef52abe52..bb3bf9b999 100644
--- a/libs/midi++2/midi++/manager.h
+++ b/libs/midi++2/midi++/manager.h
@@ -21,6 +21,8 @@
#define __midi_manager_h__
#include <map>
+#include <vector>
+
#include <string>
#include <midi++/types.h>
@@ -28,20 +30,18 @@
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;
+ void* api_data;
void close_ports ();
};
diff --git a/libs/midi++2/midi++/nullmidi.h b/libs/midi++2/midi++/nullmidi.h
index 6ed94db71c..8f36e6aed8 100644
--- a/libs/midi++2/midi++/nullmidi.h
+++ b/libs/midi++2/midi++/nullmidi.h
@@ -24,7 +24,6 @@
#include <string>
#include <midi++/port.h>
-#include <midi++/port_request.h>
namespace MIDI {
diff --git a/libs/midi++2/midi++/port.h b/libs/midi++2/midi++/port.h
index e4338cf952..dcae446c42 100644
--- a/libs/midi++2/midi++/port.h
+++ b/libs/midi++2/midi++/port.h
@@ -20,10 +20,11 @@
#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
index dfde87a63c..0000000000
--- a/libs/midi++2/midi++/port_request.h
+++ /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__
-
diff --git a/libs/midi++2/midifactory.cc b/libs/midi++2/midifactory.cc
index 9d98d9f6a7..d893cc9f47 100644
--- a/libs/midi++2/midifactory.cc
+++ b/libs/midi++2/midifactory.cc
@@ -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
diff --git a/libs/midi++2/midimanager.cc b/libs/midi++2/midimanager.cc
index ee73bdad86..8a358c3183 100644
--- a/libs/midi++2/midimanager.cc
+++ b/libs/midi++2/midimanager.cc
@@ -27,21 +27,25 @@
#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);
+}
diff --git a/libs/midi++2/midiport.cc b/libs/midi++2/midiport.cc
index 7f31b909d3..2e3d36c19c 100644
--- a/libs/midi++2/midiport.cc
+++ b/libs/midi++2/midiport.cc
@@ -17,24 +17,29 @@
$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();
+ }
+}
+
diff --git a/libs/midi++2/miditrace.cc b/libs/midi++2/miditrace.cc
index d7c65d9f29..fafe822f82 100644
--- a/libs/midi++2/miditrace.cc
+++ b/libs/midi++2/miditrace.cc
@@ -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;
diff --git a/libs/midi++2/mmctest.cc b/libs/midi++2/mmctest.cc
index 36fbd61124..062f6e8d32 100644
--- a/libs/midi++2/mmctest.cc
+++ b/libs/midi++2/mmctest.cc
@@ -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
index d209f02574..0000000000
--- a/libs/midi++2/port_request.cc
+++ /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;
- }
-}
-
diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript
index 303ac84552..d513dfc762 100644
--- a/libs/pbd/SConscript
+++ b/libs/pbd/SConscript
@@ -31,6 +31,7 @@ filesystem_paths.cc
file_utils.cc
fpu.cc
id.cc
+misc.c
mountpoint.cc
pathscanner.cc
pool.cc
diff --git a/libs/pbd/convert.cc b/libs/pbd/convert.cc
index 07fcc09ace..2ce99ba631 100644
--- a/libs/pbd/convert.cc
+++ b/libs/pbd/convert.cc
@@ -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)
diff --git a/libs/pbd/file_utils.cc b/libs/pbd/file_utils.cc
index efb065fbd4..f8dfe269c5 100644
--- a/libs/pbd/file_utils.cc
+++ b/libs/pbd/file_utils.cc
@@ -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
index 0000000000..797be5de45
--- /dev/null
+++ b/libs/pbd/misc.c
@@ -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
+}
diff --git a/libs/pbd/pbd/convert.h b/libs/pbd/pbd/convert.h
index 00176659cf..83cd285098 100644
--- a/libs/pbd/pbd/convert.h
+++ b/libs/pbd/pbd/convert.h
@@ -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
index 0000000000..e335f4418e
--- /dev/null
+++ b/libs/pbd/pbd/functor_command.h
@@ -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
index 0000000000..306c00683e
--- /dev/null
+++ b/libs/pbd/pbd/misc.h
@@ -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__ */
diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h
index 5bfccf5a06..8f1716d09f 100644
--- a/libs/pbd/pbd/undo.h
+++ b/libs/pbd/pbd/undo.h
@@ -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;
diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc
index 6db85e6ab3..aeff37cce7 100644
--- a/libs/pbd/undo.cc
+++ b/libs/pbd/undo.cc
@@ -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;
}
+
+
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
index 3906b53e36..93cbf088c7 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
@@ -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>
diff --git a/libs/surfaces/mackie/mackie_control_protocol_poll.cc b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
index 05681c0c25..fa7134fa95 100644
--- a/libs/surfaces/mackie/mackie_control_protocol_poll.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
@@ -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>
diff --git a/libs/surfaces/powermate/powermate.cc b/libs/surfaces/powermate/powermate.cc
index 139313f3f8..8b3051af20 100644
--- a/libs/surfaces/powermate/powermate.cc
+++ b/libs/surfaces/powermate/powermate.cc
@@ -14,12 +14,15 @@
#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;
}