6 author = "Ardour Lua Task Force",
7 description = [[A console classic for your console]]
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}, }
17 function dsp_params ()
20 { ["type"] = "input", name = "Bar", min = 0, max = 1, default = 0.5 },
21 { ["type"] = "input", name = "Reset", min = 0, max = 1, default = 0, toggled = true },
22 { ["type"] = "input", name = "Difficulty", min = 1, max = 10, default = 3},
27 -- NOTE: these variables are for the DSP part (not shared with the GUI instance)
28 local fps -- audio samples per game-step
29 local game_time -- counts up to fps
31 local ball_x, ball_y -- ball position [0..1]
32 local dx, dy -- current ball speed
33 local lost_sound -- audio-sample counter for game-over [0..3*fps]
34 local ping_sound -- audio-sample counter for ping-sound [0..fps]
35 local ping_phase -- ping note phase
38 function dsp_init (rate)
39 -- allocate a "shared memory" area to transfer state to the GUI
40 self:shmem ():allocate (3)
41 self:shmem ():clear ()
42 -- initialize some variables
44 ping_pitch = 752 / rate
50 game_time = fps -- start the ball immediately (notfiy GUI)
51 ping_sound = fps -- set to end of synth cycle
55 function dsp_run (ins, outs, n_samples)
56 local ctrl = CtrlPorts:array () -- get control port array (read/write)
57 local shmem = self:shmem ()
58 local state = shmem:to_float (0):array () -- "cast" into lua-table
60 local changed = false -- flag to notify GUI on every game-step
61 game_time = game_time + n_samples
63 -- reset (allow to write automation from a given start-point)
74 while game_time > fps and ctrl[2] <= 0 do
76 game_time = game_time - fps
79 ball_x = ball_x + dx * ctrl[3]
80 ball_y = ball_y + dy * ctrl[3]
83 if ball_x >= 1 or ball_x <= 0 then dx = -dx end
84 -- keep the ball in the field
85 if ball_x >= 1 then ball_x = 1 end
86 if ball_x <= 0 then ball_x = 0 end
88 -- single player (reflect top) -- TODO "stereo" version, 2 ctrls :)
89 if ball_y <= 0 then dy = - dy y = 0 end
93 local bar = ctrl[1] -- get bar position
94 if math.abs (bar - ball_x) < 0.1 then
98 dx = dx - 0.04 * (bar - ball_x)
99 -- make sure it's moving (not stuck on borders)
100 if math.abs (dx) < 0.0001 then dx = 0.0001 end
101 -- queue 'ping' sound (unless it's already playing to prevent clicks)
102 if (ping_sound >= fps) then
106 game_score = game_score + 1
117 -- forward audio if processing is not in-place
119 -- check if output and input buffers for this channel are identical
120 -- http://manual.ardour.org/lua-scripting/class_reference/#C:FloatArray
121 if not ins[c]:sameinstance (outs[c]) then
122 -- fast (accellerated) memcpy
123 -- http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:DSP
124 ARDOUR.DSP.copy_vector (out[c], ins[c], n_samples)
128 -- simple synth -- TODO Optimize
129 if ping_sound < fps then
130 -- cache audio data buffers for direct access, later
133 abufs[c] = outs[c]:array()
135 -- simple sine synth with a sine-envelope
136 for s = 1, n_samples do
137 ping_sound = ping_sound + 1
138 ping_phase = ping_phase + ping_pitch
139 local snd = 0.7 * math.sin(6.283185307 * ping_phase) * math.sin (3.141592 * ping_sound / fps)
140 -- add synthesized sound to all channels
142 abufs[c][s] = abufs[c][s] + snd
144 -- break out of the loop when the sound finished
145 if ping_sound >= fps then goto ping_end end
150 if lost_sound < 3 * fps then
153 abufs[c] = outs[c]:array()
155 for s = 1, n_samples do
156 lost_sound = lost_sound + 1
157 -- -12dBFS white noise
158 local snd = 0.5 * (math.random () - 0.5)
160 abufs[c][s] = abufs[c][s] + snd
162 if lost_sound >= 3 * fps then goto noise_end end
170 state[3] = game_score
176 -------------------------------------------------------------------------------
179 local txt = nil -- cache pango context (in GUI context)
181 function render_inline (ctx, w, max_h)
182 local ctrl = CtrlPorts:array () -- control port array
183 local shmem = self:shmem () -- shared memory region
184 local state = shmem:to_float (0):array () -- cast to lua-table
192 -- prepare text rendering
194 -- allocate PangoLayout and set font
195 --http://manual.ardour.org/lua-scripting/class_reference/#Cairo:PangoLayout
196 txt = Cairo.PangoLayout (ctx, "Mono 10px")
200 ctx:rectangle (0, 0, w, h)
201 ctx:set_source_rgba (.2, .2, .2, 1.0)
205 if (state[3] > 0) then
206 txt:set_text (string.format ("%.0f", state[3]));
207 local tw, th = txt:get_pixel_size ()
208 ctx:set_source_rgba (1, 1, 1, 1.0)
209 ctx:move_to (w - tw - 3, 3)
210 txt:show_in_cairo_context (ctx)
213 -- prepare line and dot rendering
214 ctx:set_line_cap (Cairo.LineCap.Round)
215 ctx:set_line_width (3.0)
216 ctx:set_source_rgba (.8, .8, .8, 1.0)
219 local bar_width = w * .1
220 local bar_space = w - bar_width
222 ctx:move_to (bar_space * ctrl[1], h - 3)
223 ctx:rel_line_to (bar_width, 0)
227 ctx:move_to (1 + state[1] * (w - 3), state[2] * (h - 5))