summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2020-01-14 16:52:42 +0100
committerRobin Gareus <robin@gareus.org>2020-01-14 17:04:04 +0100
commit756c5a5ee12c6b75d7c6b055e844c5a3a09e5df6 (patch)
tree9080966d74319ac87bc84ddf36e7aba4d6972b17 /scripts
parent2579e70f46a8d3d49ea45da0284ccc4d8413fe54 (diff)
Add some example Lua scripts
Diffstat (limited to 'scripts')
-rw-r--r--scripts/_rubberband_swing.lua160
-rw-r--r--scripts/_tempo_map_dump.lua14
2 files changed, 174 insertions, 0 deletions
diff --git a/scripts/_rubberband_swing.lua b/scripts/_rubberband_swing.lua
new file mode 100644
index 0000000000..da151c6bb6
--- /dev/null
+++ b/scripts/_rubberband_swing.lua
@@ -0,0 +1,160 @@
+ardour {
+ ["type"] = "EditorAction",
+ name = "Swing It (Rubberband)",
+ license = "MIT",
+ author = "Ardour Team",
+description = [[
+Create a 'swing feel' in selected regions.
+
+Analyze beat-position from the selected audio regions,
+then time-stretch the audio and move 8th notes back in
+time while keeping 1/4 note beats in place.
+
+(This script also servers as example for both VAMP
+analysis as well as Rubberband region stretching.)
+
+Kudos to Chris Cannam.
+]]
+}
+
+function factory () return function ()
+
+ -- helper function --
+ -- there is currently no direct way to find the track
+ -- corresponding to a [selected] region
+ function find_track_for_region (region_id)
+ for route in Session:get_tracks ():iter () do
+ local track = route:to_track ()
+ local pl = track:playlist ()
+ if not pl:region_by_id (region_id):isnil () then
+ return track
+ end
+ end
+ assert (0) -- can't happen, region must be in a playlist
+ end
+
+ -- get Editor selection
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:Editor
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:Selection
+ local sel = Editor:get_selection ()
+
+ -- Instantiate the QM BarBeat Tracker
+ -- see http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:LuaAPI:Vamp
+ -- http://vamp-plugins.org/plugin-doc/qm-vamp-plugins.html#qm-barbeattracker
+ local vamp = ARDOUR.LuaAPI.Vamp ("libardourvampplugins:qm-barbeattracker", Session:nominal_sample_rate ())
+
+ -- prepare undo operation
+ Session:begin_reversible_command ("Rubberband Regions")
+ local add_undo = false -- keep track if something has changed
+
+ -- for each selected region
+ -- http://manual.ardour.org/lua-scripting/class_reference/#ArdourUI:RegionSelection
+ for r in sel.regions:regionlist ():iter () do
+ -- "r" is-a http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:Region
+
+ -- test if it's an audio region
+ local ar = r:to_audioregion ()
+ if ar:isnil () then
+ goto next
+ end
+
+ -- create Rubberband stretcher
+ local rb = ARDOUR.LuaAPI.Rubberband (ar, false)
+
+ -- the rubberband-filter also implements the readable API to read from
+ -- the master-source of the given audio-region (ignoring any prior time-stretch
+ -- or pitch-shiting).
+ -- https://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:Readable
+ local max_pos = rb:readable ():readable_length ()
+
+ -- prepare table to hold analysis results
+ -- the beat-map is a table holding audio-sample positions:
+ -- [from] = to
+ local beat_map = {}
+ local prev_beat = 0
+
+ local pdialog = LuaDialog.ProgressWindow ("Rubberband", true)
+
+ -- callback to handle Vamp-Plugin analysis results
+ function vamp_callback (_, pos)
+ return pdialog:progress (pos / max_pos, "Analyzing")
+ end
+ function rb_progress (_, pos)
+ return pdialog:progress (pos / max_pos, "Stretching")
+ end
+
+ -- run VAMP plugin, analyze the first channel of the audio-region
+ vamp:analyze (rb:readable (), 0, vamp_callback)
+ -- getRemainingFeatures returns a http://manual.ardour.org/lua-scripting/class_reference/#Vamp:Plugin:FeatureSet
+ -- get the first output. here: Beats, estimated beat locations & beat-number
+ -- "fl" is-a http://manual.ardour.org/lua-scripting/class_reference/#Vamp:Plugin:FeatureList
+ local fl = vamp:plugin ():getRemainingFeatures ():at (0)
+ local beatcount = 0
+ -- iterate over returned features
+ for f in fl:iter () do
+ -- "f" is-a http://manual.ardour.org/lua-scripting/class_reference/#Vamp:Plugin:Feature
+ local fn = Vamp.RealTime.realTime2Frame (f.timestamp, Session:nominal_sample_rate ())
+ beat_map[fn] = fn -- keep beats (1/4 notes) unchanged
+ if prev_beat > 0 then
+ -- move the half beats (1/8th) back
+ local diff = (fn - prev_beat) / 2
+ beat_map[fn - diff] = fn - diff + diff / 3 -- moderate swing 2:1 (triplet)
+ --beat_map[fn - diff] = fn - diff + diff / 2 -- hard swing 3:1 (dotted 8th)
+ beatcount = beatcount + 1
+ end
+ prev_beat = fn
+ end
+ -- reset the plugin (prepare for next iteration)
+ vamp:reset ()
+
+ if pdialog:canceled () then goto out end
+
+ -- skip regions shorter than a bar
+ if beatcount < 8 then
+ pdialog:done ()
+ goto next
+ end
+
+ -- now stretch the region
+ rb:set_strech_and_pitch (1, 1)
+ rb:set_mapping (beat_map)
+
+ local nar = rb:process (rb_progress)
+
+ if pdialog:canceled () then goto out end
+
+ -- hide modal progress dialog and destroy it
+ pdialog:done ()
+ pdialog = nil
+
+ -- replace region
+ if not nar:isnil () then
+ print ("new audio region: ", nar:name (), nar:length ())
+ local track = find_track_for_region (r:to_stateful ():id ())
+ local playlist = track:playlist ()
+ playlist:to_stateful ():clear_changes () -- prepare undo
+ playlist:remove_region (r)
+ playlist:add_region (nar, r:position (), 1, false, 0, 0, false)
+ -- create a diff of the performed work, add it to the session's undo stack
+ -- and check if it is not empty
+ if not Session:add_stateful_diff_command (playlist:to_statefuldestructible ()):empty () then
+ add_undo = true
+ end
+ end
+
+ ::next::
+ end
+
+ ::out::
+
+ -- all done, commit the combined Undo Operation
+ if add_undo then
+ -- the 'nil' Command here mean to use the collected diffs added above
+ Session:commit_reversible_command (nil)
+ else
+ Session:abort_reversible_command ()
+ end
+
+ vamp = nil
+ collectgarbage ()
+end end
diff --git a/scripts/_tempo_map_dump.lua b/scripts/_tempo_map_dump.lua
new file mode 100644
index 0000000000..7e85cd5451
--- /dev/null
+++ b/scripts/_tempo_map_dump.lua
@@ -0,0 +1,14 @@
+ardour { ["type"] = "Snippet", name = "Tempo Map Dump" }
+
+function factory () return function ()
+
+ local tm = Session:tempo_map ()
+ local ts = tm:tempo_section_at_sample (0)
+
+ while true do
+ print ("TS @", ts:sample(), " | ", ts:to_tempo():note_types_per_minute (), "..", ts:to_tempo():end_note_types_per_minute (), "bpm")
+ ts = tm:next_tempo_section (ts)
+ if not ts then break end
+ end
+
+end end