An interactive equalizer curve component for Gradio. Drag control points to define a remapping curve, and use it to transform lists of float values. Double-click resets curve to default (y=x)
- Python 3.8+
- Node.js v16.14+
- npm or pnpm
# install pnpm if you don't have it
npm install -g pnpmgit clone git@github.com:G-Chist/GradioEqualizerComponent.git
cd GradioEqualizerComponent/equalizer
# install frontend deps
cd frontend && npm install && cd ..
# install python package in editable mode
pip install -e ".[dev]"cd equalizer
gradio cc devcd equalizer
gradio cc buildThis produces a wheel in equalizer/dist/. Install it anywhere with:
pip install dist/gradio_equalizer-0.0.1-py3-none-any.whlimport numpy as np
import gradio as gr
from gradio_equalizer import Equalizer
def _catmull_rom_spline(values, curve):
"""Catmull-Rom cubic Hermite spline matching the frontend visual curve."""
n = len(curve)
xs = np.linspace(0.0, 1.0, n)
tangents = np.zeros(n)
tangents[0] = curve[1] - curve[0]
tangents[-1] = curve[-1] - curve[-2]
for i in range(1, n - 1):
tangents[i] = (curve[i + 1] - curve[i - 1]) / 2.0
result = np.empty_like(values, dtype=float)
for j, x in enumerate(values):
seg = min(int(x * (n - 1)), n - 2)
t = (x - xs[seg]) / (xs[seg + 1] - xs[seg]) if n > 1 else 0.0
t = np.clip(t, 0.0, 1.0)
t2 = t * t
t3 = t2 * t
h00 = 2 * t3 - 3 * t2 + 1
h10 = t3 - 2 * t2 + t
h01 = -2 * t3 + 3 * t2
h11 = t3 - t2
result[j] = (h00 * curve[seg] + h10 * tangents[seg]
+ h01 * curve[seg + 1] + h11 * tangents[seg + 1])
return np.clip(result, 0.0, 1.0)
def remap(input_str, curve):
values = np.array([float(x.strip()) for x in input_str.split(",")])
values = np.clip(values, 0.0, 1.0)
remapped = _catmull_rom_spline(values, curve)
return "\n".join(f"{o:.4f} -> {n:.4f}" for o, n in zip(values, remapped))
with gr.Blocks() as demo:
eq = Equalizer(label="Height Curve", num_points=10)
inp = gr.Textbox(value="0.0, 0.25, 0.5, 0.75, 1.0")
btn = gr.Button("Remap")
out = gr.Textbox(label="Result")
btn.click(fn=remap, inputs=[inp, eq], outputs=out)
demo.launch()| name | type | default | description |
|---|---|---|---|
value |
list[float] | Callable | None |
Linear 0-1 | Default curve values. Each float is between 0 and 1. |
num_points |
int |
10 |
Number of control points on the curve. |
label |
str | None |
None |
Label displayed above the component. |
interactive |
bool | None |
None |
If True, user can drag points. Auto-detected from usage. |
visible |
bool |
True |
Show/hide the component. |
elem_id |
str | None |
None |
HTML element id for CSS targeting. |
elem_classes |
list[str] | str | None |
None |
HTML element classes. |
The value is a list[float] where each element is between 0 and 1. The list maps evenly-spaced input heights to output heights. For example, with num_points=10:
index: 0 1 2 3 4 5 6 7 8 9
input: 0.0 0.11 0.22 0.33 0.44 0.55 0.66 0.77 0.88 1.0
value: 0.0 0.2 0.4 0.6 0.8 1.0 0.8 0.6 0.4 0.2
To remap a value, interpolate through the curve using the same Catmull-Rom cubic Hermite spline as the frontend:
import numpy as np
curve = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 0.8, 0.6, 0.4, 0.2]
input_value = 0.5
outputs = _catmull_rom_spline(np.array([input_value]), curve)
output_value = outputs[0] # cubic-interpolated result
# remap an entire array
inputs = np.array([0.0, 0.25, 0.5, 0.75, 1.0])
outputs = _catmull_rom_spline(inputs, curve)| name | description |
|---|---|
change |
Triggered when the curve value changes (user drag or programmatic). |
input |
Triggered when the user drags a control point. |
Equalizer().example_value()
# [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 0.8, 0.6, 0.4, 0.2]