Merge with trunk R2978.
git-svn-id: svn://localhost/ardour2/branches/3.0@2988 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
85ea9028b5
commit
9f63ab9931
47
SConstruct
47
SConstruct
|
@ -33,7 +33,7 @@ opts.AddOptions(
|
|||
BoolOption('NATIVE_OSX_KEYS', 'Build key bindings file that matches OS X conventions', 0),
|
||||
BoolOption('DEBUG', 'Set to build with debugging information and no optimizations', 0),
|
||||
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),
|
||||
EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'leopard', 'none' ), ignorecase=2),
|
||||
BoolOption('DMALLOC', 'Compile and link using the dmalloc library', 0),
|
||||
BoolOption('EXTRA_WARN', 'Compile with -Wextra, -ansi, and -pedantic. Might break compilation. For pedants', 0),
|
||||
BoolOption('FFT_ANALYSIS', 'Include FFT analysis window', 0),
|
||||
|
@ -531,15 +531,19 @@ if env['FFT_ANALYSIS']:
|
|||
if env['LV2']:
|
||||
conf = env.Configure(custom_tests = { 'CheckPKGExists' : CheckPKGExists })
|
||||
|
||||
if conf.CheckPKGExists ('\"slv2 >= 0.4.4\"'):
|
||||
if conf.CheckPKGExists ('\"slv2 >= 0.6.0\"'):
|
||||
libraries['slv2'] = LibraryInfo()
|
||||
libraries['slv2'].ParseConfig('pkg-config --cflags --libs slv2')
|
||||
else:
|
||||
print 'Building Ardour with LV2 support requires SLV2 >= 0.4.4'
|
||||
print 'Building Ardour with LV2 support requires SLV2 >= 0.6.0'
|
||||
print 'WARNING: SLV2 not found, or too old. Ardour will be built without LV2 support.'
|
||||
print 'Until the 2.3 release, Ardour requires SLV2 out of SVN.'
|
||||
print 'Testing would be very much appreciated! svn co http://svn.drobilla.net/lad/slv2'
|
||||
env['LV2'] = 0
|
||||
conf.Finish()
|
||||
|
||||
else:
|
||||
print 'LV2 support is not enabled. Build with \'scons LV2=1\' to enable.'
|
||||
|
||||
libraries['jack'] = LibraryInfo()
|
||||
libraries['jack'].ParseConfig('pkg-config --cflags --libs jack')
|
||||
|
||||
|
@ -621,8 +625,10 @@ if env['DIST_TARGET'] == 'auto':
|
|||
# The [.] matches to the dot after the major version, "." would match any character
|
||||
if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
|
||||
env['DIST_TARGET'] = 'panther'
|
||||
else:
|
||||
if re.search ("darwin8[.]", config[config_kernel]) != None:
|
||||
env['DIST_TARGET'] = 'tiger'
|
||||
else:
|
||||
env['DIST_TARGET'] = 'leopard'
|
||||
else:
|
||||
if re.search ("x86_64", config[config_cpu]) != None:
|
||||
env['DIST_TARGET'] = 'x86_64'
|
||||
|
@ -688,9 +694,9 @@ elif ((re.search ("i[0-9]86", config[config_cpu]) != None) or (re.search ("x86_6
|
|||
|
||||
# optimization section
|
||||
if env['FPU_OPTIMIZATION']:
|
||||
if env['DIST_TARGET'] == 'tiger':
|
||||
opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
|
||||
debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
|
||||
if env['DIST_TARGET'] == 'tiger' or env['DIST_TARGET'] == 'leopard':
|
||||
opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS");
|
||||
debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS");
|
||||
libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
|
||||
elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
|
||||
opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
|
||||
|
@ -709,6 +715,18 @@ if env['DIST_TARGET'] == 'x86_64':
|
|||
else:
|
||||
env['LIBDIR']='lib'
|
||||
|
||||
#
|
||||
# a single way to test if we're on OS X
|
||||
#
|
||||
|
||||
if env['DIST_TARGET'] in ['panther', 'tiger', 'leopard' ]:
|
||||
env['IS_OSX'] = 1
|
||||
# force tiger or later, to avoid issues on PPC which defaults
|
||||
# back to 10.1 if we don't tell it otherwise.
|
||||
env.Append (CCFLAGS="-DMAC_OS_X_VERSION_MIN_REQUIRED=1040")
|
||||
else:
|
||||
env['IS_OSX'] = 0
|
||||
|
||||
#
|
||||
# save off guessed arch element in an env
|
||||
#
|
||||
|
@ -767,7 +785,7 @@ if env['LIBLO']:
|
|||
|
||||
|
||||
def prep_libcheck(topenv, libinfo):
|
||||
if topenv['DIST_TARGET'] == 'panther' or topenv['DIST_TARGET'] == 'tiger':
|
||||
if topenv['IS_OSX']:
|
||||
#
|
||||
# rationale: GTK-Quartz uses jhbuild and installs to /opt/gtk by default.
|
||||
# All libraries needed should be built against this location
|
||||
|
@ -780,9 +798,16 @@ def prep_libcheck(topenv, libinfo):
|
|||
prep_libcheck(env, env)
|
||||
|
||||
|
||||
#
|
||||
# these are part of the Ardour source tree because they are C++
|
||||
#
|
||||
|
||||
libraries['vamp'] = LibraryInfo (LIBS='vampsdk',
|
||||
LIBPATH='#libs/vamp-sdk',
|
||||
CPPPATH='#libs/vamp-sdk/vamp')
|
||||
CPPPATH='#libs/vamp-sdk')
|
||||
libraries['vamphost'] = LibraryInfo (LIBS='vamphostsdk',
|
||||
LIBPATH='#libs/vamp-sdk',
|
||||
CPPPATH='#libs/vamp-sdk')
|
||||
|
||||
env['RUBBERBAND'] = False
|
||||
|
||||
|
@ -1007,6 +1032,7 @@ if env['SYSLIBS']:
|
|||
'libs/midi++2',
|
||||
'libs/ardour',
|
||||
'libs/vamp-sdk',
|
||||
'libs/vamp-plugins/',
|
||||
# these are unconditionally included but have
|
||||
# tests internally to avoid compilation etc
|
||||
# if VST is not set
|
||||
|
@ -1081,6 +1107,7 @@ else:
|
|||
'libs/midi++2',
|
||||
'libs/ardour',
|
||||
'libs/vamp-sdk',
|
||||
'libs/vamp-plugins/',
|
||||
# these are unconditionally included but have
|
||||
# tests internally to avoid compilation etc
|
||||
# if VST is not set
|
||||
|
|
|
@ -24,7 +24,7 @@ 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':
|
||||
if gtkardour['IS_OSX']:
|
||||
gtkardour.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
|
||||
|
||||
gtkardour.Merge ([
|
||||
|
@ -50,6 +50,10 @@ gtkardour.Merge ([
|
|||
libraries['xml'],
|
||||
libraries['xslt'],
|
||||
libraries['samplerate'],
|
||||
libraries['vamp'],
|
||||
libraries['vamphost'],
|
||||
libraries['fftw3f'],
|
||||
libraries['fftw3'],
|
||||
libraries['jack'],
|
||||
libraries['cairomm'],
|
||||
libraries['asound']
|
||||
|
@ -77,7 +81,7 @@ if gtkardour['FFT_ANALYSIS']:
|
|||
gtkardour.Append(CCFLAGS='-DFFT_ANALYSIS')
|
||||
|
||||
if gtkardour['RUBBERBAND']:
|
||||
gtkardour.Merge ([ libraries['rubberband'], libraries['vamp'], libraries['fftw3f'], libraries['fftw3'] ])
|
||||
gtkardour.Merge ([ libraries['rubberband'] ])
|
||||
else:
|
||||
gtkardour.Merge ([ libraries['soundtouch'] ])
|
||||
|
||||
|
@ -101,50 +105,44 @@ x11.cc
|
|||
gtkardour_files=Split("""
|
||||
about.cc
|
||||
actions.cc
|
||||
add_route_dialog.cc
|
||||
add_midi_cc_track_dialog.cc
|
||||
add_route_dialog.cc
|
||||
ardour_dialog.cc
|
||||
ardour_ui.cc
|
||||
ardour_ui2.cc
|
||||
ardour_ui.cc
|
||||
ardour_ui_dependents.cc
|
||||
ardour_ui_dialogs.cc
|
||||
ardour_ui_ed.cc
|
||||
ardour_ui_mixer.cc
|
||||
ardour_ui_options.cc
|
||||
audio_clock.cc
|
||||
audio_time_axis.cc
|
||||
audio_region_editor.cc
|
||||
control_point.cc
|
||||
automation_line.cc
|
||||
automation_time_axis.cc
|
||||
automation_streamview.cc
|
||||
audio_region_view.cc
|
||||
audio_streamview.cc
|
||||
audio_time_axis.cc
|
||||
automation_controller.cc
|
||||
automation_line.cc
|
||||
automation_region_view.cc
|
||||
bundle_manager.cc
|
||||
midi_port_dialog.cc
|
||||
midi_time_axis.cc
|
||||
midi_scroomer.cc
|
||||
midi_streamview.cc
|
||||
automation_streamview.cc
|
||||
automation_time_axis.cc
|
||||
axis_view.cc
|
||||
canvas-simpleline.c
|
||||
simpleline.cc
|
||||
canvas-simplerect.c
|
||||
simplerect.cc
|
||||
lineset.cc
|
||||
canvas-waveview.c
|
||||
diamond.cc
|
||||
bundle_manager.cc
|
||||
canvas-midi-event.cc
|
||||
canvas-simpleline.c
|
||||
canvas-simplerect.c
|
||||
canvas-waveview.c
|
||||
control_point.cc
|
||||
crossfade_edit.cc
|
||||
crossfade_view.cc
|
||||
curvetest.cc
|
||||
enums.cc
|
||||
diamond.cc
|
||||
editing.cc
|
||||
editor.cc
|
||||
editor_actions.cc
|
||||
editor_audio_import.cc
|
||||
editor_audiotrack.cc
|
||||
editor_canvas.cc
|
||||
editor_canvas_events.cc
|
||||
editor.cc
|
||||
editor_cursors.cc
|
||||
editor_edit_groups.cc
|
||||
editor_export_audio.cc
|
||||
|
@ -165,66 +163,72 @@ editor_selection_list.cc
|
|||
editor_tempodisplay.cc
|
||||
editor_timefx.cc
|
||||
engine_dialog.cc
|
||||
enums.cc
|
||||
export_dialog.cc
|
||||
export_session_dialog.cc
|
||||
export_region_dialog.cc
|
||||
export_range_markers_dialog.cc
|
||||
export_region_dialog.cc
|
||||
export_session_dialog.cc
|
||||
gain_meter.cc
|
||||
generic_pluginui.cc
|
||||
ghostregion.cc
|
||||
gtk-custom-hruler.c
|
||||
gtk-custom-ruler.c
|
||||
io_selector.cc
|
||||
port_matrix.cc
|
||||
keyboard.cc
|
||||
keyeditor.cc
|
||||
latency_gui.cc
|
||||
level_meter.cc
|
||||
lineset.cc
|
||||
location_ui.cc
|
||||
main.cc
|
||||
marker.cc
|
||||
midi_port_dialog.cc
|
||||
midi_region_view.cc
|
||||
midi_scroomer.cc
|
||||
midi_streamview.cc
|
||||
midi_time_axis.cc
|
||||
mixer_strip.cc
|
||||
mixer_ui.cc
|
||||
new_session_dialog.cc
|
||||
option_editor.cc
|
||||
opts.cc
|
||||
|
||||
panner.cc
|
||||
panner2d.cc
|
||||
panner.cc
|
||||
panner_ui.cc
|
||||
piano_roll_header.cc
|
||||
playlist_selector.cc
|
||||
plugin_selector.cc
|
||||
plugin_ui.cc
|
||||
port_matrix.cc
|
||||
processor_box.cc
|
||||
prompter.cc
|
||||
public_editor.cc
|
||||
processor_box.cc
|
||||
region_gain_line.cc
|
||||
region_selection.cc
|
||||
region_view.cc
|
||||
audio_region_view.cc
|
||||
midi_region_view.cc
|
||||
tape_region_view.cc
|
||||
rhythm_ferret.cc
|
||||
route_params_ui.cc
|
||||
route_processor_selection.cc
|
||||
route_time_axis.cc
|
||||
route_ui.cc
|
||||
selection.cc
|
||||
sfdb_ui.cc
|
||||
send_ui.cc
|
||||
sfdb_ui.cc
|
||||
simpleline.cc
|
||||
simplerect.cc
|
||||
splash.cc
|
||||
streamview.cc
|
||||
audio_streamview.cc
|
||||
tape_region_view.cc
|
||||
tempo_dialog.cc
|
||||
tempo_lines.cc
|
||||
theme_manager.cc
|
||||
time_axis_view.cc
|
||||
time_axis_view_item.cc
|
||||
route_time_axis.cc
|
||||
time_selection.cc
|
||||
ui_config.cc
|
||||
utils.cc
|
||||
version.cc
|
||||
waveview.cc
|
||||
tempo_lines.cc
|
||||
""")
|
||||
|
||||
fft_analysis_files=Split("""
|
||||
|
@ -315,7 +319,7 @@ tt = gtkmmtests.Program(target = 'tt', source = tt_files)
|
|||
|
||||
my_font_dict = { }
|
||||
|
||||
if gtkardour['DIST_TARGET'] == 'panther' or gtkardour['DIST_TARGET'] == 'tiger':
|
||||
if gtkardour['IS_OSX']:
|
||||
#
|
||||
# OS X font rendering is different even with X11
|
||||
#
|
||||
|
|
|
@ -4,7 +4,7 @@ cd `dirname "$0"`/..
|
|||
|
||||
export ARDOUR_PATH=gtk2_ardour/icons:gtk2_ardour/pixmaps:gtk2_ardour:.
|
||||
export GTK_PATH=libs/clearlooks
|
||||
|
||||
export VAMP_PATH=libs/vamp-plugins:$VAMP_PATH
|
||||
|
||||
export LD_LIBRARY_PATH=libs/vamp-sdk:libs/surfaces/control_protocol:libs/ardour:libs/midi++2:libs/pbd:libs/rubberband:libs/soundtouch:libs/gtkmm2ext:libs/sigc++2:libs/glibmm2:libs/gtkmm2/atk:libs/gtkmm2/pango:libs/gtkmm2/gdk:libs/gtkmm2/gtk:libs/libgnomecanvasmm:libs/libsndfile:libs/appleutility:libs/cairomm:$LD_LIBRARY_PATH
|
||||
|
||||
|
|
|
@ -335,6 +335,8 @@
|
|||
(gtk_accel_path "<Actions>/Editor/goto-mark-9" "KP_9")
|
||||
(gtk_accel_path "<Actions>/Transport/ToggleClick" "5")
|
||||
(gtk_accel_path "<Actions>/Transport/ToggleAutoReturn" "4")
|
||||
(gtk_accel_path "<Actions>/Editor/set-tempo-from-region" "9")
|
||||
(gtk_accel_path "<Actions>/Editor/set-tempo-from-edit-range" "0")
|
||||
(gtk_accel_path "<Actions>/Transport/focus-on-clock" "KP_Divide")
|
||||
(gtk_accel_path "<Actions>/Editor/set-loop-from-edit-range" "bracketright")
|
||||
(gtk_accel_path "<Actions>/Editor/set-punch-from-edit-range" "bracketleft")
|
||||
|
|
|
@ -133,6 +133,9 @@
|
|||
<menuitem action='cycle-edit-point'/>
|
||||
<menuitem action='cycle-edit-point-with-marker'/>
|
||||
<menuitem action='toggle-edit-mode'/>
|
||||
<separator/>
|
||||
<menuitem action='boost-region-gain'/>
|
||||
<menuitem action='cut-region-gain'/>
|
||||
</menu>
|
||||
</menu>
|
||||
<menu name='Regions' action='Regions'>
|
||||
|
@ -164,6 +167,8 @@
|
|||
<menuitem action='trim-region-to-punch'/>
|
||||
<separator/>
|
||||
<menuitem action='pitch-shift-region'/>
|
||||
<menuitem action='set-tempo-from-region'/>
|
||||
<menuitem action='set-tempo-from-edit-range'/>
|
||||
</menu>
|
||||
<menu name='View' action = 'View'>
|
||||
<menuitem action='ToggleMaximalEditor'/>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
(gtk_accel_path "<Actions>/Editor/edit-cursor-to-previous-region-sync" "apostrophe")
|
||||
(gtk_accel_path "<Actions>/Editor/edit-cursor-to-next-region-sync" "semicolon")
|
||||
(gtk_accel_path "<Actions>/Editor/cycle-edit-point" "grave")
|
||||
(gtk_accel_path "<Actions>/Editor/cycle-edit-point-with-marker" "<%PRIMARY%>asciicircum")
|
||||
|
||||
(gtk_accel_path "<Actions>/Editor/playhead-to-next-region-boundary" "period")
|
||||
(gtk_accel_path "<Actions>/Editor/playhead-to-next-region-sync" "<%PRIMARY%>period")
|
||||
|
@ -38,6 +39,9 @@
|
|||
(gtk_accel_path "<Actions>/Editor/set-punch-from-edit-range" "bracketleft")
|
||||
(gtk_accel_path "<Actions>/Editor/set-punch-from-region" "<%SECONDARY%>bracketleft")
|
||||
|
||||
(gtk_accel_path "<Actions>/Editor/boost-region-gain" "asciicircum")
|
||||
(gtk_accel_path "<Actions>/Editor/cut-region-gain" "ampersand")
|
||||
|
||||
;; letters
|
||||
|
||||
;; TOP ROW
|
||||
|
@ -50,6 +54,7 @@
|
|||
(gtk_accel_path "<Actions>/Editor/select-all-before-edit-cursor" "<%PRIMARY%>e")
|
||||
(gtk_accel_path "<Actions>/Editor/show-editor-mixer" "<%TERTIARY%>e")
|
||||
(gtk_accel_path "<Actions>/Common/goto-editor" "<%WINDOW%>e")
|
||||
(gtk_accel_path "<Actions>/Editor/select-all-after-edit-cursor" "<%TERTIARY%><%PRIMARY%>e")
|
||||
(gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-range" "r")
|
||||
(gtk_accel_path "<Actions>/Editor/redo" "<%PRIMARY%>r")
|
||||
(gtk_accel_path "<Actions>/Transport/Record" "<%TERTIARY%>r")
|
||||
|
@ -62,22 +67,19 @@
|
|||
(gtk_accel_path "<Actions>/Common/ToggleOptionsEditor" "<%WINDOW%>o")
|
||||
(gtk_accel_path "<Actions>/Editor/set-playhead" "p")
|
||||
(gtk_accel_path "<Actions>/Editor/select-all-before-playhead" "<%PRIMARY%>p")
|
||||
(gtk_accel_path "<Actions>/Editor/select-all-after-playhead" "<%TERTIARY%><%PRIMARY%>p")
|
||||
|
||||
;; MIDDLE ROW
|
||||
|
||||
(gtk_accel_path "<Actions>/Editor/align-regions-sync-relative" "a")
|
||||
(gtk_accel_path "<Actions>/Editor/align-regions-start-relative" "<%PRIMARY%>a")
|
||||
(gtk_accel_path "<Actions>/Editor/select-all" "<%PRIMARY%>a")
|
||||
(gtk_accel_path "<Actions>/Editor/align-regions-end" "<%SECONDARY%>a")
|
||||
(gtk_accel_path "<Actions>/Editor/align-regions-sync" "<%TERTIARY%>a")
|
||||
(gtk_accel_path "<Actions>/Editor/align-regions-start-relative" "<%LEVEL4%>a")
|
||||
(gtk_accel_path "<Actions>/Editor/split-region" "s")
|
||||
(gtk_accel_path "<Actions>/Common/Save" "<%PRIMARY%>s")
|
||||
(gtk_accel_path "<Actions>/Editor/duplicate-region" "d")
|
||||
(gtk_accel_path "<Actions>/Editor/select-all-in-punch-range" "<%PRIMARY%>d")
|
||||
|
||||
(gtk_accel_path "<Actions>/Editor/select-all" "<%PRIMARY%>a")
|
||||
(gtk_accel_path "<Actions>/Editor/select-all-after-playhead" "<%TERTIARY%><%PRIMARY%>p")
|
||||
(gtk_accel_path "<Actions>/Editor/select-all-after-edit-cursor" "<%TERTIARY%><%PRIMARY%>e")
|
||||
|
||||
(gtk_accel_path "<Actions>/Editor/toggle-follow-playhead" "f")
|
||||
(gtk_accel_path "<Actions>/MouseMode/set-mouse-mode-gain" "g")
|
||||
(gtk_accel_path "<Actions>/Editor/play-selected-regions" "h")
|
||||
|
@ -180,6 +182,8 @@
|
|||
(gtk_accel_path "<Actions>/Editor/cycle-snap-choice" "3")
|
||||
(gtk_accel_path "<Actions>/Transport/ToggleAutoReturn" "4")
|
||||
(gtk_accel_path "<Actions>/Transport/ToggleClick" "5")
|
||||
(gtk_accel_path "<Actions>/Editor/set-tempo-from-region" "9")
|
||||
(gtk_accel_path "<Actions>/Editor/set-tempo-from-edit-range" "0")
|
||||
|
||||
;;
|
||||
;; unbound actions
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
<menuitem action='GotoStart'/>
|
||||
<menuitem action='GotoEnd'/>
|
||||
<separator/>
|
||||
<menuitem action='tab-to-transient-forwards'/>
|
||||
<menuitem action='tab-to-transient-backwards'/>
|
||||
<separator/>
|
||||
<menuitem action='Record'/>
|
||||
<separator/>
|
||||
<menuitem action='TransitionToRoll'/>
|
||||
|
@ -161,6 +164,7 @@
|
|||
<menuitem action='select-prev-route'/>
|
||||
</menu>
|
||||
<menu name='Regions' action='Regions'>
|
||||
<menuitem action='split-region-at-transients'/>
|
||||
<menuitem action='crop'/>
|
||||
<menuitem action='duplicate-region'/>
|
||||
<menuitem action='multi-duplicate-region'/>
|
||||
|
@ -194,6 +198,8 @@
|
|||
<menuitem action='trim-region-to-punch'/>
|
||||
<separator/>
|
||||
<menuitem action='pitch-shift-region'/>
|
||||
<menuitem action='set-tempo-from-region'/>
|
||||
<menuitem action='set-tempo-from-edit-range'/>
|
||||
</menu>
|
||||
<menu name='View' action = 'View'>
|
||||
<menu name='ZoomFocus' action='ZoomFocus'>
|
||||
|
@ -302,6 +308,7 @@
|
|||
<menuitem action='ToggleThemeManager'/>
|
||||
<menuitem action='ToggleBigClock'/>
|
||||
<menuitem action='ToggleBundleManager'/>
|
||||
<menuitem action='toggle-rhythm-ferret'/>
|
||||
<separator/>
|
||||
</menu>
|
||||
<menu name='Options' action='Options'>
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
<Option name="ui-rc-file" value="ardour3_ui_dark.rc"/>
|
||||
</UI>
|
||||
<Canvas>
|
||||
<Option name="waveform" value="000000d6"/>
|
||||
<Option name="waveform fill" value="0b225a78"/>
|
||||
<Option name="waveform outline" value="0f0f0fcc"/>
|
||||
<Option name="waveform fill" value="3d475378"/>
|
||||
<Option name="clipped waveform" value="ff0000e5"/>
|
||||
<Option name="region base" value="b2bcd3aa"/>
|
||||
<Option name="selected region base" value="565693a6"/>
|
||||
<Option name="region base" value="99a7b5aa"/>
|
||||
<Option name="selected region base" value="b591a8ff"/>
|
||||
<Option name="midi frame base" value="698f9d6d"/>
|
||||
<Option name="audio track base" value="c6d3d868"/>
|
||||
<Option name="audio bus base" value="dbd1ea68"/>
|
||||
|
|
|
@ -610,8 +610,6 @@ Please consider the possibilities, and perhaps (re)start JACK."));
|
|||
win.show_all ();
|
||||
win.set_position (Gtk::WIN_POS_CENTER);
|
||||
|
||||
hide_splash ();
|
||||
|
||||
/* we just don't care about the result, but we want to block */
|
||||
|
||||
win.run ();
|
||||
|
@ -2208,6 +2206,7 @@ ARDOUR_UI::end_loading_messages ()
|
|||
void
|
||||
ARDOUR_UI::loading_message (const std::string& msg)
|
||||
{
|
||||
cerr << "say: " << msg << endl;
|
||||
show_splash ();
|
||||
splash->message (msg);
|
||||
flush_pending ();
|
||||
|
@ -2254,10 +2253,6 @@ ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be
|
|||
new_session_dialog->set_existing_session (existing_session);
|
||||
new_session_dialog->reset_recent();
|
||||
|
||||
/* get this out of the way */
|
||||
|
||||
hide_splash ();
|
||||
|
||||
do {
|
||||
new_session_dialog->set_have_engine (backend_audio_is_running);
|
||||
new_session_dialog->present ();
|
||||
|
@ -2622,6 +2617,7 @@ ARDOUR_UI::show_splash ()
|
|||
}
|
||||
|
||||
splash->show ();
|
||||
splash->present ();
|
||||
splash->queue_draw ();
|
||||
splash->get_window()->process_updates (true);
|
||||
flush_pending ();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <AudioUnit/AudioUnitCarbonView.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
|
||||
/* fix up stupid apple macros */
|
||||
|
|
|
@ -796,20 +796,21 @@ AudioRegionView::set_envelope_visible (bool yn)
|
|||
void
|
||||
AudioRegionView::create_waves ()
|
||||
{
|
||||
//cerr << "AudioRegionView::create_waves() called on " << this << endl;//DEBUG
|
||||
RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
|
||||
|
||||
if (!atv.get_diskstream()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t nchans = atv.get_diskstream()->n_channels().n_audio();
|
||||
ChanCount nchans = atv.get_diskstream()->n_channels();
|
||||
|
||||
/* in tmp_waves, set up null pointers for each channel so the vector is allocated */
|
||||
for (uint32_t n = 0; n < nchans; ++n) {
|
||||
for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
|
||||
tmp_waves.push_back (0);
|
||||
}
|
||||
|
||||
for (uint32_t n = 0; n < nchans; ++n) {
|
||||
for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
|
||||
|
||||
if (n >= audio_region()->n_channels()) {
|
||||
break;
|
||||
|
@ -818,21 +819,16 @@ AudioRegionView::create_waves ()
|
|||
wave_caches.push_back (WaveView::create_cache ());
|
||||
|
||||
if (wait_for_data) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegionView::create_one_wave (uint32_t which, bool direct)
|
||||
{
|
||||
//cerr << "AudioRegionView::create_one_wave() called which: " << which << " this: " << this << endl;//DEBUG
|
||||
RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
|
||||
uint32_t nchans = atv.get_diskstream()->n_channels().n_audio();
|
||||
uint32_t n;
|
||||
|
@ -862,6 +858,7 @@ AudioRegionView::create_one_wave (uint32_t which, bool direct)
|
|||
wave->property_samples_per_unit() = samples_per_unit;
|
||||
wave->property_amplitude_above_axis() = _amplitude_above_axis;
|
||||
wave->property_wave_color() = _region->muted() ? UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA) : ARDOUR_UI::config()->canvasvar_WaveForm.get();
|
||||
wave->property_fill_color() = ARDOUR_UI::config()->canvasvar_WaveFormFill.get();
|
||||
wave->property_clip_color() = ARDOUR_UI::config()->canvasvar_WaveFormClip.get();
|
||||
wave->property_zero_color() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
|
||||
wave->property_region_start() = _region->start();
|
||||
|
@ -916,7 +913,8 @@ AudioRegionView::create_one_wave (uint32_t which, bool direct)
|
|||
void
|
||||
AudioRegionView::peaks_ready_handler (uint32_t which)
|
||||
{
|
||||
Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &AudioRegionView::create_one_wave), which, false));
|
||||
//Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &AudioRegionView::create_one_wave), which, false));
|
||||
cerr << "AudioRegionView::peaks_ready_handler() called on " << which << " this: " << this << endl;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1110,6 +1108,7 @@ AudioRegionView::add_ghost (AutomationTimeAxisView& atv)
|
|||
wave->property_samples_per_unit() = samples_per_unit;
|
||||
wave->property_amplitude_above_axis() = _amplitude_above_axis;
|
||||
wave->property_wave_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWave.get();
|
||||
wave->property_fill_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWave.get();
|
||||
wave->property_clip_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWaveClip.get();
|
||||
wave->property_zero_color() = ARDOUR_UI::config()->canvasvar_GhostTrackZeroLine.get();
|
||||
wave->property_region_start() = _region->start();
|
||||
|
|
|
@ -368,10 +368,10 @@ gnome_canvas_waveview_init (GnomeCanvasWaveView *waveview)
|
|||
waveview->screen_width = gdk_screen_width ();
|
||||
waveview->reload_cache_in_render = FALSE;
|
||||
|
||||
waveview->wave_color = RGBA_TO_UINT(44,35,126,255);
|
||||
waveview->clip_color = RGBA_TO_UINT(44,0,0,100);
|
||||
waveview->zero_color = RGBA_TO_UINT(44,0,128,100);
|
||||
waveview->fill_color = RGBA_TO_UINT(44,35,126,128);
|
||||
waveview->wave_color = 0;
|
||||
waveview->clip_color = 0;
|
||||
waveview->zero_color = 0;
|
||||
waveview->fill_color = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
CANVAS_VARIABLE(canvasvar_WaveForm, "waveform")
|
||||
CANVAS_VARIABLE(canvasvar_WaveForm, "waveform outline")
|
||||
CANVAS_VARIABLE(canvasvar_WaveFormFill, "waveform fill")
|
||||
CANVAS_VARIABLE(canvasvar_WaveFormClip, "clipped waveform")
|
||||
CANVAS_VARIABLE(canvasvar_FrameBase, "region base")
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include <Carbon/Carbon.h>
|
||||
#undef check // stupid, stupid carbon
|
||||
#undef YES // stupid, stupid gtkmm and/or NSObjC
|
||||
#undef NO // ditto
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "actions.h"
|
||||
|
@ -117,6 +119,6 @@ ARDOUR_UI::platform_setup ()
|
|||
|
||||
/* if invoked from the command line, make sure we're visible */
|
||||
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
[NSApp activateIgnoringOtherApps:1];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -982,10 +982,12 @@ CrossfadeEditor::curve_select_clicked (WhichFade wf)
|
|||
|
||||
for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
|
||||
(*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
|
||||
(*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
|
||||
}
|
||||
|
||||
for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
|
||||
(*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
|
||||
(*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
|
||||
}
|
||||
|
||||
fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
|
||||
|
@ -1005,10 +1007,12 @@ CrossfadeEditor::curve_select_clicked (WhichFade wf)
|
|||
|
||||
for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
|
||||
(*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
|
||||
(*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
|
||||
}
|
||||
|
||||
for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
|
||||
(*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
|
||||
(*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
|
||||
}
|
||||
|
||||
fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
|
||||
|
@ -1084,6 +1088,7 @@ CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade wh
|
|||
waveview->property_samples_per_unit() = spu;
|
||||
waveview->property_amplitude_above_axis() = 2.0;
|
||||
waveview->property_wave_color() = color;
|
||||
waveview->property_fill_color() = color;
|
||||
|
||||
if (which==In)
|
||||
waveview->property_region_start() = region->start();
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
#include "sfdb_ui.h"
|
||||
#include "gui_thread.h"
|
||||
#include "simpleline.h"
|
||||
#include "rhythm_ferret.h"
|
||||
|
||||
#ifdef FFT_ANALYSIS
|
||||
#include "analysis_window.h"
|
||||
|
@ -341,6 +342,7 @@ Editor::Editor ()
|
|||
_dragging_hscrollbar = false;
|
||||
select_new_marker = false;
|
||||
zoomed_to_region = false;
|
||||
rhythm_ferret = 0;
|
||||
|
||||
scrubbing_direction = 0;
|
||||
|
||||
|
@ -1190,6 +1192,10 @@ Editor::connect_to_session (Session *t)
|
|||
_playlist_selector->set_session (session);
|
||||
nudge_clock.set_session (session);
|
||||
|
||||
if (rhythm_ferret) {
|
||||
rhythm_ferret->set_session (session);
|
||||
}
|
||||
|
||||
#ifdef FFT_ANALYSIS
|
||||
if (analysis_window != 0)
|
||||
analysis_window->set_session (session);
|
||||
|
@ -3297,26 +3303,32 @@ Editor::duplicate_dialog (bool with_dialog)
|
|||
|
||||
if (with_dialog) {
|
||||
|
||||
ArdourDialog win ("duplicate dialog");
|
||||
Label label (_("Duplicate how many times?"));
|
||||
ArdourDialog win ("Duplication Dialog");
|
||||
Label label (_("Number of Duplications:"));
|
||||
Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
|
||||
SpinButton spinner (adjustment);
|
||||
SpinButton spinner (adjustment, 0.0, 1);
|
||||
HBox hbox;
|
||||
|
||||
win.get_vbox()->set_spacing (12);
|
||||
win.get_vbox()->pack_start (label);
|
||||
win.get_vbox()->pack_start (hbox);
|
||||
hbox.set_border_width (6);
|
||||
hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
|
||||
|
||||
/* dialogs have ::add_action_widget() but that puts the spinner in the wrong
|
||||
place, visually. so do this by hand.
|
||||
*/
|
||||
|
||||
win.get_vbox()->pack_start (spinner);
|
||||
hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
|
||||
spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
|
||||
|
||||
spinner.grab_focus();
|
||||
|
||||
hbox.show ();
|
||||
label.show ();
|
||||
spinner.show ();
|
||||
|
||||
win.add_button (Stock::OK, RESPONSE_ACCEPT);
|
||||
win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
|
||||
win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
|
||||
win.set_default_response (RESPONSE_ACCEPT);
|
||||
|
||||
win.set_position (WIN_POS_MOUSE);
|
||||
|
||||
|
@ -4587,3 +4599,15 @@ Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<R
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::show_rhythm_ferret ()
|
||||
{
|
||||
if (rhythm_ferret == 0) {
|
||||
rhythm_ferret = new RhythmFerret(*this);
|
||||
}
|
||||
|
||||
rhythm_ferret->set_session (session);
|
||||
rhythm_ferret->show ();
|
||||
rhythm_ferret->present ();
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ class StreamView;
|
|||
class AudioStreamView;
|
||||
class ControlPoint;
|
||||
class SoundFileOmega;
|
||||
class RhythmFerret;
|
||||
#ifdef FFT_ANALYSIS
|
||||
class AnalysisWindow;
|
||||
#endif
|
||||
|
@ -371,6 +372,8 @@ class Editor : public PublicEditor
|
|||
|
||||
void toggle_meter_updating();
|
||||
|
||||
void show_rhythm_ferret();
|
||||
|
||||
protected:
|
||||
void map_transport_state ();
|
||||
void map_position_change (nframes_t);
|
||||
|
@ -1024,6 +1027,8 @@ class Editor : public PublicEditor
|
|||
void split_region ();
|
||||
void split_region_at (nframes_t);
|
||||
void split_regions_at (nframes_t, RegionSelection&);
|
||||
void split_region_at_transients ();
|
||||
void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, std::vector<nframes64_t>&);
|
||||
void crop_region_to_selection ();
|
||||
void crop_region_to (nframes_t start, nframes_t end);
|
||||
void set_sync_point (nframes64_t, const RegionSelection&);
|
||||
|
@ -1051,6 +1056,13 @@ class Editor : public PublicEditor
|
|||
void adjust_region_scale_amplitude (bool up);
|
||||
void quantize_region ();
|
||||
|
||||
void tab_to_transient (bool forward);
|
||||
|
||||
void use_region_as_bar ();
|
||||
void use_range_as_bar ();
|
||||
|
||||
void define_one_bar (nframes64_t start, nframes64_t end);
|
||||
|
||||
void audition_region_from_region_list ();
|
||||
void hide_region_from_region_list ();
|
||||
void remove_region_from_region_list ();
|
||||
|
@ -2164,6 +2176,8 @@ class Editor : public PublicEditor
|
|||
|
||||
void select_next_route ();
|
||||
void select_prev_route ();
|
||||
|
||||
RhythmFerret* rhythm_ferret;
|
||||
};
|
||||
|
||||
#endif /* __ardour_editor_h__ */
|
||||
|
|
|
@ -356,13 +356,30 @@ Editor::register_actions ()
|
|||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (editor_actions, "normalize-region", _("Normalize Region"), mem_fun(*this, &Editor::normalize_region));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
||||
act = ActionManager::register_action (editor_actions, "boost-region-gain", _("Boost Region Gain"), bind (mem_fun(*this, &Editor::adjust_region_scale_amplitude), true));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (editor_actions, "cut-region-gain", _("Cut Region Gain"), bind (mem_fun(*this, &Editor::adjust_region_scale_amplitude), false));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
||||
act = ActionManager::register_action (editor_actions, "quantize-region", _("Quantize Region"), mem_fun(*this, &Editor::quantize_region));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
||||
act = ActionManager::register_action (editor_actions, "set-tempo-from-region", _("Set Tempo from Region=Bar"), mem_fun(*this, &Editor::use_region_as_bar));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (editor_actions, "set-tempo-from-edit-range", _("Set Tempo from Edit Range=Bar"), mem_fun(*this, &Editor::use_range_as_bar));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
||||
act = ActionManager::register_action (editor_actions, "split-region-at-transients", _("Split Regions At Percussion Onsets"), mem_fun(*this, &Editor::split_region_at_transients));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (editor_actions, "toggle-rhythm-ferret", _("Rhythm Ferret"), mem_fun(*this, &Editor::show_rhythm_ferret));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
||||
act = ActionManager::register_action (editor_actions, "tab-to-transient-forwards", _("Move Forward to Transient"), bind (mem_fun(*this, &Editor::tab_to_transient), true));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (editor_actions, "tab-to-transient-backwards", _("Move Forward to Transient"), bind (mem_fun(*this, &Editor::tab_to_transient), false));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
||||
act = ActionManager::register_action (editor_actions, "crop", _("Crop"), mem_fun(*this, &Editor::crop_region_to_selection));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
act = ActionManager::register_action (editor_actions, "insert-chunk", _("Insert Chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f));
|
||||
|
|
|
@ -453,6 +453,8 @@ Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context
|
|||
const SelectionData& data,
|
||||
guint info, guint time)
|
||||
{
|
||||
cerr << "drop on canvas, target = " << data.get_target() << endl;
|
||||
|
||||
if (data.get_target() == "regions") {
|
||||
drop_regions (context, x, y, data, info, time);
|
||||
} else {
|
||||
|
|
|
@ -45,10 +45,12 @@
|
|||
#include <ardour/location.h>
|
||||
#include <ardour/named_selection.h>
|
||||
#include <ardour/audio_track.h>
|
||||
#include <ardour/audiofilesource.h>
|
||||
#include <ardour/audioplaylist.h>
|
||||
#include <ardour/region_factory.h>
|
||||
#include <ardour/playlist_factory.h>
|
||||
#include <ardour/reverse.h>
|
||||
#include <ardour/transient_detector.h>
|
||||
#include <ardour/dB.h>
|
||||
#include <ardour/quantize.h>
|
||||
|
||||
|
@ -3042,9 +3044,9 @@ Editor::align_selection_relative (RegionPoint point, nframes_t position, const R
|
|||
return;
|
||||
}
|
||||
|
||||
nframes_t distance;
|
||||
nframes_t distance = 0;
|
||||
nframes_t pos = 0;
|
||||
int dir;
|
||||
int dir = 0;
|
||||
|
||||
list<RegionView*> sorted;
|
||||
rs.by_position (sorted);
|
||||
|
@ -4148,7 +4150,7 @@ Editor::adjust_region_scale_amplitude (bool up)
|
|||
return;
|
||||
}
|
||||
|
||||
ExclusiveRegionSelection (*this, entered_regionview);
|
||||
ExclusiveRegionSelection esr (*this, entered_regionview);
|
||||
|
||||
if (selection->regions.empty()) {
|
||||
return;
|
||||
|
@ -4164,10 +4166,6 @@ Editor::adjust_region_scale_amplitude (bool up)
|
|||
|
||||
double fraction = gain_to_slider_position (arv->audio_region()->scale_amplitude ());
|
||||
|
||||
cerr << "slider pos for " << arv->audio_region()->scale_amplitude ()
|
||||
<< " = " << fraction
|
||||
<< endl;
|
||||
|
||||
if (up) {
|
||||
fraction += 0.05;
|
||||
fraction = min (fraction, 1.0);
|
||||
|
@ -4180,16 +4178,14 @@ Editor::adjust_region_scale_amplitude (bool up)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (up && fraction >= 1.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fraction = slider_position_to_gain (fraction);
|
||||
fraction = coefficient_to_dB (fraction);
|
||||
fraction = dB_to_coefficient (fraction);
|
||||
|
||||
cerr << "set scale amp for " << arv->audio_region()->name() << " to " << fraction << endl;
|
||||
|
||||
if (up && fraction >= 2.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
arv->audio_region()->set_scale_amplitude (fraction);
|
||||
session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
|
||||
}
|
||||
|
@ -4481,7 +4477,7 @@ Editor::toggle_fade_active (bool in)
|
|||
|
||||
const char* cmd = (in ? _("toggle fade in active") : _("toggle fade out active"));
|
||||
bool have_switch = false;
|
||||
bool yn;
|
||||
bool yn = false;
|
||||
|
||||
begin_reversible_command (cmd);
|
||||
|
||||
|
@ -4986,3 +4982,233 @@ Editor::pitch_shift_regions ()
|
|||
pitch_shift (selection->regions, 1.2);
|
||||
}
|
||||
|
||||
void
|
||||
Editor::use_region_as_bar ()
|
||||
{
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
|
||||
ExclusiveRegionSelection esr (*this, entered_regionview);
|
||||
|
||||
if (selection->regions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RegionView* rv = selection->regions.front();
|
||||
|
||||
define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
|
||||
}
|
||||
|
||||
void
|
||||
Editor::use_range_as_bar ()
|
||||
{
|
||||
nframes64_t start, end;
|
||||
if (get_edit_op_range (start, end)) {
|
||||
define_one_bar (start, end);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::define_one_bar (nframes64_t start, nframes64_t end)
|
||||
{
|
||||
nframes64_t length = end - start;
|
||||
|
||||
const Meter& m (session->tempo_map().meter_at (start));
|
||||
|
||||
/* region length = 1 bar */
|
||||
|
||||
/* 1 bar = how many beats per bar */
|
||||
|
||||
double beats_per_bar = m.beats_per_bar();
|
||||
|
||||
/* now we want frames per beat.
|
||||
we have frames per bar, and beats per bar, so ...
|
||||
*/
|
||||
|
||||
double frames_per_beat = length / beats_per_bar;
|
||||
|
||||
/* beats per minute = */
|
||||
|
||||
double beats_per_minute = (session->frame_rate() * 60.0) / frames_per_beat;
|
||||
|
||||
const TempoSection& t (session->tempo_map().tempo_section_at (start));
|
||||
|
||||
begin_reversible_command (_("set tempo from region"));
|
||||
XMLNode& before (session->tempo_map().get_state());
|
||||
|
||||
if (t.frame() == start) {
|
||||
session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
|
||||
} else {
|
||||
session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
|
||||
}
|
||||
|
||||
XMLNode& after (session->tempo_map().get_state());
|
||||
|
||||
session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), &before, &after));
|
||||
commit_reversible_command ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::split_region_at_transients ()
|
||||
{
|
||||
vector<nframes64_t> positions;
|
||||
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
|
||||
ExclusiveRegionSelection esr (*this, entered_regionview);
|
||||
|
||||
if (selection->regions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
session->begin_reversible_command (_("split regions"));
|
||||
|
||||
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ) {
|
||||
|
||||
RegionSelection::iterator tmp;
|
||||
|
||||
tmp = i;
|
||||
++tmp;
|
||||
|
||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
|
||||
|
||||
if (ar && (ar->get_transients (positions) == 0)) {
|
||||
split_region_at_points ((*i)->region(), positions);
|
||||
positions.clear ();
|
||||
}
|
||||
|
||||
i = tmp;
|
||||
}
|
||||
|
||||
session->commit_reversible_command ();
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Editor::split_region_at_points (boost::shared_ptr<Region> r, vector<nframes64_t>& positions)
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
|
||||
|
||||
if (!ar) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Playlist> pl = ar->playlist();
|
||||
|
||||
if (!pl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (positions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
vector<nframes64_t>::const_iterator x;
|
||||
|
||||
nframes64_t pos = ar->position();
|
||||
|
||||
XMLNode& before (pl->get_state());
|
||||
|
||||
x = positions.begin();
|
||||
|
||||
while (x != positions.end()) {
|
||||
if ((*x) > pos) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x == positions.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pl->freeze ();
|
||||
pl->remove_region (ar);
|
||||
|
||||
do {
|
||||
|
||||
/* file start = original start + how far we from the initial position ?
|
||||
*/
|
||||
|
||||
nframes64_t file_start = ar->start() + (pos - ar->position());
|
||||
|
||||
/* length = next position - current position
|
||||
*/
|
||||
|
||||
nframes64_t len = (*x) - pos;
|
||||
|
||||
string new_name;
|
||||
|
||||
if (session->region_name (new_name, ar->name())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pl->add_region (RegionFactory::create (ar->sources(), file_start, len, new_name), pos);
|
||||
|
||||
pos += len;
|
||||
|
||||
++x;
|
||||
|
||||
} while (x != positions.end() && (*x) < ar->last_frame());
|
||||
|
||||
pl->thaw ();
|
||||
|
||||
XMLNode& after (pl->get_state());
|
||||
|
||||
session->add_command (new MementoCommand<Playlist>(*pl, &before, &after));
|
||||
}
|
||||
|
||||
void
|
||||
Editor::tab_to_transient (bool forward)
|
||||
{
|
||||
|
||||
vector<nframes64_t> positions;
|
||||
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
|
||||
ExclusiveRegionSelection esr (*this, entered_regionview);
|
||||
|
||||
if (selection->regions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (selection->regions.front()->region());
|
||||
|
||||
if (!ar) {
|
||||
return;
|
||||
}
|
||||
|
||||
ar->get_transients (positions);
|
||||
nframes64_t pos = session->audible_frame ();
|
||||
|
||||
if (forward) {
|
||||
vector<nframes64_t>::iterator x;
|
||||
|
||||
for (x = positions.begin(); x != positions.end(); ++x) {
|
||||
if ((*x) > pos) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x != positions.end ()) {
|
||||
session->request_locate (*x);
|
||||
}
|
||||
|
||||
} else {
|
||||
vector<nframes64_t>::reverse_iterator x;
|
||||
|
||||
for (x = positions.rbegin(); x != positions.rend(); ++x) {
|
||||
if ((*x) < pos) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x != positions.rend ()) {
|
||||
session->request_locate (*x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,7 +220,8 @@ Editor::mouse_add_new_tempo_event (nframes_t frame)
|
|||
TempoDialog tempo_dialog (map, frame, _("add"));
|
||||
|
||||
tempo_dialog.set_position (Gtk::WIN_POS_MOUSE);
|
||||
tempo_dialog.signal_realize().connect (bind (sigc::ptr_fun (set_decoration), &tempo_dialog, Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)));
|
||||
//this causes compiz to display no border.
|
||||
//tempo_dialog.signal_realize().connect (bind (sigc::ptr_fun (set_decoration), &tempo_dialog, Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)));
|
||||
|
||||
ensure_float (tempo_dialog);
|
||||
|
||||
|
@ -247,7 +248,7 @@ Editor::mouse_add_new_tempo_event (nframes_t frame)
|
|||
session->add_command(new MementoCommand<TempoMap>(map, &before, &after));
|
||||
commit_reversible_command ();
|
||||
|
||||
map.dump (cerr);
|
||||
//map.dump (cerr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -262,7 +263,9 @@ Editor::mouse_add_new_meter_event (nframes_t frame)
|
|||
MeterDialog meter_dialog (map, frame, _("add"));
|
||||
|
||||
meter_dialog.set_position (Gtk::WIN_POS_MOUSE);
|
||||
meter_dialog.signal_realize().connect (bind (sigc::ptr_fun (set_decoration), &meter_dialog, Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)));
|
||||
|
||||
//this causes compiz to display no border..
|
||||
//meter_dialog.signal_realize().connect (bind (sigc::ptr_fun (set_decoration), &meter_dialog, Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)));
|
||||
|
||||
ensure_float (meter_dialog);
|
||||
|
||||
|
@ -278,16 +281,16 @@ Editor::mouse_add_new_meter_event (nframes_t frame)
|
|||
|
||||
double note_type = meter_dialog.get_note_type ();
|
||||
BBT_Time requested;
|
||||
|
||||
|
||||
meter_dialog.get_bbt_time (requested);
|
||||
|
||||
|
||||
begin_reversible_command (_("add meter mark"));
|
||||
XMLNode &before = map.get_state();
|
||||
map.add_meter (Meter (bpb, note_type), requested);
|
||||
session->add_command(new MementoCommand<TempoMap>(map, &before, &map.get_state()));
|
||||
commit_reversible_command ();
|
||||
|
||||
map.dump (cerr);
|
||||
//map.dump (cerr);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -373,7 +373,7 @@ EngineControl::build_command_line (vector<string>& cmd)
|
|||
|
||||
str = timeout_combo.get_active_text ();
|
||||
if (str != _("Ignore")) {
|
||||
double secs;
|
||||
double secs = 0;
|
||||
uint32_t msecs;
|
||||
atof (str);
|
||||
msecs = (uint32_t) floor (secs * 1000.0);
|
||||
|
@ -819,7 +819,7 @@ EngineControl::driver_changed ()
|
|||
|
||||
vector<string>& strings = devices[driver];
|
||||
|
||||
if (strings.empty()) {
|
||||
if (strings.empty() && driver != "FFADO") {
|
||||
error << string_compose (_("No devices found for driver \"%1\""), driver) << endmsg;
|
||||
return;
|
||||
}
|
||||
|
@ -1096,7 +1096,7 @@ EngineControl::set_state (const XMLNode& root)
|
|||
XMLNodeList clist;
|
||||
XMLNodeConstIterator citer;
|
||||
XMLNode* child;
|
||||
XMLProperty* prop;
|
||||
XMLProperty* prop = NULL;
|
||||
bool using_dummy = false;
|
||||
|
||||
int val;
|
||||
|
@ -1112,7 +1112,8 @@ EngineControl::set_state (const XMLNode& root)
|
|||
clist = root.children();
|
||||
|
||||
for (citer = clist.begin(); citer != clist.end(); ++citer) {
|
||||
|
||||
if ( prop && (prop->value() == "FFADO" ))
|
||||
continue;
|
||||
child = *citer;
|
||||
|
||||
prop = child->property ("val");
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <ardour/plugin.h>
|
||||
#include <ardour/plugin_insert.h>
|
||||
#include <ardour/ladspa_plugin.h>
|
||||
#include <ardour/lv2_plugin.h>
|
||||
|
||||
#include <lrdf.h>
|
||||
|
||||
|
@ -384,6 +385,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr<Automat
|
|||
if (plugin->parameter_is_input (port_index)) {
|
||||
|
||||
boost::shared_ptr<LadspaPlugin> lp;
|
||||
boost::shared_ptr<LV2Plugin> lv2p;
|
||||
|
||||
if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) {
|
||||
|
||||
|
@ -406,6 +408,26 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr<Automat
|
|||
lrdf_free_setting_values(defaults);
|
||||
return control_ui;
|
||||
}
|
||||
|
||||
} else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin>(plugin)) != 0) {
|
||||
|
||||
SLV2Port port = lv2p->slv2_port(port_index);
|
||||
SLV2ScalePoints points = slv2_port_get_scale_points(lv2p->slv2_plugin(), port);
|
||||
|
||||
if (points) {
|
||||
control_ui->combo = new Gtk::ComboBoxText;
|
||||
//control_ui->combo->set_value_in_list(true, false);
|
||||
set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui));
|
||||
control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &GenericPluginUI::control_combo_changed), control_ui));
|
||||
mcontrol->Changed.connect (bind (mem_fun (*this, &GenericPluginUI::parameter_changed), control_ui));
|
||||
control_ui->pack_start(control_ui->label, true, true);
|
||||
control_ui->pack_start(*control_ui->combo, false, true);
|
||||
|
||||
update_control_display(control_ui);
|
||||
|
||||
slv2_scale_points_free(points);
|
||||
return control_ui;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc.toggled) {
|
||||
|
@ -734,26 +756,49 @@ vector<string>
|
|||
GenericPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui)
|
||||
{
|
||||
vector<string> enums;
|
||||
boost::shared_ptr<LadspaPlugin> lp = boost::dynamic_pointer_cast<LadspaPlugin> (plugin);
|
||||
boost::shared_ptr<LadspaPlugin> lp;
|
||||
boost::shared_ptr<LV2Plugin> lv2p;
|
||||
|
||||
cui->combo_map = new std::map<string, float>;
|
||||
|
||||
// FIXME: not all plugins have a numeric unique ID
|
||||
uint32_t id = atol (lp->unique_id().c_str());
|
||||
lrdf_defaults* defaults = lrdf_get_scale_values(id, port_index);
|
||||
if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) {
|
||||
// all LADPSA plugins have a numeric unique ID
|
||||
uint32_t id = atol (lp->unique_id().c_str());
|
||||
|
||||
if (defaults) {
|
||||
for (uint32_t i = 0; i < defaults->count; ++i) {
|
||||
enums.push_back(defaults->items[i].label);
|
||||
pair<string, float> newpair;
|
||||
newpair.first = defaults->items[i].label;
|
||||
newpair.second = defaults->items[i].value;
|
||||
cui->combo_map->insert(newpair);
|
||||
cui->combo_map = new std::map<string, float>;
|
||||
lrdf_defaults* defaults = lrdf_get_scale_values(id, port_index);
|
||||
if (defaults) {
|
||||
for (uint32_t i = 0; i < defaults->count; ++i) {
|
||||
enums.push_back(defaults->items[i].label);
|
||||
pair<string, float> newpair;
|
||||
newpair.first = defaults->items[i].label;
|
||||
newpair.second = defaults->items[i].value;
|
||||
cui->combo_map->insert(newpair);
|
||||
}
|
||||
|
||||
lrdf_free_setting_values(defaults);
|
||||
}
|
||||
|
||||
lrdf_free_setting_values(defaults);
|
||||
} else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin>(plugin)) != 0) {
|
||||
|
||||
SLV2Port port = lv2p->slv2_port(port_index);
|
||||
SLV2ScalePoints points = slv2_port_get_scale_points(lv2p->slv2_plugin(), port);
|
||||
cui->combo_map = new std::map<string, float>;
|
||||
|
||||
for (unsigned i=0; i < slv2_scale_points_size(points); ++i) {
|
||||
SLV2ScalePoint p = slv2_scale_points_get_at(points, i);
|
||||
SLV2Value label = slv2_scale_point_get_label(p);
|
||||
SLV2Value value = slv2_scale_point_get_value(p);
|
||||
if (label && (slv2_value_is_float(value) || slv2_value_is_int(value))) {
|
||||
enums.push_back(slv2_value_as_string(label));
|
||||
pair<string, float> newpair;
|
||||
newpair.first = slv2_value_as_string(label);
|
||||
newpair.second = slv2_value_as_float(value);
|
||||
cui->combo_map->insert(newpair);
|
||||
}
|
||||
}
|
||||
|
||||
slv2_scale_points_free(points);
|
||||
}
|
||||
|
||||
|
||||
return enums;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ GhostRegion::set_colors ()
|
|||
|
||||
for (uint32_t n=0; n < waves.size(); ++n) {
|
||||
waves[n]->property_wave_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWave.get();
|
||||
waves[n]->property_fill_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWave.get();
|
||||
|
||||
waves[n]->property_clip_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWaveClip.get();
|
||||
waves[n]->property_zero_color() = ARDOUR_UI::config()->canvasvar_GhostTrackZeroLine.get();
|
||||
|
|
|
@ -114,7 +114,7 @@ void
|
|||
LatencyGUI::change_latency_from_button (int dir)
|
||||
{
|
||||
Glib::ustring unitstr = units_combo.get_active_text();
|
||||
double shift;
|
||||
double shift = 0.0;
|
||||
|
||||
if (unitstr == unit_strings[0]) {
|
||||
shift = 1;
|
||||
|
|
|
@ -254,6 +254,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
|
|||
virtual void restore_editing_space () = 0;
|
||||
virtual nframes64_t get_preferred_edit_position (bool ignore_playhead = false) = 0;
|
||||
virtual void toggle_meter_updating() = 0;
|
||||
virtual void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, std::vector<nframes64_t>&) = 0;
|
||||
|
||||
#ifdef WITH_CMT
|
||||
virtual void add_imageframe_time_axis(const std::string & track_name, void*) = 0;
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
#include <gtkmm/stock.h>
|
||||
#include <gtkmm2ext/utils.h>
|
||||
|
||||
#include <pbd/memento_command.h>
|
||||
|
||||
#include <ardour/transient_detector.h>
|
||||
#include <ardour/audiosource.h>
|
||||
#include <ardour/audioregion.h>
|
||||
#include <ardour/playlist.h>
|
||||
#include <ardour/region_factory.h>
|
||||
#include <ardour/session.h>
|
||||
|
||||
#include "rhythm_ferret.h"
|
||||
#include "audio_region_view.h"
|
||||
#include "public_editor.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Gtk;
|
||||
using namespace Gdk;
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
|
||||
/* order of these must match the AnalysisMode enums
|
||||
in rhythm_ferret.h
|
||||
*/
|
||||
static const gchar * _analysis_mode_strings[] = {
|
||||
N_("Percussive Onset"),
|
||||
N_("Note Onset"),
|
||||
0
|
||||
};
|
||||
|
||||
RhythmFerret::RhythmFerret (PublicEditor& e)
|
||||
: ArdourDialog (_("Rhythm Ferret"))
|
||||
, editor (e)
|
||||
, operation_frame (_("Operation"))
|
||||
, selection_frame (_("Selection"))
|
||||
, ferret_frame (_("Analysis"))
|
||||
, logo (0)
|
||||
, region_split_button (operation_button_group, _("Split Region"))
|
||||
, tempo_button (operation_button_group, _("Set Tempo Map"))
|
||||
, region_conform_button (operation_button_group, _("Conform Region"))
|
||||
, analysis_mode_label (_("Mode"))
|
||||
, detection_threshold_adjustment (3, 0, 20, 1, 4)
|
||||
, detection_threshold_scale (detection_threshold_adjustment)
|
||||
, detection_threshold_label (_("Threshold"))
|
||||
, sensitivity_adjustment (40, 0, 100, 1, 10)
|
||||
, sensitivity_scale (sensitivity_adjustment)
|
||||
, sensitivity_label (_("Sensitivity"))
|
||||
, analyze_button (_("Analyze"))
|
||||
, trigger_gap_adjustment (3, 0, 100, 1, 10)
|
||||
, trigger_gap_spinner (trigger_gap_adjustment)
|
||||
, trigger_gap_label (_("Trigger gap (msecs)"))
|
||||
, action_button (Stock::APPLY)
|
||||
|
||||
{
|
||||
upper_hpacker.set_spacing (6);
|
||||
|
||||
upper_hpacker.pack_start (operation_frame, true, true);
|
||||
upper_hpacker.pack_start (selection_frame, true, true);
|
||||
upper_hpacker.pack_start (ferret_frame, true, true);
|
||||
|
||||
op_packer.pack_start (region_split_button, false, false);
|
||||
op_packer.pack_start (tempo_button, false, false);
|
||||
op_packer.pack_start (region_conform_button, false, false);
|
||||
|
||||
operation_frame.add (op_packer);
|
||||
|
||||
HBox* box;
|
||||
|
||||
ferret_packer.set_spacing (6);
|
||||
ferret_packer.set_border_width (6);
|
||||
|
||||
vector<string> strings;
|
||||
|
||||
analysis_mode_strings = I18N (_analysis_mode_strings);
|
||||
Gtkmm2ext::set_popdown_strings (analysis_mode_selector, analysis_mode_strings);
|
||||
analysis_mode_selector.set_active_text (analysis_mode_strings.front());
|
||||
|
||||
box = manage (new HBox);
|
||||
box->set_spacing (6);
|
||||
box->pack_start (analysis_mode_label, false, false);
|
||||
box->pack_start (analysis_mode_selector, true, true);
|
||||
ferret_packer.pack_start (*box, false, false);
|
||||
|
||||
box = manage (new HBox);
|
||||
box->set_spacing (6);
|
||||
box->pack_start (detection_threshold_label, false, false);
|
||||
box->pack_start (detection_threshold_scale, true, true);
|
||||
ferret_packer.pack_start (*box, false, false);
|
||||
|
||||
box = manage (new HBox);
|
||||
box->set_spacing (6);
|
||||
box->pack_start (sensitivity_label, false, false);
|
||||
box->pack_start (sensitivity_scale, true, true);
|
||||
ferret_packer.pack_start (*box, false, false);
|
||||
|
||||
box = manage (new HBox);
|
||||
box->set_spacing (6);
|
||||
box->pack_start (trigger_gap_label, false, false);
|
||||
box->pack_start (trigger_gap_spinner, false, false);
|
||||
ferret_packer.pack_start (*box, false, false);
|
||||
|
||||
ferret_packer.pack_start (analyze_button, false, false);
|
||||
|
||||
analyze_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::run_analysis));
|
||||
|
||||
ferret_frame.add (ferret_packer);
|
||||
|
||||
// Glib::RefPtr<Pixbuf> logo_pixbuf ("somefile");
|
||||
|
||||
if (logo) {
|
||||
lower_hpacker.pack_start (*logo, false, false);
|
||||
}
|
||||
|
||||
lower_hpacker.pack_start (operation_clarification_label, false, false);
|
||||
lower_hpacker.pack_start (action_button, false, false);
|
||||
|
||||
action_button.signal_clicked().connect (mem_fun (*this, &RhythmFerret::do_action));
|
||||
|
||||
get_vbox()->set_border_width (6);
|
||||
get_vbox()->set_spacing (6);
|
||||
get_vbox()->pack_start (upper_hpacker, true, true);
|
||||
get_vbox()->pack_start (lower_hpacker, false, false);
|
||||
|
||||
show_all ();
|
||||
}
|
||||
|
||||
RhythmFerret::~RhythmFerret()
|
||||
{
|
||||
if (logo) {
|
||||
delete logo;
|
||||
}
|
||||
}
|
||||
|
||||
RhythmFerret::AnalysisMode
|
||||
RhythmFerret::get_analysis_mode () const
|
||||
{
|
||||
string str = analysis_mode_selector.get_active_text ();
|
||||
|
||||
if (str == _(_analysis_mode_strings[(int) NoteOnset])) {
|
||||
return NoteOnset;
|
||||
}
|
||||
|
||||
return PercussionOnset;
|
||||
}
|
||||
|
||||
RhythmFerret::Action
|
||||
RhythmFerret::get_action () const
|
||||
{
|
||||
if (tempo_button.get_active()) {
|
||||
return DefineTempoMap;
|
||||
} else if (region_conform_button.get_active()) {
|
||||
return ConformRegion;
|
||||
}
|
||||
|
||||
return SplitRegion;
|
||||
}
|
||||
|
||||
void
|
||||
RhythmFerret::run_analysis ()
|
||||
{
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
|
||||
RegionSelection& regions (editor.get_selection().regions);
|
||||
|
||||
current_results.clear ();
|
||||
|
||||
if (regions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
|
||||
boost::shared_ptr<Readable> rd = boost::static_pointer_cast<AudioRegion> ((*i)->region());
|
||||
|
||||
switch (get_analysis_mode()) {
|
||||
case PercussionOnset:
|
||||
run_percussion_onset_analysis (rd, (*i)->region()->position(), current_results);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
(*i)->get_time_axis_view().show_temporary_lines (current_results);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr<Readable> readable, nframes64_t offset, vector<nframes64_t>& results)
|
||||
{
|
||||
TransientDetector t (session->frame_rate());
|
||||
|
||||
for (uint32_t i = 0; i < readable->n_channels(); ++i) {
|
||||
|
||||
vector<nframes64_t> these_results;
|
||||
|
||||
t.reset ();
|
||||
t.set_threshold (detection_threshold_adjustment.get_value());
|
||||
t.set_sensitivity (sensitivity_adjustment.get_value());
|
||||
|
||||
if (t.run ("", readable.get(), i, these_results)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* translate all transients to give absolute position */
|
||||
|
||||
for (vector<nframes64_t>::iterator i = these_results.begin(); i != these_results.end(); ++i) {
|
||||
(*i) += offset;
|
||||
}
|
||||
|
||||
/* merge */
|
||||
|
||||
results.insert (results.end(), these_results.begin(), these_results.end());
|
||||
}
|
||||
|
||||
if (!results.empty()) {
|
||||
|
||||
/* now resort to bring transients from different channels together */
|
||||
|
||||
sort (results.begin(), results.end());
|
||||
|
||||
/* remove duplicates or other things that are too close */
|
||||
|
||||
vector<nframes64_t>::iterator i = results.begin();
|
||||
nframes64_t curr = (*i);
|
||||
nframes64_t gap_frames = (nframes64_t) floor (trigger_gap_adjustment.get_value() * (session->frame_rate() / 1000.0));
|
||||
|
||||
++i;
|
||||
|
||||
while (i != results.end()) {
|
||||
if (((*i) == curr) || (((*i) - curr) < gap_frames)) {
|
||||
i = results.erase (i);
|
||||
} else {
|
||||
++i;
|
||||
curr = *i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
RhythmFerret::do_action ()
|
||||
{
|
||||
if (!session || current_results.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (get_action()) {
|
||||
case SplitRegion:
|
||||
do_split_action ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RhythmFerret::do_split_action ()
|
||||
{
|
||||
/* this can/will change the current selection, so work with a copy */
|
||||
|
||||
RegionSelection& regions (editor.get_selection().regions);
|
||||
|
||||
if (regions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
session->begin_reversible_command (_("split regions (rhythm ferret)"));
|
||||
|
||||
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ) {
|
||||
|
||||
RegionSelection::iterator tmp;
|
||||
|
||||
tmp = i;
|
||||
++tmp;
|
||||
|
||||
(*i)->get_time_axis_view().hide_temporary_lines ();
|
||||
|
||||
editor.split_region_at_points ((*i)->region(), current_results);
|
||||
|
||||
/* i is invalid at this point */
|
||||
|
||||
i = tmp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
RhythmFerret::set_session (Session* s)
|
||||
{
|
||||
ArdourDialog::set_session (s);
|
||||
current_results.clear ();
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
#ifndef __gtk2_ardour_rhythm_ferret_h__
|
||||
#define __gtk2_ardour_rhythm_ferret_h__
|
||||
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/scale.h>
|
||||
#include <gtkmm/spinbutton.h>
|
||||
#include <gtkmm/radiobutton.h>
|
||||
#include <gtkmm/radiobuttongroup.h>
|
||||
#include <gtkmm/frame.h>
|
||||
#include <gtkmm/image.h>
|
||||
#include <gtkmm/comboboxtext.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/label.h>
|
||||
|
||||
#include "ardour_dialog.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class Readable;
|
||||
}
|
||||
|
||||
class PublicEditor;
|
||||
class RegionView;
|
||||
|
||||
class RhythmFerret : public ArdourDialog {
|
||||
public:
|
||||
/* order of these enums must match the _analyse_mode_strings
|
||||
in rhythm_ferret.cc
|
||||
*/
|
||||
enum AnalysisMode {
|
||||
PercussionOnset,
|
||||
NoteOnset
|
||||
};
|
||||
|
||||
enum Action {
|
||||
SplitRegion,
|
||||
DefineTempoMap,
|
||||
ConformRegion
|
||||
};
|
||||
|
||||
RhythmFerret (PublicEditor&);
|
||||
~RhythmFerret ();
|
||||
|
||||
void set_session (ARDOUR::Session*);
|
||||
|
||||
private:
|
||||
PublicEditor& editor;
|
||||
|
||||
Gtk::HBox upper_hpacker;
|
||||
Gtk::HBox lower_hpacker;
|
||||
|
||||
Gtk::Frame operation_frame;
|
||||
Gtk::Frame selection_frame;
|
||||
Gtk::Frame ferret_frame;
|
||||
|
||||
Gtk::VBox op_logo_packer;
|
||||
Gtk::Image* logo;
|
||||
|
||||
/* operation frame */
|
||||
|
||||
Gtk::VBox op_packer;
|
||||
Gtk::RadioButtonGroup operation_button_group;
|
||||
Gtk::RadioButton region_split_button;
|
||||
Gtk::RadioButton tempo_button;
|
||||
Gtk::RadioButton region_conform_button;
|
||||
|
||||
/* analysis frame */
|
||||
|
||||
Gtk::VBox ferret_packer;
|
||||
Gtk::ComboBoxText analysis_mode_selector;
|
||||
Gtk::Label analysis_mode_label;
|
||||
Gtk::Adjustment detection_threshold_adjustment;
|
||||
Gtk::HScale detection_threshold_scale;
|
||||
Gtk::Label detection_threshold_label;
|
||||
Gtk::Adjustment sensitivity_adjustment;
|
||||
Gtk::HScale sensitivity_scale;
|
||||
Gtk::Label sensitivity_label;
|
||||
Gtk::Button analyze_button;
|
||||
Gtk::Adjustment trigger_gap_adjustment;
|
||||
Gtk::SpinButton trigger_gap_spinner;
|
||||
Gtk::Label trigger_gap_label;
|
||||
|
||||
Gtk::Label operation_clarification_label;
|
||||
Gtk::Button action_button;
|
||||
|
||||
std::vector<std::string> analysis_mode_strings;
|
||||
|
||||
std::vector<nframes64_t> current_results;
|
||||
|
||||
AnalysisMode get_analysis_mode () const;
|
||||
Action get_action() const;
|
||||
|
||||
void run_analysis ();
|
||||
int run_percussion_onset_analysis (boost::shared_ptr<ARDOUR::Readable> region, nframes64_t offset, std::vector<nframes64_t>& results);
|
||||
|
||||
void do_action ();
|
||||
void do_split_action ();
|
||||
void do_region_split (RegionView* rv, const std::vector<nframes64_t>&);
|
||||
};
|
||||
|
||||
#endif /* __gtk2_ardour_rhythm_ferret_h__ */
|
|
@ -29,14 +29,19 @@ Splash::Splash ()
|
|||
catch (...) {
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
|
||||
darea.set_size_request (pixbuf->get_width(), pixbuf->get_height());
|
||||
set_type_hint (Gdk::WINDOW_TYPE_HINT_SPLASHSCREEN);
|
||||
set_keep_above (true);
|
||||
set_position (WIN_POS_CENTER);
|
||||
darea.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
|
||||
|
||||
layout = create_pango_layout ("");
|
||||
string str = "<b>";
|
||||
string i18n = _("Ardour loading ...");
|
||||
str += i18n;
|
||||
str += "</b>";
|
||||
|
||||
layout->set_markup (str);
|
||||
|
||||
darea.show ();
|
||||
darea.signal_expose_event().connect (mem_fun (*this, &Splash::expose));
|
||||
|
@ -48,6 +53,7 @@ void
|
|||
Splash::on_realize ()
|
||||
{
|
||||
Window::on_realize ();
|
||||
get_window()->set_decorations (Gdk::WMDecoration(0));
|
||||
layout->set_font_description (get_style()->get_font());
|
||||
}
|
||||
|
||||
|
@ -62,21 +68,19 @@ Splash::on_button_release_event (GdkEventButton* ev)
|
|||
bool
|
||||
Splash::expose (GdkEventExpose* ev)
|
||||
{
|
||||
#if 0
|
||||
RefPtr<Gdk::Window> window = darea.get_window();
|
||||
|
||||
Glib::RefPtr<Gtk::Style> style = darea.get_style();
|
||||
|
||||
window->draw_pixbuf (darea.get_style()->get_bg_gc (STATE_NORMAL), pixbuf,
|
||||
window->draw_pixbuf (get_style()->get_bg_gc (STATE_NORMAL), pixbuf,
|
||||
ev->area.x, ev->area.y,
|
||||
ev->area.x, ev->area.y,
|
||||
ev->area.width, ev->area.height,
|
||||
Gdk::RGB_DITHER_NONE, 0, 0);
|
||||
|
||||
Glib::RefPtr<Gtk::Style> style = darea.get_style();
|
||||
Glib::RefPtr<Gdk::GC> white = style->get_white_gc();
|
||||
|
||||
window->draw_layout (white, 10, pixbuf->get_height() - 30, layout);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,12 +36,11 @@ TempoDialog::TempoDialog (TempoMap& map, nframes_t frame, const string & action)
|
|||
: ArdourDialog (_("edit tempo")),
|
||||
bpm_adjustment (60.0, 1.0, 999.9, 0.1, 1.0, 1.0),
|
||||
bpm_spinner (bpm_adjustment),
|
||||
bpm_frame (_("Beats per minute")),
|
||||
note_frame (_("BPM denominator")),
|
||||
bpm_frame (_("Tempo")),
|
||||
ok_button (action),
|
||||
cancel_button (_("Cancel")),
|
||||
when_bar_label (_("Bar")),
|
||||
when_beat_label (_("Beat")),
|
||||
when_bar_label (_("Bar"), ALIGN_LEFT, ALIGN_CENTER),
|
||||
when_beat_label (_("Beat"), ALIGN_LEFT, ALIGN_CENTER),
|
||||
when_table (2, 2),
|
||||
when_frame (_("Location"))
|
||||
{
|
||||
|
@ -56,11 +55,11 @@ TempoDialog::TempoDialog (TempoSection& section, const string & action)
|
|||
: ArdourDialog ("tempo dialog"),
|
||||
bpm_adjustment (60.0, 1.0, 999.9, 0.1, 1.0, 1.0),
|
||||
bpm_spinner (bpm_adjustment),
|
||||
bpm_frame (_("Beats per minute")),
|
||||
bpm_frame (_("Tempo")),
|
||||
ok_button (action),
|
||||
cancel_button (_("Cancel")),
|
||||
when_bar_label (_("Bar")),
|
||||
when_beat_label (_("Beat")),
|
||||
when_bar_label (_("Bar"), ALIGN_LEFT, ALIGN_CENTER),
|
||||
when_beat_label (_("Beat"), ALIGN_LEFT, ALIGN_CENTER),
|
||||
when_table (2, 2),
|
||||
when_frame (_("Location"))
|
||||
{
|
||||
|
@ -108,18 +107,18 @@ TempoDialog::init (const BBT_Time& when, double bpm, double note_type, bool mova
|
|||
else
|
||||
note_types.set_active_text (_("quarter (4)"));
|
||||
|
||||
hspacer1.set_border_width (5);
|
||||
hspacer1.pack_start (bpm_spinner, false, false);
|
||||
vspacer1.set_border_width (5);
|
||||
vspacer1.pack_start (hspacer1, false, false);
|
||||
Label* bpm_label = manage(new Label(_("Beats Per Minute:"), ALIGN_LEFT, ALIGN_CENTER));
|
||||
|
||||
hspacer2.set_border_width (5);
|
||||
hspacer2.pack_start (note_types, false, false);
|
||||
vspacer2.set_border_width (5);
|
||||
vspacer2.pack_start (hspacer2, false, false);
|
||||
hspacer1.set_border_width (6);
|
||||
hspacer1.pack_end (bpm_spinner, PACK_EXPAND_PADDING);
|
||||
hspacer1.pack_start (*bpm_label, PACK_EXPAND_PADDING);
|
||||
vspacer1.set_border_width (6);
|
||||
vspacer1.pack_start (hspacer1, PACK_EXPAND_PADDING);
|
||||
|
||||
hspacer2.set_border_width (6);
|
||||
hspacer2.pack_start (note_types, PACK_EXPAND_PADDING);
|
||||
|
||||
bpm_frame.add (vspacer1);
|
||||
note_frame.add (vspacer2);
|
||||
|
||||
if (movable) {
|
||||
snprintf (buf, sizeof (buf), "%" PRIu32, when.bars);
|
||||
|
@ -139,35 +138,40 @@ TempoDialog::init (const BBT_Time& when, double bpm, double note_type, bool mova
|
|||
when_table.set_homogeneous (true);
|
||||
when_table.set_row_spacings (2);
|
||||
when_table.set_col_spacings (2);
|
||||
when_table.set_border_width (5);
|
||||
when_table.set_border_width (6);
|
||||
|
||||
when_table.attach (when_bar_label, 0, 1, 0, 1, Gtk::AttachOptions(0), Gtk::FILL|Gtk::EXPAND);
|
||||
when_table.attach (when_bar_entry, 0, 1, 1, 2, Gtk::AttachOptions(0), Gtk::FILL|Gtk::EXPAND);
|
||||
when_table.attach (when_bar_label, 0, 1, 0, 1, AttachOptions(0), FILL|EXPAND);
|
||||
when_table.attach (when_bar_entry, 1, 2, 0, 1, AttachOptions(0), FILL|EXPAND);
|
||||
|
||||
when_table.attach (when_beat_label, 1, 2, 0, 1, Gtk::AttachOptions(0), Gtk::AttachOptions(0));
|
||||
when_table.attach (when_beat_entry, 1, 2, 1, 2, Gtk::AttachOptions(0), Gtk::AttachOptions(0));
|
||||
when_table.attach (when_beat_label, 0, 1, 1, 2, AttachOptions(0), AttachOptions(0));
|
||||
when_table.attach (when_beat_entry, 1, 2, 1, 2, AttachOptions(0), AttachOptions(0));
|
||||
|
||||
when_frame.set_name ("MetricDialogFrame");
|
||||
when_frame.add (when_table);
|
||||
HBox* when_hbox = manage (new HBox());
|
||||
Label* when_label = manage(new Label(_("Tempo Begins at:"), ALIGN_LEFT, ALIGN_TOP));
|
||||
when_hbox->pack_end(when_table, PACK_EXPAND_PADDING, 6);
|
||||
when_hbox->pack_start(*when_label, PACK_EXPAND_PADDING, 6);
|
||||
|
||||
when_frame.set_name ("MetricDialogFrame");
|
||||
when_frame.add (*when_hbox);
|
||||
|
||||
get_vbox()->pack_end (when_frame, false, false);
|
||||
when_frame.show_all();
|
||||
|
||||
get_vbox()->pack_start (when_frame, false, false);
|
||||
}
|
||||
|
||||
bpm_frame.set_name ("MetricDialogFrame");
|
||||
bpm_spinner.set_name ("MetricEntry");
|
||||
note_frame.set_name ("MetricDialogFrame");
|
||||
|
||||
get_vbox()->set_border_width (12);
|
||||
get_vbox()->pack_start (bpm_frame, false, false);
|
||||
get_vbox()->pack_start (note_frame, false, false);
|
||||
get_vbox()->pack_end (bpm_frame, false, false);
|
||||
|
||||
add_button (Stock::CANCEL, RESPONSE_CANCEL);
|
||||
add_button (Stock::APPLY, RESPONSE_ACCEPT);
|
||||
set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
|
||||
set_response_sensitive (RESPONSE_ACCEPT, false);
|
||||
set_default_response (RESPONSE_ACCEPT);
|
||||
|
||||
get_vbox()->show_all();
|
||||
bpm_spinner.show();
|
||||
bpm_frame.show_all ();
|
||||
bpm_spinner.show ();
|
||||
|
||||
set_name ("MetricDialog");
|
||||
|
||||
|
@ -188,7 +192,7 @@ TempoDialog::bpm_button_release (GdkEventButton* ev)
|
|||
{
|
||||
/* the value has been modified, accept should work now */
|
||||
|
||||
set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
|
||||
set_response_sensitive (RESPONSE_ACCEPT, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -209,6 +213,8 @@ TempoDialog::get_bbt_time (BBT_Time& requested)
|
|||
return false;
|
||||
}
|
||||
|
||||
requested.ticks = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -244,18 +250,17 @@ TempoDialog::get_note_type ()
|
|||
void
|
||||
TempoDialog::note_types_change ()
|
||||
{
|
||||
set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
|
||||
set_response_sensitive (RESPONSE_ACCEPT, true);
|
||||
}
|
||||
|
||||
|
||||
MeterDialog::MeterDialog (TempoMap& map, nframes_t frame, const string & action)
|
||||
: ArdourDialog ("meter dialog"),
|
||||
note_frame (_("Meter denominator")),
|
||||
bpb_frame (_("Beats per bar")),
|
||||
bpb_frame (_("Meter")),
|
||||
ok_button (action),
|
||||
cancel_button (_("Cancel")),
|
||||
when_bar_label (_("Bar")),
|
||||
when_beat_label (_("Beat")),
|
||||
when_bar_label (_("Bar"), ALIGN_LEFT, ALIGN_CENTER),
|
||||
when_beat_label (_("Beat"), ALIGN_LEFT, ALIGN_CENTER),
|
||||
when_frame (_("Location"))
|
||||
{
|
||||
BBT_Time when;
|
||||
|
@ -268,12 +273,11 @@ MeterDialog::MeterDialog (TempoMap& map, nframes_t frame, const string & action)
|
|||
|
||||
MeterDialog::MeterDialog (MeterSection& section, const string & action)
|
||||
: ArdourDialog ("meter dialog"),
|
||||
note_frame (_("Meter denominator")),
|
||||
bpb_frame (_("Beats per bar")),
|
||||
bpb_frame (_("Meter")),
|
||||
ok_button (action),
|
||||
cancel_button (_("Cancel")),
|
||||
when_bar_label (_("Bar")),
|
||||
when_beat_label (_("Beat")),
|
||||
when_bar_label (_("Bar"), ALIGN_LEFT, ALIGN_CENTER),
|
||||
when_beat_label (_("Beat"), ALIGN_LEFT, ALIGN_CENTER),
|
||||
when_frame (_("Location"))
|
||||
{
|
||||
init (section.start(), section.beats_per_bar(), section.note_divisor(), section.movable());
|
||||
|
@ -320,19 +324,16 @@ MeterDialog::init (const BBT_Time& when, double bpb, double note_type, bool mova
|
|||
note_types.set_active_text (_("thirty-second (32)"));
|
||||
else
|
||||
note_types.set_active_text (_("quarter (4)"));
|
||||
|
||||
hspacer1.set_border_width (5);
|
||||
hspacer1.pack_start (note_types, false, false);
|
||||
vspacer1.set_border_width (5);
|
||||
vspacer1.pack_start (hspacer1, false, false);
|
||||
|
||||
hspacer2.set_border_width (5);
|
||||
hspacer2.pack_start (bpb_entry, false, false);
|
||||
vspacer2.set_border_width (5);
|
||||
vspacer2.pack_start (hspacer2, false, false);
|
||||
Label* note_label = manage(new Label(_("Note Value:"), ALIGN_LEFT, ALIGN_CENTER));
|
||||
Label* bpb_label = manage(new Label(_("Beats Per Bar:"), ALIGN_LEFT, ALIGN_CENTER));
|
||||
Table* bpb_table = manage (new Table(2, 2));
|
||||
|
||||
note_frame.add (vspacer1);
|
||||
bpb_frame.add (vspacer2);
|
||||
bpb_table->attach (*bpb_label, 0, 1, 0, 1, FILL|EXPAND, FILL|EXPAND, 6, 6);
|
||||
bpb_table->attach (bpb_entry, 1, 2, 0, 1, FILL|EXPAND, FILL|EXPAND, 6, 6);
|
||||
bpb_table->attach (*note_label, 0, 1, 1, 2, FILL|EXPAND, FILL|EXPAND, 6, 6);
|
||||
bpb_table->attach (note_types, 1, 2, 1, 2, FILL|EXPAND, SHRINK, 6, 6);
|
||||
bpb_frame.add (*bpb_table);
|
||||
|
||||
if (movable) {
|
||||
snprintf (buf, sizeof (buf), "%" PRIu32, when.bars);
|
||||
|
@ -352,26 +353,29 @@ MeterDialog::init (const BBT_Time& when, double bpb, double note_type, bool mova
|
|||
when_table.set_homogeneous (true);
|
||||
when_table.set_row_spacings (2);
|
||||
when_table.set_col_spacings (2);
|
||||
when_table.set_border_width (5);
|
||||
when_table.set_border_width (6);
|
||||
|
||||
when_table.attach (when_bar_label, 0, 1, 0, 1, Gtk::AttachOptions(0), Gtk::FILL|Gtk::EXPAND);
|
||||
when_table.attach (when_bar_entry, 0, 1, 1, 2, Gtk::AttachOptions(0), Gtk::FILL|Gtk::EXPAND);
|
||||
|
||||
when_table.attach (when_beat_label, 1, 2, 0, 1, Gtk::AttachOptions(0), Gtk::AttachOptions(0));
|
||||
when_table.attach (when_beat_entry, 1, 2, 1, 2, Gtk::AttachOptions(0), Gtk::AttachOptions(0));
|
||||
when_table.attach (when_bar_label, 0, 1, 0, 1, AttachOptions(0), FILL|EXPAND);
|
||||
when_table.attach (when_bar_entry, 1, 2, 0, 1, AttachOptions(0), FILL|EXPAND);
|
||||
|
||||
when_table.attach (when_beat_label, 0, 1, 1, 2, AttachOptions(0), AttachOptions(0));
|
||||
when_table.attach (when_beat_entry, 1, 2, 1, 2, AttachOptions(0), AttachOptions(0));
|
||||
|
||||
HBox* when_hbox = manage (new HBox());
|
||||
Label* when_label = manage(new Label(_("Meter Begins at:"), ALIGN_LEFT, ALIGN_TOP));
|
||||
when_hbox->pack_end(when_table, PACK_EXPAND_PADDING, 6);
|
||||
when_hbox->pack_start(*when_label, PACK_EXPAND_PADDING, 6);
|
||||
|
||||
when_frame.set_name ("MetricDialogFrame");
|
||||
when_frame.add (when_table);
|
||||
when_frame.add (*when_hbox);
|
||||
|
||||
get_vbox()->pack_start (when_frame, false, false);
|
||||
get_vbox()->pack_end (when_frame, false, false);
|
||||
}
|
||||
|
||||
get_vbox()->set_border_width (12);
|
||||
get_vbox()->pack_start (bpb_frame, false, false);
|
||||
get_vbox()->pack_start (note_frame, false, false);
|
||||
|
||||
|
||||
bpb_frame.set_name ("MetricDialogFrame");
|
||||
note_frame.set_name ("MetricDialogFrame");
|
||||
bpb_entry.set_name ("MetricEntry");
|
||||
|
||||
add_button (Stock::CANCEL, RESPONSE_CANCEL);
|
||||
|
@ -380,7 +384,6 @@ MeterDialog::init (const BBT_Time& when, double bpb, double note_type, bool mova
|
|||
set_default_response (RESPONSE_ACCEPT);
|
||||
|
||||
get_vbox()->show_all ();
|
||||
bpb_entry.show ();
|
||||
|
||||
set_name ("MetricDialog");
|
||||
bpb_entry.signal_activate().connect (bind (mem_fun (*this, &MeterDialog::response), RESPONSE_ACCEPT));
|
||||
|
@ -393,48 +396,48 @@ bool
|
|||
MeterDialog::bpb_key_press (GdkEventKey* ev)
|
||||
{
|
||||
|
||||
switch (ev->keyval) {
|
||||
switch (ev->keyval) {
|
||||
|
||||
case GDK_0:
|
||||
case GDK_1:
|
||||
case GDK_2:
|
||||
case GDK_3:
|
||||
case GDK_4:
|
||||
case GDK_5:
|
||||
case GDK_6:
|
||||
case GDK_7:
|
||||
case GDK_8:
|
||||
case GDK_9:
|
||||
case GDK_KP_0:
|
||||
case GDK_KP_1:
|
||||
case GDK_KP_2:
|
||||
case GDK_KP_3:
|
||||
case GDK_KP_4:
|
||||
case GDK_KP_5:
|
||||
case GDK_KP_6:
|
||||
case GDK_KP_7:
|
||||
case GDK_KP_8:
|
||||
case GDK_KP_9:
|
||||
case GDK_period:
|
||||
case GDK_comma:
|
||||
case GDK_KP_Delete:
|
||||
case GDK_KP_Enter:
|
||||
case GDK_Delete:
|
||||
case GDK_BackSpace:
|
||||
case GDK_Escape:
|
||||
case GDK_Return:
|
||||
case GDK_Home:
|
||||
case GDK_End:
|
||||
case GDK_Left:
|
||||
case GDK_Right:
|
||||
case GDK_Num_Lock:
|
||||
case GDK_Tab:
|
||||
return FALSE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case GDK_0:
|
||||
case GDK_1:
|
||||
case GDK_2:
|
||||
case GDK_3:
|
||||
case GDK_4:
|
||||
case GDK_5:
|
||||
case GDK_6:
|
||||
case GDK_7:
|
||||
case GDK_8:
|
||||
case GDK_9:
|
||||
case GDK_KP_0:
|
||||
case GDK_KP_1:
|
||||
case GDK_KP_2:
|
||||
case GDK_KP_3:
|
||||
case GDK_KP_4:
|
||||
case GDK_KP_5:
|
||||
case GDK_KP_6:
|
||||
case GDK_KP_7:
|
||||
case GDK_KP_8:
|
||||
case GDK_KP_9:
|
||||
case GDK_period:
|
||||
case GDK_comma:
|
||||
case GDK_KP_Delete:
|
||||
case GDK_KP_Enter:
|
||||
case GDK_Delete:
|
||||
case GDK_BackSpace:
|
||||
case GDK_Escape:
|
||||
case GDK_Return:
|
||||
case GDK_Home:
|
||||
case GDK_End:
|
||||
case GDK_Left:
|
||||
case GDK_Right:
|
||||
case GDK_Num_Lock:
|
||||
case GDK_Tab:
|
||||
return FALSE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -451,7 +454,7 @@ MeterDialog::bpb_key_release (GdkEventKey* ev)
|
|||
void
|
||||
MeterDialog::note_types_change ()
|
||||
{
|
||||
set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
|
||||
set_response_sensitive (RESPONSE_ACCEPT, true);
|
||||
}
|
||||
|
||||
double
|
||||
|
@ -497,7 +500,6 @@ MeterDialog::get_note_type ()
|
|||
bool
|
||||
MeterDialog::get_bbt_time (BBT_Time& requested)
|
||||
{
|
||||
requested.ticks = 0;
|
||||
|
||||
if (sscanf (when_bar_entry.get_text().c_str(), "%" PRIu32, &requested.bars) != 1) {
|
||||
return false;
|
||||
|
@ -507,5 +509,7 @@ MeterDialog::get_bbt_time (BBT_Time& requested)
|
|||
return false;
|
||||
}
|
||||
|
||||
requested.ticks = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,74 +37,66 @@
|
|||
|
||||
struct TempoDialog : public ArdourDialog
|
||||
{
|
||||
Gtk::ComboBoxText note_types;
|
||||
vector<string> strings;
|
||||
Gtk::Adjustment bpm_adjustment;
|
||||
Gtk::SpinButton bpm_spinner;
|
||||
Gtk::Frame bpm_frame;
|
||||
Gtk::Frame note_frame;
|
||||
Gtk::VBox vpacker;
|
||||
Gtk::Button ok_button;
|
||||
Gtk::Button cancel_button;
|
||||
Gtk::HBox button_box;
|
||||
Gtk::HBox hspacer1, hspacer2;
|
||||
Gtk::VBox vspacer1, vspacer2;
|
||||
Gtk::Entry when_bar_entry;
|
||||
Gtk::Entry when_beat_entry;
|
||||
Gtk::Label when_bar_label;
|
||||
Gtk::Label when_beat_label;
|
||||
Gtk::Table when_table;
|
||||
Gtk::Frame when_frame;
|
||||
char buf[64];
|
||||
Gtk::ComboBoxText note_types;
|
||||
vector<string> strings;
|
||||
Gtk::Adjustment bpm_adjustment;
|
||||
Gtk::SpinButton bpm_spinner;
|
||||
Gtk::Frame bpm_frame;
|
||||
Gtk::Button ok_button;
|
||||
Gtk::Button cancel_button;
|
||||
Gtk::HBox hspacer1, hspacer2;
|
||||
Gtk::VBox vspacer1;
|
||||
Gtk::Entry when_bar_entry;
|
||||
Gtk::Entry when_beat_entry;
|
||||
Gtk::Label when_bar_label;
|
||||
Gtk::Label when_beat_label;
|
||||
Gtk::Table when_table;
|
||||
Gtk::Frame when_frame;
|
||||
char buf[64];
|
||||
|
||||
TempoDialog (ARDOUR::TempoMap&, nframes_t, const string & action);
|
||||
TempoDialog (ARDOUR::TempoSection&, const string & action);
|
||||
TempoDialog (ARDOUR::TempoMap&, nframes_t, const string & action);
|
||||
TempoDialog (ARDOUR::TempoSection&, const string & action);
|
||||
|
||||
double get_bpm ();
|
||||
double get_note_type ();
|
||||
bool get_bbt_time (ARDOUR::BBT_Time&);
|
||||
double get_bpm ();
|
||||
double get_note_type ();
|
||||
bool get_bbt_time (ARDOUR::BBT_Time&);
|
||||
|
||||
private:
|
||||
void init (const ARDOUR::BBT_Time& start, double, double, bool);
|
||||
void bpm_changed ();
|
||||
bool bpm_button_press (GdkEventButton* );
|
||||
bool bpm_button_release (GdkEventButton* );
|
||||
void note_types_change ();
|
||||
private:
|
||||
void init (const ARDOUR::BBT_Time& start, double, double, bool);
|
||||
void bpm_changed ();
|
||||
bool bpm_button_press (GdkEventButton* );
|
||||
bool bpm_button_release (GdkEventButton* );
|
||||
void note_types_change ();
|
||||
};
|
||||
|
||||
struct MeterDialog : public ArdourDialog
|
||||
{
|
||||
Gtk::Entry bpb_entry;
|
||||
Gtk::ComboBoxText note_types;
|
||||
vector<string> strings;
|
||||
Gtk::Frame note_frame;
|
||||
Gtk::Frame bpb_frame;
|
||||
Gtk::VBox vpacker;
|
||||
Gtk::Button ok_button;
|
||||
Gtk::Button cancel_button;
|
||||
Gtk::HBox button_box;
|
||||
Gtk::HBox hspacer1, hspacer2;
|
||||
Gtk::VBox vspacer1, vspacer2;
|
||||
Gtk::Entry when_bar_entry;
|
||||
Gtk::Entry when_beat_entry;
|
||||
Gtk::Label when_bar_label;
|
||||
Gtk::Label when_beat_label;
|
||||
Gtk::Table when_table;
|
||||
Gtk::Frame when_frame;
|
||||
char buf[64];
|
||||
Gtk::Entry bpb_entry;
|
||||
Gtk::ComboBoxText note_types;
|
||||
vector<string> strings;
|
||||
Gtk::Frame bpb_frame;
|
||||
Gtk::Button ok_button;
|
||||
Gtk::Button cancel_button;
|
||||
Gtk::Entry when_bar_entry;
|
||||
Gtk::Entry when_beat_entry;
|
||||
Gtk::Label when_bar_label;
|
||||
Gtk::Label when_beat_label;
|
||||
Gtk::Table when_table;
|
||||
Gtk::Frame when_frame;
|
||||
char buf[64];
|
||||
|
||||
MeterDialog (ARDOUR::TempoMap&, nframes_t, const string & action);
|
||||
MeterDialog (ARDOUR::MeterSection&, const string & action);
|
||||
MeterDialog (ARDOUR::TempoMap&, nframes_t, const string & action);
|
||||
MeterDialog (ARDOUR::MeterSection&, const string & action);
|
||||
|
||||
double get_bpb ();
|
||||
double get_note_type ();
|
||||
bool get_bbt_time (ARDOUR::BBT_Time&);
|
||||
double get_bpb ();
|
||||
double get_note_type ();
|
||||
bool get_bbt_time (ARDOUR::BBT_Time&);
|
||||
|
||||
private:
|
||||
void init (const ARDOUR::BBT_Time&, double, double, bool);
|
||||
bool bpb_key_press (GdkEventKey* );
|
||||
bool bpb_key_release (GdkEventKey* );
|
||||
void note_types_change ();
|
||||
private:
|
||||
void init (const ARDOUR::BBT_Time&, double, double, bool);
|
||||
bool bpb_key_press (GdkEventKey* );
|
||||
bool bpb_key_release (GdkEventKey* );
|
||||
void note_types_change ();
|
||||
};
|
||||
|
||||
#endif /* __ardour_gtk_tempo_dialog_h__ */
|
||||
|
|
|
@ -50,7 +50,8 @@ sigc::signal<void,uint32_t> ColorChanged;
|
|||
ThemeManager::ThemeManager()
|
||||
: ArdourDialog ("ThemeManager"),
|
||||
dark_button ("Dark Theme"),
|
||||
light_button ("Light Theme")
|
||||
light_button ("Light Theme"),
|
||||
reset_button ("Restore Defaults")
|
||||
{
|
||||
Gtkmm2ext::WindowTitle title (Glib::get_application_name ());
|
||||
title += _("Theme Manager");
|
||||
|
@ -81,6 +82,7 @@ ThemeManager::ThemeManager()
|
|||
|
||||
get_vbox()->set_homogeneous(false);
|
||||
get_vbox()->pack_start (theme_selection_hbox, PACK_SHRINK);
|
||||
get_vbox()->pack_start (reset_button, PACK_SHRINK);
|
||||
get_vbox()->pack_start (scroller);
|
||||
|
||||
color_display.signal_button_press_event().connect (mem_fun (*this, &ThemeManager::button_press_event), false);
|
||||
|
@ -92,6 +94,7 @@ ThemeManager::ThemeManager()
|
|||
color_dialog.get_cancel_button()->signal_clicked().connect (bind (mem_fun (color_dialog, &Gtk::Dialog::response), RESPONSE_CANCEL));
|
||||
dark_button.signal_toggled().connect (mem_fun (*this, &ThemeManager::on_dark_theme_button_toggled));
|
||||
light_button.signal_toggled().connect (mem_fun (*this, &ThemeManager::on_light_theme_button_toggled));
|
||||
reset_button.signal_clicked().connect (mem_fun (*this, &ThemeManager::reset_canvas_colors));
|
||||
|
||||
set_size_request (-1, 400);
|
||||
setup_theme ();
|
||||
|
@ -226,6 +229,8 @@ void
|
|||
ThemeManager::setup_theme ()
|
||||
{
|
||||
int r, g, b, a;
|
||||
color_list->clear();
|
||||
|
||||
for (std::vector<UIConfigVariable<uint32_t> *>::iterator i = ARDOUR_UI::config()->canvas_colors.begin(); i != ARDOUR_UI::config()->canvas_colors.end(); i++) {
|
||||
|
||||
TreeModel::Row row = *(color_list->append());
|
||||
|
@ -262,3 +267,10 @@ ThemeManager::setup_theme ()
|
|||
load_rc_file(rcfile, false);
|
||||
}
|
||||
|
||||
void
|
||||
ThemeManager::reset_canvas_colors()
|
||||
{
|
||||
ARDOUR_UI::config()->load_defaults();
|
||||
setup_theme ();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <gtkmm/scrolledwindow.h>
|
||||
#include <gtkmm/colorselection.h>
|
||||
#include <gtkmm/radiobutton.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/rc.h>
|
||||
#include "ardour_dialog.h"
|
||||
#include "ui_config.h"
|
||||
|
@ -37,6 +38,7 @@ class ThemeManager : public ArdourDialog
|
|||
|
||||
int save (std::string path);
|
||||
void setup_theme ();
|
||||
void reset_canvas_colors();
|
||||
|
||||
void on_dark_theme_button_toggled ();
|
||||
void on_light_theme_button_toggled ();
|
||||
|
@ -66,6 +68,7 @@ class ThemeManager : public ArdourDialog
|
|||
Gtk::HBox theme_selection_hbox;
|
||||
Gtk::RadioButton dark_button;
|
||||
Gtk::RadioButton light_button;
|
||||
Gtk::Button reset_button;
|
||||
|
||||
bool button_press_event (GdkEventButton*);
|
||||
};
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "public_editor.h"
|
||||
#include "time_axis_view.h"
|
||||
#include "simplerect.h"
|
||||
#include "simpleline.h"
|
||||
#include "selection.h"
|
||||
#include "keyboard.h"
|
||||
#include "rgb_macros.h"
|
||||
|
@ -1101,3 +1102,37 @@ TimeAxisView::covers_y_position (double y)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
TimeAxisView::show_temporary_lines (const vector<nframes64_t>& pos)
|
||||
{
|
||||
while (temp_lines.size()< pos.size()) {
|
||||
ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*canvas_display);
|
||||
l->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();
|
||||
l->property_y1() = 0;
|
||||
l->property_y2() = height;
|
||||
temp_lines.push_back (l);
|
||||
}
|
||||
|
||||
while (temp_lines.size() > pos.size()) {
|
||||
ArdourCanvas::SimpleLine *line = temp_lines.back();
|
||||
temp_lines.pop_back ();
|
||||
delete line;
|
||||
}
|
||||
|
||||
vector<nframes64_t>::const_iterator i;
|
||||
list<ArdourCanvas::SimpleLine*>::iterator l;
|
||||
|
||||
for (i = pos.begin(), l = temp_lines.begin(); i != pos.end() && l != temp_lines.end(); ++i, ++l) {
|
||||
(*l)->property_x1() = editor.frame_to_pixel (*i);
|
||||
(*l)->property_x2() = editor.frame_to_pixel (*i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimeAxisView::hide_temporary_lines ()
|
||||
{
|
||||
for (list<ArdourCanvas::SimpleLine*>::iterator l = temp_lines.begin(); l != temp_lines.end(); ++l) {
|
||||
(*l)->hide ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,6 +172,9 @@ class TimeAxisView : public virtual AxisView
|
|||
virtual ARDOUR::RouteGroup* edit_group() const { return 0; }
|
||||
virtual boost::shared_ptr<ARDOUR::Playlist> playlist() const { return boost::shared_ptr<ARDOUR::Playlist> (); }
|
||||
|
||||
virtual void show_temporary_lines (const std::vector<nframes64_t>&);
|
||||
virtual void hide_temporary_lines ();
|
||||
|
||||
virtual void set_samples_per_unit (double);
|
||||
virtual void show_selection (TimeSelection&);
|
||||
virtual void hide_selection ();
|
||||
|
@ -309,6 +312,8 @@ class TimeAxisView : public virtual AxisView
|
|||
|
||||
void set_height_pixels (uint32_t h);
|
||||
void color_handler ();
|
||||
list<ArdourCanvas::SimpleLine*> temp_lines;
|
||||
|
||||
}; /* class TimeAxisView */
|
||||
|
||||
#endif /* __ardour_gtk_time_axis_h__ */
|
||||
|
|
|
@ -56,11 +56,40 @@ UIConfiguration::~UIConfiguration ()
|
|||
{
|
||||
}
|
||||
|
||||
int
|
||||
UIConfiguration::load_defaults ()
|
||||
{
|
||||
int found = 0;
|
||||
sys::path default_ui_rc_file;
|
||||
|
||||
if ( find_file_in_search_path (ardour_search_path() + system_config_search_path(),
|
||||
"ardour3_ui_default.conf", default_ui_rc_file) )
|
||||
{
|
||||
XMLTree tree;
|
||||
found = 1;
|
||||
|
||||
string rcfile = default_ui_rc_file.to_string();
|
||||
|
||||
cerr << string_compose (_("loading default ui configuration file %1"), rcfile) << endl;
|
||||
|
||||
if (!tree.read (rcfile.c_str())) {
|
||||
error << string_compose(_("Ardour: cannot read default ui configuration file \"%1\""), rcfile) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (set_state (*tree.root())) {
|
||||
error << string_compose(_("Ardour: default ui configuration file \"%1\" not loaded successfully."), rcfile) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
int
|
||||
UIConfiguration::load_state ()
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
|
||||
sys::path default_ui_rc_file;
|
||||
|
||||
if ( find_file_in_search_path (ardour_search_path() + system_config_search_path(),
|
||||
|
|
|
@ -108,6 +108,7 @@ class UIConfiguration : public PBD::Stateful
|
|||
|
||||
int load_state ();
|
||||
int save_state ();
|
||||
int load_defaults ();
|
||||
|
||||
int set_state (const XMLNode&);
|
||||
XMLNode& get_state (void);
|
||||
|
|
|
@ -31,6 +31,7 @@ amp.cc
|
|||
audio_buffer.cc
|
||||
auto_bundle.cc
|
||||
user_bundle.cc
|
||||
audioanalyser.cc
|
||||
audio_diskstream.cc
|
||||
audio_library.cc
|
||||
audio_playlist.cc
|
||||
|
@ -134,6 +135,7 @@ tape_file_matcher.cc
|
|||
template_utils.cc
|
||||
tempo.cc
|
||||
track.cc
|
||||
transient_detector.cc
|
||||
utils.cc
|
||||
version.cc
|
||||
""")
|
||||
|
@ -162,6 +164,7 @@ if ardour['LIBLO']:
|
|||
ardour.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
|
||||
ardour.Append(CXXFLAGS="-DDATA_DIR=\\\"" + os.path.join (final_prefix, 'share') + "\\\"")
|
||||
ardour.Append(CXXFLAGS="-DMODULE_DIR=\\\"" + os.path.join (final_prefix, env['LIBDIR']) + "\\\"")
|
||||
ardour.Append(CXXFLAGS="-DVAMP_DIR=\\\"" + os.path.join (final_prefix, env['LIBDIR'], 'ardour2', 'vamp') + "\\\"")
|
||||
ardour.Append(CXXFLAGS="-DCONFIG_DIR=\\\"" + final_config_prefix + "\\\"")
|
||||
ardour.Append(CXXFLAGS="-DLOCALEDIR=\\\"" + os.path.join (final_prefix, 'share', 'locale') + "\\\"")
|
||||
|
||||
|
@ -304,15 +307,19 @@ ardour.Merge ([
|
|||
libraries['pbd'],
|
||||
libraries['midi++2'],
|
||||
libraries['glib2'],
|
||||
libraries['glibmm2']
|
||||
libraries['glibmm2'],
|
||||
libraries['vamp'],
|
||||
libraries['vamphost'],
|
||||
libraries['fftw3f'],
|
||||
libraries['fftw3'],
|
||||
])
|
||||
|
||||
#if ardour['RUBBERBAND']:
|
||||
# ardour.Merge ([ libraries['rubberband'], libraries['vamp'], libraries['fftw3f'] ])
|
||||
# timefx_sources += [ 'rb_effect.cc' ]
|
||||
#else:
|
||||
ardour.Merge ([ libraries['soundtouch'] ])
|
||||
timefx_sources += [ 'st_stretch.cc', 'st_pitch.cc' ]
|
||||
if ardour['RUBBERBAND']:
|
||||
ardour.Merge ([ libraries['rubberband']])
|
||||
timefx_sources += [ 'rb_effect.cc' ]
|
||||
else:
|
||||
ardour.Merge ([ libraries['soundtouch'] ])
|
||||
timefx_sources += [ 'st_stretch.cc', 'st_pitch.cc' ]
|
||||
|
||||
if ardour['LV2']:
|
||||
ardour.Merge ([ libraries['slv2'] ])
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright (C) 2008 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_audioanalyser_h__
|
||||
#define __ardour_audioanalyser_h__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <fstream>
|
||||
#include <vamp-sdk/Plugin.h>
|
||||
#include <ardour/audioregion.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Readable;
|
||||
class Session;
|
||||
|
||||
class AudioAnalyser {
|
||||
|
||||
public:
|
||||
typedef Vamp::Plugin AnalysisPlugin;
|
||||
typedef std::string AnalysisPluginKey;
|
||||
|
||||
AudioAnalyser (float sample_rate, AnalysisPluginKey key);
|
||||
virtual ~AudioAnalyser();
|
||||
|
||||
/* analysis object should provide a run method
|
||||
that accepts a path to write the results to (optionally empty)
|
||||
a Readable* to read data from
|
||||
and a reference to a type-specific container to return the
|
||||
results.
|
||||
*/
|
||||
|
||||
void reset ();
|
||||
|
||||
protected:
|
||||
float sample_rate;
|
||||
AnalysisPlugin* plugin;
|
||||
AnalysisPluginKey plugin_key;
|
||||
|
||||
nframes64_t bufsize;
|
||||
nframes64_t stepsize;
|
||||
|
||||
int initialize_plugin (AnalysisPluginKey name, float sample_rate);
|
||||
int analyse (const std::string& path, Readable*, uint32_t channel);
|
||||
|
||||
/* instances of an analysis object will have this method called
|
||||
whenever there are results to process. if out is non-null,
|
||||
the data should be written to the stream it points to.
|
||||
*/
|
||||
|
||||
virtual int use_features (Vamp::Plugin::FeatureSet&, std::ostream*) = 0;
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#endif /* __ardour_audioanalyser_h__ */
|
|
@ -21,6 +21,7 @@
|
|||
#define __ardour_audio_region_h__
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include <pbd/fastlog.h>
|
||||
#include <pbd/undo.h>
|
||||
|
@ -75,6 +76,11 @@ class AudioRegion : public Region
|
|||
nframes_t offset, nframes_t cnt,
|
||||
uint32_t chan_n=0, double samples_per_unit= 1.0) const;
|
||||
|
||||
/* Readable interface */
|
||||
|
||||
virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const;
|
||||
virtual nframes64_t readable_length() const { return length(); }
|
||||
|
||||
virtual nframes_t read_at (Sample *buf, Sample *mixdown_buf,
|
||||
float *gain_buf, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
|
@ -128,12 +134,14 @@ class AudioRegion : public Region
|
|||
void resume_fade_in ();
|
||||
void resume_fade_out ();
|
||||
|
||||
int get_transients (std::vector<nframes64_t>&, bool force_new = false);
|
||||
|
||||
private:
|
||||
friend class RegionFactory;
|
||||
|
||||
AudioRegion (boost::shared_ptr<AudioSource>, nframes_t start, nframes_t length);
|
||||
AudioRegion (boost::shared_ptr<AudioSource>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
AudioRegion (SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
AudioRegion (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
AudioRegion (boost::shared_ptr<const AudioRegion>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
AudioRegion (boost::shared_ptr<AudioSource>, const XMLNode&);
|
||||
AudioRegion (SourceList &, const XMLNode&);
|
||||
|
@ -148,10 +156,11 @@ class AudioRegion : public Region
|
|||
void recompute_gain_at_start ();
|
||||
|
||||
nframes_t _read_at (const SourceList&, Sample *buf, Sample *mixdown_buffer,
|
||||
float *gain_buffer, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0) const;
|
||||
float *gain_buffer, nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n = 0,
|
||||
nframes_t read_frames = 0,
|
||||
nframes_t skip_frames = 0,
|
||||
bool raw = false) const;
|
||||
|
||||
void recompute_at_start ();
|
||||
void recompute_at_end ();
|
||||
|
@ -178,6 +187,11 @@ class AudioRegion : public Region
|
|||
AudioRegion (boost::shared_ptr<const AudioRegion>);
|
||||
|
||||
int set_live_state (const XMLNode&, Change&, bool send);
|
||||
|
||||
std::vector<nframes64_t> _transients;
|
||||
bool valid_transients;
|
||||
void invalidate_transients ();
|
||||
void cleanup_transients (std::vector<nframes64_t>&);
|
||||
};
|
||||
|
||||
} /* namespace ARDOUR */
|
||||
|
|
|
@ -50,10 +50,20 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
|
|||
AudioSource (Session&, const XMLNode&);
|
||||
virtual ~AudioSource ();
|
||||
|
||||
/* returns the number of items in this `audio_source' */
|
||||
nframes64_t readable_length() const { return _length; }
|
||||
uint32_t n_channels() const { return 1; }
|
||||
|
||||
virtual nframes_t available_peaks (double zoom) const;
|
||||
|
||||
/* stopgap until nframes_t becomes nframes64_t. this function is needed by the Readable interface */
|
||||
|
||||
virtual nframes64_t read (Sample *dst, nframes64_t start, nframes64_t cnt, int channel) const {
|
||||
/* XXX currently ignores channel, assuming that source is always mono, which
|
||||
historically has been true.
|
||||
*/
|
||||
return read (dst, (nframes_t) start, (nframes_t) cnt);
|
||||
}
|
||||
|
||||
virtual nframes_t read (Sample *dst, nframes_t start, nframes_t cnt) const;
|
||||
virtual nframes_t write (Sample *src, nframes_t cnt);
|
||||
|
||||
|
@ -101,6 +111,9 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
|
|||
int prepare_for_peakfile_writes ();
|
||||
void done_with_peakfile_writes (bool done = true);
|
||||
|
||||
std::vector<nframes64_t> transients;
|
||||
std::string get_transients_path() const;
|
||||
|
||||
protected:
|
||||
static bool _build_missing_peakfiles;
|
||||
static bool _build_peakfiles;
|
||||
|
@ -134,6 +147,8 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
|
|||
int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force,
|
||||
bool intermediate_peaks_ready_signal, nframes_t frames_per_peak);
|
||||
|
||||
int load_transients (const std::string&);
|
||||
|
||||
private:
|
||||
int peakfile;
|
||||
nframes_t peak_leftover_cnt;
|
||||
|
|
|
@ -186,17 +186,7 @@ static inline cycles_t get_cycles (void)
|
|||
/* begin mach */
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#ifdef HAVE_WEAK_COREAUDIO
|
||||
#include <CoreAudio/HostTime.h>
|
||||
#else // Due to MacTypes.h and libgnomecanvasmm Rect conflict
|
||||
typedef unsigned long long UInt64;
|
||||
|
||||
extern UInt64
|
||||
AudioGetCurrentHostTime();
|
||||
|
||||
extern UInt64
|
||||
AudioConvertHostTimeToNanos(UInt64 inHostTime);
|
||||
#endif
|
||||
|
||||
typedef UInt64 cycles_t;
|
||||
static inline cycles_t get_cycles (void)
|
||||
|
|
|
@ -37,20 +37,21 @@
|
|||
namespace ARDOUR {
|
||||
class AudioEngine;
|
||||
class Session;
|
||||
struct LV2World;
|
||||
|
||||
class LV2Plugin : public ARDOUR::Plugin
|
||||
{
|
||||
public:
|
||||
LV2Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&, SLV2Plugin plugin, nframes_t sample_rate);
|
||||
LV2Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&, ARDOUR::LV2World&, SLV2Plugin plugin, nframes_t sample_rate);
|
||||
LV2Plugin (const LV2Plugin &);
|
||||
~LV2Plugin ();
|
||||
|
||||
/* Plugin interface */
|
||||
|
||||
std::string unique_id() const;
|
||||
const char* label() const { return slv2_plugin_get_name(_plugin); }
|
||||
const char* name() const { return slv2_plugin_get_name(_plugin); }
|
||||
const char* maker() const { return slv2_plugin_get_author_name(_plugin); }
|
||||
const char* label() const { return slv2_value_as_string(_name); }
|
||||
const char* name() const { return slv2_value_as_string(_name); }
|
||||
const char* maker() const { return _author ? slv2_value_as_string(_author) : "Unknown"; }
|
||||
uint32_t parameter_count() const { return slv2_plugin_get_num_ports(_plugin); }
|
||||
float default_value (uint32_t port);
|
||||
nframes_t signal_latency() const;
|
||||
|
@ -58,6 +59,9 @@ class LV2Plugin : public ARDOUR::Plugin
|
|||
float get_parameter (uint32_t port) const;
|
||||
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
|
||||
uint32_t nth_parameter (uint32_t port, bool& ok) const;
|
||||
|
||||
SLV2Plugin slv2_plugin() { return _plugin; }
|
||||
SLV2Port slv2_port(uint32_t i) { return slv2_plugin_get_port_by_index(_plugin, i); }
|
||||
|
||||
std::set<Parameter> automatable() const;
|
||||
|
||||
|
@ -105,29 +109,56 @@ class LV2Plugin : public ARDOUR::Plugin
|
|||
|
||||
private:
|
||||
void* _module;
|
||||
LV2World& _world;
|
||||
SLV2Plugin _plugin;
|
||||
SLV2Template _template;
|
||||
SLV2Value _name;
|
||||
SLV2Value _author;
|
||||
SLV2Instance _instance;
|
||||
nframes_t _sample_rate;
|
||||
float* _control_data;
|
||||
float* _shadow_data;
|
||||
float* _defaults;
|
||||
float* _latency_control_port;
|
||||
bool _was_activated;
|
||||
vector<bool> _port_is_input;
|
||||
|
||||
void init (SLV2Plugin plugin, nframes_t rate);
|
||||
void init (LV2World& world, SLV2Plugin plugin, nframes_t rate);
|
||||
void run (nframes_t nsamples);
|
||||
void latency_compute_run ();
|
||||
};
|
||||
|
||||
|
||||
/** The SLV2World, and various cached (as symbols, fast) URIs.
|
||||
*
|
||||
* This object represents everything ardour 'knows' about LV2
|
||||
* (ie understood extensions/features/etc)
|
||||
*/
|
||||
struct LV2World {
|
||||
LV2World();
|
||||
~LV2World();
|
||||
|
||||
SLV2World world;
|
||||
SLV2Value input_class;
|
||||
SLV2Value output_class;
|
||||
SLV2Value audio_class;
|
||||
SLV2Value control_class;
|
||||
SLV2Value event_class;
|
||||
SLV2Value in_place_broken;
|
||||
SLV2Value integer;
|
||||
SLV2Value toggled;
|
||||
SLV2Value srate;
|
||||
};
|
||||
|
||||
|
||||
class LV2PluginInfo : public PluginInfo {
|
||||
public:
|
||||
LV2PluginInfo (void* slv2_plugin);;
|
||||
LV2PluginInfo (void* slv2_world, void* slv2_plugin);;
|
||||
~LV2PluginInfo ();;
|
||||
static PluginInfoList discover (void* slv2_world);
|
||||
|
||||
PluginPtr load (Session& session);
|
||||
|
||||
void* _lv2_world;
|
||||
void* _slv2_plugin;
|
||||
};
|
||||
|
||||
|
|
|
@ -50,6 +50,10 @@ class MidiRegion : public Region
|
|||
~MidiRegion();
|
||||
|
||||
boost::shared_ptr<MidiSource> midi_source (uint32_t n=0) const;
|
||||
|
||||
/* Stub Readable interface */
|
||||
virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const { return 0; }
|
||||
virtual nframes64_t readable_length() const { return length(); }
|
||||
|
||||
nframes_t read_at (MidiRingBuffer& dst,
|
||||
nframes_t position,
|
||||
|
@ -86,11 +90,11 @@ class MidiRegion : public Region
|
|||
|
||||
MidiRegion (boost::shared_ptr<MidiSource>, nframes_t start, nframes_t length);
|
||||
MidiRegion (boost::shared_ptr<MidiSource>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
MidiRegion (SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
MidiRegion (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
MidiRegion (boost::shared_ptr<const MidiRegion>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags);
|
||||
MidiRegion (boost::shared_ptr<const MidiRegion>);
|
||||
MidiRegion (boost::shared_ptr<MidiSource>, const XMLNode&);
|
||||
MidiRegion (SourceList &, const XMLNode&);
|
||||
MidiRegion (const SourceList &, const XMLNode&);
|
||||
|
||||
private:
|
||||
nframes_t _read_at (const SourceList&, MidiRingBuffer& dst,
|
||||
|
|
|
@ -49,8 +49,15 @@ class MidiSource : public Source
|
|||
MidiSource (Session& session, const XMLNode&);
|
||||
virtual ~MidiSource ();
|
||||
|
||||
virtual nframes_t read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const;
|
||||
virtual nframes_t write (MidiRingBuffer& src, nframes_t cnt);
|
||||
/* Stub Readable interface */
|
||||
virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const { return 0; }
|
||||
virtual nframes64_t readable_length() const { return length(); }
|
||||
virtual uint32_t n_channels () const { return 1; }
|
||||
|
||||
// FIXME: integrate this with the Readable::read interface somehow
|
||||
virtual nframes_t midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const;
|
||||
virtual nframes_t midi_write (MidiRingBuffer& src, nframes_t cnt);
|
||||
|
||||
virtual void append_event_unlocked(const MidiEvent& ev) = 0;
|
||||
|
||||
virtual void mark_for_remove() = 0;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <ardour/plugin.h>
|
||||
|
||||
#ifdef HAVE_SLV2
|
||||
#include <slv2/slv2.h>
|
||||
#include <ardour/lv2_plugin.h>
|
||||
#endif
|
||||
|
||||
namespace ARDOUR {
|
||||
|
@ -40,6 +40,8 @@ class PluginManager {
|
|||
PluginManager ();
|
||||
~PluginManager ();
|
||||
|
||||
/* realtime plugin APIs */
|
||||
|
||||
ARDOUR::PluginInfoList &vst_plugin_info () { return _vst_plugin_info; }
|
||||
ARDOUR::PluginInfoList &ladspa_plugin_info () { return _ladspa_plugin_info; }
|
||||
ARDOUR::PluginInfoList &lv2_plugin_info () { return _lv2_plugin_info; }
|
||||
|
@ -59,7 +61,7 @@ class PluginManager {
|
|||
ARDOUR::PluginInfoList _au_plugin_info;
|
||||
|
||||
#ifdef HAVE_SLV2
|
||||
SLV2World _lv2_world;
|
||||
LV2World* _lv2_world;
|
||||
#endif
|
||||
|
||||
std::map<uint32_t, std::string> rdf_type;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef __ardour_readable_h__
|
||||
#define __ardour_readable_h__
|
||||
|
||||
#include <ardour/types.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Readable {
|
||||
public:
|
||||
Readable () {}
|
||||
virtual ~Readable() {}
|
||||
|
||||
virtual nframes64_t read (Sample*, nframes64_t pos, nframes64_t cnt, int channel) const = 0;
|
||||
virtual nframes64_t readable_length() const = 0;
|
||||
virtual uint32_t n_channels () const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ardour_readable_h__ */
|
|
@ -29,6 +29,7 @@
|
|||
#include <ardour/ardour.h>
|
||||
#include <ardour/data_type.h>
|
||||
#include <ardour/automatable.h>
|
||||
#include <ardour/readable.h>
|
||||
|
||||
class XMLNode;
|
||||
|
||||
|
@ -43,7 +44,7 @@ enum RegionEditState {
|
|||
EditChangesID = 2
|
||||
};
|
||||
|
||||
class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
||||
class Region : public Automatable, public boost::enable_shared_from_this<Region>, public Readable
|
||||
{
|
||||
public:
|
||||
typedef std::vector<boost::shared_ptr<Source> > SourceList;
|
||||
|
@ -217,13 +218,13 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
|
|||
|
||||
Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length,
|
||||
const string& name, DataType type, layer_t = 0, Flag flags = DefaultFlags);
|
||||
Region (SourceList& srcs, nframes_t start, nframes_t length,
|
||||
Region (const SourceList& srcs, nframes_t start, nframes_t length,
|
||||
const string& name, DataType type, layer_t = 0, Flag flags = DefaultFlags);
|
||||
|
||||
Region (boost::shared_ptr<const Region>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Flag flags = DefaultFlags);
|
||||
Region (boost::shared_ptr<const Region>);
|
||||
Region (boost::shared_ptr<Source> src, const XMLNode&);
|
||||
Region (SourceList& srcs, const XMLNode&);
|
||||
Region (const SourceList& srcs, const XMLNode&);
|
||||
|
||||
/* this one is for derived types of derived types */
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class RegionFactory {
|
|||
nframes_t length, std::string name,
|
||||
layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (boost::shared_ptr<Source>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (boost::shared_ptr<Region>);
|
||||
static boost::shared_ptr<Region> create (Session&, XMLNode&, bool);
|
||||
static boost::shared_ptr<Region> create (SourceList &, const XMLNode&);
|
||||
|
|
|
@ -261,6 +261,9 @@ class Session : public PBD::StatefulDestructible
|
|||
const SessionDirectory& session_directory () const { return *(_session_dir.get()); }
|
||||
|
||||
std::string automation_dir () const;
|
||||
std::string analysis_dir() const;
|
||||
|
||||
int ensure_subdirs ();
|
||||
|
||||
Glib::ustring peak_path (Glib::ustring) const;
|
||||
|
||||
|
|
|
@ -30,13 +30,14 @@
|
|||
#include <ardour/ardour.h>
|
||||
#include <ardour/session_object.h>
|
||||
#include <ardour/data_type.h>
|
||||
#include <ardour/readable.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Session;
|
||||
class Playlist;
|
||||
|
||||
class Source : public SessionObject
|
||||
class Source : public SessionObject, public ARDOUR::Readable
|
||||
{
|
||||
public:
|
||||
Source (Session&, const std::string& name, DataType type);
|
||||
|
|
|
@ -109,6 +109,9 @@ class MetricSection {
|
|||
public:
|
||||
MetricSection (const BBT_Time& start)
|
||||
: _start (start), _frame (0), _movable (true) {}
|
||||
MetricSection (nframes_t start)
|
||||
: _frame (start), _movable (true) {}
|
||||
|
||||
virtual ~MetricSection() {}
|
||||
|
||||
const BBT_Time& start() const { return _start; }
|
||||
|
@ -142,6 +145,8 @@ class MeterSection : public MetricSection, public Meter {
|
|||
public:
|
||||
MeterSection (const BBT_Time& start, double bpb, double note_type)
|
||||
: MetricSection (start), Meter (bpb, note_type) {}
|
||||
MeterSection (nframes_t start, double bpb, double note_type)
|
||||
: MetricSection (start), Meter (bpb, note_type) {}
|
||||
MeterSection (const XMLNode&);
|
||||
|
||||
static const string xml_state_node_name;
|
||||
|
@ -153,6 +158,8 @@ class TempoSection : public MetricSection, public Tempo {
|
|||
public:
|
||||
TempoSection (const BBT_Time& start, double qpm, double note_type)
|
||||
: MetricSection (start), Tempo (qpm, note_type) {}
|
||||
TempoSection (nframes_t start, double qpm, double note_type)
|
||||
: MetricSection (start), Tempo (qpm, note_type) {}
|
||||
TempoSection (const XMLNode&);
|
||||
|
||||
static const string xml_state_node_name;
|
||||
|
@ -165,7 +172,6 @@ typedef list<MetricSection*> Metrics;
|
|||
class TempoMap : public PBD::StatefulDestructible
|
||||
{
|
||||
public:
|
||||
|
||||
TempoMap (nframes_t frame_rate);
|
||||
~TempoMap();
|
||||
|
||||
|
@ -207,9 +213,14 @@ class TempoMap : public PBD::StatefulDestructible
|
|||
const Tempo& tempo_at (nframes_t);
|
||||
const Meter& meter_at (nframes_t);
|
||||
|
||||
const TempoSection& tempo_section_at (nframes_t);
|
||||
|
||||
void add_tempo(const Tempo&, BBT_Time where);
|
||||
void add_meter(const Meter&, BBT_Time where);
|
||||
|
||||
void add_tempo(const Tempo&, nframes_t where);
|
||||
void add_meter(const Meter&, nframes_t where);
|
||||
|
||||
void move_tempo (TempoSection&, const BBT_Time& to);
|
||||
void move_meter (MeterSection&, const BBT_Time& to);
|
||||
|
||||
|
@ -267,6 +278,8 @@ class TempoMap : public PBD::StatefulDestructible
|
|||
Metric metric_at (nframes_t) const;
|
||||
void bbt_time_with_metric (nframes_t, BBT_Time&, const Metric&) const;
|
||||
|
||||
void change_existing_tempo_at (nframes_t, double bpm, double note_type);
|
||||
|
||||
sigc::signal<void,ARDOUR::Change> StateChanged;
|
||||
|
||||
private:
|
||||
|
@ -280,8 +293,7 @@ class TempoMap : public PBD::StatefulDestructible
|
|||
BBT_Time last_bbt;
|
||||
mutable Glib::RWLock lock;
|
||||
|
||||
void timestamp_metrics ();
|
||||
|
||||
void timestamp_metrics (bool use_bbt);
|
||||
|
||||
nframes_t round_to_type (nframes_t fr, int dir, BBTPointType);
|
||||
|
||||
|
@ -298,7 +310,7 @@ class TempoMap : public PBD::StatefulDestructible
|
|||
nframes_t count_frames_between_metrics (const Meter&, const Tempo&, const BBT_Time&, const BBT_Time&) const;
|
||||
|
||||
int move_metric_section (MetricSection&, const BBT_Time& to);
|
||||
void do_insert (MetricSection* section);
|
||||
void do_insert (MetricSection* section, bool with_bbt);
|
||||
};
|
||||
|
||||
}; /* namespace ARDOUR */
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2008 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_transient_detector_h__
|
||||
#define __ardour_transient_detector_h__
|
||||
|
||||
#include <ardour/audioanalyser.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class AudioSource;
|
||||
class Session;
|
||||
|
||||
class TransientDetector : public AudioAnalyser
|
||||
{
|
||||
|
||||
public:
|
||||
TransientDetector (float sample_rate);
|
||||
~TransientDetector();
|
||||
|
||||
void set_threshold (float);
|
||||
void set_sensitivity (float);
|
||||
|
||||
float get_threshold () const;
|
||||
float get_sensitivity () const;
|
||||
|
||||
int run (const std::string& path, Readable*, uint32_t channel, std::vector<nframes64_t>& results);
|
||||
|
||||
protected:
|
||||
std::vector<nframes64_t>* current_results;
|
||||
int use_features (Vamp::Plugin::FeatureSet&, std::ostream*);
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
#endif /* __ardour_audioanalyser_h__ */
|
|
@ -0,0 +1,157 @@
|
|||
#include <vamp-sdk/hostext/PluginLoader.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
#include <glibmm/fileutils.h>
|
||||
#include <glib/gstdio.h> // for g_remove()
|
||||
|
||||
#include <pbd/error.h>
|
||||
|
||||
#include <ardour/audioanalyser.h>
|
||||
#include <ardour/readable.h>
|
||||
#include <ardour/readable.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Vamp;
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
|
||||
AudioAnalyser::AudioAnalyser (float sr, AnalysisPluginKey key)
|
||||
: sample_rate (sr)
|
||||
, plugin (0)
|
||||
, plugin_key (key)
|
||||
{
|
||||
}
|
||||
|
||||
AudioAnalyser::~AudioAnalyser ()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
AudioAnalyser::initialize_plugin (AnalysisPluginKey key, float sr)
|
||||
{
|
||||
using namespace Vamp::HostExt;
|
||||
|
||||
PluginLoader* loader (PluginLoader::getInstance());
|
||||
|
||||
plugin = loader->loadPlugin (key, sr, PluginLoader::ADAPT_ALL);
|
||||
|
||||
if (!plugin) {
|
||||
error << string_compose (_("VAMP Plugin \"%1\" could not be loaded"), key) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we asked for the buffering adapter, so set the blocksize to
|
||||
something that makes for efficient disk i/o
|
||||
*/
|
||||
|
||||
bufsize = 65536;
|
||||
stepsize = bufsize;
|
||||
|
||||
if (plugin->getMinChannelCount() > 1) {
|
||||
delete plugin;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!plugin->initialise (1, stepsize, bufsize)) {
|
||||
delete plugin;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
AudioAnalyser::reset ()
|
||||
{
|
||||
if (plugin) {
|
||||
plugin->reset ();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel)
|
||||
{
|
||||
ofstream ofile;
|
||||
Plugin::FeatureSet onsets;
|
||||
int ret = -1;
|
||||
bool done = false;
|
||||
Sample* data = 0;
|
||||
nframes64_t len = src->readable_length();
|
||||
nframes64_t pos = 0;
|
||||
float* bufs[1] = { 0 };
|
||||
|
||||
if (!path.empty()) {
|
||||
ofile.open (path.c_str());
|
||||
if (!ofile) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* create VAMP percussion onset plugin and initialize */
|
||||
|
||||
if (plugin == 0) {
|
||||
if (initialize_plugin (plugin_key, sample_rate)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
data = new Sample[bufsize];
|
||||
bufs[0] = data;
|
||||
|
||||
while (!done) {
|
||||
|
||||
nframes64_t to_read;
|
||||
|
||||
/* read from source */
|
||||
|
||||
to_read = min ((len - pos), bufsize);
|
||||
|
||||
if (src->read (data, pos, to_read, channel) != to_read) {
|
||||
cerr << "bad read\n";
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* zero fill buffer if necessary */
|
||||
|
||||
if (to_read != bufsize) {
|
||||
memset (data + to_read, 0, (bufsize - to_read));
|
||||
}
|
||||
|
||||
onsets = plugin->process (bufs, RealTime::fromSeconds ((double) pos / sample_rate));
|
||||
|
||||
if (use_features (onsets, (path.empty() ? &ofile : 0))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
pos += stepsize;
|
||||
|
||||
if (pos >= len) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* finish up VAMP plugin */
|
||||
|
||||
onsets = plugin->getRemainingFeatures ();
|
||||
|
||||
if (use_features (onsets, (path.empty() ? &ofile : 0))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
/* works even if it has not been opened */
|
||||
ofile.close ();
|
||||
|
||||
if (ret) {
|
||||
g_remove (path.c_str());
|
||||
}
|
||||
if (data) {
|
||||
delete data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include <cmath>
|
||||
#include <climits>
|
||||
#include <cfloat>
|
||||
#include <algorithm>
|
||||
|
||||
#include <set>
|
||||
|
||||
|
@ -42,6 +43,7 @@
|
|||
#include <ardour/audiofilesource.h>
|
||||
#include <ardour/region_factory.h>
|
||||
#include <ardour/runtime_functions.h>
|
||||
#include <ardour/transient_detector.h>
|
||||
|
||||
#include "i18n.h"
|
||||
#include <locale.h>
|
||||
|
@ -64,6 +66,7 @@ void
|
|||
AudioRegion::init ()
|
||||
{
|
||||
_scale_amplitude = 1.0;
|
||||
valid_transients = false;
|
||||
|
||||
set_default_fades ();
|
||||
set_default_envelope ();
|
||||
|
@ -112,7 +115,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
|
|||
}
|
||||
|
||||
/* Basic AudioRegion constructor (many channels) */
|
||||
AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
|
||||
AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
|
||||
: Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
|
||||
, _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
|
||||
, _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
|
||||
|
@ -121,7 +124,6 @@ AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, c
|
|||
init ();
|
||||
}
|
||||
|
||||
|
||||
/** Create a new AudioRegion, that is part of an existing one */
|
||||
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
|
||||
: Region (other, offset, length, name, layer, flags)
|
||||
|
@ -170,6 +172,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
|
|||
}
|
||||
|
||||
_scale_amplitude = other->_scale_amplitude;
|
||||
valid_transients = false;
|
||||
|
||||
assert(_type == DataType::AUDIO);
|
||||
}
|
||||
|
@ -181,6 +184,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
|
|||
, _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
|
||||
{
|
||||
_scale_amplitude = other->_scale_amplitude;
|
||||
valid_transients = false;
|
||||
_envelope = other->_envelope;
|
||||
|
||||
set_default_fades ();
|
||||
|
@ -202,6 +206,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
|
|||
}
|
||||
|
||||
init ();
|
||||
valid_transients = false;
|
||||
|
||||
if (set_state (node)) {
|
||||
throw failed_constructor();
|
||||
|
@ -229,6 +234,13 @@ AudioRegion::~AudioRegion ()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegion::invalidate_transients ()
|
||||
{
|
||||
valid_transients = false;
|
||||
_transients.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegion::listen_to_my_curves ()
|
||||
{
|
||||
|
@ -273,12 +285,20 @@ AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nfra
|
|||
}
|
||||
}
|
||||
|
||||
nframes64_t
|
||||
AudioRegion::read (Sample* buf, nframes64_t position, nframes64_t cnt, int channel) const
|
||||
{
|
||||
/* raw read, no fades, no gain, nada */
|
||||
return _read_at (_sources, buf, 0, 0, _position + position, cnt, channel, 0, 0, true);
|
||||
}
|
||||
|
||||
nframes_t
|
||||
AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position,
|
||||
nframes_t cnt,
|
||||
uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
|
||||
{
|
||||
return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames);
|
||||
/* regular diskstream/butler read complete with fades etc */
|
||||
return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames, false);
|
||||
}
|
||||
|
||||
nframes_t
|
||||
|
@ -291,13 +311,16 @@ AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_bu
|
|||
nframes_t
|
||||
AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
|
||||
nframes_t position, nframes_t cnt,
|
||||
uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
|
||||
uint32_t chan_n,
|
||||
nframes_t read_frames,
|
||||
nframes_t skip_frames,
|
||||
bool raw) const
|
||||
{
|
||||
nframes_t internal_offset;
|
||||
nframes_t buf_offset;
|
||||
nframes_t to_read;
|
||||
|
||||
if (muted()) {
|
||||
if (muted() && !raw) {
|
||||
return 0; /* read nothing */
|
||||
}
|
||||
|
||||
|
@ -320,14 +343,16 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
return 0; /* read nothing */
|
||||
}
|
||||
|
||||
if (opaque()) {
|
||||
if (opaque() || raw) {
|
||||
/* overwrite whatever is there */
|
||||
mixdown_buffer = buf + buf_offset;
|
||||
} else {
|
||||
mixdown_buffer += buf_offset;
|
||||
}
|
||||
|
||||
_read_data_count = 0;
|
||||
if (!raw) {
|
||||
_read_data_count = 0;
|
||||
}
|
||||
|
||||
if (chan_n < n_channels()) {
|
||||
|
||||
|
@ -336,7 +361,9 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
return 0; /* "read nothing" */
|
||||
}
|
||||
|
||||
_read_data_count += src->read_data_count();
|
||||
if (!raw) {
|
||||
_read_data_count += src->read_data_count();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -348,37 +375,41 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
|
||||
/* no fades required */
|
||||
|
||||
goto merge;
|
||||
if (!raw) {
|
||||
goto merge;
|
||||
}
|
||||
}
|
||||
|
||||
/* fade in */
|
||||
|
||||
if (_flags & FadeIn) {
|
||||
|
||||
nframes_t fade_in_length = (nframes_t) _fade_in->back()->when;
|
||||
|
||||
/* see if this read is within the fade in */
|
||||
|
||||
if (internal_offset < fade_in_length) {
|
||||
|
||||
nframes_t limit;
|
||||
|
||||
limit = min (to_read, fade_in_length - internal_offset);
|
||||
|
||||
_fade_in->curve().get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
|
||||
|
||||
for (nframes_t n = 0; n < limit; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
if (!raw) {
|
||||
|
||||
if (_flags & FadeIn) {
|
||||
|
||||
nframes_t fade_in_length = (nframes_t) _fade_in->back()->when;
|
||||
|
||||
/* see if this read is within the fade in */
|
||||
|
||||
if (internal_offset < fade_in_length) {
|
||||
|
||||
nframes_t limit;
|
||||
|
||||
limit = min (to_read, fade_in_length - internal_offset);
|
||||
|
||||
_fade_in->curve().get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
|
||||
|
||||
for (nframes_t n = 0; n < limit; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* fade out */
|
||||
|
||||
if (_flags & FadeOut) {
|
||||
|
||||
/* see if some part of this read is within the fade out */
|
||||
|
||||
|
||||
/* fade out */
|
||||
|
||||
if (_flags & FadeOut) {
|
||||
|
||||
/* see if some part of this read is within the fade out */
|
||||
|
||||
/* ................. >| REGION
|
||||
_length
|
||||
|
||||
|
@ -389,65 +420,66 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
|
|||
|--------------|
|
||||
^internal_offset
|
||||
^internal_offset + to_read
|
||||
|
||||
we need the intersection of [internal_offset,internal_offset+to_read] with
|
||||
[_length - fade_out_length, _length]
|
||||
|
||||
|
||||
we need the intersection of [internal_offset,internal_offset+to_read] with
|
||||
[_length - fade_out_length, _length]
|
||||
|
||||
*/
|
||||
|
||||
|
||||
nframes_t fade_out_length = (nframes_t) _fade_out->back()->when;
|
||||
nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
|
||||
nframes_t fade_interval_end = min(internal_offset + to_read, _length);
|
||||
|
||||
if (fade_interval_end > fade_interval_start) {
|
||||
/* (part of the) the fade out is in this buffer */
|
||||
nframes_t fade_out_length = (nframes_t) _fade_out->back()->when;
|
||||
nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
|
||||
nframes_t fade_interval_end = min(internal_offset + to_read, _length);
|
||||
|
||||
nframes_t limit = fade_interval_end - fade_interval_start;
|
||||
nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
|
||||
nframes_t fade_offset = fade_interval_start - internal_offset;
|
||||
|
||||
_fade_out->curve().get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
|
||||
|
||||
for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
|
||||
mixdown_buffer[m] *= gain_buffer[n];
|
||||
if (fade_interval_end > fade_interval_start) {
|
||||
/* (part of the) the fade out is in this buffer */
|
||||
|
||||
nframes_t limit = fade_interval_end - fade_interval_start;
|
||||
nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
|
||||
nframes_t fade_offset = fade_interval_start - internal_offset;
|
||||
|
||||
_fade_out->curve().get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
|
||||
|
||||
for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
|
||||
mixdown_buffer[m] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Regular gain curves */
|
||||
|
||||
if (envelope_active()) {
|
||||
_envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
|
||||
|
||||
if (_scale_amplitude != 1.0f) {
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
|
||||
}
|
||||
} else {
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
} else if (_scale_amplitude != 1.0f) {
|
||||
Session::apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
|
||||
}
|
||||
|
||||
merge:
|
||||
|
||||
if (!opaque()) {
|
||||
|
||||
/* gack. the things we do for users.
|
||||
*/
|
||||
|
||||
buf += buf_offset;
|
||||
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
buf[n] += mixdown_buffer[n];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Regular gain curves */
|
||||
|
||||
if (envelope_active()) {
|
||||
_envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
|
||||
|
||||
if (_scale_amplitude != 1.0f) {
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
|
||||
}
|
||||
} else {
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
} else if (_scale_amplitude != 1.0f) {
|
||||
apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
|
||||
}
|
||||
|
||||
merge:
|
||||
|
||||
if (!opaque()) {
|
||||
|
||||
/* gack. the things we do for users.
|
||||
*/
|
||||
|
||||
buf += buf_offset;
|
||||
|
||||
for (nframes_t n = 0; n < to_read; ++n) {
|
||||
buf[n] += mixdown_buffer[n];
|
||||
}
|
||||
}
|
||||
|
||||
return to_read;
|
||||
}
|
||||
|
||||
|
@ -1224,6 +1256,93 @@ AudioRegion::audio_source (uint32_t n) const
|
|||
return boost::dynamic_pointer_cast<AudioSource>(source(n));
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegion::cleanup_transients (vector<nframes64_t>& t)
|
||||
{
|
||||
sort (t.begin(), t.end());
|
||||
|
||||
/* remove duplicates or other things that are too close */
|
||||
|
||||
vector<nframes64_t>::iterator i = t.begin();
|
||||
nframes64_t curr = (*i);
|
||||
|
||||
/* XXX force a 3msec gap - use a config variable */
|
||||
|
||||
nframes64_t gap_frames = (nframes64_t) floor (3.0 * (playlist()->session().frame_rate() / 1000.0));
|
||||
|
||||
++i;
|
||||
|
||||
while (i != t.end()) {
|
||||
if (((*i) == curr) || (((*i) - curr) < gap_frames)) {
|
||||
i = t.erase (i);
|
||||
} else {
|
||||
++i;
|
||||
curr = *i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
AudioRegion::get_transients (vector<nframes64_t>& results, bool force_new)
|
||||
{
|
||||
if (!playlist()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (valid_transients && !force_new) {
|
||||
results = _transients;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TransientDetector t (playlist()->session().frame_rate());
|
||||
bool existing_results = !results.empty();
|
||||
|
||||
_transients.clear ();
|
||||
valid_transients = false;
|
||||
|
||||
for (uint32_t i = 0; i < n_channels(); ++i) {
|
||||
|
||||
vector<nframes64_t> these_results;
|
||||
|
||||
t.reset ();
|
||||
|
||||
if (t.run ("", this, i, these_results)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* translate all transients to give absolute position */
|
||||
|
||||
for (vector<nframes64_t>::iterator i = these_results.begin(); i != these_results.end(); ++i) {
|
||||
(*i) += _position;
|
||||
}
|
||||
|
||||
/* merge */
|
||||
|
||||
_transients.insert (_transients.end(), these_results.begin(), these_results.end());
|
||||
}
|
||||
|
||||
if (!results.empty()) {
|
||||
if (existing_results) {
|
||||
|
||||
/* merge our transients into the existing ones, then clean up
|
||||
those.
|
||||
*/
|
||||
|
||||
results.insert (results.end(), _transients.begin(), _transients.end());
|
||||
cleanup_transients (results);
|
||||
}
|
||||
|
||||
/* make sure ours are clean too */
|
||||
|
||||
cleanup_transients (_transients);
|
||||
}
|
||||
|
||||
valid_transients = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit)
|
||||
|
|
|
@ -27,10 +27,12 @@
|
|||
#include <ctime>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <glibmm/fileutils.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
|
||||
#include <pbd/xml++.h>
|
||||
#include <pbd/pthread_utils.h>
|
||||
|
@ -38,6 +40,7 @@
|
|||
#include <ardour/audiosource.h>
|
||||
#include <ardour/cycle_timer.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/transient_detector.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
@ -916,3 +919,50 @@ AudioSource::update_length (nframes_t pos, nframes_t cnt)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
AudioSource::load_transients (const string& path)
|
||||
{
|
||||
ifstream file (path.c_str());
|
||||
|
||||
if (!file) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
transients.clear ();
|
||||
|
||||
stringstream strstr;
|
||||
double val;
|
||||
|
||||
while (file.good()) {
|
||||
file >> val;
|
||||
|
||||
if (!file.fail()) {
|
||||
nframes64_t frame = (nframes64_t) floor (val * _session.frame_rate());
|
||||
transients.push_back (frame);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string
|
||||
AudioSource::get_transients_path () const
|
||||
{
|
||||
vector<string> parts;
|
||||
string s;
|
||||
|
||||
/* old sessions may not have the analysis directory */
|
||||
|
||||
_session.ensure_subdirs ();
|
||||
|
||||
s = _session.analysis_dir ();
|
||||
parts.push_back (s);
|
||||
|
||||
s = _id.to_s();
|
||||
s += '.';
|
||||
s += X_("transients");
|
||||
parts.push_back (s);
|
||||
|
||||
return Glib::build_filename (parts);
|
||||
}
|
||||
|
||||
|
|
|
@ -285,6 +285,17 @@ ARDOUR::init (bool use_vst, bool try_optimization)
|
|||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make VAMP look in our library ahead of anything else */
|
||||
|
||||
char *p = getenv ("VAMP_PATH");
|
||||
string vamppath = VAMP_DIR;
|
||||
if (p) {
|
||||
vamppath += ':';
|
||||
vamppath += p;
|
||||
}
|
||||
setenv ("VAMP_PATH", vamppath.c_str(), 1);
|
||||
|
||||
|
||||
setup_hardware_optimization (try_optimization);
|
||||
|
||||
|
|
|
@ -467,7 +467,6 @@ LadspaPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& des
|
|||
|
||||
desc.label = port_names()[which];
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,16 +43,18 @@ using namespace std;
|
|||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
LV2Plugin::LV2Plugin (AudioEngine& e, Session& session, SLV2Plugin plugin, nframes_t rate)
|
||||
LV2Plugin::LV2Plugin (AudioEngine& e, Session& session, LV2World& world, SLV2Plugin plugin, nframes_t rate)
|
||||
: Plugin (e, session)
|
||||
, _world(world)
|
||||
{
|
||||
init (plugin, rate);
|
||||
init (world, plugin, rate);
|
||||
}
|
||||
|
||||
LV2Plugin::LV2Plugin (const LV2Plugin &other)
|
||||
: Plugin (other)
|
||||
, _world(other._world)
|
||||
{
|
||||
init (other._plugin, other._sample_rate);
|
||||
init (other._world, other._plugin, other._sample_rate);
|
||||
|
||||
for (uint32_t i = 0; i < parameter_count(); ++i) {
|
||||
_control_data[i] = other._shadow_data[i];
|
||||
|
@ -61,24 +63,30 @@ LV2Plugin::LV2Plugin (const LV2Plugin &other)
|
|||
}
|
||||
|
||||
void
|
||||
LV2Plugin::init (SLV2Plugin plugin, nframes_t rate)
|
||||
LV2Plugin::init (LV2World& world, SLV2Plugin plugin, nframes_t rate)
|
||||
{
|
||||
_world = world;
|
||||
_plugin = plugin;
|
||||
_template = slv2_plugin_get_template(plugin);
|
||||
_control_data = 0;
|
||||
_shadow_data = 0;
|
||||
_latency_control_port = 0;
|
||||
_was_activated = false;
|
||||
|
||||
_instance = slv2_plugin_instantiate(plugin, rate, NULL);
|
||||
_name = slv2_plugin_get_name(plugin);
|
||||
assert(_name);
|
||||
_author = slv2_plugin_get_author_name(plugin);
|
||||
|
||||
if (_instance == 0) {
|
||||
error << _("LV2: Failed to instantiate plugin ") << slv2_plugin_get_uri(plugin) << endl;
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
if (slv2_plugin_has_feature(plugin, "http://lv2plug.in/ns/lv2core#inPlaceBroken")) {
|
||||
error << string_compose(_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"), slv2_plugin_get_name(plugin)) << endmsg;
|
||||
if (slv2_plugin_has_feature(plugin, world.in_place_broken)) {
|
||||
error << string_compose(_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
|
||||
slv2_value_as_string(_name));
|
||||
slv2_value_free(_name);
|
||||
slv2_value_free(_author);
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
|
@ -88,14 +96,21 @@ LV2Plugin::init (SLV2Plugin plugin, nframes_t rate)
|
|||
|
||||
_control_data = new float[num_ports];
|
||||
_shadow_data = new float[num_ports];
|
||||
_defaults = new float[num_ports];
|
||||
|
||||
const bool latent = slv2_plugin_has_latency(plugin);
|
||||
uint32_t latency_port = (latent ? slv2_plugin_get_latency_port(plugin) : 0);
|
||||
uint32_t latency_port = (latent ? slv2_plugin_get_latency_port_index(plugin) : 0);
|
||||
|
||||
for (uint32_t i = 0; i < num_ports; ++i) {
|
||||
if (parameter_is_control(i)) {
|
||||
SLV2Port port = slv2_plugin_get_port_by_index(plugin, i);
|
||||
SLV2Value def;
|
||||
slv2_port_get_range(plugin, port, &def, NULL, NULL);
|
||||
_defaults[i] = def ? slv2_value_as_float(def) : 0.0f;
|
||||
slv2_value_free(def);
|
||||
|
||||
slv2_instance_connect_port (_instance, i, &_control_data[i]);
|
||||
|
||||
|
||||
if (latent && i == latency_port) {
|
||||
_latency_control_port = &_control_data[i];
|
||||
*_latency_control_port = 0;
|
||||
|
@ -104,6 +119,8 @@ LV2Plugin::init (SLV2Plugin plugin, nframes_t rate)
|
|||
if (parameter_is_input(i)) {
|
||||
_shadow_data[i] = default_value (i);
|
||||
}
|
||||
} else {
|
||||
_defaults[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,6 +135,8 @@ LV2Plugin::~LV2Plugin ()
|
|||
GoingAway (); /* EMIT SIGNAL */
|
||||
|
||||
slv2_instance_free(_instance);
|
||||
slv2_value_free(_name);
|
||||
slv2_value_free(_author);
|
||||
|
||||
if (_control_data) {
|
||||
delete [] _control_data;
|
||||
|
@ -131,15 +150,14 @@ LV2Plugin::~LV2Plugin ()
|
|||
string
|
||||
LV2Plugin::unique_id() const
|
||||
{
|
||||
return slv2_plugin_get_uri(_plugin);
|
||||
return slv2_value_as_uri(slv2_plugin_get_uri(_plugin));
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
LV2Plugin::default_value (uint32_t port)
|
||||
{
|
||||
return slv2_port_get_default_value(_plugin,
|
||||
slv2_plugin_get_port_by_index(_plugin, port));
|
||||
return _defaults[port];
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -276,15 +294,16 @@ LV2Plugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
|
|||
{
|
||||
SLV2Port port = slv2_plugin_get_port_by_index(_plugin, which);
|
||||
|
||||
#define LV2_URI "http://lv2plug.in/ns/lv2core#"
|
||||
SLV2Value def, min, max;
|
||||
slv2_port_get_range(_plugin, port, &def, &min, &max);
|
||||
|
||||
desc.integer_step = slv2_port_has_property(_plugin, port, LV2_URI "integer");
|
||||
desc.toggled = slv2_port_has_property(_plugin, port, LV2_URI "toggled");
|
||||
desc.integer_step = slv2_port_has_property(_plugin, port, _world.integer);
|
||||
desc.toggled = slv2_port_has_property(_plugin, port, _world.toggled);
|
||||
desc.logarithmic = false; // TODO (LV2 extension)
|
||||
desc.sr_dependent = slv2_port_has_property(_plugin, port, LV2_URI "sampleRate");
|
||||
desc.label = slv2_port_get_name(_plugin, port);
|
||||
desc.lower = slv2_port_get_minimum_value(_plugin, port);
|
||||
desc.upper = slv2_port_get_maximum_value(_plugin, port);
|
||||
desc.sr_dependent = slv2_port_has_property(_plugin, port, _world.srate);
|
||||
desc.label = slv2_value_as_string(slv2_port_get_name(_plugin, port));
|
||||
desc.lower = min ? slv2_value_as_float(min) : 0.0f;
|
||||
desc.upper = max ? slv2_value_as_float(max) : 1.0f;
|
||||
desc.min_unbound = false; // TODO (LV2 extension)
|
||||
desc.max_unbound = false; // TODO (LV2 extension)
|
||||
|
||||
|
@ -299,6 +318,10 @@ LV2Plugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
|
|||
desc.largestep = delta/10.0f;
|
||||
}
|
||||
|
||||
slv2_value_free(def);
|
||||
slv2_value_free(min);
|
||||
slv2_value_free(max);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -307,8 +330,11 @@ string
|
|||
LV2Plugin::describe_parameter (Parameter which)
|
||||
{
|
||||
if (which.type() == PluginAutomation && which.id() < parameter_count()) {
|
||||
return slv2_port_get_name(_plugin,
|
||||
slv2_plugin_get_port_by_index(_plugin, which));
|
||||
SLV2Value name = slv2_port_get_name(_plugin,
|
||||
slv2_plugin_get_port_by_index(_plugin, which));
|
||||
string ret(slv2_value_as_string(name));
|
||||
slv2_value_free(name);
|
||||
return ret;
|
||||
} else {
|
||||
return "??";
|
||||
}
|
||||
|
@ -377,29 +403,29 @@ LV2Plugin::connect_and_run (BufferSet& bufs, uint32_t& in_index, uint32_t& out_i
|
|||
bool
|
||||
LV2Plugin::parameter_is_control (uint32_t param) const
|
||||
{
|
||||
SLV2PortSignature sig = slv2_template_get_port(_template, param);
|
||||
return (slv2_port_signature_get_type(sig) == SLV2_PORT_DATA_TYPE_CONTROL);
|
||||
SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
|
||||
return slv2_port_is_a(_plugin, port, _world.control_class);
|
||||
}
|
||||
|
||||
bool
|
||||
LV2Plugin::parameter_is_audio (uint32_t param) const
|
||||
{
|
||||
SLV2PortSignature sig = slv2_template_get_port(_template, param);
|
||||
return (slv2_port_signature_get_type(sig) == SLV2_PORT_DATA_TYPE_AUDIO);
|
||||
SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
|
||||
return slv2_port_is_a(_plugin, port, _world.audio_class);
|
||||
}
|
||||
|
||||
bool
|
||||
LV2Plugin::parameter_is_output (uint32_t param) const
|
||||
{
|
||||
SLV2PortSignature sig = slv2_template_get_port(_template, param);
|
||||
return (slv2_port_signature_get_direction(sig) == SLV2_PORT_DIRECTION_OUTPUT);
|
||||
SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
|
||||
return slv2_port_is_a(_plugin, port, _world.output_class);
|
||||
}
|
||||
|
||||
bool
|
||||
LV2Plugin::parameter_is_input (uint32_t param) const
|
||||
{
|
||||
SLV2PortSignature sig = slv2_template_get_port(_template, param);
|
||||
return (slv2_port_signature_get_direction(sig) == SLV2_PORT_DIRECTION_INPUT);
|
||||
SLV2Port port = slv2_plugin_get_port_by_index(_plugin, param);
|
||||
return slv2_port_is_a(_plugin, port, _world.input_class);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -418,9 +444,7 @@ void
|
|||
LV2Plugin::run (nframes_t nframes)
|
||||
{
|
||||
for (uint32_t i = 0; i < parameter_count(); ++i) {
|
||||
SLV2PortSignature sig = slv2_template_get_port(_template, i);
|
||||
if (slv2_port_signature_get_type(sig) == SLV2_PORT_DATA_TYPE_CONTROL
|
||||
&& slv2_port_signature_get_direction(sig) == SLV2_PORT_DIRECTION_INPUT) {
|
||||
if (parameter_is_control(i) && parameter_is_input(i)) {
|
||||
_control_data[i] = _shadow_data[i];
|
||||
}
|
||||
}
|
||||
|
@ -472,8 +496,34 @@ LV2Plugin::latency_compute_run ()
|
|||
deactivate ();
|
||||
}
|
||||
|
||||
LV2PluginInfo::LV2PluginInfo (void* slv2_plugin)
|
||||
: _slv2_plugin(slv2_plugin)
|
||||
LV2World::LV2World()
|
||||
: world(slv2_world_new())
|
||||
{
|
||||
slv2_world_load_all(world);
|
||||
input_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_INPUT);
|
||||
output_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_OUTPUT);
|
||||
control_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_CONTROL);
|
||||
audio_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_AUDIO);
|
||||
event_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_EVENT);
|
||||
in_place_broken = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "inPlaceBroken");
|
||||
integer = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "integer");
|
||||
toggled = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "toggled");
|
||||
srate = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "sampleRate");
|
||||
}
|
||||
|
||||
LV2World::~LV2World()
|
||||
{
|
||||
slv2_value_free(input_class);
|
||||
slv2_value_free(output_class);
|
||||
slv2_value_free(control_class);
|
||||
slv2_value_free(audio_class);
|
||||
slv2_value_free(event_class);
|
||||
slv2_value_free(in_place_broken);
|
||||
}
|
||||
|
||||
LV2PluginInfo::LV2PluginInfo (void* lv2_world, void* slv2_plugin)
|
||||
: _lv2_world(lv2_world)
|
||||
, _slv2_plugin(slv2_plugin)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -484,12 +534,11 @@ LV2PluginInfo::~LV2PluginInfo()
|
|||
PluginPtr
|
||||
LV2PluginInfo::load (Session& session)
|
||||
{
|
||||
SLV2Plugin p = (SLV2Plugin)_slv2_plugin;
|
||||
|
||||
try {
|
||||
PluginPtr plugin;
|
||||
|
||||
plugin.reset (new LV2Plugin (session.engine(), session, p, session.frame_rate()));
|
||||
plugin.reset (new LV2Plugin (session.engine(), session,
|
||||
*(LV2World*)_lv2_world, (SLV2Plugin)_slv2_plugin, session.frame_rate()));
|
||||
|
||||
plugin->set_info(PluginInfoPtr(new LV2PluginInfo(*this)));
|
||||
return plugin;
|
||||
|
@ -503,40 +552,42 @@ LV2PluginInfo::load (Session& session)
|
|||
}
|
||||
|
||||
PluginInfoList
|
||||
LV2PluginInfo::discover (void* slv2_world)
|
||||
LV2PluginInfo::discover (void* lv2_world)
|
||||
{
|
||||
PluginInfoList plugs;
|
||||
|
||||
SLV2Plugins plugins = slv2_world_get_all_plugins((SLV2World)slv2_world);
|
||||
LV2World* world = (LV2World*)lv2_world;
|
||||
SLV2Plugins plugins = slv2_world_get_all_plugins(world->world);
|
||||
|
||||
for (unsigned i=0; i < slv2_plugins_size(plugins); ++i) {
|
||||
SLV2Plugin p = slv2_plugins_get_at(plugins, i);
|
||||
LV2PluginInfoPtr info (new LV2PluginInfo(p));
|
||||
LV2PluginInfoPtr info (new LV2PluginInfo(lv2_world, p));
|
||||
|
||||
info->name = slv2_plugin_get_name(p);
|
||||
SLV2Value name = slv2_plugin_get_name(p);
|
||||
info->name = string(slv2_value_as_string(name));
|
||||
slv2_value_free(name);
|
||||
|
||||
SLV2PluginClass pclass = slv2_plugin_get_class(p);
|
||||
info->category = slv2_plugin_class_get_label(pclass);
|
||||
SLV2Value label = slv2_plugin_class_get_label(pclass);
|
||||
info->category = slv2_value_as_string(label);
|
||||
|
||||
char* author_name = slv2_plugin_get_author_name(p);
|
||||
info->creator = author_name ? string(author_name) : "Unknown";
|
||||
free(author_name);
|
||||
SLV2Value author_name = slv2_plugin_get_author_name(p);
|
||||
info->creator = author_name ? string(slv2_value_as_string(author_name)) : "Unknown";
|
||||
slv2_value_free(author_name);
|
||||
|
||||
info->path = "/NOPATH"; // Meaningless for LV2
|
||||
|
||||
SLV2Template io = slv2_plugin_get_template(p);
|
||||
|
||||
info->n_inputs.set_audio(slv2_template_get_num_ports_of_type(io,
|
||||
SLV2_PORT_DIRECTION_INPUT, SLV2_PORT_DATA_TYPE_AUDIO));
|
||||
info->n_outputs.set_audio(slv2_template_get_num_ports_of_type(io,
|
||||
SLV2_PORT_DIRECTION_OUTPUT, SLV2_PORT_DATA_TYPE_AUDIO));
|
||||
info->n_inputs.set_audio(slv2_plugin_get_num_ports_of_class(p,
|
||||
world->input_class, world->audio_class, NULL));
|
||||
info->n_inputs.set_midi(slv2_plugin_get_num_ports_of_class(p,
|
||||
world->input_class, world->event_class, NULL));
|
||||
|
||||
info->n_inputs.set_midi(slv2_template_get_num_ports_of_type(io,
|
||||
SLV2_PORT_DIRECTION_INPUT, SLV2_PORT_DATA_TYPE_MIDI));
|
||||
info->n_outputs.set_midi(slv2_template_get_num_ports_of_type(io,
|
||||
SLV2_PORT_DIRECTION_OUTPUT, SLV2_PORT_DATA_TYPE_MIDI));
|
||||
info->n_outputs.set_audio(slv2_plugin_get_num_ports_of_class(p,
|
||||
world->output_class, world->audio_class, NULL));
|
||||
info->n_outputs.set_midi(slv2_plugin_get_num_ports_of_class(p,
|
||||
world->output_class, world->event_class, NULL));
|
||||
|
||||
info->unique_id = slv2_plugin_get_uri(p);
|
||||
info->unique_id = slv2_value_as_uri(slv2_plugin_get_uri(p));
|
||||
info->index = 0; // Meaningless for LV2
|
||||
|
||||
plugs.push_back (info);
|
||||
|
|
|
@ -933,7 +933,7 @@ MidiDiskstream::do_flush (Session::RunContext context, bool force_flush)
|
|||
assert(!destructive());
|
||||
|
||||
if (record_enabled() && _session.transport_frame() - _last_flush_frame > disk_io_chunk_frames) {
|
||||
if ((!_write_source) || _write_source->write (*_capture_buf, to_write) != to_write) {
|
||||
if ((!_write_source) || _write_source->midi_write (*_capture_buf, to_write) != to_write) {
|
||||
error << string_compose(_("MidiDiskstream %1: cannot write to disk"), _id) << endmsg;
|
||||
return -1;
|
||||
} else {
|
||||
|
|
|
@ -65,7 +65,7 @@ MidiRegion::MidiRegion (boost::shared_ptr<MidiSource> src, nframes_t start, nfra
|
|||
}
|
||||
|
||||
/* Basic MidiRegion constructor (many channels) */
|
||||
MidiRegion::MidiRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
|
||||
MidiRegion::MidiRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
|
||||
: Region (srcs, start, length, name, DataType::MIDI, layer, flags)
|
||||
{
|
||||
assert(_name.find("/") == string::npos);
|
||||
|
@ -100,7 +100,7 @@ MidiRegion::MidiRegion (boost::shared_ptr<MidiSource> src, const XMLNode& node)
|
|||
assert(_type == DataType::MIDI);
|
||||
}
|
||||
|
||||
MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node)
|
||||
MidiRegion::MidiRegion (const SourceList& srcs, const XMLNode& node)
|
||||
: Region (srcs, node)
|
||||
{
|
||||
if (set_state (node)) {
|
||||
|
@ -171,7 +171,7 @@ MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer& dst, nframes_t pos
|
|||
boost::shared_ptr<MidiSource> src = midi_source(chan_n);
|
||||
src->set_note_mode(mode);
|
||||
|
||||
if (src->read (dst, _start + internal_offset, to_read, _position) != to_read) {
|
||||
if (src->midi_read (dst, _start + internal_offset, to_read, _position) != to_read) {
|
||||
return 0; /* "read nothing" */
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ MidiSource::set_state (const XMLNode& node)
|
|||
}
|
||||
|
||||
nframes_t
|
||||
MidiSource::read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
|
||||
MidiSource::midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
|
||||
{
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
if (_model) {
|
||||
|
@ -114,7 +114,7 @@ MidiSource::read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t
|
|||
}
|
||||
|
||||
nframes_t
|
||||
MidiSource::write (MidiRingBuffer& dst, nframes_t cnt)
|
||||
MidiSource::midi_write (MidiRingBuffer& dst, nframes_t cnt)
|
||||
{
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
return write_unlocked (dst, cnt);
|
||||
|
|
|
@ -110,8 +110,7 @@ PluginManager::PluginManager ()
|
|||
}
|
||||
|
||||
#ifdef HAVE_SLV2
|
||||
_lv2_world = slv2_world_new();
|
||||
slv2_world_load_all(_lv2_world);
|
||||
_lv2_world = new LV2World();
|
||||
#endif
|
||||
|
||||
refresh ();
|
||||
|
|
|
@ -296,8 +296,8 @@ PortFacade::disconnect (Port& other)
|
|||
int
|
||||
PortFacade::disconnect_all ()
|
||||
{
|
||||
int reta;
|
||||
int retb;
|
||||
int reta = 0;
|
||||
int retb = 0;
|
||||
|
||||
if (_ext_port) {
|
||||
reta = _ext_port->disconnect_all ();
|
||||
|
|
|
@ -71,9 +71,9 @@ Quantize::run (boost::shared_ptr<Region> r)
|
|||
|
||||
for (MidiModel::Notes::iterator i = model->notes().begin(); i != model->notes().end(); ++i) {
|
||||
const double new_time = lrint((*i)->time() / q_frames) * q_frames;
|
||||
const double new_dur = (((*i)->time() != 0 && new_dur < (q_frames * 1.5))
|
||||
? q_frames
|
||||
: lrint((*i)->duration() / q_frames) * q_frames);
|
||||
double new_dur = lrint((*i)->duration() / q_frames) * q_frames;
|
||||
if (new_dur == 0.0)
|
||||
new_dur = q_frames;
|
||||
|
||||
(*i)->set_time(new_time);
|
||||
(*i)->set_duration(new_dur);
|
||||
|
|
|
@ -99,7 +99,7 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
|
|||
}
|
||||
|
||||
/** Basic Region constructor (many sources) */
|
||||
Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
|
||||
Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
|
||||
: Automatable(srcs.front()->session(), name)
|
||||
, _type(type)
|
||||
, _flags(flags)
|
||||
|
@ -117,13 +117,13 @@ Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const strin
|
|||
|
||||
set<boost::shared_ptr<Source> > unique_srcs;
|
||||
|
||||
for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
|
||||
for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
|
||||
_sources.push_back (*i);
|
||||
(*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
|
||||
unique_srcs.insert (*i);
|
||||
}
|
||||
|
||||
for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
|
||||
for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
|
||||
_master_sources.push_back (*i);
|
||||
if (unique_srcs.find (*i) == unique_srcs.end()) {
|
||||
(*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
|
||||
|
@ -222,7 +222,7 @@ Region::Region (boost::shared_ptr<const Region> other)
|
|||
assert(_sources.size() > 0);
|
||||
}
|
||||
|
||||
Region::Region (SourceList& srcs, const XMLNode& node)
|
||||
Region::Region (const SourceList& srcs, const XMLNode& node)
|
||||
: Automatable(srcs.front()->session(), X_("error: XML did not reset this"))
|
||||
, _type(DataType::NIL) // to be loaded from XML
|
||||
, _flags(Flag(0))
|
||||
|
@ -239,13 +239,13 @@ Region::Region (SourceList& srcs, const XMLNode& node)
|
|||
{
|
||||
set<boost::shared_ptr<Source> > unique_srcs;
|
||||
|
||||
for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
|
||||
for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
|
||||
_sources.push_back (*i);
|
||||
(*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
|
||||
unique_srcs.insert (*i);
|
||||
}
|
||||
|
||||
for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
|
||||
for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
|
||||
_master_sources.push_back (*i);
|
||||
if (unique_srcs.find (*i) == unique_srcs.end()) {
|
||||
(*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
|
||||
|
@ -974,9 +974,9 @@ Region::state (bool full_state)
|
|||
node->add_property ("length", buf);
|
||||
snprintf (buf, sizeof (buf), "%u", _position);
|
||||
node->add_property ("position", buf);
|
||||
snprintf (buf, sizeof (buf), "%lu", _ancestral_start);
|
||||
snprintf (buf, sizeof (buf), "%Ld", _ancestral_start);
|
||||
node->add_property ("ancestral-start", buf);
|
||||
snprintf (buf, sizeof (buf), "%lu", _ancestral_length);
|
||||
snprintf (buf, sizeof (buf), "%Ld", _ancestral_length);
|
||||
node->add_property ("ancestral-length", buf);
|
||||
snprintf (buf, sizeof (buf), "%.12g", _stretch);
|
||||
node->add_property ("stretch", buf);
|
||||
|
|
|
@ -106,7 +106,7 @@ RegionFactory::create (Session& session, XMLNode& node, bool yn)
|
|||
}
|
||||
|
||||
boost::shared_ptr<Region>
|
||||
RegionFactory::create (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Region::Flag flags, bool announce)
|
||||
RegionFactory::create (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Region::Flag flags, bool announce)
|
||||
{
|
||||
if (srcs.empty()) {
|
||||
return boost::shared_ptr<Region>();
|
||||
|
|
|
@ -38,7 +38,7 @@ ResampledImportableSource::ResampledImportableSource (const std::string& path,
|
|||
|
||||
/* Initialize the sample rate converter. */
|
||||
|
||||
int src_type;
|
||||
int src_type = SRC_LINEAR;
|
||||
|
||||
switch (srcq) {
|
||||
case SrcBest:
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <glibmm/thread.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
#include <glibmm/fileutils.h>
|
||||
|
||||
#include <pbd/error.h>
|
||||
#include <glibmm/thread.h>
|
||||
|
@ -148,7 +149,8 @@ Session::Session (AudioEngine &eng,
|
|||
|
||||
first_stage_init (fullpath, snapshot_name);
|
||||
|
||||
new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
|
||||
new_session = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
|
||||
|
||||
if (new_session) {
|
||||
if (create (new_session, mix_template, compute_initial_length())) {
|
||||
destroy ();
|
||||
|
|
|
@ -432,19 +432,14 @@ Session::setup_raid_path (string path)
|
|||
}
|
||||
|
||||
int
|
||||
Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
|
||||
Session::ensure_subdirs ()
|
||||
{
|
||||
string dir;
|
||||
|
||||
if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session dir \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = session_directory().peak_path().to_string();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -465,17 +460,39 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
|
|||
dir = session_directory().dead_sound_path().to_string();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session dead sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = session_directory().export_path().to_string();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session export dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir = analysis_dir ();
|
||||
|
||||
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
|
||||
{
|
||||
|
||||
if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ensure_subdirs ()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check new_session so we don't overwrite an existing one */
|
||||
|
||||
|
@ -524,7 +541,6 @@ Session::create (bool& new_session, const string& mix_template, nframes_t initia
|
|||
|
||||
_state_of_the_state = Clean;
|
||||
|
||||
|
||||
save_state ("");
|
||||
|
||||
return 0;
|
||||
|
@ -1979,6 +1995,14 @@ Session::automation_dir () const
|
|||
return res;
|
||||
}
|
||||
|
||||
string
|
||||
Session::analysis_dir () const
|
||||
{
|
||||
string res = _path;
|
||||
res += "analysis/";
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
Session::load_bundles (XMLNode const & node)
|
||||
{
|
||||
|
@ -2544,7 +2568,7 @@ Session::cleanup_sources (Session::cleanup_report& rep)
|
|||
newpath += dead_sound_dir_name;
|
||||
|
||||
if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
|
||||
error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ using namespace PBD;
|
|||
|
||||
sigc::signal<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated;
|
||||
Glib::Cond* SourceFactory::PeaksToBuild;
|
||||
Glib::StaticMutex SourceFactory::peak_building_lock;
|
||||
Glib::StaticMutex SourceFactory::peak_building_lock = GLIBMM_STATIC_MUTEX_INIT;
|
||||
std::list<boost::weak_ptr<AudioSource> > SourceFactory::files_with_peaks;
|
||||
|
||||
static void
|
||||
|
|
|
@ -268,7 +268,7 @@ TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when)
|
|||
|
||||
section.set_start (corrected);
|
||||
metrics->sort (cmp);
|
||||
timestamp_metrics ();
|
||||
timestamp_metrics (true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -345,16 +345,22 @@ TempoMap::remove_meter (const MeterSection& tempo)
|
|||
}
|
||||
|
||||
void
|
||||
TempoMap::do_insert (MetricSection* section)
|
||||
TempoMap::do_insert (MetricSection* section, bool with_bbt)
|
||||
{
|
||||
Metrics::iterator i;
|
||||
|
||||
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
|
||||
if ((*i)->start() < section->start()) {
|
||||
continue;
|
||||
if (with_bbt) {
|
||||
if ((*i)->start() < section->start()) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if ((*i)->frame() < section->frame()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
metrics->insert (i, section);
|
||||
break;
|
||||
}
|
||||
|
@ -363,7 +369,7 @@ TempoMap::do_insert (MetricSection* section)
|
|||
metrics->insert (metrics->end(), section);
|
||||
}
|
||||
|
||||
timestamp_metrics ();
|
||||
timestamp_metrics (with_bbt);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -376,7 +382,18 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
|
|||
|
||||
where.ticks = 0;
|
||||
|
||||
do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()));
|
||||
do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), true);
|
||||
}
|
||||
|
||||
StateChanged (Change (0));
|
||||
}
|
||||
|
||||
void
|
||||
TempoMap::add_tempo (const Tempo& tempo, nframes_t where)
|
||||
{
|
||||
{
|
||||
Glib::RWLock::WriterLock lm (lock);
|
||||
do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), false);
|
||||
}
|
||||
|
||||
StateChanged (Change (0));
|
||||
|
@ -399,7 +416,7 @@ TempoMap::replace_tempo (TempoSection& existing, const Tempo& replacement)
|
|||
*((Tempo *) ts) = replacement;
|
||||
|
||||
replaced = true;
|
||||
timestamp_metrics ();
|
||||
timestamp_metrics (true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -432,7 +449,18 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where)
|
|||
|
||||
where.ticks = 0;
|
||||
|
||||
do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()));
|
||||
do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), true);
|
||||
}
|
||||
|
||||
StateChanged (Change (0));
|
||||
}
|
||||
|
||||
void
|
||||
TempoMap::add_meter (const Meter& meter, nframes_t where)
|
||||
{
|
||||
{
|
||||
Glib::RWLock::WriterLock lm (lock);
|
||||
do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor()), false);
|
||||
}
|
||||
|
||||
StateChanged (Change (0));
|
||||
|
@ -454,7 +482,7 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement)
|
|||
*((Meter*) ms) = replacement;
|
||||
|
||||
replaced = true;
|
||||
timestamp_metrics ();
|
||||
timestamp_metrics (true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -465,6 +493,49 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
TempoMap::change_existing_tempo_at (nframes_t where, double beats_per_minute, double note_type)
|
||||
{
|
||||
Tempo newtempo (beats_per_minute, note_type);
|
||||
|
||||
TempoSection* prev;
|
||||
TempoSection* first;
|
||||
Metrics::iterator i;
|
||||
|
||||
/* find the TempoSection immediately preceding "where"
|
||||
*/
|
||||
|
||||
for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
|
||||
|
||||
if ((*i)->frame() > where) {
|
||||
break;
|
||||
}
|
||||
|
||||
TempoSection* t;
|
||||
|
||||
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
|
||||
if (!first) {
|
||||
first = t;
|
||||
}
|
||||
prev = t;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prev) {
|
||||
if (!first) {
|
||||
error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
prev = first;
|
||||
}
|
||||
|
||||
/* reset */
|
||||
|
||||
*((Tempo*)prev) = newtempo;
|
||||
StateChanged (Change (0));
|
||||
}
|
||||
|
||||
const MeterSection&
|
||||
TempoMap::first_meter () const
|
||||
{
|
||||
|
@ -498,43 +569,84 @@ TempoMap::first_tempo () const
|
|||
}
|
||||
|
||||
void
|
||||
TempoMap::timestamp_metrics ()
|
||||
TempoMap::timestamp_metrics (bool use_bbt)
|
||||
{
|
||||
Metrics::iterator i;
|
||||
const Meter* meter;
|
||||
const Tempo* tempo;
|
||||
Meter *m;
|
||||
Tempo *t;
|
||||
nframes_t current;
|
||||
nframes_t section_frames;
|
||||
BBT_Time start;
|
||||
BBT_Time end;
|
||||
|
||||
meter = &first_meter ();
|
||||
tempo = &first_tempo ();
|
||||
current = 0;
|
||||
|
||||
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
|
||||
end = (*i)->start();
|
||||
if (use_bbt) {
|
||||
|
||||
section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
|
||||
nframes_t current = 0;
|
||||
nframes_t section_frames;
|
||||
BBT_Time start;
|
||||
BBT_Time end;
|
||||
|
||||
current += section_frames;
|
||||
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
|
||||
end = (*i)->start();
|
||||
|
||||
section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
|
||||
|
||||
current += section_frames;
|
||||
|
||||
start = end;
|
||||
|
||||
(*i)->set_frame (current);
|
||||
|
||||
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
|
||||
tempo = t;
|
||||
} else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
|
||||
meter = m;
|
||||
} else {
|
||||
fatal << _("programming error: unhandled MetricSection type") << endmsg;
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
start = end;
|
||||
} else {
|
||||
|
||||
(*i)->set_frame (current);
|
||||
bool first = true;
|
||||
|
||||
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
|
||||
tempo = t;
|
||||
} else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
|
||||
meter = m;
|
||||
} else {
|
||||
fatal << _("programming error: unhandled MetricSection type") << endmsg;
|
||||
/*NOTREACHED*/
|
||||
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
|
||||
BBT_Time bbt;
|
||||
|
||||
bbt_time_with_metric ((*i)->frame(), bbt, Metric (*meter, *tempo));
|
||||
|
||||
// cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
if (bbt.beats != 1 || bbt.ticks != 0) {
|
||||
bbt.bars += 1;
|
||||
bbt.beats = 1;
|
||||
bbt.ticks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// cerr << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << endl;
|
||||
|
||||
(*i)->set_start (bbt);
|
||||
|
||||
if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
|
||||
tempo = t;
|
||||
} else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
|
||||
meter = m;
|
||||
} else {
|
||||
fatal << _("programming error: unhandled MetricSection type") << endmsg;
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dump (cerr);
|
||||
}
|
||||
|
||||
TempoMap::Metric
|
||||
|
@ -666,17 +778,15 @@ TempoMap::bbt_time_with_metric (nframes_t frame, BBT_Time& bbt, const Metric& me
|
|||
nframes_t
|
||||
TempoMap::count_frames_between ( const BBT_Time& start, const BBT_Time& end) const
|
||||
{
|
||||
|
||||
/* for this to work with fractional measure types, start and end have to "legal" BBT types,
|
||||
that means that the beats and ticks should be inside a bar
|
||||
/* for this to work with fractional measure types, start and end have to be "legal" BBT types,
|
||||
that means that the beats and ticks should be inside a bar
|
||||
*/
|
||||
|
||||
|
||||
nframes_t frames = 0;
|
||||
nframes_t start_frame = 0;
|
||||
nframes_t end_frame = 0;
|
||||
|
||||
Metric m = metric_at(start);
|
||||
Metric m = metric_at (start);
|
||||
|
||||
uint32_t bar_offset = start.bars - m.start().bars;
|
||||
|
||||
|
@ -939,67 +1049,6 @@ TempoMap::round_to_beat_subdivision (nframes_t fr, int sub_num)
|
|||
}
|
||||
|
||||
return frame_time (the_beat);
|
||||
|
||||
|
||||
|
||||
/*****************************
|
||||
XXX just keeping this for reference
|
||||
|
||||
TempoMap::BBTPointList::iterator i;
|
||||
TempoMap::BBTPointList *more_zoomed_bbt_points;
|
||||
nframes_t frame_one_beats_worth;
|
||||
nframes_t pos = 0;
|
||||
nframes_t next_pos = 0 ;
|
||||
double tempo = 1;
|
||||
double frames_one_subdivisions_worth;
|
||||
bool fr_has_changed = false;
|
||||
|
||||
int n;
|
||||
|
||||
frame_one_beats_worth = (nframes_t) ::floor ((double) _frame_rate * 60 / 20 ); //one beat @ 20 bpm
|
||||
{
|
||||
Glib::RWLock::ReaderLock lm (lock);
|
||||
more_zoomed_bbt_points = get_points((fr >= frame_one_beats_worth) ?
|
||||
fr - frame_one_beats_worth : 0, fr+frame_one_beats_worth );
|
||||
}
|
||||
if (more_zoomed_bbt_points == 0 || more_zoomed_bbt_points->empty()) {
|
||||
return fr;
|
||||
}
|
||||
|
||||
for (i = more_zoomed_bbt_points->begin(); i != more_zoomed_bbt_points->end(); i++) {
|
||||
if ((*i).frame <= fr) {
|
||||
pos = (*i).frame;
|
||||
tempo = (*i).tempo->beats_per_minute();
|
||||
|
||||
} else {
|
||||
i++;
|
||||
next_pos = (*i).frame;
|
||||
break;
|
||||
}
|
||||
}
|
||||
frames_one_subdivisions_worth = ((double) _frame_rate * 60 / (sub_num * tempo));
|
||||
|
||||
for (n = sub_num; n > 0; n--) {
|
||||
if (fr >= (pos + ((n - 0.5) * frames_one_subdivisions_worth))) {
|
||||
fr = (nframes_t) round(pos + (n * frames_one_subdivisions_worth));
|
||||
if (fr > next_pos) {
|
||||
fr = next_pos; //take care of fractional beats that don't match the subdivision asked
|
||||
}
|
||||
fr_has_changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fr_has_changed) {
|
||||
fr = pos;
|
||||
}
|
||||
|
||||
delete more_zoomed_bbt_points;
|
||||
return fr ;
|
||||
|
||||
******************************/
|
||||
|
||||
|
||||
}
|
||||
|
||||
nframes_t
|
||||
|
@ -1051,6 +1100,12 @@ TempoMap::round_to_type (nframes_t frame, int dir, BBTPointType type)
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
cerr << "for " << frame << " round to " << bbt << " using "
|
||||
<< metric.start()
|
||||
<< endl;
|
||||
*/
|
||||
|
||||
return metric.frame() + count_frames_between (metric.start(), bbt);
|
||||
}
|
||||
|
||||
|
@ -1148,6 +1203,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
|
|||
|
||||
if (beat == 1) {
|
||||
if (current >= lower) {
|
||||
// cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl;
|
||||
points->push_back (BBTPoint (*meter, *tempo,(nframes_t)rint(current), Bar, bar, 1));
|
||||
|
||||
}
|
||||
|
@ -1159,6 +1215,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
|
|||
|
||||
while (beat <= ceil( beats_per_bar) && beat_frame < limit) {
|
||||
if (beat_frame >= lower) {
|
||||
// cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
|
||||
points->push_back (BBTPoint (*meter, *tempo, (nframes_t) rint(beat_frame), Beat, bar, beat));
|
||||
}
|
||||
beat_frame += beat_frames;
|
||||
|
@ -1167,7 +1224,7 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
|
|||
beat++;
|
||||
}
|
||||
|
||||
if (beat > ceil(beats_per_bar) ) {
|
||||
if (beat > ceil(beats_per_bar) || i != metrics->end()) {
|
||||
|
||||
/* we walked an entire bar. its
|
||||
important to move `current' forward
|
||||
|
@ -1185,10 +1242,15 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
|
|||
so we subtract the possible extra fraction from the current
|
||||
*/
|
||||
|
||||
current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar);
|
||||
if (beat > ceil (beats_per_bar)) {
|
||||
/* next bar goes where the numbers suggest */
|
||||
current -= beat_frames * (ceil(beats_per_bar)-beats_per_bar);
|
||||
} else {
|
||||
/* next bar goes where the next metric is */
|
||||
current = limit;
|
||||
}
|
||||
bar++;
|
||||
beat = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1225,6 +1287,33 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const
|
|||
return points;
|
||||
}
|
||||
|
||||
const TempoSection&
|
||||
TempoMap::tempo_section_at (nframes_t frame)
|
||||
{
|
||||
Glib::RWLock::ReaderLock lm (lock);
|
||||
Metrics::iterator i;
|
||||
TempoSection* prev = 0;
|
||||
|
||||
for (i = metrics->begin(); i != metrics->end(); ++i) {
|
||||
TempoSection* t;
|
||||
|
||||
if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
|
||||
|
||||
if ((*i)->frame() > frame) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev = t;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev == 0) {
|
||||
fatal << endmsg;
|
||||
}
|
||||
|
||||
return *prev;
|
||||
}
|
||||
|
||||
const Tempo&
|
||||
TempoMap::tempo_at (nframes_t frame)
|
||||
{
|
||||
|
@ -1303,7 +1392,7 @@ TempoMap::set_state (const XMLNode& node)
|
|||
|
||||
MetricSectionSorter cmp;
|
||||
metrics->sort (cmp);
|
||||
timestamp_metrics ();
|
||||
timestamp_metrics (true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
#include <ardour/transient_detector.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace Vamp;
|
||||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
|
||||
TransientDetector::TransientDetector (float sr)
|
||||
: AudioAnalyser (sr, X_("libardourvampplugins:percussiononsets"))
|
||||
{
|
||||
}
|
||||
|
||||
TransientDetector::~TransientDetector()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
TransientDetector::run (const std::string& path, Readable* src, uint32_t channel, vector<nframes64_t>& results)
|
||||
{
|
||||
current_results = &results;
|
||||
int ret = analyse (path, src, channel);
|
||||
current_results = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
TransientDetector::use_features (Plugin::FeatureSet& features, ostream* out)
|
||||
{
|
||||
const Plugin::FeatureList& fl (features[0]);
|
||||
|
||||
for (Plugin::FeatureList::const_iterator f = fl.begin(); f != fl.end(); ++f) {
|
||||
|
||||
if ((*f).hasTimestamp) {
|
||||
|
||||
if (out) {
|
||||
(*out) << (*f).timestamp.toString() << endl;
|
||||
}
|
||||
|
||||
current_results->push_back (RealTime::realTime2Frame ((*f).timestamp, (nframes_t) floor(sample_rate)));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
TransientDetector::set_threshold (float val)
|
||||
{
|
||||
if (plugin) {
|
||||
plugin->setParameter ("threshold", val);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TransientDetector::set_sensitivity (float val)
|
||||
{
|
||||
if (plugin) {
|
||||
plugin->setParameter ("sensitivity", val);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,9 @@ gtkmm2 = env.Copy()
|
|||
gtkmm2.Merge([libraries['glibmm2'], libraries['gtk2'], libraries['sigc2'], libraries['pangomm'], libraries['atkmm'], libraries['gdkmm2'], libraries['cairomm'], libraries['gtk2-unix-print'] ])
|
||||
gtkmm2.Append(CXXFLAGS = ['-DGLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED', '-DGLIBMM_PROPERTIES_ENABLED', '-DGLIBMM_EXCEPTIONS_ENABLED'])
|
||||
|
||||
if gtkmm2['IS_OSX']:
|
||||
gtkmm2.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
|
||||
|
||||
libgtkmm2 = gtkmm2.SharedLibrary('gtkmm2', gtkmm2_files)
|
||||
Default(libgtkmm2)
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ mackie.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
|
|||
mackie.Append(PACKAGE = domain)
|
||||
mackie.Append(POTFILE = domain + '.pot')
|
||||
|
||||
if mackie['IS_OSX']:
|
||||
mackie.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
|
||||
|
||||
mackie_files=Split("""
|
||||
interface.cc
|
||||
midi_byte_array.cc
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
This file copyright 2006 Dan Stowell.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#include "AmplitudeFollower.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
/**
|
||||
* An implementation of SuperCollider's amplitude-follower algorithm
|
||||
* as a simple Vamp plugin.
|
||||
*/
|
||||
|
||||
AmplitudeFollower::AmplitudeFollower(float inputSampleRate) :
|
||||
Plugin(inputSampleRate),
|
||||
m_stepSize(0),
|
||||
m_previn(0.0f),
|
||||
m_clampcoef(0.01f),
|
||||
m_relaxcoef(0.01f)
|
||||
{
|
||||
}
|
||||
|
||||
AmplitudeFollower::~AmplitudeFollower()
|
||||
{
|
||||
}
|
||||
|
||||
string
|
||||
AmplitudeFollower::getIdentifier() const
|
||||
{
|
||||
return "amplitudefollower";
|
||||
}
|
||||
|
||||
string
|
||||
AmplitudeFollower::getName() const
|
||||
{
|
||||
return "Amplitude Follower";
|
||||
}
|
||||
|
||||
string
|
||||
AmplitudeFollower::getDescription() const
|
||||
{
|
||||
return "Track the amplitude of the audio signal";
|
||||
}
|
||||
|
||||
string
|
||||
AmplitudeFollower::getMaker() const
|
||||
{
|
||||
return "Vamp SDK Example Plugins";
|
||||
}
|
||||
|
||||
int
|
||||
AmplitudeFollower::getPluginVersion() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
string
|
||||
AmplitudeFollower::getCopyright() const
|
||||
{
|
||||
return "Code copyright 2006 Dan Stowell; method from SuperCollider. Freely redistributable (BSD license)";
|
||||
}
|
||||
|
||||
bool
|
||||
AmplitudeFollower::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
||||
{
|
||||
if (channels < getMinChannelCount() ||
|
||||
channels > getMaxChannelCount()) return false;
|
||||
|
||||
m_stepSize = std::min(stepSize, blockSize);
|
||||
|
||||
// Translate the coefficients
|
||||
// from their "convenient" 60dB convergence-time values
|
||||
// to real coefficients
|
||||
m_clampcoef = m_clampcoef==0.0 ? 0.0 : exp(log(0.1)/(m_clampcoef * m_inputSampleRate));
|
||||
m_relaxcoef = m_relaxcoef==0.0 ? 0.0 : exp(log(0.1)/(m_relaxcoef * m_inputSampleRate));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AmplitudeFollower::reset()
|
||||
{
|
||||
m_previn = 0.0f;
|
||||
}
|
||||
|
||||
AmplitudeFollower::OutputList
|
||||
AmplitudeFollower::getOutputDescriptors() const
|
||||
{
|
||||
OutputList list;
|
||||
|
||||
OutputDescriptor sca;
|
||||
sca.identifier = "amplitude";
|
||||
sca.name = "Amplitude";
|
||||
sca.description = "";
|
||||
sca.unit = "V";
|
||||
sca.hasFixedBinCount = true;
|
||||
sca.binCount = 1;
|
||||
sca.hasKnownExtents = false;
|
||||
sca.isQuantized = false;
|
||||
sca.sampleType = OutputDescriptor::OneSamplePerStep;
|
||||
list.push_back(sca);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
AmplitudeFollower::ParameterList
|
||||
AmplitudeFollower::getParameterDescriptors() const
|
||||
{
|
||||
ParameterList list;
|
||||
|
||||
ParameterDescriptor att;
|
||||
att.identifier = "attack";
|
||||
att.name = "Attack time";
|
||||
att.description = "";
|
||||
att.unit = "s";
|
||||
att.minValue = 0.0f;
|
||||
att.maxValue = 1.f;
|
||||
att.defaultValue = 0.01f;
|
||||
att.isQuantized = false;
|
||||
|
||||
list.push_back(att);
|
||||
|
||||
ParameterDescriptor dec;
|
||||
dec.identifier = "release";
|
||||
dec.name = "Release time";
|
||||
dec.description = "";
|
||||
dec.unit = "s";
|
||||
dec.minValue = 0.0f;
|
||||
dec.maxValue = 1.f;
|
||||
dec.defaultValue = 0.01f;
|
||||
dec.isQuantized = false;
|
||||
|
||||
list.push_back(dec);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void AmplitudeFollower::setParameter(std::string paramid, float newval)
|
||||
{
|
||||
if (paramid == "attack") {
|
||||
m_clampcoef = newval;
|
||||
} else if (paramid == "release") {
|
||||
m_relaxcoef = newval;
|
||||
}
|
||||
}
|
||||
|
||||
float AmplitudeFollower::getParameter(std::string paramid) const
|
||||
{
|
||||
if (paramid == "attack") {
|
||||
return m_clampcoef;
|
||||
} else if (paramid == "release") {
|
||||
return m_relaxcoef;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
AmplitudeFollower::FeatureSet
|
||||
AmplitudeFollower::process(const float *const *inputBuffers,
|
||||
Vamp::RealTime timestamp)
|
||||
{
|
||||
if (m_stepSize == 0) {
|
||||
cerr << "ERROR: AmplitudeFollower::process: "
|
||||
<< "AmplitudeFollower has not been initialised"
|
||||
<< endl;
|
||||
return FeatureSet();
|
||||
}
|
||||
|
||||
float previn = m_previn;
|
||||
|
||||
FeatureSet returnFeatures;
|
||||
|
||||
float val;
|
||||
float peak = 0.0f;
|
||||
|
||||
for (size_t i = 0; i < m_stepSize; ++i) {
|
||||
|
||||
val = fabs(inputBuffers[0][i]);
|
||||
|
||||
if (val < previn) {
|
||||
val = val + (previn - val) * m_relaxcoef;
|
||||
} else {
|
||||
val = val + (previn - val) * m_clampcoef;
|
||||
}
|
||||
|
||||
if (val > peak) peak = val;
|
||||
previn = val;
|
||||
}
|
||||
|
||||
m_previn = previn;
|
||||
|
||||
// Now store the "feature" (peak amp) for this sample
|
||||
Feature feature;
|
||||
feature.hasTimestamp = false;
|
||||
feature.values.push_back(peak);
|
||||
returnFeatures[0].push_back(feature);
|
||||
|
||||
return returnFeatures;
|
||||
}
|
||||
|
||||
AmplitudeFollower::FeatureSet
|
||||
AmplitudeFollower::getRemainingFeatures()
|
||||
{
|
||||
return FeatureSet();
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
This file copyright 2006 Dan Stowell.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#ifndef _AMPLITUDE_FOLLOWER_PLUGIN_H_
|
||||
#define _AMPLITUDE_FOLLOWER_PLUGIN_H_
|
||||
|
||||
#include "vamp-sdk/Plugin.h"
|
||||
|
||||
/**
|
||||
* Example plugin implementing the SuperCollider amplitude follower
|
||||
* function.
|
||||
*/
|
||||
|
||||
class AmplitudeFollower : public Vamp::Plugin
|
||||
{
|
||||
public:
|
||||
AmplitudeFollower(float inputSampleRate);
|
||||
virtual ~AmplitudeFollower();
|
||||
|
||||
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
||||
void reset();
|
||||
|
||||
InputDomain getInputDomain() const { return TimeDomain; }
|
||||
|
||||
std::string getIdentifier() const;
|
||||
std::string getName() const;
|
||||
std::string getDescription() const;
|
||||
std::string getMaker() const;
|
||||
int getPluginVersion() const;
|
||||
std::string getCopyright() const;
|
||||
|
||||
OutputList getOutputDescriptors() const;
|
||||
|
||||
ParameterList getParameterDescriptors() const;
|
||||
float getParameter(std::string paramid) const;
|
||||
void setParameter(std::string paramid, float newval);
|
||||
|
||||
FeatureSet process(const float *const *inputBuffers,
|
||||
Vamp::RealTime timestamp);
|
||||
|
||||
FeatureSet getRemainingFeatures();
|
||||
|
||||
protected:
|
||||
size_t m_stepSize;
|
||||
float m_previn;
|
||||
float m_clampcoef;
|
||||
float m_relaxcoef;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,285 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006 Chris Cannam.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#include "PercussionOnsetDetector.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) :
|
||||
Plugin(inputSampleRate),
|
||||
m_stepSize(0),
|
||||
m_blockSize(0),
|
||||
m_threshold(3),
|
||||
m_sensitivity(40),
|
||||
m_priorMagnitudes(0),
|
||||
m_dfMinus1(0),
|
||||
m_dfMinus2(0)
|
||||
{
|
||||
}
|
||||
|
||||
PercussionOnsetDetector::~PercussionOnsetDetector()
|
||||
{
|
||||
delete[] m_priorMagnitudes;
|
||||
}
|
||||
|
||||
string
|
||||
PercussionOnsetDetector::getIdentifier() const
|
||||
{
|
||||
return "percussiononsets";
|
||||
}
|
||||
|
||||
string
|
||||
PercussionOnsetDetector::getName() const
|
||||
{
|
||||
return "Simple Percussion Onset Detector";
|
||||
}
|
||||
|
||||
string
|
||||
PercussionOnsetDetector::getDescription() const
|
||||
{
|
||||
return "Detect percussive note onsets by identifying broadband energy rises";
|
||||
}
|
||||
|
||||
string
|
||||
PercussionOnsetDetector::getMaker() const
|
||||
{
|
||||
return "Vamp SDK Example Plugins";
|
||||
}
|
||||
|
||||
int
|
||||
PercussionOnsetDetector::getPluginVersion() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
string
|
||||
PercussionOnsetDetector::getCopyright() const
|
||||
{
|
||||
return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005. Freely redistributable (BSD license)";
|
||||
}
|
||||
|
||||
size_t
|
||||
PercussionOnsetDetector::getPreferredStepSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
PercussionOnsetDetector::getPreferredBlockSize() const
|
||||
{
|
||||
return 1024;
|
||||
}
|
||||
|
||||
bool
|
||||
PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
||||
{
|
||||
if (channels < getMinChannelCount() ||
|
||||
channels > getMaxChannelCount()) return false;
|
||||
|
||||
m_stepSize = stepSize;
|
||||
m_blockSize = blockSize;
|
||||
|
||||
m_priorMagnitudes = new float[m_blockSize/2];
|
||||
|
||||
for (size_t i = 0; i < m_blockSize/2; ++i) {
|
||||
m_priorMagnitudes[i] = 0.f;
|
||||
}
|
||||
|
||||
m_dfMinus1 = 0.f;
|
||||
m_dfMinus2 = 0.f;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PercussionOnsetDetector::reset()
|
||||
{
|
||||
for (size_t i = 0; i < m_blockSize/2; ++i) {
|
||||
m_priorMagnitudes[i] = 0.f;
|
||||
}
|
||||
|
||||
m_dfMinus1 = 0.f;
|
||||
m_dfMinus2 = 0.f;
|
||||
}
|
||||
|
||||
PercussionOnsetDetector::ParameterList
|
||||
PercussionOnsetDetector::getParameterDescriptors() const
|
||||
{
|
||||
ParameterList list;
|
||||
|
||||
ParameterDescriptor d;
|
||||
d.identifier = "threshold";
|
||||
d.name = "Energy rise threshold";
|
||||
d.description = "Energy rise within a frequency bin necessary to count toward broadband total";
|
||||
d.unit = "dB";
|
||||
d.minValue = 0;
|
||||
d.maxValue = 20;
|
||||
d.defaultValue = 3;
|
||||
d.isQuantized = false;
|
||||
list.push_back(d);
|
||||
|
||||
d.identifier = "sensitivity";
|
||||
d.name = "Sensitivity";
|
||||
d.description = "Sensitivity of peak detector applied to broadband detection function";
|
||||
d.unit = "%";
|
||||
d.minValue = 0;
|
||||
d.maxValue = 100;
|
||||
d.defaultValue = 40;
|
||||
d.isQuantized = false;
|
||||
list.push_back(d);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
float
|
||||
PercussionOnsetDetector::getParameter(std::string id) const
|
||||
{
|
||||
if (id == "threshold") return m_threshold;
|
||||
if (id == "sensitivity") return m_sensitivity;
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
void
|
||||
PercussionOnsetDetector::setParameter(std::string id, float value)
|
||||
{
|
||||
if (id == "threshold") {
|
||||
if (value < 0) value = 0;
|
||||
if (value > 20) value = 20;
|
||||
m_threshold = value;
|
||||
} else if (id == "sensitivity") {
|
||||
if (value < 0) value = 0;
|
||||
if (value > 100) value = 100;
|
||||
m_sensitivity = value;
|
||||
}
|
||||
}
|
||||
|
||||
PercussionOnsetDetector::OutputList
|
||||
PercussionOnsetDetector::getOutputDescriptors() const
|
||||
{
|
||||
OutputList list;
|
||||
|
||||
OutputDescriptor d;
|
||||
d.identifier = "onsets";
|
||||
d.name = "Onsets";
|
||||
d.description = "Percussive note onset locations";
|
||||
d.unit = "";
|
||||
d.hasFixedBinCount = true;
|
||||
d.binCount = 0;
|
||||
d.hasKnownExtents = false;
|
||||
d.isQuantized = false;
|
||||
d.sampleType = OutputDescriptor::VariableSampleRate;
|
||||
d.sampleRate = m_inputSampleRate;
|
||||
list.push_back(d);
|
||||
|
||||
d.identifier = "detectionfunction";
|
||||
d.name = "Detection Function";
|
||||
d.description = "Broadband energy rise detection function";
|
||||
d.binCount = 1;
|
||||
d.isQuantized = true;
|
||||
d.quantizeStep = 1.0;
|
||||
d.sampleType = OutputDescriptor::OneSamplePerStep;
|
||||
list.push_back(d);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
PercussionOnsetDetector::FeatureSet
|
||||
PercussionOnsetDetector::process(const float *const *inputBuffers,
|
||||
Vamp::RealTime ts)
|
||||
{
|
||||
if (m_stepSize == 0) {
|
||||
cerr << "ERROR: PercussionOnsetDetector::process: "
|
||||
<< "PercussionOnsetDetector has not been initialised"
|
||||
<< endl;
|
||||
return FeatureSet();
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (size_t i = 1; i < m_blockSize/2; ++i) {
|
||||
|
||||
float real = inputBuffers[0][i*2];
|
||||
float imag = inputBuffers[0][i*2 + 1];
|
||||
|
||||
float sqrmag = real * real + imag * imag;
|
||||
|
||||
if (m_priorMagnitudes[i] > 0.f) {
|
||||
float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
|
||||
|
||||
// std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl;
|
||||
|
||||
if (diff >= m_threshold) ++count;
|
||||
}
|
||||
|
||||
m_priorMagnitudes[i] = sqrmag;
|
||||
}
|
||||
|
||||
FeatureSet returnFeatures;
|
||||
|
||||
Feature detectionFunction;
|
||||
detectionFunction.hasTimestamp = false;
|
||||
detectionFunction.values.push_back(count);
|
||||
returnFeatures[1].push_back(detectionFunction);
|
||||
|
||||
if (m_dfMinus2 < m_dfMinus1 &&
|
||||
m_dfMinus1 >= count &&
|
||||
m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
|
||||
|
||||
Feature onset;
|
||||
onset.hasTimestamp = true;
|
||||
onset.timestamp = ts - Vamp::RealTime::frame2RealTime
|
||||
(m_stepSize, lrintf(m_inputSampleRate));
|
||||
returnFeatures[0].push_back(onset);
|
||||
}
|
||||
|
||||
m_dfMinus2 = m_dfMinus1;
|
||||
m_dfMinus1 = count;
|
||||
|
||||
return returnFeatures;
|
||||
}
|
||||
|
||||
PercussionOnsetDetector::FeatureSet
|
||||
PercussionOnsetDetector::getRemainingFeatures()
|
||||
{
|
||||
return FeatureSet();
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006 Chris Cannam.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#ifndef _PERCUSSION_ONSET_DETECTOR_PLUGIN_H_
|
||||
#define _PERCUSSION_ONSET_DETECTOR_PLUGIN_H_
|
||||
|
||||
#include "vamp-sdk/Plugin.h"
|
||||
|
||||
/**
|
||||
* Example plugin that detects percussive events.
|
||||
*/
|
||||
|
||||
class PercussionOnsetDetector : public Vamp::Plugin
|
||||
{
|
||||
public:
|
||||
PercussionOnsetDetector(float inputSampleRate);
|
||||
virtual ~PercussionOnsetDetector();
|
||||
|
||||
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
||||
void reset();
|
||||
|
||||
InputDomain getInputDomain() const { return FrequencyDomain; }
|
||||
|
||||
std::string getIdentifier() const;
|
||||
std::string getName() const;
|
||||
std::string getDescription() const;
|
||||
std::string getMaker() const;
|
||||
int getPluginVersion() const;
|
||||
std::string getCopyright() const;
|
||||
|
||||
size_t getPreferredStepSize() const;
|
||||
size_t getPreferredBlockSize() const;
|
||||
|
||||
ParameterList getParameterDescriptors() const;
|
||||
float getParameter(std::string id) const;
|
||||
void setParameter(std::string id, float value);
|
||||
|
||||
OutputList getOutputDescriptors() const;
|
||||
|
||||
FeatureSet process(const float *const *inputBuffers,
|
||||
Vamp::RealTime timestamp);
|
||||
|
||||
FeatureSet getRemainingFeatures();
|
||||
|
||||
protected:
|
||||
size_t m_stepSize;
|
||||
size_t m_blockSize;
|
||||
|
||||
float m_threshold;
|
||||
float m_sensitivity;
|
||||
float *m_priorMagnitudes;
|
||||
float m_dfMinus1;
|
||||
float m_dfMinus2;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
# -*- python -*-
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import glob
|
||||
|
||||
plugin_files = glob.glob ("*.cpp")
|
||||
|
||||
Import('env install_prefix libraries')
|
||||
vampplugs = env.Copy()
|
||||
|
||||
vampplugs.Append (CPPATH='#libs/vamp-sdk/vamp', CXXFLAGS="-Ilibs/vamp-sdk")
|
||||
vampplugs.Merge ([libraries['vamp'],
|
||||
libraries['vamphost']
|
||||
])
|
||||
|
||||
libvampplugins = vampplugs.SharedLibrary('ardourvampplugins', plugin_files)
|
||||
|
||||
Default(libvampplugins)
|
||||
|
||||
env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'vamp'), libvampplugins))
|
||||
|
||||
env.Alias('tarball', env.Distribute (env['DISTTREE'],
|
||||
[ 'SConscript', 'COPYING', 'README' ] +
|
||||
plugin_files +
|
||||
glob.glob('*.h')))
|
|
@ -0,0 +1,188 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006 Chris Cannam.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#include "SpectralCentroid.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
SpectralCentroid::SpectralCentroid(float inputSampleRate) :
|
||||
Plugin(inputSampleRate),
|
||||
m_stepSize(0),
|
||||
m_blockSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
SpectralCentroid::~SpectralCentroid()
|
||||
{
|
||||
}
|
||||
|
||||
string
|
||||
SpectralCentroid::getIdentifier() const
|
||||
{
|
||||
return "spectralcentroid";
|
||||
}
|
||||
|
||||
string
|
||||
SpectralCentroid::getName() const
|
||||
{
|
||||
return "Spectral Centroid";
|
||||
}
|
||||
|
||||
string
|
||||
SpectralCentroid::getDescription() const
|
||||
{
|
||||
return "Calculate the centroid frequency of the spectrum of the input signal";
|
||||
}
|
||||
|
||||
string
|
||||
SpectralCentroid::getMaker() const
|
||||
{
|
||||
return "Vamp SDK Example Plugins";
|
||||
}
|
||||
|
||||
int
|
||||
SpectralCentroid::getPluginVersion() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
string
|
||||
SpectralCentroid::getCopyright() const
|
||||
{
|
||||
return "Freely redistributable (BSD license)";
|
||||
}
|
||||
|
||||
bool
|
||||
SpectralCentroid::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
||||
{
|
||||
if (channels < getMinChannelCount() ||
|
||||
channels > getMaxChannelCount()) return false;
|
||||
|
||||
m_stepSize = stepSize;
|
||||
m_blockSize = blockSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SpectralCentroid::reset()
|
||||
{
|
||||
}
|
||||
|
||||
SpectralCentroid::OutputList
|
||||
SpectralCentroid::getOutputDescriptors() const
|
||||
{
|
||||
OutputList list;
|
||||
|
||||
OutputDescriptor d;
|
||||
d.identifier = "logcentroid";
|
||||
d.name = "Log Frequency Centroid";
|
||||
d.description = "Centroid of the log weighted frequency spectrum";
|
||||
d.unit = "Hz";
|
||||
d.hasFixedBinCount = true;
|
||||
d.binCount = 1;
|
||||
d.hasKnownExtents = false;
|
||||
d.isQuantized = false;
|
||||
d.sampleType = OutputDescriptor::OneSamplePerStep;
|
||||
list.push_back(d);
|
||||
|
||||
d.identifier = "linearcentroid";
|
||||
d.name = "Linear Frequency Centroid";
|
||||
d.description = "Centroid of the linear frequency spectrum";
|
||||
list.push_back(d);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
SpectralCentroid::FeatureSet
|
||||
SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime)
|
||||
{
|
||||
if (m_stepSize == 0) {
|
||||
cerr << "ERROR: SpectralCentroid::process: "
|
||||
<< "SpectralCentroid has not been initialised"
|
||||
<< endl;
|
||||
return FeatureSet();
|
||||
}
|
||||
|
||||
double numLin = 0.0, numLog = 0.0, denom = 0.0;
|
||||
|
||||
for (size_t i = 1; i <= m_blockSize/2; ++i) {
|
||||
double freq = (double(i) * m_inputSampleRate) / m_blockSize;
|
||||
double real = inputBuffers[0][i*2];
|
||||
double imag = inputBuffers[0][i*2 + 1];
|
||||
double power = sqrt(real * real + imag * imag) / (m_blockSize/2);
|
||||
numLin += freq * power;
|
||||
numLog += log10f(freq) * power;
|
||||
denom += power;
|
||||
}
|
||||
|
||||
FeatureSet returnFeatures;
|
||||
|
||||
// std::cerr << "power " << denom << ", block size " << m_blockSize << std::endl;
|
||||
|
||||
if (denom != 0.0) {
|
||||
float centroidLin = float(numLin / denom);
|
||||
float centroidLog = powf(10, float(numLog / denom));
|
||||
|
||||
Feature feature;
|
||||
feature.hasTimestamp = false;
|
||||
if (!std::isnan(centroidLog) && !std::isinf(centroidLog)) {
|
||||
feature.values.push_back(centroidLog);
|
||||
}
|
||||
returnFeatures[0].push_back(feature);
|
||||
|
||||
feature.values.clear();
|
||||
if (!std::isnan(centroidLin) && !std::isinf(centroidLin)) {
|
||||
feature.values.push_back(centroidLin);
|
||||
}
|
||||
returnFeatures[1].push_back(feature);
|
||||
}
|
||||
|
||||
return returnFeatures;
|
||||
}
|
||||
|
||||
SpectralCentroid::FeatureSet
|
||||
SpectralCentroid::getRemainingFeatures()
|
||||
{
|
||||
return FeatureSet();
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006 Chris Cannam.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#ifndef _SPECTRAL_CENTROID_PLUGIN_H_
|
||||
#define _SPECTRAL_CENTROID_PLUGIN_H_
|
||||
|
||||
#include "vamp-sdk/Plugin.h"
|
||||
|
||||
/**
|
||||
* Example plugin that calculates the centre of gravity of the
|
||||
* frequency domain representation of each block of audio.
|
||||
*/
|
||||
|
||||
class SpectralCentroid : public Vamp::Plugin
|
||||
{
|
||||
public:
|
||||
SpectralCentroid(float inputSampleRate);
|
||||
virtual ~SpectralCentroid();
|
||||
|
||||
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
||||
void reset();
|
||||
|
||||
InputDomain getInputDomain() const { return FrequencyDomain; }
|
||||
|
||||
std::string getIdentifier() const;
|
||||
std::string getName() const;
|
||||
std::string getDescription() const;
|
||||
std::string getMaker() const;
|
||||
int getPluginVersion() const;
|
||||
std::string getCopyright() const;
|
||||
|
||||
OutputList getOutputDescriptors() const;
|
||||
|
||||
FeatureSet process(const float *const *inputBuffers,
|
||||
Vamp::RealTime timestamp);
|
||||
|
||||
FeatureSet getRemainingFeatures();
|
||||
|
||||
protected:
|
||||
size_t m_stepSize;
|
||||
size_t m_blockSize;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,194 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006 Chris Cannam.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#include "ZeroCrossing.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
|
||||
ZeroCrossing::ZeroCrossing(float inputSampleRate) :
|
||||
Plugin(inputSampleRate),
|
||||
m_stepSize(0),
|
||||
m_previousSample(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
ZeroCrossing::~ZeroCrossing()
|
||||
{
|
||||
}
|
||||
|
||||
string
|
||||
ZeroCrossing::getIdentifier() const
|
||||
{
|
||||
return "zerocrossing";
|
||||
}
|
||||
|
||||
string
|
||||
ZeroCrossing::getName() const
|
||||
{
|
||||
return "Zero Crossings";
|
||||
}
|
||||
|
||||
string
|
||||
ZeroCrossing::getDescription() const
|
||||
{
|
||||
return "Detect and count zero crossing points";
|
||||
}
|
||||
|
||||
string
|
||||
ZeroCrossing::getMaker() const
|
||||
{
|
||||
return "Vamp SDK Example Plugins";
|
||||
}
|
||||
|
||||
int
|
||||
ZeroCrossing::getPluginVersion() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
string
|
||||
ZeroCrossing::getCopyright() const
|
||||
{
|
||||
return "Freely redistributable (BSD license)";
|
||||
}
|
||||
|
||||
bool
|
||||
ZeroCrossing::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
||||
{
|
||||
if (channels < getMinChannelCount() ||
|
||||
channels > getMaxChannelCount()) return false;
|
||||
|
||||
m_stepSize = std::min(stepSize, blockSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ZeroCrossing::reset()
|
||||
{
|
||||
m_previousSample = 0.0f;
|
||||
}
|
||||
|
||||
ZeroCrossing::OutputList
|
||||
ZeroCrossing::getOutputDescriptors() const
|
||||
{
|
||||
OutputList list;
|
||||
|
||||
OutputDescriptor zc;
|
||||
zc.identifier = "counts";
|
||||
zc.name = "Zero Crossing Counts";
|
||||
zc.description = "The number of zero crossing points per processing block";
|
||||
zc.unit = "crossings";
|
||||
zc.hasFixedBinCount = true;
|
||||
zc.binCount = 1;
|
||||
zc.hasKnownExtents = false;
|
||||
zc.isQuantized = true;
|
||||
zc.quantizeStep = 1.0;
|
||||
zc.sampleType = OutputDescriptor::OneSamplePerStep;
|
||||
list.push_back(zc);
|
||||
|
||||
zc.identifier = "zerocrossings";
|
||||
zc.name = "Zero Crossings";
|
||||
zc.description = "The locations of zero crossing points";
|
||||
zc.unit = "";
|
||||
zc.hasFixedBinCount = true;
|
||||
zc.binCount = 0;
|
||||
zc.sampleType = OutputDescriptor::VariableSampleRate;
|
||||
zc.sampleRate = m_inputSampleRate;
|
||||
list.push_back(zc);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
ZeroCrossing::FeatureSet
|
||||
ZeroCrossing::process(const float *const *inputBuffers,
|
||||
Vamp::RealTime timestamp)
|
||||
{
|
||||
if (m_stepSize == 0) {
|
||||
cerr << "ERROR: ZeroCrossing::process: "
|
||||
<< "ZeroCrossing has not been initialised"
|
||||
<< endl;
|
||||
return FeatureSet();
|
||||
}
|
||||
|
||||
float prev = m_previousSample;
|
||||
size_t count = 0;
|
||||
|
||||
FeatureSet returnFeatures;
|
||||
|
||||
for (size_t i = 0; i < m_stepSize; ++i) {
|
||||
|
||||
float sample = inputBuffers[0][i];
|
||||
bool crossing = false;
|
||||
|
||||
if (sample <= 0.0) {
|
||||
if (prev > 0.0) crossing = true;
|
||||
} else if (sample > 0.0) {
|
||||
if (prev <= 0.0) crossing = true;
|
||||
}
|
||||
|
||||
if (crossing) {
|
||||
++count;
|
||||
Feature feature;
|
||||
feature.hasTimestamp = true;
|
||||
feature.timestamp = timestamp +
|
||||
Vamp::RealTime::frame2RealTime(i, (size_t)m_inputSampleRate);
|
||||
returnFeatures[1].push_back(feature);
|
||||
}
|
||||
|
||||
prev = sample;
|
||||
}
|
||||
|
||||
m_previousSample = prev;
|
||||
|
||||
Feature feature;
|
||||
feature.hasTimestamp = false;
|
||||
feature.values.push_back(count);
|
||||
|
||||
returnFeatures[0].push_back(feature);
|
||||
return returnFeatures;
|
||||
}
|
||||
|
||||
ZeroCrossing::FeatureSet
|
||||
ZeroCrossing::getRemainingFeatures()
|
||||
{
|
||||
return FeatureSet();
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006 Chris Cannam.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#ifndef _ZERO_CROSSING_PLUGIN_H_
|
||||
#define _ZERO_CROSSING_PLUGIN_H_
|
||||
|
||||
#include "vamp-sdk/Plugin.h"
|
||||
|
||||
/**
|
||||
* Example plugin that calculates the positions and density of
|
||||
* zero-crossing points in an audio waveform.
|
||||
*/
|
||||
|
||||
class ZeroCrossing : public Vamp::Plugin
|
||||
{
|
||||
public:
|
||||
ZeroCrossing(float inputSampleRate);
|
||||
virtual ~ZeroCrossing();
|
||||
|
||||
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
||||
void reset();
|
||||
|
||||
InputDomain getInputDomain() const { return TimeDomain; }
|
||||
|
||||
std::string getIdentifier() const;
|
||||
std::string getName() const;
|
||||
std::string getDescription() const;
|
||||
std::string getMaker() const;
|
||||
int getPluginVersion() const;
|
||||
std::string getCopyright() const;
|
||||
|
||||
OutputList getOutputDescriptors() const;
|
||||
|
||||
FeatureSet process(const float *const *inputBuffers,
|
||||
Vamp::RealTime timestamp);
|
||||
|
||||
FeatureSet getRemainingFeatures();
|
||||
|
||||
protected:
|
||||
size_t m_stepSize;
|
||||
float m_previousSample;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006 Chris Cannam.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#include "vamp/vamp.h"
|
||||
#include "vamp-sdk/PluginAdapter.h"
|
||||
|
||||
#include "ZeroCrossing.h"
|
||||
#include "SpectralCentroid.h"
|
||||
#include "PercussionOnsetDetector.h"
|
||||
#include "AmplitudeFollower.h"
|
||||
|
||||
static Vamp::PluginAdapter<ZeroCrossing> zeroCrossingAdapter;
|
||||
static Vamp::PluginAdapter<SpectralCentroid> spectralCentroidAdapter;
|
||||
static Vamp::PluginAdapter<PercussionOnsetDetector> percussionOnsetAdapter;
|
||||
static Vamp::PluginAdapter<AmplitudeFollower> amplitudeAdapter;
|
||||
|
||||
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
|
||||
unsigned int index)
|
||||
{
|
||||
if (version < 1) return 0;
|
||||
|
||||
switch (index) {
|
||||
case 0: return zeroCrossingAdapter.getDescriptor();
|
||||
case 1: return spectralCentroidAdapter.getDescriptor();
|
||||
case 2: return percussionOnsetAdapter.getDescriptor();
|
||||
case 3: return amplitudeAdapter.getDescriptor();
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ vamp-sdk/RealTime.cpp
|
|||
|
||||
vamphostsdk_files = Split ("""
|
||||
vamp-sdk/PluginHostAdapter.cpp
|
||||
vamp-sdk/hostext/PluginBufferingAdapter.cpp
|
||||
vamp-sdk/hostext/PluginChannelAdapter.cpp
|
||||
vamp-sdk/hostext/PluginInputDomainAdapter.cpp
|
||||
vamp-sdk/hostext/PluginLoader.cpp
|
||||
|
@ -21,7 +22,11 @@ vamp-sdk/RealTime.cpp
|
|||
Import('env install_prefix libraries')
|
||||
vampsdk = env.Copy()
|
||||
|
||||
vampsdk.Append (CPPATH='#libs/vamp-sdk/vamp', CXXFLAGS="-Ilibs/vamp-sdk")
|
||||
vampsdk.Merge ([libraries['fftw3'], libraries['fftw3f']])
|
||||
|
||||
# HAVE_FFTW3 is used to help improve some performance aspects of VAMP's InputDomainAdapter
|
||||
|
||||
vampsdk.Append (CPPATH='#libs/vamp-sdk/vamp', CXXFLAGS="-Ilibs/vamp-sdk -DHAVE_FFTW3")
|
||||
|
||||
libvampsdk = vampsdk.SharedLibrary('vampsdk', vampsdk_files)
|
||||
libvamphostsdk = vampsdk.SharedLibrary('vamphostsdk', vamphostsdk_files)
|
||||
|
@ -30,6 +35,8 @@ Default(libvampsdk)
|
|||
Default(libvamphostsdk)
|
||||
|
||||
env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libvampsdk))
|
||||
env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libvamphostsdk))
|
||||
|
||||
env.Alias('tarball', env.Distribute (env['DISTTREE'],
|
||||
[ 'SConscript', 'COPYING', 'README' ] +
|
||||
vampsdk_files +
|
||||
|
|
|
@ -125,23 +125,31 @@ struct RealTime
|
|||
|
||||
RealTime operator/(int d) const;
|
||||
|
||||
// Find the fractional difference between times
|
||||
//
|
||||
/**
|
||||
* Return the ratio of two times.
|
||||
*/
|
||||
double operator/(const RealTime &r) const;
|
||||
|
||||
// Return a human-readable debug-type string to full precision
|
||||
// (probably not a format to show to a user directly)
|
||||
//
|
||||
/**
|
||||
* Return a human-readable debug-type string to full precision
|
||||
* (probably not a format to show to a user directly)
|
||||
*/
|
||||
std::string toString() const;
|
||||
|
||||
// Return a user-readable string to the nearest millisecond
|
||||
// in a form like HH:MM:SS.mmm
|
||||
//
|
||||
/**
|
||||
* Return a user-readable string to the nearest millisecond
|
||||
* in a form like HH:MM:SS.mmm
|
||||
*/
|
||||
std::string toText(bool fixedDp = false) const;
|
||||
|
||||
// Convenience functions for handling sample frames
|
||||
//
|
||||
/**
|
||||
* Convert a RealTime into a sample frame at the given sample rate.
|
||||
*/
|
||||
static long realTime2Frame(const RealTime &r, unsigned int sampleRate);
|
||||
|
||||
/**
|
||||
* Convert a sample frame at the given sample rate into a RealTime.
|
||||
*/
|
||||
static RealTime frame2RealTime(long frame, unsigned int sampleRate);
|
||||
|
||||
static const RealTime zeroTime;
|
||||
|
|
|
@ -0,0 +1,490 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006-2007 Chris Cannam and QMUL.
|
||||
This file by Mark Levy and Chris Cannam.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "PluginBufferingAdapter.h"
|
||||
|
||||
using std::vector;
|
||||
using std::map;
|
||||
|
||||
namespace Vamp {
|
||||
|
||||
namespace HostExt {
|
||||
|
||||
class PluginBufferingAdapter::Impl
|
||||
{
|
||||
public:
|
||||
Impl(Plugin *plugin, float inputSampleRate);
|
||||
~Impl();
|
||||
|
||||
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
||||
|
||||
OutputList getOutputDescriptors() const;
|
||||
|
||||
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
||||
|
||||
FeatureSet getRemainingFeatures();
|
||||
|
||||
protected:
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer(int n) :
|
||||
m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
|
||||
virtual ~RingBuffer() { delete[] m_buffer; }
|
||||
|
||||
int getSize() const { return m_size-1; }
|
||||
void reset() { m_writer = 0; m_reader = 0; }
|
||||
|
||||
int getReadSpace() const {
|
||||
int writer = m_writer, reader = m_reader, space;
|
||||
if (writer > reader) space = writer - reader;
|
||||
else if (writer < reader) space = (writer + m_size) - reader;
|
||||
else space = 0;
|
||||
return space;
|
||||
}
|
||||
|
||||
int getWriteSpace() const {
|
||||
int writer = m_writer;
|
||||
int reader = m_reader;
|
||||
int space = (reader + m_size - writer - 1);
|
||||
if (space >= m_size) space -= m_size;
|
||||
return space;
|
||||
}
|
||||
|
||||
int peek(float *destination, int n) const {
|
||||
|
||||
int available = getReadSpace();
|
||||
|
||||
if (n > available) {
|
||||
for (int i = available; i < n; ++i) {
|
||||
destination[i] = 0.f;
|
||||
}
|
||||
n = available;
|
||||
}
|
||||
if (n == 0) return n;
|
||||
|
||||
int reader = m_reader;
|
||||
int here = m_size - reader;
|
||||
const float *const bufbase = m_buffer + reader;
|
||||
|
||||
if (here >= n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
destination[i] = bufbase[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < here; ++i) {
|
||||
destination[i] = bufbase[i];
|
||||
}
|
||||
float *const destbase = destination + here;
|
||||
const int nh = n - here;
|
||||
for (int i = 0; i < nh; ++i) {
|
||||
destbase[i] = m_buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int skip(int n) {
|
||||
|
||||
int available = getReadSpace();
|
||||
if (n > available) {
|
||||
n = available;
|
||||
}
|
||||
if (n == 0) return n;
|
||||
|
||||
int reader = m_reader;
|
||||
reader += n;
|
||||
while (reader >= m_size) reader -= m_size;
|
||||
m_reader = reader;
|
||||
return n;
|
||||
}
|
||||
|
||||
int write(const float *source, int n) {
|
||||
|
||||
int available = getWriteSpace();
|
||||
if (n > available) {
|
||||
n = available;
|
||||
}
|
||||
if (n == 0) return n;
|
||||
|
||||
int writer = m_writer;
|
||||
int here = m_size - writer;
|
||||
float *const bufbase = m_buffer + writer;
|
||||
|
||||
if (here >= n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
bufbase[i] = source[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < here; ++i) {
|
||||
bufbase[i] = source[i];
|
||||
}
|
||||
const int nh = n - here;
|
||||
const float *const srcbase = source + here;
|
||||
float *const buf = m_buffer;
|
||||
for (int i = 0; i < nh; ++i) {
|
||||
buf[i] = srcbase[i];
|
||||
}
|
||||
}
|
||||
|
||||
writer += n;
|
||||
while (writer >= m_size) writer -= m_size;
|
||||
m_writer = writer;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int zero(int n) {
|
||||
|
||||
int available = getWriteSpace();
|
||||
if (n > available) {
|
||||
n = available;
|
||||
}
|
||||
if (n == 0) return n;
|
||||
|
||||
int writer = m_writer;
|
||||
int here = m_size - writer;
|
||||
float *const bufbase = m_buffer + writer;
|
||||
|
||||
if (here >= n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
bufbase[i] = 0.f;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < here; ++i) {
|
||||
bufbase[i] = 0.f;
|
||||
}
|
||||
const int nh = n - here;
|
||||
for (int i = 0; i < nh; ++i) {
|
||||
m_buffer[i] = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
writer += n;
|
||||
while (writer >= m_size) writer -= m_size;
|
||||
m_writer = writer;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
protected:
|
||||
float *m_buffer;
|
||||
int m_writer;
|
||||
int m_reader;
|
||||
int m_size;
|
||||
|
||||
private:
|
||||
RingBuffer(const RingBuffer &); // not provided
|
||||
RingBuffer &operator=(const RingBuffer &); // not provided
|
||||
};
|
||||
|
||||
Plugin *m_plugin;
|
||||
size_t m_inputStepSize;
|
||||
size_t m_inputBlockSize;
|
||||
size_t m_stepSize;
|
||||
size_t m_blockSize;
|
||||
size_t m_channels;
|
||||
vector<RingBuffer *> m_queue;
|
||||
float **m_buffers;
|
||||
float m_inputSampleRate;
|
||||
RealTime m_timestamp;
|
||||
OutputList m_outputs;
|
||||
|
||||
void processBlock(FeatureSet& allFeatureSets, RealTime timestamp);
|
||||
};
|
||||
|
||||
PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
|
||||
PluginWrapper(plugin)
|
||||
{
|
||||
m_impl = new Impl(plugin, m_inputSampleRate);
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::~PluginBufferingAdapter()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
||||
{
|
||||
return m_impl->initialise(channels, stepSize, blockSize);
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::OutputList
|
||||
PluginBufferingAdapter::getOutputDescriptors() const
|
||||
{
|
||||
return m_impl->getOutputDescriptors();
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::FeatureSet
|
||||
PluginBufferingAdapter::process(const float *const *inputBuffers,
|
||||
RealTime timestamp)
|
||||
{
|
||||
return m_impl->process(inputBuffers, timestamp);
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::FeatureSet
|
||||
PluginBufferingAdapter::getRemainingFeatures()
|
||||
{
|
||||
return m_impl->getRemainingFeatures();
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
||||
m_plugin(plugin),
|
||||
m_inputStepSize(0),
|
||||
m_inputBlockSize(0),
|
||||
m_stepSize(0),
|
||||
m_blockSize(0),
|
||||
m_channels(0),
|
||||
m_queue(0),
|
||||
m_buffers(0),
|
||||
m_inputSampleRate(inputSampleRate),
|
||||
m_timestamp()
|
||||
{
|
||||
m_outputs = plugin->getOutputDescriptors();
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::Impl::~Impl()
|
||||
{
|
||||
// the adapter will delete the plugin
|
||||
|
||||
for (size_t i = 0; i < m_channels; ++i) {
|
||||
delete m_queue[i];
|
||||
delete[] m_buffers[i];
|
||||
}
|
||||
delete[] m_buffers;
|
||||
}
|
||||
|
||||
size_t
|
||||
PluginBufferingAdapter::getPreferredStepSize() const
|
||||
{
|
||||
return getPreferredBlockSize();
|
||||
}
|
||||
|
||||
bool
|
||||
PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
||||
{
|
||||
if (stepSize != blockSize) {
|
||||
std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_channels = channels;
|
||||
m_inputStepSize = stepSize;
|
||||
m_inputBlockSize = blockSize;
|
||||
|
||||
// use the step and block sizes which the plugin prefers
|
||||
m_stepSize = m_plugin->getPreferredStepSize();
|
||||
m_blockSize = m_plugin->getPreferredBlockSize();
|
||||
|
||||
// or sensible defaults if it has no preference
|
||||
if (m_blockSize == 0) {
|
||||
m_blockSize = 1024;
|
||||
}
|
||||
if (m_stepSize == 0) {
|
||||
if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
|
||||
m_stepSize = m_blockSize/2;
|
||||
} else {
|
||||
m_stepSize = m_blockSize;
|
||||
}
|
||||
} else if (m_stepSize > m_blockSize) {
|
||||
if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
|
||||
m_blockSize = m_stepSize * 2;
|
||||
} else {
|
||||
m_blockSize = m_stepSize;
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "PluginBufferingAdapter::initialise: stepSize " << m_inputStepSize << " -> " << m_stepSize
|
||||
<< ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
|
||||
|
||||
// current implementation breaks if step is greater than block
|
||||
if (m_stepSize > m_blockSize) {
|
||||
std::cerr << "PluginBufferingAdapter::initialise: plugin's preferred stepSize greater than blockSize, giving up!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_buffers = new float *[m_channels];
|
||||
|
||||
for (size_t i = 0; i < m_channels; ++i) {
|
||||
m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
|
||||
m_buffers[i] = new float[m_blockSize];
|
||||
}
|
||||
|
||||
return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::OutputList
|
||||
PluginBufferingAdapter::Impl::getOutputDescriptors() const
|
||||
{
|
||||
OutputList outs = m_plugin->getOutputDescriptors();
|
||||
for (size_t i = 0; i < outs.size(); ++i) {
|
||||
if (outs[i].sampleType == OutputDescriptor::OneSamplePerStep) {
|
||||
outs[i].sampleRate = 1.f / m_stepSize;
|
||||
}
|
||||
outs[i].sampleType = OutputDescriptor::VariableSampleRate;
|
||||
}
|
||||
return outs;
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::FeatureSet
|
||||
PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
|
||||
RealTime timestamp)
|
||||
{
|
||||
FeatureSet allFeatureSets;
|
||||
|
||||
// queue the new input
|
||||
|
||||
for (size_t i = 0; i < m_channels; ++i) {
|
||||
int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
|
||||
if (written < int(m_inputBlockSize) && i == 0) {
|
||||
std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
|
||||
<< "Buffer overflow: wrote " << written
|
||||
<< " of " << m_inputBlockSize
|
||||
<< " input samples (for plugin step size "
|
||||
<< m_stepSize << ", block size " << m_blockSize << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// process as much as we can
|
||||
|
||||
while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
|
||||
processBlock(allFeatureSets, timestamp);
|
||||
}
|
||||
|
||||
return allFeatureSets;
|
||||
}
|
||||
|
||||
PluginBufferingAdapter::FeatureSet
|
||||
PluginBufferingAdapter::Impl::getRemainingFeatures()
|
||||
{
|
||||
FeatureSet allFeatureSets;
|
||||
|
||||
// process remaining samples in queue
|
||||
while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
|
||||
processBlock(allFeatureSets, m_timestamp);
|
||||
}
|
||||
|
||||
// pad any last samples remaining and process
|
||||
if (m_queue[0]->getReadSpace() > 0) {
|
||||
for (size_t i = 0; i < m_channels; ++i) {
|
||||
m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
|
||||
}
|
||||
processBlock(allFeatureSets, m_timestamp);
|
||||
}
|
||||
|
||||
// get remaining features
|
||||
|
||||
FeatureSet featureSet = m_plugin->getRemainingFeatures();
|
||||
|
||||
for (map<int, FeatureList>::iterator iter = featureSet.begin();
|
||||
iter != featureSet.end(); ++iter) {
|
||||
FeatureList featureList = iter->second;
|
||||
for (size_t i = 0; i < featureList.size(); ++i) {
|
||||
allFeatureSets[iter->first].push_back(featureList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return allFeatureSets;
|
||||
}
|
||||
|
||||
void
|
||||
PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets,
|
||||
RealTime timestamp)
|
||||
{
|
||||
for (size_t i = 0; i < m_channels; ++i) {
|
||||
m_queue[i]->peek(m_buffers[i], m_blockSize);
|
||||
}
|
||||
|
||||
FeatureSet featureSet = m_plugin->process(m_buffers, m_timestamp);
|
||||
|
||||
for (map<int, FeatureList>::iterator iter = featureSet.begin();
|
||||
iter != featureSet.end(); ++iter) {
|
||||
|
||||
FeatureList featureList = iter->second;
|
||||
int outputNo = iter->first;
|
||||
|
||||
for (size_t i = 0; i < featureList.size(); ++i) {
|
||||
|
||||
// make sure the timestamp is set
|
||||
switch (m_outputs[outputNo].sampleType) {
|
||||
|
||||
case OutputDescriptor::OneSamplePerStep:
|
||||
// use our internal timestamp - OK????
|
||||
featureList[i].timestamp = m_timestamp;
|
||||
break;
|
||||
|
||||
case OutputDescriptor::FixedSampleRate:
|
||||
// use our internal timestamp
|
||||
featureList[i].timestamp = m_timestamp;
|
||||
break;
|
||||
|
||||
case OutputDescriptor::VariableSampleRate:
|
||||
break; // plugin must set timestamp
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
allFeatureSets[outputNo].push_back(featureList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// step forward
|
||||
|
||||
for (size_t i = 0; i < m_channels; ++i) {
|
||||
m_queue[i]->skip(m_stepSize);
|
||||
}
|
||||
|
||||
// fake up the timestamp each time we step forward
|
||||
|
||||
long frame = RealTime::realTime2Frame(m_timestamp,
|
||||
int(m_inputSampleRate + 0.5));
|
||||
m_timestamp = RealTime::frame2RealTime(frame + m_stepSize,
|
||||
int(m_inputSampleRate + 0.5));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Vamp
|
||||
|
||||
An API for audio analysis and feature extraction plugins.
|
||||
|
||||
Centre for Digital Music, Queen Mary, University of London.
|
||||
Copyright 2006-2007 Chris Cannam and QMUL.
|
||||
This file by Mark Levy, Copyright 2007 QMUL.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of the Centre for
|
||||
Digital Music; Queen Mary, University of London; and Chris Cannam
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in this Software without prior written
|
||||
authorization.
|
||||
*/
|
||||
|
||||
#ifndef _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
|
||||
#define _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
|
||||
|
||||
#include "PluginWrapper.h"
|
||||
|
||||
namespace Vamp {
|
||||
|
||||
namespace HostExt {
|
||||
|
||||
/**
|
||||
* \class PluginBufferingAdapter PluginBufferingAdapter.h <vamp-sdk/hostext/PluginBufferingAdapter.h>
|
||||
*
|
||||
* PluginBufferingAdapter is a Vamp plugin adapter that allows plugins
|
||||
* to be used by a host supplying an audio stream in non-overlapping
|
||||
* buffers of arbitrary size.
|
||||
*
|
||||
* A host using PluginBufferingAdapter may ignore the preferred step
|
||||
* and block size reported by the plugin, and still expect the plugin
|
||||
* to run. The value of blockSize and stepSize passed to initialise
|
||||
* should be the size of the buffer which the host will supply; the
|
||||
* stepSize should be equal to the blockSize.
|
||||
*
|
||||
* If the internal step size used for the plugin differs from that
|
||||
* supplied by the host, the adapter will modify the sample rate
|
||||
* specifications for the plugin outputs (setting them all to
|
||||
* VariableSampleRate) and set timestamps on the output features for
|
||||
* outputs that formerly used a different sample rate specification.
|
||||
* This is necessary in order to obtain correct time stamping.
|
||||
*
|
||||
* In other respects, the PluginBufferingAdapter behaves identically
|
||||
* to the plugin that it wraps. The wrapped plugin will be deleted
|
||||
* when the wrapper is deleted.
|
||||
*/
|
||||
|
||||
class PluginBufferingAdapter : public PluginWrapper
|
||||
{
|
||||
public:
|
||||
PluginBufferingAdapter(Plugin *plugin); // I take ownership of plugin
|
||||
virtual ~PluginBufferingAdapter();
|
||||
|
||||
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
||||
|
||||
size_t getPreferredStepSize() const;
|
||||
|
||||
OutputList getOutputDescriptors() const;
|
||||
|
||||
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
||||
|
||||
FeatureSet getRemainingFeatures();
|
||||
|
||||
protected:
|
||||
class Impl;
|
||||
Impl *m_impl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -38,6 +38,28 @@
|
|||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
/**
|
||||
* If you want to compile using FFTW instead of the built-in FFT
|
||||
* implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
|
||||
* in the Makefile.
|
||||
*
|
||||
* Remember that FFTW is licensed under the GPL (unlike this SDK, which
|
||||
* is licensed liberally in order to permit closed-source usage), so
|
||||
* you should not define this symbol unless your code is also under the
|
||||
* GPL. Also, parties redistributing this SDK for use in other
|
||||
* programs should be careful _not_ to define this symbol in order not
|
||||
* to affect the stated license of this SDK.
|
||||
*
|
||||
* Note: This code uses FFTW_MEASURE, and will perform badly on its
|
||||
* first invocation unless the host has saved and restored FFTW wisdom
|
||||
* (see the FFTW documentation).
|
||||
*/
|
||||
#ifdef HAVE_FFTW3
|
||||
#include <fftw3.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace Vamp {
|
||||
|
||||
namespace HostExt {
|
||||
|
@ -58,15 +80,22 @@ public:
|
|||
protected:
|
||||
Plugin *m_plugin;
|
||||
float m_inputSampleRate;
|
||||
size_t m_channels;
|
||||
size_t m_blockSize;
|
||||
int m_channels;
|
||||
int m_blockSize;
|
||||
float **m_freqbuf;
|
||||
|
||||
double *m_ri;
|
||||
double *m_window;
|
||||
|
||||
#ifdef HAVE_FFTW3
|
||||
fftw_plan m_plan;
|
||||
fftw_complex *m_cbuf;
|
||||
#else
|
||||
double *m_ro;
|
||||
double *m_io;
|
||||
|
||||
void fft(unsigned int n, bool inverse,
|
||||
double *ri, double *ii, double *ro, double *io);
|
||||
#endif
|
||||
|
||||
size_t makeBlockSizeAcceptable(size_t) const;
|
||||
};
|
||||
|
@ -112,12 +141,21 @@ PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime tim
|
|||
return m_impl->process(inputBuffers, timestamp);
|
||||
}
|
||||
|
||||
PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
||||
PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
||||
m_plugin(plugin),
|
||||
m_inputSampleRate(inputSampleRate),
|
||||
m_channels(0),
|
||||
m_blockSize(0),
|
||||
m_freqbuf(0)
|
||||
m_freqbuf(0),
|
||||
m_ri(0),
|
||||
m_window(0),
|
||||
#ifdef HAVE_FFTW3
|
||||
m_plan(0),
|
||||
m_cbuf(0)
|
||||
#else
|
||||
m_ro(0),
|
||||
m_io(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -126,23 +164,38 @@ PluginInputDomainAdapter::Impl::~Impl()
|
|||
// the adapter will delete the plugin
|
||||
|
||||
if (m_channels > 0) {
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
delete[] m_freqbuf[c];
|
||||
}
|
||||
delete[] m_freqbuf;
|
||||
#ifdef HAVE_FFTW3
|
||||
if (m_plan) {
|
||||
fftw_destroy_plan(m_plan);
|
||||
fftw_free(m_ri);
|
||||
fftw_free(m_cbuf);
|
||||
m_plan = 0;
|
||||
}
|
||||
#else
|
||||
delete[] m_ri;
|
||||
delete[] m_ro;
|
||||
delete[] m_io;
|
||||
#endif
|
||||
delete[] m_window;
|
||||
}
|
||||
}
|
||||
|
||||
// for some visual studii apparently
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979232846
|
||||
#endif
|
||||
|
||||
bool
|
||||
PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
||||
{
|
||||
if (m_plugin->getInputDomain() == TimeDomain) {
|
||||
|
||||
m_blockSize = blockSize;
|
||||
m_channels = channels;
|
||||
m_blockSize = int(blockSize);
|
||||
m_channels = int(channels);
|
||||
|
||||
return m_plugin->initialise(channels, stepSize, blockSize);
|
||||
}
|
||||
|
@ -158,25 +211,48 @@ PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, siz
|
|||
}
|
||||
|
||||
if (m_channels > 0) {
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
delete[] m_freqbuf[c];
|
||||
}
|
||||
delete[] m_freqbuf;
|
||||
#ifdef HAVE_FFTW3
|
||||
if (m_plan) {
|
||||
fftw_destroy_plan(m_plan);
|
||||
fftw_free(m_ri);
|
||||
fftw_free(m_cbuf);
|
||||
m_plan = 0;
|
||||
}
|
||||
#else
|
||||
delete[] m_ri;
|
||||
delete[] m_ro;
|
||||
delete[] m_io;
|
||||
#endif
|
||||
delete[] m_window;
|
||||
}
|
||||
|
||||
m_blockSize = blockSize;
|
||||
m_channels = channels;
|
||||
m_blockSize = int(blockSize);
|
||||
m_channels = int(channels);
|
||||
|
||||
m_freqbuf = new float *[m_channels];
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
m_freqbuf[c] = new float[m_blockSize + 2];
|
||||
}
|
||||
m_window = new double[m_blockSize];
|
||||
|
||||
for (int i = 0; i < m_blockSize; ++i) {
|
||||
// Hanning window
|
||||
m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize));
|
||||
}
|
||||
|
||||
#ifdef HAVE_FFTW3
|
||||
m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
|
||||
m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
|
||||
m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
|
||||
#else
|
||||
m_ri = new double[m_blockSize];
|
||||
m_ro = new double[m_blockSize];
|
||||
m_io = new double[m_blockSize];
|
||||
#endif
|
||||
|
||||
return m_plugin->initialise(channels, stepSize, blockSize);
|
||||
}
|
||||
|
@ -220,7 +296,11 @@ PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
|
|||
|
||||
} else if (blockSize & (blockSize-1)) {
|
||||
|
||||
// not a power of two, can't handle that with our current fft
|
||||
#ifdef HAVE_FFTW3
|
||||
// not an issue with FFTW
|
||||
#else
|
||||
|
||||
// not a power of two, can't handle that with our built-in FFT
|
||||
// implementation
|
||||
|
||||
size_t nearest = blockSize;
|
||||
|
@ -241,16 +321,13 @@ PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
|
|||
|
||||
std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
|
||||
blockSize = nearest;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
// for some visual studii apparently
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979232846
|
||||
#endif
|
||||
|
||||
Plugin::FeatureSet
|
||||
PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
|
||||
RealTime timestamp)
|
||||
|
@ -308,33 +385,45 @@ PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
|
|||
|
||||
// std::cerr << " to " << timestamp << std::endl;
|
||||
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
for (int c = 0; c < m_channels; ++c) {
|
||||
|
||||
for (size_t i = 0; i < m_blockSize; ++i) {
|
||||
// Hanning window
|
||||
m_ri[i] = double(inputBuffers[c][i])
|
||||
* (0.50 - 0.50 * cos((2 * M_PI * i)
|
||||
/ m_blockSize));
|
||||
for (int i = 0; i < m_blockSize; ++i) {
|
||||
m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_blockSize/2; ++i) {
|
||||
for (int i = 0; i < m_blockSize/2; ++i) {
|
||||
// FFT shift
|
||||
double value = m_ri[i];
|
||||
m_ri[i] = m_ri[i + m_blockSize/2];
|
||||
m_ri[i + m_blockSize/2] = value;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FFTW3
|
||||
|
||||
fftw_execute(m_plan);
|
||||
|
||||
for (int i = 0; i <= m_blockSize/2; ++i) {
|
||||
m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
|
||||
m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
|
||||
|
||||
for (size_t i = 0; i <= m_blockSize/2; ++i) {
|
||||
m_freqbuf[c][i * 2] = m_ro[i];
|
||||
m_freqbuf[c][i * 2 + 1] = m_io[i];
|
||||
for (int i = 0; i <= m_blockSize/2; ++i) {
|
||||
m_freqbuf[c][i * 2] = float(m_ro[i]);
|
||||
m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return m_plugin->process(m_freqbuf, timestamp);
|
||||
}
|
||||
|
||||
#ifndef HAVE_FFTW3
|
||||
|
||||
void
|
||||
PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
|
||||
double *ri, double *ii, double *ro, double *io)
|
||||
|
@ -452,6 +541,8 @@ PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "PluginLoader.h"
|
||||
#include "PluginInputDomainAdapter.h"
|
||||
#include "PluginChannelAdapter.h"
|
||||
#include "PluginBufferingAdapter.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <cctype> // tolower
|
||||
|
@ -85,6 +86,8 @@ public:
|
|||
|
||||
string getLibraryPathForPlugin(PluginKey key);
|
||||
|
||||
static void setInstanceToClean(PluginLoader *instance);
|
||||
|
||||
protected:
|
||||
class PluginDeletionNotifyAdapter : public PluginWrapper {
|
||||
public:
|
||||
|
@ -94,6 +97,15 @@ protected:
|
|||
Impl *m_loader;
|
||||
};
|
||||
|
||||
class InstanceCleaner {
|
||||
public:
|
||||
InstanceCleaner() : m_instance(0) { }
|
||||
~InstanceCleaner() { delete m_instance; }
|
||||
void setInstance(PluginLoader *instance) { m_instance = instance; }
|
||||
protected:
|
||||
PluginLoader *m_instance;
|
||||
};
|
||||
|
||||
virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
|
||||
|
||||
map<PluginKey, string> m_pluginLibraryNameMap;
|
||||
|
@ -114,11 +126,16 @@ protected:
|
|||
|
||||
string splicePath(string a, string b);
|
||||
vector<string> listFiles(string dir, string ext);
|
||||
|
||||
static InstanceCleaner m_cleaner;
|
||||
};
|
||||
|
||||
PluginLoader *
|
||||
PluginLoader::m_instance = 0;
|
||||
|
||||
PluginLoader::Impl::InstanceCleaner
|
||||
PluginLoader::Impl::m_cleaner;
|
||||
|
||||
PluginLoader::PluginLoader()
|
||||
{
|
||||
m_impl = new Impl();
|
||||
|
@ -132,7 +149,13 @@ PluginLoader::~PluginLoader()
|
|||
PluginLoader *
|
||||
PluginLoader::getInstance()
|
||||
{
|
||||
if (!m_instance) m_instance = new PluginLoader();
|
||||
if (!m_instance) {
|
||||
// The cleaner doesn't own the instance, because we leave the
|
||||
// instance pointer in the base class for binary backwards
|
||||
// compatibility reasons and to avoid waste
|
||||
m_instance = new PluginLoader();
|
||||
Impl::setInstanceToClean(m_instance);
|
||||
}
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
|
@ -177,6 +200,12 @@ PluginLoader::Impl::~Impl()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
|
||||
{
|
||||
m_cleaner.setInstance(instance);
|
||||
}
|
||||
|
||||
vector<PluginLoader::PluginKey>
|
||||
PluginLoader::Impl::listPlugins()
|
||||
{
|
||||
|
@ -366,6 +395,10 @@ PluginLoader::Impl::loadPlugin(PluginKey key,
|
|||
}
|
||||
}
|
||||
|
||||
if (adapterFlags & ADAPT_BUFFER_SIZE) {
|
||||
adapter = new PluginBufferingAdapter(adapter);
|
||||
}
|
||||
|
||||
if (adapterFlags & ADAPT_CHANNEL_COUNT) {
|
||||
adapter = new PluginChannelAdapter(adapter);
|
||||
}
|
||||
|
@ -549,9 +582,11 @@ PluginLoader::Impl::listFiles(string dir, string extension)
|
|||
|
||||
struct dirent *e = 0;
|
||||
while ((e = readdir(d))) {
|
||||
|
||||
if (!(e->d_type & DT_REG) && (e->d_type != DT_UNKNOWN)) continue;
|
||||
|
||||
if (!(e->d_type & DT_REG) || !e->d_name) continue;
|
||||
|
||||
if (!e->d_name) continue;
|
||||
|
||||
size_t len = strlen(e->d_name);
|
||||
if (len < extlen + 2 ||
|
||||
e->d_name + len - extlen - 1 != "." + extension) {
|
||||
|
|
|
@ -142,15 +142,35 @@ public:
|
|||
* to be mixed down to mono, etc., without having to worry about
|
||||
* doing that itself.
|
||||
*
|
||||
* ADAPT_ALL - Perform all available adaptations, where meaningful.
|
||||
* ADAPT_BUFFER_SIZE - Wrap the plugin in a PluginBufferingAdapter
|
||||
* permitting the host to provide audio input using any block
|
||||
* size, with no overlap, regardless of the plugin's preferred
|
||||
* block size (suitable for hosts that read from non-seekable
|
||||
* streaming media, for example). This adapter introduces some
|
||||
* run-time overhead and also changes the semantics of the plugin
|
||||
* slightly (see the PluginBufferingAdapter header documentation
|
||||
* for details).
|
||||
*
|
||||
* ADAPT_ALL_SAFE - Perform all available adaptations that are
|
||||
* meaningful for the plugin and "safe". Currently this means to
|
||||
* ADAPT_INPUT_DOMAIN if the plugin wants FrequencyDomain input;
|
||||
* ADAPT_CHANNEL_COUNT always; and ADAPT_BUFFER_SIZE never.
|
||||
*
|
||||
* See PluginInputDomainAdapter and PluginChannelAdapter for more
|
||||
* details of the classes that the loader may use if these flags
|
||||
* are set.
|
||||
* ADAPT_ALL - Perform all available adaptations that are
|
||||
* meaningful for the plugin.
|
||||
*
|
||||
* See PluginInputDomainAdapter, PluginChannelAdapter and
|
||||
* PluginBufferingAdapter for more details of the classes that the
|
||||
* loader may use if these flags are set.
|
||||
*/
|
||||
enum AdapterFlags {
|
||||
|
||||
ADAPT_INPUT_DOMAIN = 0x01,
|
||||
ADAPT_CHANNEL_COUNT = 0x02,
|
||||
ADAPT_BUFFER_SIZE = 0x04,
|
||||
|
||||
ADAPT_ALL_SAFE = 0x03,
|
||||
|
||||
ADAPT_ALL = 0xff
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue