├── Readme.md ├── UNLICENSE ├── firequalizer15.lua ├── screenshoots ├── avectorscope.jpg ├── firequalizer15.jpg ├── showcqt.jpg ├── showcqtbar.jpg ├── showspectrum.jpg └── showwaves.jpg └── visualizer.lua /Readme.md: -------------------------------------------------------------------------------- 1 | ## Various mpv lua scripts 2 | 3 | - visualizer.lua - various audio visualization. 4 | 5 | - firequalizer.lua - linear phase 15-bands equalizer. 6 | 7 | ## Key bindings 8 | 9 | Look at the lua scripts. 10 | 11 | ## Screenshoots 12 | 13 | ### visualizer.lua 14 | 15 | - showcqt 16 | 17 | ![showcqt](screenshoots/showcqt.jpg) 18 | 19 | - avectorscope 20 | 21 | ![avectorscope](screenshoots/avectorscope.jpg) 22 | 23 | - showspectrum 24 | 25 | ![showspectrum](screenshoots/showspectrum.jpg) 26 | 27 | - showcqtbar 28 | 29 | ![showcqtbar](screenshoots/showcqtbar.jpg) 30 | 31 | - showwaves 32 | 33 | ![showwaves](screenshoots/showwaves.jpg) 34 | 35 | ### firequalizer15.lua 36 | 37 | ![firequalizer15](screenshoots/firequalizer15.jpg) 38 | 39 | ## Related projects 40 | 41 | - [HTML5 ShowCQTBar](https://github.com/mfcc64/html5-showcqtbar) - showcqt/showcqtbar visualizer on an HTML5 page. 42 | - [YouTube Musical Spectrum](https://github.com/mfcc64/youtube-musical-spectrum) - showcqt visualizer as a Chrome extension. 43 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /firequalizer15.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Linear Phase 15-Bands Equalizer 3 | Key: 4 | - toggle equalizer control: ctrl+e 5 | - prev/next gain control: UP / DOWN 6 | - decrease/increase gain: LEFT / RIGHT 7 | - copy gain value from prev gain control: [ 8 | - copy gain value from next gain control: ] 9 | Note that ~~/lua-settings directory should exist to save gain values. 10 | --]] 11 | 12 | local options = require "mp.options" 13 | local msg = require "mp.msg" 14 | 15 | local key_toggle_control = "ctrl+e" 16 | local key_prev_entry = "UP" 17 | local key_next_entry = "DOWN" 18 | local key_decrease = "LEFT" 19 | local key_increase = "RIGHT" 20 | local key_copy_prev = "[" 21 | local key_copy_next = "]" 22 | 23 | local control_enabled = false 24 | local num_entry = 15 25 | local selected_entry = 0 26 | local min_val = -360 27 | local max_val = 120 28 | local stale_gain_entry = "" 29 | 30 | local function eq(x) 31 | return "eq" .. x 32 | end 33 | 34 | local gain_table = { 35 | eq0 = 0, 36 | eq1 = 0, 37 | eq2 = 0, 38 | eq3 = 0, 39 | eq4 = 0, 40 | eq5 = 0, 41 | eq6 = 0, 42 | eq7 = 0, 43 | eq8 = 0, 44 | eq9 = 0, 45 | eq10 = 0, 46 | eq11 = 0, 47 | eq12 = 0, 48 | eq13 = 0, 49 | eq14 = 0 50 | } 51 | 52 | local freq_label = { 53 | eq0 = "# 0 Hz:", 54 | eq1 = "# 65 Hz:", 55 | eq2 = "# 157 Hz:", 56 | eq3 = "# 288 Hz:", 57 | eq4 = "# 472 Hz:", 58 | eq5 = "# 733 Hz:", 59 | eq6 = "# 1k1 Hz:", 60 | eq7 = "# 1k6 Hz:", 61 | eq8 = "# 2k4 Hz:", 62 | eq9 = "# 3k4 Hz:", 63 | eq10 = "# 4k9 Hz:", 64 | eq11 = "# 7k0 Hz:", 65 | eq12 = "# 10k Hz:", 66 | eq13 = "# 14k Hz:", 67 | eq14 = "# 20k Hz:" 68 | } 69 | 70 | options.read_options(gain_table) 71 | 72 | for x = 0, num_entry-1 do 73 | gain_table[eq(x)] = math.min(math.max(gain_table[eq(x)], min_val), max_val) 74 | end 75 | 76 | local function save_gain_table() 77 | local settingdir = mp.find_config_file("lua-settings") 78 | local fp = settingdir and io.open(settingdir .. "/" .. mp.get_script_name() .. ".conf", "w") 79 | if fp == nil then 80 | msg.warn("Cannot save gain table.") 81 | else 82 | for x = 0, num_entry-1 do 83 | fp:write(eq(x) .. "=" .. gain_table[eq(x)] .. "\n") 84 | end 85 | fp:close() 86 | end 87 | end 88 | 89 | local normalcolor = "ffffff" 90 | local selectedcolor = "00ffff" 91 | local fontsize = 70 92 | local fontfamily = "mono" 93 | local pdefault = "{\\fn" .. fontfamily .. "\\fscx" .. fontsize .. "\\fscy" .. fontsize .. "\\1c&" .. normalcolor .. "&}" 94 | local pselected = "{\\fn" .. fontfamily .. "\\fscx" .. fontsize .. "\\fscy" .. fontsize .. "\\1c&" .. selectedcolor .. "&}" 95 | 96 | local function gain_line(x) 97 | local val = gain_table[eq(x)] - min_val; 98 | local str = "" 99 | local x = 10 100 | while x <= val do 101 | str = str .. "=" 102 | x = x + 20 103 | end 104 | return str 105 | end 106 | 107 | local function show_osd_ass() 108 | local str = pdefault .. "Linear Phase 15-Bands Equalizer\n" 109 | for x = 0, num_entry-1 do 110 | local pval = pdefault 111 | if x == selected_entry then 112 | pval = pselected 113 | end 114 | str = str .. pval .. freq_label[eq(x)] .. string.format("%7.1f", gain_table[eq(x)]*0.1) .. " dB |" .. gain_line(x) .. "\n" 115 | end 116 | mp.set_osd_ass(0, 0, str) 117 | end 118 | 119 | local function hide_osd_ass() 120 | mp.set_osd_ass(0, 0, "{}") 121 | end 122 | 123 | local function gen_gain_entry() 124 | local str = string.format("entry(0,%.1f)", gain_table[eq(0)]*0.1) 125 | for x = 1, num_entry-1 do 126 | str = str .. string.format(";entry(%d,%.1f)", x, gain_table[eq(x)]*0.1) 127 | end 128 | return str 129 | end 130 | 131 | local function insert_filter(gain_entry) 132 | local graph = "firequalizer = " .. 133 | "wfunc = tukey:" .. 134 | "delay = 0.028:" .. 135 | "scale = linlog:" .. 136 | "zero_phase = on:" .. 137 | "gain_entry = '" .. gain_entry .. "':" .. 138 | "gain = 'cubic_interpolate(2.8853900817779269*log(f/157.48+1))'" 139 | mp.commandv("af", "add", "@" .. mp.get_script_name() .. ":lavfi=graph=[" .. graph .. "]") 140 | end 141 | 142 | local function audio_reconfig() 143 | local gain_entry = gen_gain_entry() 144 | if not (stale_gain_entry == gain_entry) then 145 | insert_filter(gain_entry) 146 | stale_gain_entry = gain_entry 147 | end 148 | end 149 | 150 | audio_reconfig() 151 | mp.register_event("playback-restart", audio_reconfig) 152 | 153 | local function send_command() 154 | mp.commandv("af-command", mp.get_script_name(), "gain_entry", gen_gain_entry()) 155 | end 156 | 157 | local function prev_entry() 158 | selected_entry = math.max(selected_entry-1, 0) 159 | show_osd_ass() 160 | end 161 | 162 | local function next_entry() 163 | selected_entry = math.min(selected_entry+1, num_entry-1) 164 | show_osd_ass() 165 | end 166 | 167 | local function decrease_gain() 168 | gain_table[eq(selected_entry)] = math.max(gain_table[eq(selected_entry)]-1, min_val) 169 | send_command() 170 | show_osd_ass() 171 | save_gain_table() 172 | end 173 | 174 | local function increase_gain() 175 | gain_table[eq(selected_entry)] = math.min(gain_table[eq(selected_entry)]+1, max_val) 176 | send_command() 177 | show_osd_ass() 178 | save_gain_table() 179 | end 180 | 181 | local function copy_prev() 182 | gain_table[eq(selected_entry)] = gain_table[eq(math.max(selected_entry-1, 0))] 183 | send_command() 184 | show_osd_ass() 185 | save_gain_table() 186 | end 187 | 188 | local function copy_next() 189 | gain_table[eq(selected_entry)] = gain_table[eq(math.min(selected_entry+1, num_entry-1))] 190 | send_command() 191 | show_osd_ass() 192 | save_gain_table() 193 | end 194 | 195 | local function binding_name(name) 196 | return mp.get_script_name() .. "-" .. name 197 | end 198 | 199 | local function toggle_control() 200 | control_enabled = not control_enabled 201 | if control_enabled then 202 | show_osd_ass() 203 | mp.add_forced_key_binding(key_prev_entry, binding_name("prev"), prev_entry, {repeatable=true}) 204 | mp.add_forced_key_binding(key_next_entry, binding_name("next"), next_entry, {repeatable=true}) 205 | mp.add_forced_key_binding(key_decrease, binding_name("decrease"), decrease_gain, {repeatable=true}) 206 | mp.add_forced_key_binding(key_increase, binding_name("increase"), increase_gain, {repeatable=true}) 207 | mp.add_forced_key_binding(key_copy_prev, binding_name("copy_prev"), copy_prev) 208 | mp.add_forced_key_binding(key_copy_next, binding_name("copy_next"), copy_next) 209 | else 210 | hide_osd_ass() 211 | mp.remove_key_binding(binding_name("prev")) 212 | mp.remove_key_binding(binding_name("next")) 213 | mp.remove_key_binding(binding_name("decrease")) 214 | mp.remove_key_binding(binding_name("increase")) 215 | mp.remove_key_binding(binding_name("copy_prev")) 216 | mp.remove_key_binding(binding_name("copy_next")) 217 | end 218 | end 219 | 220 | mp.add_forced_key_binding(key_toggle_control, binding_name("toggle_control"), toggle_control) 221 | -------------------------------------------------------------------------------- /screenshoots/avectorscope.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfcc64/mpv-scripts/bf6776f5c3dae8d83ba29b820496af89dc436613/screenshoots/avectorscope.jpg -------------------------------------------------------------------------------- /screenshoots/firequalizer15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfcc64/mpv-scripts/bf6776f5c3dae8d83ba29b820496af89dc436613/screenshoots/firequalizer15.jpg -------------------------------------------------------------------------------- /screenshoots/showcqt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfcc64/mpv-scripts/bf6776f5c3dae8d83ba29b820496af89dc436613/screenshoots/showcqt.jpg -------------------------------------------------------------------------------- /screenshoots/showcqtbar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfcc64/mpv-scripts/bf6776f5c3dae8d83ba29b820496af89dc436613/screenshoots/showcqtbar.jpg -------------------------------------------------------------------------------- /screenshoots/showspectrum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfcc64/mpv-scripts/bf6776f5c3dae8d83ba29b820496af89dc436613/screenshoots/showspectrum.jpg -------------------------------------------------------------------------------- /screenshoots/showwaves.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfcc64/mpv-scripts/bf6776f5c3dae8d83ba29b820496af89dc436613/screenshoots/showwaves.jpg -------------------------------------------------------------------------------- /visualizer.lua: -------------------------------------------------------------------------------- 1 | -- various audio visualization 2 | 3 | local opts = { 4 | mode = "novideo", 5 | -- off disable visualization 6 | -- noalbumart enable visualization when no albumart and no video 7 | -- novideo enable visualization when no video 8 | -- force always enable visualization 9 | 10 | name = "showcqt", 11 | -- off 12 | -- showcqt 13 | -- avectorscope 14 | -- showspectrum 15 | -- showcqtbar 16 | -- showwaves 17 | 18 | quality = "medium", 19 | -- verylow 20 | -- low 21 | -- medium 22 | -- high 23 | -- veryhigh 24 | 25 | height = 6, 26 | -- [4 .. 12] 27 | 28 | forcewindow = true, 29 | -- true (yes) always run visualizer regardless of force-window settings 30 | -- false (no) does not run visualizer when force-window is no 31 | } 32 | 33 | -- key bindings 34 | -- cycle visualizer 35 | local cycle_key = "c" 36 | 37 | if not (mp.get_property("options/lavfi-complex", "") == "") then 38 | return 39 | end 40 | 41 | local visualizer_name_list = { 42 | "off", 43 | "showcqt", 44 | "avectorscope", 45 | "showspectrum", 46 | "showcqtbar", 47 | "showwaves", 48 | } 49 | 50 | local axis_0 = "image/png;base64," .. 51 | "iVBORw0KGgoAAAANSUhEUgAAB4AAAAAgCAQAAABZEK0tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAASO0lEQVR42u2de2wU1xXGV/IfSJEqVUJCQrIUISFFiiqhSFWkKFKFokpB1TqxHROT8ApueDgEE9u4MW4TSqFA" .. 52 | "3TSUQmkSChRwII6BkAQCDSYlBtc1hiSA4/CyMcYGtsZvY3t3vXu719vVPjxzz71zd+wBvnOkdvHZ78w5v7mZmbt7Z9blgsFgMBgMBoPBYDAYDAaDwWAwGAwGg8FgMBgMBoPBYDAYDAaDwWCw+9HYBFbKboe8lE1A" .. 53 | "HHHEEUccccQRRxxxxBFHHPEHNe4KBSJWijjiiCOOOOKII4444ogjjjjiD1icwWAwGAwGg8FgMBgM9hAYJsAwGAwGg8FgMBgMBnsozOVyR7zuQOSPdQeif0UcccQRRxxxxBFHHHHEEUcc8QciHn05KaPuwGDHYEfd" .. 54 | "gUkZRgkQRxxxxBFHHHHEEUccccQRR/w+jhu9FQ6Hw+FwOBwOh8Ph8AfOx3Zz07LTXpmYzl89McuJOJ6e/czcCWkP7u4Gf/AHf/AHf/AHf/AHf/AHf/B/iPm73D99qaW2u7n7RqI/8lz4LWbxw1tVNjQh7dgH/Z6R" .. 55 | "JdjBzmuXKxl7b42sdvqctrORCjqvTc1S3elx9V9vOXNy1+gcP3r+5K6Bu7y8YW/jqZO7PPU5S+Tyx/Fp9lysO/CLV1TqA3/wB3/wB3/wB3/wB3/wB3/wB/8x4e9yL37N+PlYP3o+/BazePVe+c089XL7D4n6qjJZ" .. 56 | "dUlhrO7TLWo7wKj+gbvxkGbMv3sl8T3Ht8vlL8hLVPr6dq7Xqw/8wR/8wR/8wR/8wR/8wR/8wR/8k86f/89bK26eYazjSsXGsJ8ui90Bo+MVG7ua1HZAY1VoZj9Utacof8b8DSU15cGAmn5tcfnG/zaE2+tqUtsB" .. 57 | "8fXv33T6w8EOxpprYt9xs46xgK9qT0Hes/M2rbr13cgA2SOfP+hnrLacZ68t72sNiYNvrbBWH/iDP/iDP/iDP/iDP/iDP/iDP/jbxD/8f3UVjF2v5q8ef9HlXpQbyjAcuxY7Gp8y8uV1878ZO7lLtsDNv+Ul/e5X" .. 58 | "0b9cqlT9JGFypq+XscZTHM3bRaq7IFo/9z+/zZivPxrdsY7Xt35l5N8paV3XGavcLp8/4GMs0t+UrFvf8mESWcKgVh/4gz/4gz/4gz/4gz/4gz/4gz/428Q/vsC1xQFf9b5JGXcvf3/UqIE1bw57az5yuff/uadl" .. 59 | "eZ5sefzzh8ZTsX+ZPmfvO5MzVRCWv8tXhz8xi6O5+pXeDqjaw1hvazTaFNqtjV/Hvn/Xho4ruUut7QCXO/vV4DBja95Ur0+Ff+Fy8Ad/8Ad/8Ad/8Ad/8Ad/8Ad/8FfgHy2wt7Wugs+d284aNxCJ36xTbb+7mbGj" .. 60 | "76uq4p2vYb9U6XIf3sq/LH/qZfUdwOuvq/juM89F/nnD3ndi6gvt1C+06ovfAaGMN9Q6Bn/wB3/wB3/wB3/wB3/wB3/wB3/b+UcLjFjbOeMGRPFHnpu7yBzKPQ9jkduSH39xweKcJTlLFiz+Sbas3uVe9jrf8soC" .. 61 | "rh8eZOzETpXtx9cfvgm7IOb76/6Y+sw8Je3Jl+R3AF/TfrpMXq/LX5yf5k/VR/FX6c8K/4npOUvi61XjT+l1+Yvz0/yp+ij+Kv1Z4f/oC4tyfz7POn9Kr8tfnJ/mT9VH8Vfpz9rxR+0EMPr4Q5+g9I4/Ipc5/oid" .. 62 | "Pv7I9wf+9yf/1MxXc/kCQav8Rfpk8DfPL8dfVJ8Mf9n+MP7vv/HPr29/Nts6f0qfjOt/8/xy1/+i+mSu/2X7szb+017JWWK+qJYe/2K9/vgX5ZcZ/+L66PEv35/Djj/RAgfaG6u6Gs0/gTCPry4aaOdtNf/70ReM" .. 63 | "NtJ/i7GyUv6qII/ffv1/Cxbly+ld7otH+Kr469Xcvd2M9d+OXSFP60fqv8vVzdWe+oCXsYA3+hV5/23GPvyjGaKfZB/a0nTK211/VH4H3DkfGiQ75PU6/On8Yv4y9Yn4S/dnkX9KWs1HXMEXUZj9epmIv4xehz+d" .. 64 | "X8xfpj4Rf+n+LPJPzfz+GOfLWOfVuYvU+cvodfjT+cX8ZeoT8ZfuzyL/sJcU+geHB+ctVucvo9c7/lP5qeM/XZ/4+C/Zn0X+0+cEfGEf9n77qTp/Gb0Ofzq/mL9MfSL+0v1pjP8JabUf8wsvFvzkL1bGP6XXHf/i" .. 65 | "/PT4p+qjxr9Ufxb5tzdE9i/3jBxV/jJ6Hf50fjF/mfpE/KX7szz+95R6e3jBd86b/cCLePzTer3xT+Wnxj9dn3j8S/Znmf9rr/e08Pz9HmvnX1qvx5/KT/Gn6xPzl+xP6/pHbQI8+vpHYgLM12i/t4axugMu94aS" .. 66 | "tm8W5cY3wON/X8fYuYOJF6D3PN7ek7svf8VYTbnRRtrOMla1m796Zm74t564+e+FPwWg9VOz/AOJj7revEp++4lr0J98qb2BsfYfIv/mzzerrTBDdO4gX/3OmPwEeELaUGeowt/K63X40/nF/Gm9mL9Kf1b4f7mN" .. 67 | "sdvnj29vrmbBq1+r85fR6/Cn84v503oxf5X+rPCv2MhYS+2xbRePDA92XlPnL6PX4U/nF/On9WL+Kv1Z4R8m2nmNb9Xst/FE/GX0Ovzp/GL+tF7MX6U/K/yfmcsfqXG58nLlD8e3rlbnL6PX4U/nF/On9WL+Kv1Z" .. 68 | "G/+pmfwpop3Xaj769tDqIvXxT+v1xj+Vnxr/lJ4a//L9WeHf3jDQwffu5cq+NsaM17mI+MvodfjT+cX8ab2Yv0p/Vvgvez043Nd6uqzhy4DPU69+/JHR6/Cn84v503oxf5X+rPBPSeu+4R+s3ne6zD8w0G5856yI" .. 69 | "v4xehz+dX8yf1ov5q/Rn9fpHbQI8+vpHegLscucuTQnN7fnTvmK/5o7G85alpI2+AA3jaP5PwBt9eHfUa/kK8JsRNFOypmbxXRJ5DDetP7QltLsG+ArysPe2hi45z8hvP3EHuNzb1jLm7Y386/SHoX/1zJgfjU9M" .. 70 | "L3931sLI7nq7aGK6ygT4c75O3v/MXHm9Dn86v5g/rRfzV+tPnX/bue7m8OdNjaeGBxO/+aH5y+h1+NP5xfxpvZi/Wn/q/KdmrS0Ovzr/GWPGP4Mu4i+j1+FP5xfzp/Vi/mr9qfPnzu+84ZdXchPgeP4yeh3+dH4x" .. 71 | "f1ov5q/Wnzp/PsGjfjJCxF9Gr8Ofzi/mT+vF/NX6szL++c+CfHPI+MgmM/5pvd74p/JT45/SU+NfpT91/sX5kUl1b2t3szp/Gb0Ofzq/mD+tF/NX60+d/4kdjIUnQ98eYsx4kbuIv4xehz+dX8yf1ov5q/Wnzn/m" .. 72 | "Lxk7/eFIH+WM7Vinyl9Gr8Ofzi/mT+vF/NX6s3b9ozYBHn39Q0yAfzabPxb79vmi/Ih7vo89QEfjK94YfaftuU+CgfC0k4My+hJ8xnz/YGjG31BakprJPzFYnsefJRbJT+mfnce/+G89G/ls7cmX6vYzFgwW54eH" .. 73 | "Ar39+P7eWlGx0VPPF0xE4o/N7LvFv9bfUxr+z6cg785Fxm7GXWKJJnjTsgN+xg5uKsovzt/2+4tHWHD0CnSRXo8/nT+Rf96yWP6UnuKv2p8q/6deDt/dMTG9+8Y9jyz/aHe0Xo8/nV/Mn9JT/FX7szb+p8/ZvGqw" .. 74 | "o7NRnT+tT8b4F+WXGf/mernxL9+fOv+nZ/v6Oq9+9Q+zCR7Fn9Lr8qfyU/zFepq/Wn+q/PkEr/1Sc03LmSPvGU8yxPxpvR5/Or+YP6Wn+Kv2p8p/UoZ/sKvx6dkbSqbPkT//RunRej3+dH4xf0pP8Vftz9rxn196" .. 75 | "m91XJ3P8F+mTcfwX5Zc5/pvr5Y7/8v2p8t+6mrHPt05Ie2LWnfP3/qvOn9br8afzi/lTeoq/an+q/GctDH8r63Lvfcf4m0oxf1qvx5/OL+ZP6Sn+qv1ZPf6Yu9zxx3QCnLuUPzR6tEVShOLRdeMsGEicmTediszl" .. 76 | "d65nrLTEaDOfbuFFcbm3h/9oMbfIwUKsX1v8f2XI+CdtM+aH73fkFl7wTG0/vv6IBXwlhdH3FC739ob/7usN5w8Gd/9BboI4a+Fofo1f/zhddoKqy5+egIr5i/WJ/J+dF+Vf+7Fkf0ngPymj5Qxjxz6Q4990amJ6" .. 77 | "4mWKmT45/M3zy/E308vyF/anzX/Lav63oU6jB03I8Bfpk8FflF+Gv7lejj/Rnyb/H44Hg0X5lduNJ3g0f7Fen784P81fpJfhT/anxf+JWSMLxgYHOxJ/rEGOP6XX5U/lp/iL9TR/if60+OcuDV0sXeCXcEG/0ZM9" .. 78 | "Kf6UXpc/lZ/iL9bT/CX6S8L51+Wu/djq8UesT8751zy/3PnXTC97/hX2p8mf32Tm7Q0O+/tXvGGFv1ivz1+cn+Yv0svwJ/vT4p+S1tfq69+/6eRufpc9fxKyGn9Kr8ufyk/xF+tp/hL9JeX4Y+ayxx/TCfC07PAt" .. 79 | "zGY7ID7e70m8zb/pdOwE9I+/Nt5QacmdC1EQnVc/+lOkRLF+1kK+tG3k8rKLD+/JmXevhHfJ8ODx7TLbT+wvGLznaTr12uuJlxEXDocfZcOt7WxkWSM9wZuW3R3NH/T3tzfsKVWZoOryl5kAi/iL9Yn8J2Uk8lft" .. 80 | "zwr/adn8AfDG9wmM5l9WOvo9Ir0+f1F+Gf7mejn+Kv1Z4f/YzENbQtOMQHP16AOLDH+xXp+/KL8Mf3O9HH+V/lT5/6aQBS8cdrnNJngUf1qvx5/KT/EX62n+qv2pj/+y0tKSiekpafVfMBb74C7Z8U/pdce/OD89" .. 81 | "/kV6mfGv1p8q/02r+F+aq/f+6e6lYDD26aFy/Gm9Hn8qP8VfrKf5q/Zn7fqHP6rGeIGvzPFfrE/G9Y95frnrHzO97PWPfH+q/FMz275hbLAj4AsGyt9V50/r9fhT+Sn+Yj3NX7U/9fFflD/QMfLX0DVWzT718U/p" .. 82 | "dce/OD89/kV6mfGv1p/V44+Zyx5/TCfAuv7NoeBw+AHYfAnygsXm73xs5sqCzauK8uO/xpfX626f8tTMksLNqwryjB6QT00wKdfVJyO/MX/n9GfGf/ZCftdBVZnVvLr6ZOU34++U/kTjn/snf9F7Wp+uXje/aPw7" .. 83 | "oT9j/vyjjb62riZ+kmk7a/yMA5Hr6pOX35i/c/qjxn9BHmOf/dV6fl29bn5q/I93f8b8V7zBHzLHX5UUMnZyl2pWXX3y8hvzd05/ovFflK93htHVJyO/aPw7oT9j/l+8z9i2tSlpU7MaqwL+KVmqWXX1yctvzN85" .. 84 | "/ZmP/ylZ61fmLj25m2/JSmZdfXLym49/Z/RHnX9tcf0U+zcxtvEt/up6dcCnfgEy3no5fxAmwPdnf+uKfb1BP/9s76mX/75u7PVOr8/u/qK+Yx1j5p/x2q93en329Hf5q86r3PlPvd08o35809U7vT67+5ucGbnX" .. 85 | "74M1jO3aMNZ6p9dnd39TsoaHum/wVzlLGPvXP8Za7/T67O4v7GcPitZ32K93en329dfwZdCfOvIAoyN/Y8xskbF9eqfXZ3d/EV/zZsDXdV30qDl79U6vz+7+bPJknAAG2oe6jm///hhjdfvvPz3lxfkXDtcfZay7" .. 86 | "pf5obYX02vKk6Z1en739PTuP37PQ1VR/tP6o5yJjks92S5re6fXZ3Z/L3VzdXP351oObqvcNdfv6jX/mwU690+uzu7+wn9jZfinysInx0Du9Pvv662rsaancvn9TzT5vz1D3tOyx1ju9Prv7c7n5mb3hn59u6bjC" .. 87 | "TJcY26l3en1298f9nqf7+njqnV6fff2Vv8t/4urEzu8+8/V7e1Izx1rv9Prs7u/xF2srTuy4+q9gYKizcPnY651en9392ezJSLJ+5VAXX4DdenZq1v2oF3vl9uhN1v7+2Id1j43e6fXZ29/shfF3RryQM7Z6p9dn" .. 88 | "d38ud/W+yL0Zva3rV4693un12d0f9x+n8x+zZ+yeZ1LGeOidXp+d/ZVv9PaE9293i9kdtnbqnV6f3f3x59u3/Cf84JQv3h8PvdPrs7s/l/uR5/pu6Sxu19U7vT57+6v9OHyG6WuL/tTLWOqdXp+9/WXk8AfMMea5" .. 89 | "+ItXxkPv9Prs7s9mT9YpIHepTvvjrYfD4Waempm7tDj/+QVWl7fo6p1en939wcfXH3luweKifLMfmbFf7/T67O6Pe/ary/MefWH89E6vz+7+4OPpU7Pyls38pfXzi67e6fXZ29/kzOV5OrMLXb3T67O7P1sdBxc4" .. 90 | "HA6Hw+FwOBwOhz8UDgRwOBwOh8PhcDgcDn8oHAjgcDgcDofD4XA4HP4w+P8AQEuXMXpD8/kAAAAASUVORK5CYII=" 91 | 92 | local axis_1 = "image/png;base64," .. 93 | "iVBORw0KGgoAAAANSUhEUgAAB4AAAAAwCAQAAABaxq+2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAATVklEQVR42u2df0xUZ7rHJ+EPkiabbGJiYkLSmJg0aTYxTTZNmiYb09ykZjO0QLHY+quy9Qe1YgG5Re62rlev" .. 94 | "etluXVevt62rrkq1FLG21epW7FqUZRFtq1LqLxAR1FnkNwIzw8x752V27gzDOe/zvuedA0f5fp9kd+SZ7zPv8zlvz5x35pwzLhcEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAE" .. 95 | "QRAEQRAEQRAEQRAEQRAEQRAEQRBkq1gyK2F3Q1HCkpFHHnnkkUceeeSRRx555JFH/lHNu0KJiEqQRx555JFHHnnkkUceeeSRR/4RyzMIgiAIgiAIgiAImgTCAhiCIAiCIAiCIAiaFHK53JGoq4j8sa4i+lfkkUce" .. 96 | "eeSRRx555JFHHnnkkX8k8tGHU9PrKgY7BjvqKqamGxVAHnnkkUceeeSRRx555JFHHvmHOG/0VAQCgUAgEAgEAoFAIB65AAIEAoFAIBAIBAKBQEyKAAIEAoFAIBAIBAKBQEyKGN+Xm5mV+tqUNP7oqblOxPHsvOcW" .. 97 | "JKc+upsb/MEf/MEf/MEf/MEf/MEf/MF/EvN3uX/5Skttd3P3rfh47IXwU8zyR3eovFBy6omP+j0jN+EKdt64WsnYB+tlvbPmt52PjKDzxoxM1Y0+avw3W86d3ju2xs9ePL134D4f3rC38czpvZ767OVy9UfxafZc" .. 98 | "rqv49Wsq4wN/8Ad/8Ad/8Ad/8Ad/8Ad/8Af/ceHvci97w/gXkn72YvgpZvnqA/Iv88yr7T/F+6tKZd3FBbG+z7erbQCj8Q/cHw1p9qL71+Kfc3KXXP383Hinr2/PJr3xgT/4gz/4gz/4gz/4gz/4gz/4g3/C+fP/" .. 99 | "eWf17XOMdVwr3xKOs6WxG2BsvnxLV5PaBmisCq3sh6r2F+bNXrS5uKYsGFDzbygq2/LPhnB7XU1qG2D0+A9tPfvxYAdjzTWxz7hdx1jAV7U/P/f5hVvX3vlhZILsl68f9DNWW8ar15b1tYbMwXdWWxsf+IM/+IM/" .. 100 | "+IM/+IM/+IM/+IM/+NvEP/x/deWM3azmj5582eVemhOqMBx7LnY0P33ky+vmvzN2eq/sALf9jg/pP/89+pcrlaqfJEzL8PUy1niGo3m3UHUTRMfP44/vMubrj2Z3b+Tj27Qm8u+k1K6bjFXukq8f8DEW6W965p3v" .. 101 | "+TSJnMKgNj7wB3/wB3/wB3/wB3/wB3/wB3/wt4n/6AFuKAr4qg9OTb9/9cfjRg2sf3vYW/OJy33ojz0tq3Jlh8c/f2g8E/uXWfMPvDctQwVh2fv87PCn5nI017/R2wBV+xnrbY1mm0KbtfHb2Ofv3dxxLWeFtQ3g" .. 102 | "cme9HhxmbP3b6uNT4V+wCvzBH/zBH/zBH/zBH/zBH/zBH/wV+EcH2NtaV87Xzm3njRuI5G/Xqbbf3czY8Q9VXaODn8N+pdLlPrqDf1n+zKvqG4CPv678hy88l/nnDQfeixlfaKN+pTW+0RsgVPGWWsfgD/7gD/7g" .. 103 | "D/7gD/7gD/7gD/7gbzv/6AAjartg3IAo/9gLC5aaQ3ngYSxyWfKTLy9elr08e/niZb/IkvW73Cvf5K+8Jp/7hwcZO7VH5fVHjz98EXZ+zPfX/THjM4uk1Kdfkd8A/Jz2s6Xyfl3+4vo0f2p8FH+V/qzwn5KWvXz0" .. 104 | "eNX4U35d/uL6NH9qfBR/lf6s8H/8paU5/7bQOn/Kr8tfXJ/mT42P4q/Sn7X9j9obwNj9D/0Gpbf/EYXM/kcc9P5Hvj/wfzj5p2S8nsNPELTKX+RPBH/z+nL8ReOT4S/bH+b/wzf/+fHtr+ZZ50/5E3H8b15f7vhf" .. 105 | "ND6Z43/Z/qzN/9TXspebn1RLz3+xX3/+i+rLzH/x+Oj5L9+fw/Y/0QEOtDdWdTWafwJhnl9XONDO22r+++MvGb1I/x3GSkv4o/xcfvn1vxQszJPzu9yXj/Gz4m9W8/B2M9Z/N/YMedo/Mv773N1c7akPeBkLeKNf" .. 106 | "kfffZezj35sh+kXWke1NZ7zd9cflN8C9i6FJslver8Ofri/mLzM+EX/p/izyT0qt+YQ7+EkUZr9eJuIv49fhT9cX85cZn4i/dH8W+adk/HiC82Ws8/qCper8Zfw6/On6Yv4y4xPxl+7PIv9wFBf4B4cHFy5T5y/j" .. 107 | "19v/U/Wp/T89PvH+X7I/i/xnzQ/4wjHs/f5zdf4yfh3+dH0xf5nxifhL96cx/5NTaz/lB14s+NmfrMx/yq87/8X16flPjY+a/1L9WeTf3hDZvjzSs1X5y/h1+NP1xfxlxifiL92f5fm/v8Tbwwd876LZD7yI5z/t" .. 108 | "15v/VH1q/tPjE89/yf4s83/jzZ4WXr/fY+39l/br8afqU/zp8Yn5S/andfyjtgAee/wjsQDm52h/sJ6xugqXe3Nx23dLc0Y3wPN/3sjYhcPxB6APPN7e0/uufsNYTZnRi7SdZ6xqH3/03ILwbz1x+R+EPwWg/TMy" .. 109 | "/QPxt7retlb+9ePPQX/6lfYGxtp/ivyb39+sttwM0YXD/Ox3xuQXwMmpQ52hEf5O3q/Dn64v5k/7xfxV+rPC/+udjN29eHJXczULXv9Wnb+MX4c/XV/Mn/aL+av0Z4V/+RbGWmpP7Lx8bHiw84Y6fxm/Dn+6vpg/" .. 110 | "7RfzV+nPCv8w0c4b/FXNfhtPxF/Gr8Ofri/mT/vF/FX6s8L/uQX8lhpXK69W/nRyxzp1/jJ+Hf50fTF/2i/mr9KftfmfksHvItp5o+aT74+sK1Sf/7Rfb/5T9an5T/mp+S/fnxX+7Q0DHXzrXq3sa2PM+DwXEX8Z" .. 111 | "vw5/ur6YP+0X81fpzwr/lW8Gh/taz5Y2fB3weerV9z8yfh3+dH0xf9ov5q/SnxX+Sandt/yD1QfPlvoHBtqNr5wV8Zfx6/Cn64v5034xf5X+rB7/qC2Axx7/SC+AXe6cFUmhtT2/21fs19zRfO7KpNSxB6BhHM3/" .. 112 | "CHijN++ORi0/A/x2BM30zBmZfJNEbsNN+49sD22uAX4GeTh6W0OHnOfkXz9+A7jcOzcw5u2N/Ovsx6F/9cxeFM1PSSt7f+6SyOZ6t3BKmsoC+Et+nrz/uQXyfh3+dH0xf9ov5q/Wnzr/tgvdzeHPmxrPDA/Gf/ND" .. 113 | "85fx6/Cn64v5034xf7X+1PnPyNxQFH508QvGjH8GXcRfxq/Dn64v5k/7xfzV+lPnz4NfecMPr+QWwKP5y/h1+NP1xfxpv5i/Wn/q/PkCj/rJCBF/Gb8Of7q+mD/tF/NX68/K/Oc/C/LdEeM9m8z8p/1685+qT81/" .. 114 | "yk/Nf5X+1PkX5UUW1b2t3c3q/GX8Ovzp+mL+tF/MX60/df6ndjMWXgx9f4Qx45PcRfxl/Dr86fpi/rRfzF+tP3X+c37D2NmPR/ooY2z3RlX+Mn4d/nR9MX/aL+av1p+14x+1BfDY4x9iAfyrefy22HcvFuZFwvNj" .. 115 | "7A46ml/91tgrbS98FgyEl50clNGX4LMX+QdDK/6GkuKUDP6Jwapcfi+xSH3K//xC/sV/6/nIZ2tPv1J3iLFgsCgvPBXo1x/d3zury7d46vkJE5H8E3P67vCv9feXhP/zyc+9d5mx26MOsUQLvJlZAT9jh7cW5hXl" .. 116 | "7fyvy8dYcOwZ6CK/Hn+6fjz/3JWx/Ck/xV+1P1X+z7wavrpjSlr3rQceWf7R7mi/Hn+6vpg/5af4q/Znbf7Pmr9t7WBHZ6M6f9qfiPkvqi8z/839cvNfvj91/s/O8/V1Xv/mL2YLPIo/5dflT9Wn+Iv9NH+1/lT5" .. 117 | "8wVe+5XmmpZzxz4wXmSI+dN+Pf50fTF/yk/xV+1Plf/UdP9gV+Oz8zYXz5ov//4bpUf79fjT9cX8KT/FX7U/a/t/fuhtdl2dzP5f5E/E/l9UX2b/b+6X2//L96fKf8c6xr7ckZz61Nx7Fx/8U50/7dfjT9cX86f8" .. 118 | "FH/V/lT5z10S/lbW5T7wnvE3lWL+tF+PP11fzJ/yU/xV+7O6/zEPuf2P6QI4ZwW/afRYRUqE8tHzxlkwEL8ybzoTWcvv2cRYSbHRy3y+nQ+K2709/EeLuSI7C7F/Q9G/nCHxT9pmLwpf78gVPuGZev3R448o4Csu" .. 119 | "iD6nYJW3N/x3X2+4fjC477/lFohzl4zl1/jtz9NkF6i6/OkFqJi/2B/P//mFUf61n0r2lwD+U9NbzjF24iM5/k1npqTFH6aY+RPD37y+HH8zvyx/YX/a/Lev438b6jS60YQMf5E/EfxF9WX4m/vl+BP9afL/6WQw" .. 120 | "WJhXuct4gUfzF/v1+Yvr0/xFfhn+ZH9a/J+aO3LC2OBgR/yPNcjxp/y6/Kn6FH+xn+Yv0Z8W/5wVoYOlS/wQLug3urMnxZ/y6/Kn6lP8xX6av0R/CXj/dblrP7W6/xH7E/P+a15f7v3XzC/7/ivsT5M/v8jM2xsc" .. 121 | "9vevfssKf7Ffn7+4Ps1f5JfhT/anxT8pta/V139o6+l9/Cp7fidkNf6UX5c/VZ/iL/bT/CX6S8j+xyxk9z+mC+CZWeFLmM02wOh8vyf+Mv+ms7EL0N//h/ELlRTfuxQF0Xn9kz9Ehij2z13CT20bObzs4tN7Wsb9" .. 122 | "a+FNMjx4cpfM68f3Fww+8DSdeePN+MOIS0fDt7LhajsfOa2RXuDNzOqO1g/6+9sb9peoLFB1+cssgEX8xf54/lPT4/mr9meF/8wsfgN44+sExvIvLRn7HJFfn7+ovgx/c78cf5X+rPB/Ys6R7aFlRqC5euyORYa/" .. 123 | "2K/PX1Rfhr+5X46/Sn+q/H9bwIKXjrrcZgs8ij/t1+NP1af4i/00f9X+1Od/aUlJ8ZS0pNT6rxiLvXGX7Pyn/LrzX1yfnv8iv8z8V+tPlf/WtfwvzdUH/nD/SjAYe/dQOf60X48/VZ/iL/bT/FX7s3b8w29VY3yC" .. 124 | "r8z+X+xPxPGPeX254x8zv+zxj3x/qvxTMtq+Y2ywI+ALBsreV+dP+/X4U/Up/mI/zV+1P/X5X5g30DHy19AxVs1B9flP+XXnv7g+Pf9Ffpn5r9af1f2PWcjuf0wXwLrx3ZHgcPgG2PwU5MXLzJ/5xJw1+dvWFuaN" .. 125 | "/hpf3q/7+lSkZBQXbFubn2t0g3xqgUmFrj8R9Y35O6c/M/7zlvCrDqpKrdbV9Seqvhl/p/Qnmv88PvuT3t36dP269UXz3wn9GfPnH230tXU18TeZtvPG9zgQha4/cfWN+TunP2r+5+cy9sX/WK+v69etT83/ie7P" .. 126 | "mP/qt/hN5vij4gLGTu9VrarrT1x9Y/7O6U80/wvz9N5hdP2JqC+a/07oz5j/Vx8ytnNDUuqMzMaqgH96pmpVXX/i6hvzd05/5vN/euamNTkrTu/jr2Slsq4/MfXN578z+qPef20J/RKHtjK25R3+6GZ1wKd+ADLR" .. 127 | "frl4FBbAD2d/G4t8vUE//2zvmVf/vHH8/U4fn939RWP3RsbMP+O13+/08dnT39VvOq/z4D/1dvuc+v5N1+/08dnd37SMyLV+H61nbO/m8fY7fXx29zc9c3io+xZ/lL2csb/9Zbz9Th+f3f2F4/xh0fkd9vudPj77" .. 128 | "+mv4OuhPGbmB0bH/ZczsJGP7/E4fn939RWL92wFf103Rrebs9Tt9fHb3Z1Mk4g1goH2o6+SuH08wVnfo4fNTUZR36Wj9cca6W+qP15ZLn1ueML/Tx2dvf88v5NcsdDXVH68/7rnMmOS93RLmd/r47O7P5W6ubq7+" .. 129 | "csfhrdUHh7p9/cY/82Cn3+njs7u/cJza034lcrOJifA7fXz29dfV2NNSuevQ1pqD3p6h7plZ4+13+vjs7s/l5u/sDX/9fHvHNWZ6irGdfqePz+7+eDzwdN+cSL/Tx2dff2Xv85+4OrXnhy98/d6elIzx9jt9fHb3" .. 130 | "9+TLteWndl//WzAw1Fmwavz9Th+f3f3ZHIkosmnNUBc/Abv1/IzMh9Evjspd0Yus/f2xN+seH7/Tx2dvf/OWjL4y4qXs8fU7fXx29+dyVx+MXJvR27ppzfj7nT4+u/vj8fM0/mP2jD3wTE2fCL/Tx2dnf2VbvD3h" .. 131 | "7dvdYnaFrZ1+p4/P7v74/e1b/hG+ccpXH06E3+njs7s/l/uxF/ru6Jzcrut3+vjs7a/20/A7TF9b9KdextPv9PHZ2196Nr/BHGOey79+bSL8Th+f3f3ZHIl6C8hZodP+RPsRCIRZpGTkrCjKe3Gx1dNbdP1OH5/d" .. 132 | "/SEmNh57YfGywjyzH5mx3+/08dndH4+s11flPv7SxPmdPj67+0NMZMzIzF055zfW3190/U4fn739TctYlauzutD1O318dvdna2DngkAgEAgEAoFAIBCISRFAgEAgEAgEAoFAIBCISRHRh1PT6yqGOoc66yqMr6NC" .. 133 | "HnnkkUceeeSRRx555JFHHvmHOB99WFcRuZGO8b00kUceeeSRRx555JFHHnnkkUf+Ic4zCIIgCIIgCIIgCJoEwgIYgiAIgiAIgiAImhRyRcVK/v+vJS4DIY888sgjjzzyyCOPPPLII4/8o5B3seTQU+6EooQlI488" .. 134 | "8sgjjzzyyCOPPPLII4/8o5qHIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCEqf/A/SNfayCCBqGAAAAAElFTkSuQmCC" 135 | 136 | local options = require 'mp.options' 137 | local msg = require 'mp.msg' 138 | 139 | local function get_visualizer(name, quality, vtrack) 140 | local w, h, fps 141 | 142 | if quality == "verylow" then 143 | w = 640 144 | fps = 30 145 | elseif quality == "low" then 146 | w = 960 147 | fps = 30 148 | elseif quality == "medium" then 149 | w = 1280 150 | fps = 60 151 | elseif quality == "high" then 152 | w = 1920 153 | fps = 60 154 | elseif quality == "veryhigh" then 155 | w = 2560 156 | fps = 60 157 | else 158 | msg.log("error", "invalid quality") 159 | return "" 160 | end 161 | 162 | h = w * opts.height / 16 163 | 164 | if name == "showcqt" then 165 | local count = math.ceil(w * 180 / 1920 / fps) 166 | 167 | return "[aid1] asplit [ao]," .. 168 | "aformat = channel_layouts = stereo," .. 169 | "firequalizer =" .. 170 | "gain = '1.4884e8 * f*f*f / (f*f + 424.36) / (f*f + 1.4884e8) / sqrt(f*f + 25122.25)':" .. 171 | "scale = linlin:" .. 172 | "wfunc = tukey:" .. 173 | "zero_phase = on:" .. 174 | "fft2 = on," .. 175 | "showcqt =" .. 176 | "fps =" .. fps .. ":" .. 177 | "size =" .. w .. "x" .. h .. ":" .. 178 | "count =" .. count .. ":" .. 179 | "csp = bt709:" .. 180 | "bar_g = 2:" .. 181 | "sono_g = 4:" .. 182 | "bar_v = 9:" .. 183 | "sono_v = 17:" .. 184 | "axisfile = data\\\\:'" .. axis_0 .. "':" .. 185 | "font = 'Nimbus Mono L,Courier New,mono|bold':" .. 186 | "fontcolor = 'st(0, (midi(f)-53.5)/12); st(1, 0.5 - 0.5 * cos(PI*ld(0))); r(1-ld(1)) + b(ld(1))':" .. 187 | "tc = 0.33:" .. 188 | "attack = 0.033:" .. 189 | "tlength = 'st(0,0.17); 384*tc / (384 / ld(0) + tc*f /(1-ld(0))) + 384*tc / (tc*f / ld(0) + 384 /(1-ld(0)))'," .. 190 | "format = yuv420p [vo]" 191 | 192 | 193 | elseif name == "avectorscope" then 194 | return "[aid1] asplit [ao]," .. 195 | "aformat =" .. 196 | "sample_rates = 192000," .. 197 | "avectorscope =" .. 198 | "size =" .. w .. "x" .. h .. ":" .. 199 | "r =" .. fps .. "," .. 200 | "format = rgb0 [vo]" 201 | 202 | 203 | elseif name == "showspectrum" then 204 | return "[aid1] asplit [ao]," .. 205 | "showspectrum =" .. 206 | "size =" .. w .. "x" .. h .. ":" .. 207 | "win_func = blackman [vo]" 208 | 209 | 210 | elseif name == "showcqtbar" then 211 | local axis_h = math.ceil(w * 12 / 1920) * 4 212 | 213 | return "[aid1] asplit [ao]," .. 214 | "aformat = channel_layouts = stereo," .. 215 | "firequalizer =" .. 216 | "gain = '1.4884e8 * f*f*f / (f*f + 424.36) / (f*f + 1.4884e8) / sqrt(f*f + 25122.25)':" .. 217 | "scale = linlin:" .. 218 | "wfunc = tukey:" .. 219 | "zero_phase = on:" .. 220 | "fft2 = on," .. 221 | "showcqt =" .. 222 | "fps =" .. fps .. ":" .. 223 | "size =" .. w .. "x" .. (h + axis_h)/2 .. ":" .. 224 | "count = 1:" .. 225 | "csp = bt709:" .. 226 | "bar_g = 2:" .. 227 | "sono_g = 4:" .. 228 | "bar_v = 9:" .. 229 | "sono_v = 17:" .. 230 | "sono_h = 0:" .. 231 | "axisfile = data\\\\:'" .. axis_1 .. "':" .. 232 | "axis_h =" .. axis_h .. ":" .. 233 | "font = 'Nimbus Mono L,Courier New,mono|bold':" .. 234 | "fontcolor = 'st(0, (midi(f)-53.5)/12); st(1, 0.5 - 0.5 * cos(PI*ld(0))); r(1-ld(1)) + b(ld(1))':" .. 235 | "tc = 0.33:" .. 236 | "attack = 0.033:" .. 237 | "tlength = 'st(0,0.17); 384*tc / (384 / ld(0) + tc*f /(1-ld(0))) + 384*tc / (tc*f / ld(0) + 384 /(1-ld(0)))'," .. 238 | "format = yuv420p," .. 239 | "split [v0]," .. 240 | "crop =" .. 241 | "h =" .. (h - axis_h)/2 .. ":" .. 242 | "y = 0," .. 243 | "vflip [v1];" .. 244 | "[v0][v1] vstack [vo]" 245 | 246 | 247 | elseif name == "showwaves" then 248 | return "[aid1] asplit [ao]," .. 249 | "showwaves =" .. 250 | "size =" .. w .. "x" .. h .. ":" .. 251 | "r =" .. fps .. ":" .. 252 | "mode = p2p," .. 253 | "format = rgb0 [vo]" 254 | elseif name == "off" then 255 | local hasvideo = false 256 | for id, track in ipairs(mp.get_property_native("track-list")) do 257 | if track.type == "video" then 258 | hasvideo = true 259 | break 260 | end 261 | end 262 | if hasvideo then 263 | return "[aid1] asetpts=PTS [ao]; [vid1] setpts=PTS [vo]" 264 | else 265 | return "[aid1] asetpts=PTS [ao];" .. 266 | "color =" .. 267 | "c = Black:" .. 268 | "s =" .. w .. "x" .. h .. "," .. 269 | "format = yuv420p [vo]" 270 | end 271 | end 272 | 273 | msg.log("error", "invalid visualizer name") 274 | return "" 275 | end 276 | 277 | local function select_visualizer(vtrack, atrack) 278 | if atrack == nil or opts.mode == "off" then 279 | return "" 280 | elseif opts.mode == "force" then 281 | return get_visualizer(opts.name, opts.quality, vtrack) 282 | elseif opts.mode == "noalbumart" then 283 | if vtrack == nil then 284 | return get_visualizer(opts.name, opts.quality, vtrack) 285 | end 286 | return "" 287 | elseif opts.mode == "novideo" then 288 | if vtrack == nil or vtrack.albumart then 289 | return get_visualizer(opts.name, opts.quality, vtrack) 290 | end 291 | return "" 292 | end 293 | 294 | msg.log("error", "invalid mode") 295 | return "" 296 | end 297 | 298 | local function visualizer_hook() 299 | local count = mp.get_property_number("track-list/count", -1) 300 | if count <= 0 then 301 | return 302 | end 303 | 304 | local atrack = mp.get_property_native("current-tracks/audio") 305 | local vtrack = mp.get_property_native("current-tracks/video") 306 | 307 | --no tracks selected (yet) 308 | if atrack == nil and vtrack == nil then 309 | for id, track in ipairs(mp.get_property_native("track-list")) do 310 | if track.type == "video" and (vtrack == nil or vtrack.albumart == true) and mp.get_property("vid") ~= "no" then 311 | vtrack = track 312 | elseif track.type == "audio" then 313 | atrack = track 314 | end 315 | end 316 | end 317 | 318 | local lavfi = select_visualizer(vtrack, atrack) 319 | --prevent endless loop 320 | if lavfi ~= "" and lavfi ~= mp.get_property("lavfi-complex", "") then 321 | mp.set_property("file-local-options/lavfi-complex", lavfi) 322 | end 323 | end 324 | 325 | options.read_options(opts, nil, visualizer_hook) 326 | opts.height = math.min(12, math.max(4, opts.height)) 327 | opts.height = math.floor(opts.height) 328 | 329 | if not opts.forcewindow and mp.get_property('force-window') == "no" then 330 | return 331 | end 332 | 333 | mp.add_hook("on_preloaded", 50, visualizer_hook) 334 | mp.observe_property("current-tracks/audio", "native", visualizer_hook) 335 | mp.observe_property("current-tracks/video", "native", visualizer_hook) 336 | 337 | local function cycle_visualizer() 338 | local i, index = 1 339 | for i = 1, #visualizer_name_list do 340 | if (visualizer_name_list[i] == opts.name) then 341 | index = i + 1 342 | if index > #visualizer_name_list then 343 | index = 1 344 | end 345 | break 346 | end 347 | end 348 | opts.name = visualizer_name_list[index] 349 | visualizer_hook() 350 | end 351 | 352 | mp.add_key_binding(cycle_key, "cycle-visualizer", cycle_visualizer) 353 | --------------------------------------------------------------------------------