e1fa4a699a62ebd043ba7ac841afc1a1517a79f5
[ardour.git] / scripts / filt.lua
1 ardour {
2         ["type"]    = "dsp",
3         name        = "Biquad Filter",
4         category    = "Filter",
5         license     = "MIT",
6         author      = "Robin Gareus",
7         email       = "robin@gareus.org",
8         site        = "http://gareus.org",
9         description = [[
10         An Example DSP Plugin for processing audio, to
11         be used with Ardour's Lua scripting facility.]]
12 }
13
14 function dsp_ioconfig ()
15         return
16         {
17                 { audio_in = -1, audio_out = -1},
18         }
19 end
20
21
22 function dsp_params ()
23         return
24         {
25                 { ["type"] = "input", name = "Type", min = 0, max = 4, default = 0, enum = true, scalepoints =
26                         {
27                                 ["Peaking"]    = 0,
28                                 ["Low Shelf"]  = 1,
29                                 ["High Shelf"] = 2,
30                                 ["Low Pass"]   = 3,
31                                 ["High Pass"]  = 4,
32                         }
33                 },
34                 { ["type"] = "input", name = "Gain", min = -20, max = 20,    default = 0,    unit="dB" },
35                 { ["type"] = "input", name = "Freq", min =  20, max = 20000, default = 1000, unit="Hz", logarithmic = true },
36                 { ["type"] = "input", name = "Q",    min = 0.1, max = 8,     default = .707, logarithmic = true },
37         }
38 end
39
40 -- these globals are *not* shared between DSP and UI
41 local filt -- the filter instance
42 local cur = {0, 0, 0, 0} -- current settings
43
44 function dsp_init (rate)
45         self:shmem ():allocate (1) -- shared mem to tell UI about samplerate
46         local cfg = self:shmem ():to_int (0):array ()
47         cfg[1] = rate
48         filt = ARDOUR.DSP.Biquad (rate) -- initialize filter
49 end
50
51
52 -- apply parameters, re-compute filter coefficients if needed
53 function apply_params (ctrl)
54         if ctrl[1] == cur[1] and ctrl[2] == cur[2] and ctrl[3] == cur[3] and ctrl[4] == cur[4] then
55                 return false
56         end
57
58         local ft
59         if     ctrl[1] == 1 then
60                 ft = ARDOUR.DSP.BiQuadType.LowShelf
61         elseif ctrl[1] == 2 then
62                 ft = ARDOUR.DSP.BiQuadType.HighShelf
63         elseif ctrl[1] == 3 then
64                 ft = ARDOUR.DSP.BiQuadType.LowPass
65         elseif ctrl[1] == 4 then
66                 ft = ARDOUR.DSP.BiQuadType.HighPass
67         else
68                 ft = ARDOUR.DSP.BiQuadType.Peaking
69         end
70
71         -- TODO low-pass filter ctrl values, smooth transition
72         filt:compute (ft, ctrl[3], ctrl[4], ctrl[2])
73         cur[1] = ctrl[1]
74         cur[2] = ctrl[2]
75         cur[3] = ctrl[3]
76         cur[4] = ctrl[4]
77         return true
78 end
79
80
81 -- the actual DSP callback
82 function dsp_run (ins, outs, n_samples)
83         if apply_params (CtrlPorts:array ()) then
84                 self:queue_draw ()
85         end
86         for c = 1,#ins do
87                 if ins[c]:sameinstance (outs[c]) then
88                         filt:run (ins[c], n_samples) -- in-place
89                 else
90                         ARDOUR.DSP.copy_vector (outs[c], ins[c], n_samples)
91                         filt:run (outs[c], n_samples)
92                 end
93         end
94 end
95
96
97 -------------------------------------------------------------------------------
98 --- inline display
99
100 function round (n)
101         return math.floor (n + .5)
102 end
103
104 function freq_at_x (x, w)
105         return 20 * 1000 ^ (x / w)
106 end
107
108 function x_at_freq (f, w)
109         return w * math.log (f / 20.0) / math.log (1000.0)
110 end
111
112 function db_to_y (db, h)
113         if db < -20 then db = -20 end
114         if db >  20 then db =  20 end
115         return -.5 + 0.5 * h * (1 - db / 20)
116 end
117
118 function grid_db (ctx, w, h, db)
119         local y = -.5 + round (db_to_y (db, h))
120         ctx:move_to (0, y)
121         ctx:line_to (w, y)
122         ctx:stroke ()
123 end
124
125 function grid_freq (ctx, w, h, f)
126         local x = -.5 + round (x_at_freq (f, w))
127         ctx:move_to (x, 0)
128         ctx:line_to (x, h)
129         ctx:stroke ()
130 end
131
132 function render_inline (ctx, w, max_h)
133         if not filt then
134                 -- instantiate filter (to calculate the transfer function)
135                 local shmem = self:shmem () -- get shared memory region
136                 local cfg = shmem:to_int (0):array () -- "cast" into lua-table
137                 filt = ARDOUR.DSP.Biquad (cfg[1])
138         end
139
140         apply_params (CtrlPorts:array ())
141
142         -- calc height of inline display
143         local h = math.ceil (w * 10 / 16) -- 16:10 aspect
144         h = 2 * round (h / 2) -- even number of vertical px
145         if (h > max_h) then
146                 h = max_h
147         end
148
149         -- clear background
150         ctx:rectangle (0, 0, w, h)
151         ctx:set_source_rgba (.2, .2, .2, 1.0)
152         ctx:fill ()
153
154         ctx:set_line_width (1.0)
155
156         -- draw grid
157         local dash3 = C.DoubleVector ()
158         dash3:add ({1, 3})
159         ctx:set_dash (dash3, 2)
160         ctx:set_source_rgba (.5, .5, .5, .5)
161         grid_db (ctx, w, h, 0)
162         grid_db (ctx, w, h, 6)
163         grid_db (ctx, w, h, 12)
164         grid_db (ctx, w, h, 18)
165         grid_db (ctx, w, h, -6)
166         grid_db (ctx, w, h, -12)
167         grid_db (ctx, w, h, -18)
168         grid_freq (ctx, w, h, 100)
169         grid_freq (ctx, w, h, 1000)
170         grid_freq (ctx, w, h, 10000)
171         ctx:unset_dash ()
172
173         -- draw transfer function
174         ctx:set_source_rgba (.8, .8, .8, 1.0)
175         ctx:move_to (-.5, db_to_y (filt:dB_at_freq (freq_at_x (0, w)), h))
176         for x = 1,w do
177                 local db = filt:dB_at_freq (freq_at_x (x, w))
178                 ctx:line_to (-.5 + x, db_to_y (db, h))
179         end
180         ctx:stroke_preserve ()
181
182         -- fill area to zero under the curve
183         ctx:line_to (w, -.5 + h * .5)
184         ctx:line_to (0, -.5 + h * .5)
185         ctx:close_path ()
186         ctx:set_source_rgba (.5, .5, .5, .5)
187         ctx:fill ()
188
189         return {w, h}
190 end