5 author = "Robin Gareus",
6 email = "robin@gareus.org",
7 site = "http://gareus.org",
8 description = [[An Example DSP Plugin to display the waveform on the mixer strip]]
11 -- return possible i/o configurations
12 function dsp_ioconfig ()
13 -- -1, -1 = any number of channels as long as input and output count matches
14 return { [1] = { audio_in = -1, audio_out = -1}, }
17 function dsp_params ()
20 { ["type"] = "input", name = "Timescale", min = .1, max = 5, default = 2, unit="sec", logarithmic = true },
21 { ["type"] = "input", name = "Logscale", min = 0, max = 1, default = 0, toggled = true },
22 { ["type"] = "input", name = "Height", min = 0, max = 3, default = 1, unit="dB", enum = true, scalepoints =
34 function dsp_init (rate)
35 -- global variables (DSP part only)
42 function dsp_configure (ins, outs)
43 -- store configuration in global variable
44 audio_ins = ins:n_audio ()
45 -- allocate shared memory area
46 -- this is used to speed up DSP computaton (using a C array)
47 -- and to share data with the GUI
48 self:shmem ():allocate (4 + bufsiz * audio_ins)
49 self:shmem ():clear ()
50 self:shmem ():atomic_set_int (0, 0)
51 local cfg = self:shmem ():to_int (1):array ()
57 function dsp_runmap (bufs, in_map, out_map, n_samples, offset)
58 local shmem = self:shmem ()
59 local write_ptr = shmem:atomic_get_int (0)
61 for c = 1,audio_ins do
62 -- Note: lua starts counting at 1, ardour's ChanMapping::get() at 0
63 local ib = in_map:get (ARDOUR.DataType ("audio"), c - 1); -- get id of mapped input buffer for given cannel
64 local ob = out_map:get (ARDOUR.DataType ("audio"), c - 1); -- get id of mapped output buffer for given cannel
65 local chn_off = 4 + bufsiz * (c - 1)
66 if (ib ~= ARDOUR.ChanMapping.Invalid) then
67 if (write_ptr + n_samples < bufsiz) then
68 ARDOUR.DSP.copy_vector (shmem:to_float (write_ptr + chn_off), bufs:get_audio (ib):data (offset), n_samples)
70 local w0 = bufsiz - write_ptr;
71 ARDOUR.DSP.copy_vector (shmem:to_float (write_ptr + chn_off), bufs:get_audio (ib):data (offset), w0)
72 ARDOUR.DSP.copy_vector (shmem:to_float (chn_off) , bufs:get_audio (ib):data (offset), n_samples - w0)
74 if (ob ~= ARDOUR.ChanMapping.Invalid and ib ~= ob) then
75 ARDOUR.DSP.copy_vector (bufs:get_audio (ob):data (offset), bufs:get_audio (ib):data (offset), n_samples)
78 if (write_ptr + n_samples < bufsiz) then
79 ARDOUR.DSP.memset (shmem:to_float (write_ptr + chn_off), 0, n_samples)
81 local w0 = bufsiz - write_ptr;
82 ARDOUR.DSP.memset (shmem:to_float (write_ptr + chn_off), 0, w0)
83 ARDOUR.DSP.memset (shmem:to_float (chn_off) , 0, n_samples - w0)
87 -- clear unconnected inplace buffers
88 for c = 1,audio_ins do
89 local ib = in_map:get (ARDOUR.DataType ("audio"), c - 1); -- get id of mapped input buffer for given cannel
90 local ob = out_map:get (ARDOUR.DataType ("audio"), c - 1); -- get id of mapped output buffer for given cannel
91 if (ib == ARDOUR.ChanMapping.Invalid and ob ~= ARDOUR.ChanMapping.Invalid) then
92 bufs:get_audio (ob):silence (n_samples, offset)
96 write_ptr = (write_ptr + n_samples) % bufsiz
97 shmem:atomic_set_int (0, write_ptr)
99 -- emit QueueDraw every FPS
100 dpy_wr = dpy_wr + n_samples
101 if (dpy_wr > dpy_hz) then
102 dpy_wr = dpy_wr % dpy_hz;
108 -- helper function for drawing symmetric grid
109 function gridline (ctx, x, xr, h, val)
110 ctx:move_to (math.floor (.5 + x + val * xr) -.5, 1)
111 ctx:line_to (math.floor (.5 + x + val * xr) -.5, h - 1)
113 ctx:move_to (math.floor (.5 + x - val * xr) -.5, 1)
114 ctx:line_to (math.floor (.5 + x - val * xr) -.5, h - 1)
118 function render_inline (ctx, w, max_h)
119 local ctrl = CtrlPorts:array () -- get control port array (read/write)
120 local shmem = self:shmem () -- get shared memory region
121 local cfg = shmem:to_int (1):array () -- "cast" into lua-table
123 local buf_size = cfg[2]
127 local timescale = ctrl[1] or 1.0 -- display size in seconds
128 local logscale = ctrl[2] or 0; logscale = logscale > 0 -- logscale
129 local hmode = ctrl[3] or 1 -- height mode
133 h = math.ceil (w * 10 / 16)
137 elseif (hmode == 2) then
139 elseif (hmode == 3) then
142 h = math.ceil (w * 10 / 16)
150 local spp = math.floor (timescale * rate / (h - 2)) -- samples per pixel
151 local spl = spp * (h - 1) -- total number of audio samples to read
152 local read_ptr = (shmem:atomic_get_int (0) + buf_size - spl - 1) % buf_size -- read pointer
153 local xr = math.ceil ((w - 2) * (0.47 / n_chn)) -- x-axis range (per channel)
156 ctx:rectangle (0, 0, w, h)
157 ctx:set_source_rgba (.2, .2, .2, 1.0)
161 ctx:set_line_width (1.0)
162 local dash3 = C.DoubleVector ()
164 local dash4 = C.DoubleVector ()
167 -- plot every channel
169 local x = math.floor ((w - 2) * (c - .5) / n_chn) + 1.5 -- x-axis center for given channel
172 ctx:set_source_rgba (.5, .5, .5, 1.0)
173 ctx:move_to (x, 1) ctx:line_to (x, h - 1) ctx:stroke ()
175 ctx:set_dash (dash4, 2)
176 ctx:set_source_rgba (.4, .4, .4, 1.0)
178 gridline (ctx, x, xr, h, ARDOUR.DSP.log_meter(-18))
179 gridline (ctx, x, xr, h, ARDOUR.DSP.log_meter(-6))
180 ctx:set_dash (dash3, 2)
181 ctx:set_source_rgba (.5, .1, .1, 1.0)
182 gridline (ctx, x, xr, h, ARDOUR.DSP.log_meter(-3))
184 gridline (ctx, x, xr, h, .1258)
185 gridline (ctx, x, xr, h, .5)
186 ctx:set_dash (dash3, 2)
187 ctx:set_source_rgba (.5, .1, .1, 1.0)
188 gridline (ctx, x, xr, h, .7079)
191 ctx:set_source_rgba (.5, .1, .1, 0.7)
192 gridline (ctx, x, xr, h, 1)
195 -- prepare waveform display drawing
196 ctx:set_source_rgba (.8, .8, .8, .7)
198 ctx:rectangle (math.floor (x - xr), 0, math.ceil (2 * xr), h)
201 local chn_off = 4 + buf_size * (c - 1)
202 local buf_off = read_ptr;
204 -- iterate over every y-axis pixel
208 -- calc min/max values for given range
209 if (buf_off + spp < buf_size) then
210 _, s_min, s_max = table.unpack (ARDOUR.DSP.peaks (shmem:to_float (chn_off + buf_off), s_min, s_max, spp))
212 local r0 = buf_size - buf_off;
213 _, s_min, s_max = table.unpack (ARDOUR.DSP.peaks (shmem:to_float (chn_off + buf_off), s_min, s_max, r0))
214 _, s_min, s_max = table.unpack (ARDOUR.DSP.peaks (shmem:to_float (chn_off) , s_min, s_max, spp - r0))
216 buf_off = (buf_off + spp) % buf_size;
219 s_max = ARDOUR.DSP.log_meter_coeff (s_max)
220 s_min = - ARDOUR.DSP.log_meter_coeff (-s_min)
223 ctx:move_to (x + s_min * xr, h - y + .5)
224 ctx:line_to (x + s_max * xr, h - y + .5)