-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathaudio.lua
More file actions
325 lines (284 loc) · 7.89 KB
/
audio.lua
File metadata and controls
325 lines (284 loc) · 7.89 KB
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
local soluna = require "soluna"
local matquad = require "soluna.material.quad"
local mattext = require "soluna.material.text"
local font = require "soluna.font"
local file = require "soluna.file"
soluna.load_sounds "asset/sounds.dl"
soluna.set_window_title "Soluna sound sample"
local args = ...
local batch = args.batch
local screen_w = args.width
local screen_h = args.height
local sound_bus = assert(soluna.audio_bus "sound")
local music_bus = assert(soluna.audio_bus "music")
local BUTTON_W <const> = 220
local BUTTON_H <const> = 56
local BUTTON_GAP <const> = 18
local BUTTON_COLS <const> = 2
local BUTTON_ROWS <const> = 5
local SHADOW_Y <const> = 6
local BUTTON_TEXT_COLOR <const> = 0xff28435c
local STATUS_TEXT_COLOR <const> = 0xffdce7f2
local BUTTON_PLAY_SHOT <const> = 1
local BUTTON_TOGGLE_LOOP <const> = 2
local BUTTON_STOP_LAST <const> = 3
local BUTTON_STOP_LOOP <const> = 4
local BUTTON_SEEK_START <const> = 5
local BUTTON_SEEK_STEP <const> = 6
local BUTTON_SOUND_DOWN <const> = 7
local BUTTON_SOUND_UP <const> = 8
local BUTTON_MUSIC_DOWN <const> = 9
local BUTTON_MUSIC_UP <const> = 10
local pointer_x = screen_w // 2
local pointer_y = screen_h // 2
local pressed = false
local pressed_button
local sound_volume = 1.0
local music_volume = 1.0
local last_voice
local loop_voice
local loop_time = 0.0
local function load_font(data, name)
if not data then
return
end
font.import(data)
return font.name(name or "")
end
local function font_init()
if soluna.platform == "wasm" then
local fontid = load_font(file.load "asset/font/SourceHanSansSC-Regular.ttf", "Source Han Sans SC Regular")
if fontid then
return fontid
end
end
local sysfont = require "soluna.font.system"
for _, name in ipairs {
"WenQuanYi Micro Hei",
"Microsoft YaHei",
"Yuanti SC",
"Source Han Sans SC Regular",
} do
local ok, data = pcall(sysfont.ttfdata, name)
local fontid = ok and load_font(data, name)
if fontid then
return fontid
end
end
error "No available system font for audio sample"
end
local fontid = font_init()
local button_text = mattext.block(font.cobj(), fontid, 24, BUTTON_TEXT_COLOR, "CV")
local info_text = mattext.block(font.cobj(), fontid, 20, STATUS_TEXT_COLOR, "L")
local labels = {
[BUTTON_PLAY_SHOT] = button_text("Play Shot", BUTTON_W, BUTTON_H),
[BUTTON_TOGGLE_LOOP] = button_text("Toggle Loop", BUTTON_W, BUTTON_H),
[BUTTON_STOP_LAST] = button_text("Stop Last Voice", BUTTON_W, BUTTON_H),
[BUTTON_STOP_LOOP] = button_text("Stop Loop Voice", BUTTON_W, BUTTON_H),
[BUTTON_SEEK_START] = button_text("Seek Loop 0.00", BUTTON_W, BUTTON_H),
[BUTTON_SEEK_STEP] = button_text("Seek Loop +0.20", BUTTON_W, BUTTON_H),
[BUTTON_SOUND_DOWN] = button_text("Sound -", BUTTON_W, BUTTON_H),
[BUTTON_SOUND_UP] = button_text("Sound +", BUTTON_W, BUTTON_H),
[BUTTON_MUSIC_DOWN] = button_text("Music -", BUTTON_W, BUTTON_H),
[BUTTON_MUSIC_UP] = button_text("Music +", BUTTON_W, BUTTON_H),
}
local function clamp(v, lo, hi)
if v < lo then
return lo
elseif v > hi then
return hi
end
return v
end
local function playing(voice)
return voice ~= nil and voice:playing()
end
local function update_pointer(x, y)
pointer_x = x
pointer_y = y
end
local function button_rect(index)
local total_w = BUTTON_COLS * BUTTON_W + (BUTTON_COLS - 1) * BUTTON_GAP
local total_h = BUTTON_ROWS * BUTTON_H + (BUTTON_ROWS - 1) * BUTTON_GAP
local origin_x = (screen_w - total_w) // 2
local origin_y = (screen_h - total_h) // 2 - 40
local col = (index - 1) % BUTTON_COLS
local row = (index - 1) // BUTTON_COLS
return origin_x + col * (BUTTON_W + BUTTON_GAP), origin_y + row * (BUTTON_H + BUTTON_GAP)
end
local function button_at(x, y)
for i = 1, BUTTON_ROWS * BUTTON_COLS do
local bx, by = button_rect(i)
if x >= bx and x <= bx + BUTTON_W and y >= by and y <= by + BUTTON_H then
return i
end
end
end
local function click_button(index)
if index == BUTTON_PLAY_SHOT then
last_voice = assert(soluna.play_sound("bloop", {
volume = 0.25,
pan = clamp(pointer_x / screen_w * 2.0 - 1.0, -1.0, 1.0),
pitch = 0.95,
}))
return
end
if index == BUTTON_TOGGLE_LOOP then
local voice = loop_voice
if playing(voice) then
voice:stop(0.1)
if loop_voice == voice then
loop_voice = nil
end
else
loop_voice = assert(soluna.play_sound "bloop_loop")
end
return
end
if index == BUTTON_STOP_LAST then
local voice = last_voice
if voice then
voice:stop()
if last_voice == voice then
last_voice = nil
end
end
return
end
if index == BUTTON_STOP_LOOP then
local voice = loop_voice
if voice then
voice:stop(0.1)
if loop_voice == voice then
loop_voice = nil
loop_time = 0.0
end
end
return
end
if index == BUTTON_SEEK_START then
local voice = loop_voice
if voice then
voice:seek(0.0)
end
return
end
if index == BUTTON_SEEK_STEP then
local voice = loop_voice
if voice then
local now = voice:tell() or 0.0
voice:seek(now + 0.2)
end
return
end
if index == BUTTON_SOUND_DOWN then
sound_volume = clamp(sound_volume - 0.1, 0.0, 1.0)
sound_bus:set_volume(sound_volume)
return
end
if index == BUTTON_SOUND_UP then
sound_volume = clamp(sound_volume + 0.1, 0.0, 1.0)
sound_bus:set_volume(sound_volume)
return
end
if index == BUTTON_MUSIC_DOWN then
music_volume = clamp(music_volume - 0.1, 0.0, 1.0)
music_bus:set_volume(music_volume)
return
end
if index == BUTTON_MUSIC_UP then
music_volume = clamp(music_volume + 0.1, 0.0, 1.0)
music_bus:set_volume(music_volume)
end
end
local callback = {}
function callback.window_resize(w, h)
screen_w = w
screen_h = h
end
function callback.mouse_move(x, y)
update_pointer(x, y)
end
function callback.mouse_button(button, key_state)
if button ~= 0 then
return
end
if key_state == 1 then
pressed_button = button_at(pointer_x, pointer_y)
pressed = pressed_button ~= nil
return
end
local index = button_at(pointer_x, pointer_y)
if pressed and index == pressed_button then
click_button(index)
end
pressed = false
pressed_button = nil
end
function callback.touch_begin(x, y)
update_pointer(x, y)
pressed_button = button_at(x, y)
pressed = pressed_button ~= nil
end
function callback.touch_moved(x, y)
update_pointer(x, y)
if button_at(x, y) ~= pressed_button then
pressed = false
end
end
function callback.touch_end(x, y)
update_pointer(x, y)
local index = button_at(x, y)
if pressed and index == pressed_button then
click_button(index)
end
pressed = false
pressed_button = nil
end
function callback.touch_cancelled()
pressed = false
pressed_button = nil
end
function callback.frame()
local last = last_voice
local loop = loop_voice
local last_playing = playing(last)
local loop_playing = playing(loop)
if loop_playing then
loop_time = loop:tell() or loop_time
else
loop_time = 0.0
end
local title = info_text("Audio API Sample", 400, 28)
local subtitle = info_text("Play voices, seek a stream voice, and adjust sound/music buses.", 640, 24)
local status_1 = info_text(
string.format("sound bus %.1f | music bus %.1f", sound_volume, music_volume),
480,
24
)
local status_2 = info_text(
string.format(
"last voice %s | loop voice %s | loop time %.2f",
last_playing and "playing" or "idle",
loop_playing and "playing" or "idle",
loop_time
),
640,
24
)
batch:add(title, (screen_w - 400) // 2, 40)
batch:add(subtitle, (screen_w - 640) // 2, 72)
batch:add(status_1, (screen_w - 480) // 2, screen_h - 90)
batch:add(status_2, (screen_w - 640) // 2, screen_h - 62)
for i = 1, BUTTON_ROWS * BUTTON_COLS do
local bx, by = button_rect(i)
local hovered = button_at(pointer_x, pointer_y) == i
local active = pressed and pressed_button == i
local face_y = by + (active and 4 or 0)
local face_color = active and 0xffcfd8e4 or hovered and 0xfffbfdff or 0xffeef3f8
batch:add(matquad.quad(BUTTON_W, BUTTON_H, 0xff7389a3), bx, by + SHADOW_Y)
batch:add(matquad.quad(BUTTON_W, BUTTON_H, face_color), bx, face_y)
batch:add(labels[i], bx, face_y)
end
end
return callback