3 name = "a-Inline Scope",
4 category = "Visualization",
6 author = "Ardour Team",
7 description = [[Mixer strip inline waveform display]]
10 -- return possible i/o configurations
11 function dsp_ioconfig ()
12 -- -1, -1 = any number of channels as long as input and output count matches
13 return { [1] = { audio_in = -1, audio_out = -1}, }
16 function dsp_params ()
19 { ["type"] = "input", name = "Timescale", min = .1, max = 5, default = 2, unit="sec", logarithmic = true },
20 { ["type"] = "input", name = "Logscale", min = 0, max = 1, default = 0, toggled = true },
21 { ["type"] = "input", name = "Height (Aspect)", min = 0, max = 3, default = 1, enum = true, scalepoints =
33 function dsp_init (rate)
34 -- global variables (DSP part only)
41 function dsp_configure (ins, outs)
42 -- store configuration in global variable
43 audio_ins = ins:n_audio ()
44 -- allocate shared memory area
45 -- this is used to speed up DSP computaton (using a C array)
46 -- and to share data with the GUI
47 self:shmem ():allocate (4 + bufsiz * audio_ins)
48 self:shmem ():clear ()
49 self:shmem ():atomic_set_int (0, 0)
50 local cfg = self:shmem ():to_int (1):array ()
56 function dsp_runmap (bufs, in_map, out_map, n_samples, offset)
57 local shmem = self:shmem ()
58 local write_ptr = shmem:atomic_get_int (0)
60 for c = 1,audio_ins do
61 -- Note: lua starts counting at 1, ardour's ChanMapping::get() at 0
62 local ib = in_map:get (ARDOUR.DataType ("audio"), c - 1); -- get id of mapped input buffer for given cannel
63 local ob = out_map:get (ARDOUR.DataType ("audio"), c - 1); -- get id of mapped output buffer for given cannel
64 local chn_off = 4 + bufsiz * (c - 1)
65 if (ib ~= ARDOUR.ChanMapping.Invalid) then
66 if (write_ptr + n_samples < bufsiz) then
67 ARDOUR.DSP.copy_vector (shmem:to_float (write_ptr + chn_off), bufs:get_audio (ib):data (offset), n_samples)
69 local w0 = bufsiz - write_ptr;
70 ARDOUR.DSP.copy_vector (shmem:to_float (write_ptr + chn_off), bufs:get_audio (ib):data (offset), w0)
71 ARDOUR.DSP.copy_vector (shmem:to_float (chn_off) , bufs:get_audio (ib):data (offset + w0), n_samples - w0)
73 if (ob ~= ARDOUR.ChanMapping.Invalid and ib ~= ob) then
74 ARDOUR.DSP.copy_vector (bufs:get_audio (ob):data (offset), bufs:get_audio (ib):data (offset), n_samples)
77 if (write_ptr + n_samples < bufsiz) then
78 ARDOUR.DSP.memset (shmem:to_float (write_ptr + chn_off), 0, n_samples)
80 local w0 = bufsiz - write_ptr;
81 ARDOUR.DSP.memset (shmem:to_float (write_ptr + chn_off), 0, w0)
82 ARDOUR.DSP.memset (shmem:to_float (chn_off) , 0, n_samples - w0)
86 -- clear unconnected inplace buffers
87 for c = 1,audio_ins do
88 local ib = in_map:get (ARDOUR.DataType ("audio"), c - 1); -- get id of mapped input buffer for given cannel
89 local ob = out_map:get (ARDOUR.DataType ("audio"), c - 1); -- get id of mapped output buffer for given cannel
90 if (ib == ARDOUR.ChanMapping.Invalid and ob ~= ARDOUR.ChanMapping.Invalid) then
91 bufs:get_audio (ob):silence (n_samples, offset)
95 write_ptr = (write_ptr + n_samples) % bufsiz
96 shmem:atomic_set_int (0, write_ptr)
98 -- emit QueueDraw every FPS
99 dpy_wr = dpy_wr + n_samples
100 if (dpy_wr > dpy_hz) then
101 dpy_wr = dpy_wr % dpy_hz;
107 -- helper function for drawing symmetric grid
108 function gridline (ctx, x, xr, h, val)
109 ctx:move_to (math.floor (.5 + x + val * xr) -.5, 1)
110 ctx:line_to (math.floor (.5 + x + val * xr) -.5, h - 1)
112 ctx:move_to (math.floor (.5 + x - val * xr) -.5, 1)
113 ctx:line_to (math.floor (.5 + x - val * xr) -.5, h - 1)
117 function render_inline (ctx, w, max_h)
118 local ctrl = CtrlPorts:array () -- get control port array (read/write)
119 local shmem = self:shmem () -- get shared memory region
120 local cfg = shmem:to_int (1):array () -- "cast" into lua-table
122 local buf_size = cfg[2]
126 local timescale = ctrl[1] or 1.0 -- display size in seconds
127 local logscale = ctrl[2] or 0; logscale = logscale > 0 -- logscale
128 local hmode = ctrl[3] or 1 -- height mode
132 h = math.ceil (w * 10 / 16)
136 elseif (hmode == 2) then
138 elseif (hmode == 3) then
141 h = math.ceil (w * 10 / 16)
149 local spp = math.floor (timescale * rate / (h - 2)) -- samples per pixel
150 local spl = spp * (h - 1) -- total number of audio samples to read
151 local read_ptr = (shmem:atomic_get_int (0) + buf_size - spl - 1) % buf_size -- read pointer
152 local xr = math.ceil ((w - 2) * (0.47 / n_chn)) -- x-axis range (per channel)
155 ctx:rectangle (0, 0, w, h)
156 ctx:set_source_rgba (.2, .2, .2, 1.0)
160 ctx:set_line_width (1.0)
161 local dash3 = C.DoubleVector ()
163 local dash4 = C.DoubleVector ()
166 -- plot every channel
168 local x = math.floor ((w - 2) * (c - .5) / n_chn) + 1.5 -- x-axis center for given channel
171 ctx:set_source_rgba (.5, .5, .5, 1.0)
172 ctx:move_to (x, 1) ctx:line_to (x, h - 1) ctx:stroke ()
174 ctx:set_dash (dash4, 2)
175 ctx:set_source_rgba (.4, .4, .4, 1.0)
177 gridline (ctx, x, xr, h, ARDOUR.DSP.log_meter(-18))
178 gridline (ctx, x, xr, h, ARDOUR.DSP.log_meter(-6))
179 ctx:set_dash (dash3, 2)
180 ctx:set_source_rgba (.5, .1, .1, 1.0)
181 gridline (ctx, x, xr, h, ARDOUR.DSP.log_meter(-3))
183 gridline (ctx, x, xr, h, .1258)
184 gridline (ctx, x, xr, h, .5)
185 ctx:set_dash (dash3, 2)
186 ctx:set_source_rgba (.5, .1, .1, 1.0)
187 gridline (ctx, x, xr, h, .7079)
190 ctx:set_source_rgba (.5, .1, .1, 0.7)
191 gridline (ctx, x, xr, h, 1)
194 -- prepare waveform display drawing
195 ctx:set_source_rgba (.8, .8, .8, .7)
197 ctx:rectangle (math.floor (x - xr), 0, math.ceil (2 * xr), h)
200 local chn_off = 4 + buf_size * (c - 1)
201 local buf_off = read_ptr;
203 -- iterate over every y-axis pixel
207 -- calc min/max values for given range
208 if (buf_off + spp < buf_size) then
209 _, s_min, s_max = table.unpack (ARDOUR.DSP.peaks (shmem:to_float (chn_off + buf_off), s_min, s_max, spp))
211 local r0 = buf_size - buf_off;
212 _, s_min, s_max = table.unpack (ARDOUR.DSP.peaks (shmem:to_float (chn_off + buf_off), s_min, s_max, r0))
213 _, s_min, s_max = table.unpack (ARDOUR.DSP.peaks (shmem:to_float (chn_off) , s_min, s_max, spp - r0))
215 buf_off = (buf_off + spp) % buf_size;
218 s_max = ARDOUR.DSP.log_meter_coeff (s_max)
219 s_min = - ARDOUR.DSP.log_meter_coeff (-s_min)
222 ctx:move_to (x + s_min * xr, h - y + .5)
223 ctx:line_to (x + s_max * xr, h - y + .5)