Icon representing a recipe

Recipe: band equalizer r10

created by alcor29

Profile


Name
band equalizer r10
ID
46757
Shared with
Public
Parent
None
Children
Created on
August 10, 2013 at 16:39 PM UTC
Updated on
August 10, 2013 at 16:39 PM UTC
Description

Manage the properties of large numbers of bands.
Inspired on bandsliders2. Bands are grouped in flocks if they have the same properties (e.g. like recently added bands). To split off bands from a flock, disable them, then set all their properties at once. To merge flocks, set their properties equal and apply.

Best for


Code


-- band equalizer -- Constants max_bunches_listed = 5 length_slider_max = 5 bunch_separator = "\n" -- '""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""\n' function strength_compose(checkbox, slider) if checkbox then return math.min(slider * 10, 10) else return slider end end function strength_decompose(strength) if strength > 1.5 then return true, strength / 10 else return false, strength end end function band_props_get(bi) -- min_length and max_length because band_props needs it local length = band.GetGoalLength(bi) return { enabled=band.IsEnabled(bi), min_length=length, max_length=length, strength=band.GetStrength(bi) } end function band_props_key(b) return (b.max_length == 0 and "z" or "n")..b.strength..(b.enabled and "+" or "-") end function describe_bunch(bunch) local name = "" if #bunch.bilist == 1 then if bunch.max_length == 0 then name = "zero length band "..bunch.bilist[1] else name = "band "..bunch.bilist[1] end elseif #bunch.bilist <= 7 then if bunch.max_length == 0 then name = "zero length bands " else name = "bands " end for i,bi in ipairs(bunch.bilist) do if i > 1 then name = name..", " end name = name..bi end else if bunch.max_length == 0 then name = #bunch.bilist.." similar zero length bands" else name = #bunch.bilist.." similar bands" end name = name.." including band "..bunch.bilist[1] end return name end function bunch_order(l, r) if (l.max_length == 0) ~= (r.max_length == 0) then return l.max_length == 0 end if l.strength ~= r.strength then return l.strength > r.strength end if l.enabled ~= r.enabled then return l.enabled end return false end mission = {} function mission.Init() local bands = band.GetCount() mission.bunchlist = {} local band_key_to_bunchnr = {} for bi=1,bands do local band_props = band_props_get(bi) local band_key = band_props_key(band_props) local bunchnr = band_key_to_bunchnr[band_key] local bunch if bunchnr then bunch = mission.bunchlist[bunchnr] -- print("Adding band "..bi.." of length "..band_props.max_length.." to bunch #"..bunchnr.." with "..#bunch.bilist.." bamds of length "..bunch.max_length) else bunch = band_props bunch.bilist = {} table.insert(mission.bunchlist, bunch) table.sort(mission.bunchlist, bunch_order) band_key_to_bunchnr = {} for i,bunch in pairs(mission.bunchlist) do local band_key = band_props_key(bunch) band_key_to_bunchnr[band_key] = i end end table.insert(bunch.bilist, bi) bunch.min_length = math.min(bunch.min_length, band_props.min_length) bunch.max_length = math.max(bunch.max_length, band_props.max_length) end return bands > 0 end function mission.Main() while mission.Init() do local main = dialog.CreateDialog("Band Equalizer") local num_excess_bunches = math.max(0, #mission.bunchlist - max_bunches_listed) for i=1,#mission.bunchlist-num_excess_bunches do local bunch = mission.bunchlist[i] local name = "Bunch #"..i..": "..describe_bunch(bunch) if i > 1 then main[" "..i] = dialog.AddLabel("") end main["l"..i] = dialog.AddLabel(name) main["e"..i] = dialog.AddCheckbox("Enabled", bunch.enabled) local strong, strength = strength_decompose(bunch.strength) main["S"..i] = dialog.AddCheckbox("Strength boost x10", strong) main["s"..i] = dialog.AddSlider(" Strength", math.min(strength+.001, 1.5), -0.01, 1.5, 2) if bunch.min_length < bunch.max_length then main["gmin"..i] = dialog.AddSlider(" Min goal length", bunch.min_length, bunch.min_length, bunch.max_length, 1) main["gmax"..i] = dialog.AddSlider(" Max goal length", bunch.max_length, bunch.min_length, bunch.max_length, 1) elseif 0 < bunch.max_length then main["g"..i] = dialog.AddSlider(" Goal length", bunch.min_length, 0, math.ceil(math.max(bunch.min_length/length_slider_max), 1) * length_slider_max, 1) end end if num_excess_bunches > 0 then local num_excess_bands = 0 for i=max_bunches_listed+1,#mission.bunchlist do local bunch = mission.bunchlist[i] num_excess_bands = num_excess_bands + #bunch.bilist end if num_excess_bunches > 1 then main.excess = dialog.AddLabel(bunch_separator..num_excess_bunches.." more bunches with "..num_excess_bands.." bands not listed") elseif num_excess_bands > 1 then main.excess = dialog.AddLabel(bunch_separator.."1 more bunch of "..num_excess_bands.. " bands not listed") else main.excess = dialog.AddLabel(bunch_separator.."1 more bamd not listed") end end local ok_button, apply_button, refresh_button, merge_button = 1, 2, 3, 4 main.ok = dialog.AddButton("OK", ok_button) main.apply = dialog.AddButton("Apply", apply_button) main.refresh = dialog.AddButton("Refresh", refresh_button) main.merge = dialog.AddButton("Merge", merge_button) local update_dialog = false repeat -- show dialog until user chose and - if needed - confirmed local button = dialog.Show(main) if button == 0 then return end local apply = false if button == refresh_button then update_dialog = true end if button == merge_button then local merge = dialog.CreateDialog("Merge bunches of bands") for i=1,#mission.bunchlist do local bunch = mission.bunchlist[i] local name = "Bunch #"..i..": "..describe_bunch(bunch) merge["m"..i] = dialog.AddCheckbox(name, true) end --merge.min = dialog.AddSlider("Merge from", #mission.bunchlist, 1, #mission.bunchlist, 0) --merge.max = dialog.AddSlider("Merge to", #mission.bunchlist, 1, #mission.bunchlist, 0) merge.ok = dialog.AddButton("Merge", 1) merge.cancel = dialog.AddButton("Cancel", 0) if dialog.Show(merge) == 1 then local source_bunch for i=1,#mission.bunchlist do local bunch = mission.bunchlist[i] if merge["m"..i].value then if not source_bunch then source_bunch = bunch else bunch.enabled = source_bunch.enabled bunch.strength = source_bunch.strength bunch.min_length = source_bunch.min_length bunch.max_length = source_bunch.max_length end end end apply = true end end if button == ok_button or button == apply_button then local possibly_unintended = false warn = dialog.CreateDialog("Warning") local new_band_key_to_old_bunchnr = {} for i=1,#mission.bunchlist-num_excess_bunches do local bunch = mission.bunchlist[i] bunch.strength = strength_compose(main["S"..i].value, main["s"..i].value) if bunch.strength >= 0 then bunch.enabled = main["e"..i].value if bunch.min_length < bunch.max_length then bunch.min_length = main["gmin"..i].value bunch.max_length = main["gmax"..i].value if bunch.min_length > bunch.max_length then possibly_unintended = true warn["l"..i] = dialog.AddLabel("Inconsistent length range for bunch #"..i..", using max") bunch.min_length = bunch.max_length end elseif 0 < bunch.max_length then bunch.min_length = main["g"..i].value bunch.max_length = bunch.min_length end local band_key = band_props_key(bunch) local conflicting_old_bunchnr = new_band_key_to_old_bunchnr[band_key] if conflicting_old_bunchnr then possibly_unintended = true warn["l"..conflicting_old_bunchnr.."x"..i] = dialog.AddLabel("This will merge bunches #"..conflicting_old_bunchnr.." and #"..i) else new_band_key_to_old_bunchnr[band_key] = i end end end if possibly_unintended then warn.ok = dialog.AddButton("OK", 1) warn.cancel = dialog.AddButton("Cancel", 0) apply = dialog.Show(warn) == 1 else apply = true end end if apply then local doomed_bi = {} for i,bunch in ipairs(mission.bunchlist) do for j,bi in ipairs(bunch.bilist) do if bunch.strength < 0 then -- keep band indices intact for now doomed_bi[bi] = true else if not band.IsEnabled(bi) and bunch.enabled then print("Enabling band "..bi) band.Enable(bi) elseif band.IsEnabled(bi) and not bunch.enabled then print("Disabling band "..bi) band.Disable(bi) end if band.GetStrength(bi) > bunch.strength then print("Weakening band "..bi) band.SetStrength(bi, bunch.strength) elseif band.GetStrength(bi) < bunch.strength then print("Strengthening band "..bi) band.SetStrength(bi, bunch.strength) end if band.GetGoalLength(bi) < bunch.min_length then print("Stretching band "..bi) band.SetGoalLength(bi, bunch.min_length) elseif band.GetGoalLength(bi) > bunch.max_length then print("Shortening band "..bi) band.SetGoalLength(bi, bunch.max_length) end end end end for bi = band.GetCount(), 1, -1 do if doomed_bi[bi] then print("Deleting band "..bi) band.Delete(bi) end end if button == ok_button then return end update_dialog = true end until update_dialog end end function mission.Exit(why) if not mission.exiting then mission.exiting = true print(why) end end function mission.Catch(what) if what:match("Cancelled$") then mission.Exit("Cancelled.") else print(what) mission.Exit("Error!") end end xpcall(mission.Main, mission.Catch) mission.Exit("Finished.")

Comments