summaryrefslogtreecommitdiff
path: root/scripts/_pong.lua
blob: 3683209a2b20acb8e4f33e85dfddd5c25c9e0e4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
ardour {
	["type"]    = "dsp",
	name        = "a-Pong",
	category    = "Visualization",
	license     = "MIT",
	author      = "Ardour Lua Task Force",
	description = [[classic game of mixer pong]]
}

-- return possible i/o configurations
function dsp_ioconfig ()
	-- -1, -1 = any number of channels as long as input and output count matches
	return { [1] = { audio_in = -1, audio_out = -1}, }
end

function dsp_params ()
	return
	{
		{ ["type"] = "input", name = "Bar", min = 0, max = 1, default = 0.5 },
	}
end

local gametime
local fps
local ball_x, ball_y
local dx, dy
local pingsound
local lotsound
local pingnote

function dsp_init (rate)
	self:shmem ():allocate (4)
	self:shmem ():clear ()
	fps = rate / 25
	pingnote = 352 / rate
	ball_x = 0.5
	ball_y = 0
	dx = 0.011
	dy = 0.021
end

function dsp_configure (ins, outs)
	gametime = fps
	pingsound = fps
	lostsound = 3 * fps
end

function dsp_run (ins, outs, n_samples)
	local ctrl = CtrlPorts:array () -- get control port array (read/write)
	local shmem = self:shmem ()
	local state = shmem:to_float (0):array () -- "cast" into lua-table

	local changed = false
	gametime = gametime + n_samples

	-- simple game engine
	while gametime > fps do
		changed = true
		gametime = gametime - fps

		ball_x = ball_x + dx
		ball_y = ball_y + dy

		if ball_x >= 1 or ball_x <= 0 then dx = -dx end
		if ball_y <= 0 then dy = - dy end

		if ball_y > 1 then
			local bar = ctrl[1]
			if math.abs (bar - ball_x) < 0.1 then
				dy = - dy
				ball_y = 1.0
				dx = dx + 0.1 * (bar - ball_x)
				-- queue sound (unless it's playing)
				if (pingsound > fps) then
					pingsound = 0
				end
				phase = 0
			else
				-- game over
				lostsound = 0
				ball_y = 0
				dx = 0.011
			end
		end
	end

	-- simple synth -- TODO Optimize
	if pingsound <= fps then
		for s = 1, n_samples do
			pingsound = pingsound + 1
			if pingsound > fps then goto note_end end
			phase = phase + pingnote
			local snd = 0.7 * math.sin(6.283185307 * phase) * math.sin (3.141592 * pingsound / fps)
			for c = 1,#outs do
				-- don't copy this code, it's quick/dirty and not efficient
				outs[c]:array()[s] = outs[c]:array()[s] + snd
			end
			::note_end::
		end
	end

	if lostsound <= 3 * fps then
		for s = 1, n_samples do
			lostsound = lostsound + 1
			if lostsound > 3 * fps then goto noise_end end
			local snd = 0.5 * (math.random () - 0.5)
			for c = 1,#outs do
				-- don't copy this code, it's quick/dirty and not efficient
				outs[c]:array()[s] = outs[c]:array()[s] + snd
			end
			::noise_end::
		end
	end

	if changed then
		state[1] = ball_x
		state[2] = ball_y
		self:queue_draw ()
	end
end


function render_inline (ctx, w, max_h)
	local ctrl = CtrlPorts:array () -- get control port array (read/write)
	local shmem = self:shmem () -- get shared memory region
	local state = shmem:to_float (0):array () -- "cast" into lua-table

	if (w > max_h) then
		h = max_h
	else
		h = w
	end

	-- clear background
	ctx:rectangle (0, 0, w, h)
	ctx:set_source_rgba (.2, .2, .2, 1.0)
	ctx:fill ()

	-- display bar
	local bar_width = w * .1
	local bar_space = w - bar_width

	ctx:set_line_cap (Cairo.LineCap.Round)
	ctx:set_source_rgba (.8, .8, .8, 1.0)
	ctx:set_line_width (3.0)
	ctx:move_to (bar_space * ctrl[1], h - 3)
	ctx:rel_line_to (bar_width, 0)
	ctx:stroke ()

	-- display ball
	ctx:move_to (state[1] * w, state[2] * (h - 5))
	ctx:close_path ()
	ctx:stroke ()

	return {w, h}
end