@mthines/reaper-mcp 0.19.0 → 0.70.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +19 -570
  2. package/bridge-ui/mcp_bridge.html +129 -0
  3. package/bridge-ui/mcp_bridge.webmanifest +16 -0
  4. package/bridge-ui/mcp_bridge_icon_192.png +0 -0
  5. package/bridge-ui/mcp_bridge_icon_512.png +0 -0
  6. package/bridge-ui/mcp_bridge_sw.js +35 -0
  7. package/claude/agents/plugin-researcher.md +188 -0
  8. package/claude/knowledge/reference/aesthetics-scoring.md +48 -0
  9. package/{knowledge → claude/knowledge}/reference/common-mistakes.md +1 -1
  10. package/claude/knowledge/reference/lorekit-setup.md +36 -0
  11. package/claude/knowledge/reference/memory-protocol.md +377 -0
  12. package/{knowledge → claude/knowledge}/reference/metering.md +5 -5
  13. package/claude/knowledge/reference/perceived-loudness.md +182 -0
  14. package/{knowledge → claude/knowledge}/workflows/editing.md +4 -0
  15. package/{knowledge → claude/knowledge}/workflows/gain-staging.md +21 -23
  16. package/{knowledge → claude/knowledge}/workflows/learn-plugin.md +15 -48
  17. package/{knowledge → claude/knowledge}/workflows/master-bus.md +13 -1
  18. package/claude/knowledge/workflows/section-levels.md +138 -0
  19. package/{knowledge → claude/knowledge}/workflows/session-prep.md +4 -0
  20. package/claude/knowledge/workflows/transient-lighting.md +52 -0
  21. package/claude/skills/critique/SKILL.md +131 -0
  22. package/claude/skills/editing/SKILL.md +281 -0
  23. package/claude/skills/learn-plugin/SKILL.md +210 -0
  24. package/claude/skills/mastering/SKILL.md +151 -0
  25. package/claude/skills/mix-memory/SKILL.md +140 -0
  26. package/claude/skills/mixer/SKILL.md +253 -0
  27. package/claude/skills/new-extension/SKILL.md +324 -0
  28. package/main.js +7843 -1940
  29. package/package.json +17 -15
  30. package/reaper/CLAUDE.md +22 -4
  31. package/reaper/mcp_actions_lib.lua +375 -0
  32. package/reaper/mcp_analyzer.jsfx +27 -12
  33. package/reaper/mcp_arrange_lib.lua +949 -0
  34. package/reaper/mcp_bridge.lua +2321 -758
  35. package/reaper/mcp_edit_views_lib.lua +1378 -0
  36. package/reaper/mcp_envelopes_lib.lua +748 -0
  37. package/reaper/mcp_extensions_lib.lua +55 -0
  38. package/reaper/mcp_fxstate_lib.lua +144 -0
  39. package/reaper/mcp_gain_trace.jsfx +126 -0
  40. package/reaper/mcp_items_lib.lua +877 -0
  41. package/reaper/mcp_lufs_meter.jsfx +16 -13
  42. package/reaper/mcp_midi_lib.lua +555 -0
  43. package/reaper/mcp_mixing_lib.lua +1021 -0
  44. package/reaper/mcp_plan_lib.lua +801 -0
  45. package/reaper/mcp_prefs_lib.lua +127 -0
  46. package/reaper/mcp_project_lib.lua +1088 -0
  47. package/reaper/mcp_recording_lib.lua +595 -0
  48. package/reaper/mcp_render_lib.lua +492 -0
  49. package/reaper/mcp_snapshot_lib.lua +547 -120
  50. package/reaper/mcp_snapshot_next.lua +10 -4
  51. package/reaper/mcp_snapshot_prev.lua +11 -4
  52. package/reaper/mcp_snapshot_quick_save.lua +7 -32
  53. package/reaper/mcp_snapshots_ui_lib.lua +258 -0
  54. package/reaper/mcp_tracks_lib.lua +409 -0
  55. package/sidecar/analysis.py +661 -0
  56. package/sidecar/chords.py +96 -0
  57. package/sidecar/mixcheck.py +295 -0
  58. package/sidecar/requirements-chords.txt +6 -0
  59. package/sidecar/requirements-separation.txt +3 -0
  60. package/sidecar/requirements.txt +17 -0
  61. package/sidecar/separation.py +142 -0
  62. package/sidecar/server.py +622 -0
  63. package/sidecar/tests/test_analysis.py +249 -0
  64. package/sidecar/tests/test_chords.py +117 -0
  65. package/sidecar/tests/test_mixcheck.py +163 -0
  66. package/sidecar/tests/test_separation.py +73 -0
  67. package/sidecar/tests/test_server.py +464 -0
  68. package/sidecar/tests/test_verify.py +243 -0
  69. package/sidecar/tests/test_voice_render.py +268 -0
  70. package/sidecar/tests/test_voice_sketch.py +140 -0
  71. package/sidecar/verify.py +224 -0
  72. package/sidecar/voice_render.py +295 -0
  73. package/sidecar/voice_sketch.py +280 -0
  74. package/claude-agents/critique.md +0 -147
  75. package/claude-agents/editor.md +0 -184
  76. package/claude-agents/levels.md +0 -107
  77. package/claude-agents/mastering.md +0 -129
  78. package/claude-agents/mixer.md +0 -248
  79. package/claude-agents/preflight.md +0 -149
  80. package/claude-agents/producer.md +0 -159
  81. package/claude-agents/setup.md +0 -150
  82. package/claude-agents/stems.md +0 -135
  83. package/claude-rules/architecture.md +0 -39
  84. package/claude-rules/development.md +0 -54
  85. package/claude-rules/lua-bridge.md +0 -50
  86. package/claude-rules/testing.md +0 -42
  87. package/claude-skills/learn-plugin.md +0 -123
  88. package/knowledge/CLAUDE.md +0 -71
  89. package/knowledge/plugins/_template.md +0 -82
  90. package/knowledge/plugins/fabfilter/pro-c-2.md +0 -117
  91. package/knowledge/plugins/fabfilter/pro-l-2.md +0 -95
  92. package/knowledge/plugins/fabfilter/pro-q-3.md +0 -112
  93. package/knowledge/plugins/neural-dsp/helix-native.md +0 -104
  94. package/knowledge/plugins/stock-reaper/js-1175-compressor.md +0 -94
  95. package/knowledge/plugins/stock-reaper/rea-comp.md +0 -100
  96. package/knowledge/plugins/stock-reaper/rea-delay.md +0 -95
  97. package/knowledge/plugins/stock-reaper/rea-eq.md +0 -103
  98. package/knowledge/plugins/stock-reaper/rea-gate.md +0 -99
  99. package/knowledge/plugins/stock-reaper/rea-limit.md +0 -75
  100. package/knowledge/plugins/stock-reaper/rea-verb.md +0 -76
  101. package/knowledge/reference/perceived-loudness.md +0 -122
  102. package/reaper/mcp_snapshot_manager.lua +0 -1001
  103. /package/{knowledge → claude/knowledge}/genres/_template.md +0 -0
  104. /package/{knowledge → claude/knowledge}/genres/electronic.md +0 -0
  105. /package/{knowledge → claude/knowledge}/genres/hip-hop.md +0 -0
  106. /package/{knowledge → claude/knowledge}/genres/metal.md +0 -0
  107. /package/{knowledge → claude/knowledge}/genres/orchestral.md +0 -0
  108. /package/{knowledge → claude/knowledge}/genres/pop.md +0 -0
  109. /package/{knowledge → claude/knowledge}/genres/rock.md +0 -0
  110. /package/{knowledge → claude/knowledge}/reference/compression.md +0 -0
  111. /package/{knowledge → claude/knowledge}/reference/frequencies.md +0 -0
  112. /package/{knowledge → claude/knowledge}/workflows/delivery.md +0 -0
  113. /package/{knowledge → claude/knowledge}/workflows/drum-bus.md +0 -0
  114. /package/{knowledge → claude/knowledge}/workflows/low-end.md +0 -0
  115. /package/{knowledge → claude/knowledge}/workflows/stem-prep.md +0 -0
  116. /package/{knowledge → claude/knowledge}/workflows/vocal-chain.md +0 -0
@@ -0,0 +1,55 @@
1
+ -- mcp_extensions_lib.lua — run a Lua command that an extension ships (extension_call).
2
+ --
3
+ -- An extension's handlers live in <bridge folder>/extensions/<name>/handlers.lua (the server copies the file
4
+ -- there when it loads the extension) and return a table of command functions:
5
+ --
6
+ -- return { my_command = function(params, host) ... return data end } -- or: return nil, "refusal"
7
+ --
8
+ -- `host` = { reaper, plan, fxstate, json_decode }. Extensions are trusted code the user installed; this lib
9
+ -- only makes sure a command can name nothing outside its own file. Loaded by mcp_bridge.lua with dofile.
10
+
11
+ local M = {}
12
+
13
+ local cache = {} -- extension name -> { src, mod }: reloaded when the file's text changes
14
+
15
+ function M.call(api, params, ctx)
16
+ local name, command = params.extension, params.command
17
+ if type(name) ~= "string" or not name:match("^[a-z][a-z0-9%-]+$") or #name > 32 then
18
+ return nil, "invalid extension name"
19
+ end
20
+ if type(command) ~= "string" or not command:match("^[%a_][%w_]*$") then
21
+ return nil, "invalid command name"
22
+ end
23
+
24
+ local path = ctx.dir .. name .. "/handlers.lua"
25
+ local src = ctx.read(path)
26
+ if not src then
27
+ return nil, "extension '" .. name .. "' has no Lua handlers installed; its manifest needs a \"lua\" file and the server must have loaded it"
28
+ end
29
+
30
+ local entry = cache[name]
31
+ if not entry or entry.src ~= src then
32
+ local chunk, cerr = load(src, "@" .. path, "t")
33
+ if not chunk then return nil, "extension '" .. name .. "': handlers.lua does not compile: " .. tostring(cerr) end
34
+ local ok, mod = pcall(chunk)
35
+ if not ok then return nil, "extension '" .. name .. "': handlers.lua failed to load: " .. tostring(mod) end
36
+ if type(mod) ~= "table" then return nil, "extension '" .. name .. "': handlers.lua must return a table of commands" end
37
+ entry = { src = src, mod = mod }
38
+ cache[name] = entry
39
+ end
40
+
41
+ local fn = entry.mod[command]
42
+ if type(fn) ~= "function" then return nil, "extension '" .. name .. "' has no Lua command '" .. command .. "'" end
43
+
44
+ local args = {}
45
+ if type(params.paramsJson) == "string" and params.paramsJson ~= "" then
46
+ local decoded, derr = ctx.plan.json_decode(params.paramsJson)
47
+ if derr then return nil, "paramsJson is not valid JSON: " .. tostring(derr) end
48
+ args = type(decoded) == "table" and decoded or {}
49
+ end
50
+
51
+ -- A crash inside the handler is the bridge's "Handler error:", a system fault: it is not caught here.
52
+ return fn(args, { reaper = api, plan = ctx.plan, fxstate = ctx.fxstate, json_decode = ctx.plan.json_decode })
53
+ end
54
+
55
+ return M
@@ -0,0 +1,144 @@
1
+ -- mcp_fxstate_lib.lua — read and replace one VST3 plugin's saved state in a track chunk.
2
+ --
3
+ -- Pure logic: every function takes the ReaScript API as `api` and `ctx` = { plan, dir, read, write }, so it
4
+ -- runs under a fake API in unit tests. Loaded by mcp_bridge.lua with dofile.
5
+ --
6
+ -- The state is megabytes, so it never travels inside the command JSON: the caller names a file inside the
7
+ -- bridge's data folder and this lib reads or writes it (line 1: base64 header, line 2: base64 state).
8
+ --
9
+ -- Why a new FXID on write: with the same FXID REAPER keeps the loaded instance and ignores the new state
10
+ -- (verified on Vital, 2026-11-04). The VST3 length fields are the caller's job (libs/extension-api).
11
+
12
+ local M = {}
13
+
14
+ local WRAP = 280
15
+ local FX_TAGS = { VST = true, JS = true, AU = true, CLAP = true, DX = true, VIDEO_EFFECT = true }
16
+
17
+ local function split_lines(chunk)
18
+ local lines = {}
19
+ for line in (chunk .. "\n"):gmatch("(.-)\r?\n") do lines[#lines + 1] = line end
20
+ if lines[#lines] == "" then lines[#lines] = nil end
21
+ return lines
22
+ end
23
+
24
+ local function trim(s) return s:match("^%s*(.-)%s*$") end
25
+
26
+ local function norm(path) return (tostring(path):gsub("\\", "/")) end
27
+
28
+ --- A file this lib may touch: inside the bridge folder, named fxstate_<id>.in/.out, no "..".
29
+ local function allowed_file(path, dir)
30
+ if type(path) ~= "string" or type(dir) ~= "string" then return false end
31
+ local p, d = norm(path), norm(dir)
32
+ if d:sub(-1) ~= "/" then d = d .. "/" end
33
+ if p:sub(1, #d) ~= d or p:find("..", 1, true) then return false end
34
+ return p:sub(#d + 1):match("^fxstate_[%w%-]+%.%a+$") ~= nil
35
+ end
36
+
37
+ --- The FX of a track chunk in chain order: { open, close, tag, header, name, fxid_line } (1-based line numbers).
38
+ --- Returns list, lines, chain_end or nil, err.
39
+ local function list_fx(chunk, plan)
40
+ local lines = split_lines(chunk)
41
+ local cs, ce = plan.find_block(lines, "FXCHAIN")
42
+ if not cs then return nil, "the track has no FX chain" end
43
+ local fx, current, d = {}, nil, 1
44
+ for i = cs + 1, ce - 1 do
45
+ local t = trim(lines[i])
46
+ if t:sub(1, 1) == "<" then
47
+ if d == 1 then
48
+ local tag = t:match("^<(%u[%u_%d]*)")
49
+ if tag == "CONTAINER" then
50
+ return nil, "FX containers are not supported yet (this track's chain has one)"
51
+ end
52
+ current = nil
53
+ if FX_TAGS[tag] then
54
+ current = { open = i, tag = tag, header = t, name = t:match('^<%u[%u_%d]*%s+"([^"]*)"') or "" }
55
+ fx[#fx + 1] = current
56
+ end
57
+ end
58
+ d = d + 1
59
+ elseif t == ">" then
60
+ d = d - 1
61
+ if d == 1 and current and not current.close then current.close = i end
62
+ elseif d == 1 and t:match("^FXID%s") and #fx > 0 and not fx[#fx].fxid_line then
63
+ fx[#fx].fxid_line = i
64
+ end
65
+ end
66
+ return fx, lines, ce
67
+ end
68
+
69
+ local function locate(api, params, ctx)
70
+ local track_ref = params.trackIndex
71
+ if track_ref == nil then return nil, "trackIndex is required" end
72
+ local fx_index = tonumber(params.fxIndex)
73
+ if not fx_index or fx_index < 0 or fx_index ~= math.floor(fx_index) then
74
+ return nil, "fxIndex must be a whole number, 0 or more"
75
+ end
76
+ local r, err = ctx.plan.resolve_track(api, track_ref, {})
77
+ if not r then return nil, err end
78
+ local ok, chunk = api.GetTrackStateChunk(r.track, "", false)
79
+ if not ok or not chunk or chunk == "" then return nil, "could not read the track's state" end
80
+ local fx, lines = list_fx(chunk, ctx.plan)
81
+ if not fx then return nil, lines end
82
+ local target = fx[fx_index + 1]
83
+ if not target then return nil, "FX " .. fx_index .. " not found (the track has " .. #fx .. " FX)" end
84
+ if target.tag ~= "VST" or not target.name:match("^VST3") then
85
+ return nil, "FX " .. fx_index .. " (" .. target.name .. ") is not a VST3 plugin; only VST3 state is supported"
86
+ end
87
+ if not target.close then return nil, "FX " .. fx_index .. " has an unreadable state block" end
88
+ return { track = r.track, fx = target, lines = lines, index = fx_index }
89
+ end
90
+
91
+ --- Read one VST3's state into params.outFile. Returns { name, format }.
92
+ function M.get_fx_state(api, params, ctx)
93
+ if not allowed_file(params.outFile, ctx.dir) then return nil, "outFile must be an fxstate_* file in the bridge folder" end
94
+ local loc, err = locate(api, params, ctx)
95
+ if not loc then return nil, err end
96
+ local data = {}
97
+ for i = loc.fx.open + 1, loc.fx.close - 1 do
98
+ local t = trim(loc.lines[i])
99
+ if t ~= "" then data[#data + 1] = t end
100
+ end
101
+ if #data < 2 then return nil, "FX " .. loc.index .. " has no saved state to read" end
102
+ local ok, werr = ctx.write(params.outFile, data[1] .. "\n" .. table.concat(data, "", 2) .. "\n")
103
+ if not ok then return nil, "could not write " .. tostring(params.outFile) .. ": " .. tostring(werr) end
104
+ return { name = loc.fx.name, format = "vst3" }
105
+ end
106
+
107
+ --- Replace one VST3's state with the file params.inFile and give it a new FXID so REAPER reloads it.
108
+ function M.set_fx_state(api, params, ctx)
109
+ if not allowed_file(params.inFile, ctx.dir) then return nil, "inFile must be an fxstate_* file in the bridge folder" end
110
+ local text = ctx.read(params.inFile)
111
+ if not text then return nil, "could not read " .. tostring(params.inFile) end
112
+ local header, state = text:match("^([^\n]+)\n([^\n]+)\n?")
113
+ local b64 = "^[A-Za-z0-9+/]+=?=?$"
114
+ if not header or not state or not header:match(b64) or not state:match(b64) then
115
+ return nil, "inFile must hold two base64 lines: the header, then the state"
116
+ end
117
+
118
+ local loc, err = locate(api, params, ctx)
119
+ if not loc then return nil, err end
120
+ if params.expectName and not loc.fx.name:find(tostring(params.expectName), 1, true) then
121
+ return nil, "FX " .. loc.index .. " is '" .. loc.fx.name .. "', not '" .. tostring(params.expectName) .. "'; nothing changed"
122
+ end
123
+ if not loc.fx.fxid_line then return nil, "FX " .. loc.index .. " has no FXID to renew; nothing changed" end
124
+
125
+ local out = {}
126
+ for i = 1, loc.fx.open do out[#out + 1] = loc.lines[i] end
127
+ out[#out + 1] = header
128
+ for at = 1, #state, WRAP do out[#out + 1] = state:sub(at, at + WRAP - 1) end
129
+ for i = loc.fx.close, #loc.lines do
130
+ if i == loc.fx.fxid_line then
131
+ out[#out + 1] = loc.lines[i]:match("^(%s*)") .. "FXID " .. api.genGuid("")
132
+ else
133
+ out[#out + 1] = loc.lines[i]
134
+ end
135
+ end
136
+
137
+ api.Undo_BeginBlock()
138
+ local ok = api.SetTrackStateChunk(loc.track, table.concat(out, "\n") .. "\n", false)
139
+ api.Undo_EndBlock("MCP: Set FX state (" .. loc.fx.name .. ")", -1)
140
+ if not ok then return nil, "REAPER refused the new track state" end
141
+ return { name = loc.fx.name, fxIndex = loc.index }
142
+ end
143
+
144
+ return M
@@ -0,0 +1,126 @@
1
+ desc:MCP Gain Trace (pre/post ducking meter)
2
+ // Measures how much a chain of processors moves the level over time, live during playback.
3
+ // Put one instance in mode "pre" at the start of a chain and one in mode "post" at the end (same slot).
4
+ // Every 5 ms the post instance compares its 30 ms RMS with the pre RMS (post - pre, dB), at the
5
+ // lag where they line up best (plugin latency in between), and reports percentiles relative to the
6
+ // median gain: p5 / p1 = how deep the dips go, std = how much the gain moves.
7
+ // Stats reset when playback starts or Reset changes. Audio passes through unmodified.
8
+ // Everything runs in @sample. EEL2 has no scientific-notation literals (1e9 fails to compile).
9
+
10
+ options:gmem=MCPGainTrace
11
+
12
+ slider1:0<0,1,1{pre,post}>Mode
13
+ slider2:0<0,7,1>Slot
14
+ slider3:-45<-80,-20,1>Gate (dBFS, pre)
15
+ slider4:0<-40,10,0.01>p5 (dB, rel. median)
16
+ slider5:0<-40,10,0.01>p1 (dB, rel. median)
17
+ slider6:0<0,20,0.01>Std (dB)
18
+ slider7:0<-40,40,0.01>Median gain (dB)
19
+ slider8:0<0,100000,0.1>Gated time (s)
20
+ slider9:0<0,100,0.1>Lag (ms)
21
+ slider10:0<0,1,1>Reset
22
+
23
+ in_pin:left input
24
+ in_pin:right input
25
+ out_pin:left output
26
+ out_pin:right output
27
+
28
+ @init
29
+ RING = 4096; // windows kept per slot
30
+ LAGS = 16; // lags tried, in windows
31
+ BINS = 600; // histogram bins: -40..+20 dB, 0.1 dB
32
+ BINLO = -40;
33
+ hist = 0; // LAGS * BINS
34
+ sums = hist + LAGS * BINS; // per lag: n, sum, sumsq
35
+ ph = sums + LAGS * 3; // post window energies, ring of 64
36
+ AVG = 6; // gain is compared over AVG windows (30 ms RMS), so waveform phase doesn't count
37
+ win = floor(srate * 0.005);
38
+ acc = 0; total = 0; seen = -1;
39
+ was_playing = 0;
40
+ last_reset = slider10;
41
+ nwin = 0;
42
+
43
+ function reset_stats() local(i) (
44
+ i = 0; loop(LAGS * BINS + LAGS * 3 + 64, hist[i] = 0; i += 1);
45
+ slider4 = slider5 = slider6 = slider7 = slider8 = slider9 = 0;
46
+ );
47
+
48
+ function update_stats() local(l, s, sd, best, bstd, n, h, c, b, q1, q5, q50) (
49
+ best = -1; bstd = 1000000000; l = 0;
50
+ loop(LAGS,
51
+ s = sums + l * 3;
52
+ s[0] > 20 ? (
53
+ sd = sqrt(max(0, s[2] / s[0] - sqr(s[1] / s[0])));
54
+ sd < bstd ? ( bstd = sd; best = l; );
55
+ );
56
+ l += 1;
57
+ );
58
+ best >= 0 ? (
59
+ s = sums + best * 3; n = s[0]; h = hist + best * BINS;
60
+ c = 0; b = 0; q1 = q5 = q50 = -1;
61
+ loop(BINS,
62
+ c += h[b];
63
+ q1 < 0 && c >= n * 0.01 ? q1 = b;
64
+ q5 < 0 && c >= n * 0.05 ? q5 = b;
65
+ q50 < 0 && c >= n * 0.5 ? q50 = b;
66
+ b += 1;
67
+ );
68
+ slider4 = (q5 - q50) / 10;
69
+ slider5 = (q1 - q50) / 10;
70
+ slider6 = bstd;
71
+ slider7 = BINLO + (q50 + 0.5) / 10;
72
+ slider8 = n * win / srate;
73
+ slider9 = best * win / srate * 1000;
74
+ );
75
+ );
76
+
77
+ reset_stats();
78
+
79
+ @slider
80
+ slider10 != last_reset ? ( last_reset = slider10; reset_stats(); );
81
+
82
+ @sample
83
+ base = 16 + slider2 * (RING + 16);
84
+ playing = play_state & 1;
85
+ slider1 == 1 && playing && !was_playing ? reset_stats();
86
+ was_playing = playing;
87
+
88
+ slider1 == 0 ? (
89
+ total += 1;
90
+ gmem[base - 16] = total;
91
+ ) : (
92
+ // pre ran its whole block before this one: when its count moves, this block starts at count - samplesblock
93
+ gmem[base - 16] != seen ? ( seen = gmem[base - 16]; total = seen - samplesblock; acc = 0; );
94
+ total += 1;
95
+ );
96
+ acc += spl0 * spl0 + spl1 * spl1;
97
+
98
+ total % win == 0 ? (
99
+ k = total / win - 1;
100
+ e = acc / win;
101
+ slider1 == 0 ? (
102
+ gmem[base + (k % RING)] = e;
103
+ ) : playing ? (
104
+ ph[k % 64] = e;
105
+ E = 0; j = 0; loop(AVG, E += ph[(k - j + 64) % 64]; j += 1);
106
+ E /= AVG;
107
+ l = 0;
108
+ loop(LAGS,
109
+ kk = k - l;
110
+ p = 0; j = 0;
111
+ loop(AVG, p += (kk - j >= 0 ? gmem[base + ((kk - j) % RING)] : 0); j += 1);
112
+ p /= AVG;
113
+ p > 0 && E > 0 && 10 * log10(p) > slider3 ? (
114
+ g = 10 * log10(E / p);
115
+ b = min(BINS - 1, max(0, floor((g - BINLO) * 10)));
116
+ hist[l * BINS + b] += 1;
117
+ s = sums + l * 3;
118
+ s[0] += 1; s[1] += g; s[2] += g * g;
119
+ );
120
+ l += 1;
121
+ );
122
+ nwin += 1;
123
+ nwin % 100 == 0 ? update_stats();
124
+ );
125
+ acc = 0;
126
+ );