1 | /** |
2 | * Copyright (c) 2006-2023 LOVE Development Team |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * |
8 | * Permission is granted to anyone to use this software for any purpose, |
9 | * including commercial applications, and to alter it and redistribute it |
10 | * freely, subject to the following restrictions: |
11 | * |
12 | * 1. The origin of this software must not be misrepresented; you must not |
13 | * claim that you wrote the original software. If you use this software |
14 | * in a product, an acknowledgment in the product documentation would be |
15 | * appreciated but is not required. |
16 | * 2. Altered source versions must be plainly marked as such, and must not be |
17 | * misrepresented as being the original software. |
18 | * 3. This notice may not be removed or altered from any source distribution. |
19 | **/ |
20 | |
21 | #include <limits> |
22 | |
23 | #include "sound/SoundData.h" |
24 | #include "wrap_Source.h" |
25 | |
26 | #include <cmath> |
27 | #include <iostream> |
28 | |
29 | namespace love |
30 | { |
31 | namespace audio |
32 | { |
33 | |
34 | Source *luax_checksource(lua_State *L, int idx) |
35 | { |
36 | return luax_checktype<Source>(L, idx); |
37 | } |
38 | |
39 | int w_Source_clone(lua_State *L) |
40 | { |
41 | Source *t = luax_checksource(L, 1); |
42 | Source *clone = nullptr; |
43 | luax_catchexcept(L, [&](){ clone = t->clone(); }); |
44 | luax_pushtype(L, clone); |
45 | clone->release(); |
46 | return 1; |
47 | } |
48 | |
49 | int w_Source_play(lua_State *L) |
50 | { |
51 | Source *t = luax_checksource(L, 1); |
52 | luax_pushboolean(L, t->play()); |
53 | return 1; |
54 | } |
55 | |
56 | int w_Source_stop(lua_State *L) |
57 | { |
58 | Source *t = luax_checksource(L, 1); |
59 | t->stop(); |
60 | return 0; |
61 | } |
62 | |
63 | int w_Source_pause(lua_State *L) |
64 | { |
65 | Source *t = luax_checksource(L, 1); |
66 | t->pause(); |
67 | return 0; |
68 | } |
69 | |
70 | int w_Source_setPitch(lua_State *L) |
71 | { |
72 | Source *t = luax_checksource(L, 1); |
73 | float p = (float)luaL_checknumber(L, 2); |
74 | if (p != p) |
75 | return luaL_error(L, "Pitch cannot be NaN." ); |
76 | if (p > std::numeric_limits<lua_Number>::max() || |
77 | p <= 0.0f) |
78 | return luaL_error(L, "Pitch has to be non-zero, positive, finite number." ); |
79 | t->setPitch(p); |
80 | return 0; |
81 | } |
82 | |
83 | int w_Source_getPitch(lua_State *L) |
84 | { |
85 | Source *t = luax_checksource(L, 1); |
86 | lua_pushnumber(L, t->getPitch()); |
87 | return 1; |
88 | } |
89 | |
90 | int w_Source_setVolume(lua_State *L) |
91 | { |
92 | Source *t = luax_checksource(L, 1); |
93 | float p = (float)luaL_checknumber(L, 2); |
94 | t->setVolume(p); |
95 | return 0; |
96 | } |
97 | |
98 | int w_Source_getVolume(lua_State *L) |
99 | { |
100 | Source *t = luax_checksource(L, 1); |
101 | lua_pushnumber(L, t->getVolume()); |
102 | return 1; |
103 | } |
104 | |
105 | int w_Source_seek(lua_State *L) |
106 | { |
107 | Source *t = luax_checksource(L, 1); |
108 | double offset = luaL_checknumber(L, 2); |
109 | if (offset < 0) |
110 | return luaL_argerror(L, 2, "can't seek to a negative position" ); |
111 | |
112 | Source::Unit u = Source::UNIT_SECONDS; |
113 | const char *unit = lua_isnoneornil(L, 3) ? 0 : lua_tostring(L, 3); |
114 | if (unit && !t->getConstant(unit, u)) |
115 | return luax_enumerror(L, "time unit" , Source::getConstants(u), unit); |
116 | |
117 | t->seek(offset, u); |
118 | return 0; |
119 | } |
120 | |
121 | int w_Source_tell(lua_State *L) |
122 | { |
123 | Source *t = luax_checksource(L, 1); |
124 | |
125 | Source::Unit u = Source::UNIT_SECONDS; |
126 | const char *unit = lua_isnoneornil(L, 2) ? 0 : lua_tostring(L, 2); |
127 | if (unit && !t->getConstant(unit, u)) |
128 | return luax_enumerror(L, "time unit" , Source::getConstants(u), unit); |
129 | |
130 | lua_pushnumber(L, t->tell(u)); |
131 | return 1; |
132 | } |
133 | |
134 | int w_Source_getDuration(lua_State *L) |
135 | { |
136 | Source *t = luax_checksource(L, 1); |
137 | |
138 | Source::Unit u = Source::UNIT_SECONDS; |
139 | const char *unit = lua_isnoneornil(L, 2) ? 0 : lua_tostring(L, 2); |
140 | if (unit && !t->getConstant(unit, u)) |
141 | return luax_enumerror(L, "time unit" , Source::getConstants(u), unit); |
142 | |
143 | lua_pushnumber(L, t->getDuration(u)); |
144 | return 1; |
145 | } |
146 | |
147 | int w_Source_setPosition(lua_State *L) |
148 | { |
149 | Source *t = luax_checksource(L, 1); |
150 | float v[3]; |
151 | v[0] = (float)luaL_checknumber(L, 2); |
152 | v[1] = (float)luaL_checknumber(L, 3); |
153 | v[2] = (float)luaL_optnumber(L, 4, 0); |
154 | luax_catchexcept(L, [&](){ t->setPosition(v); }); |
155 | return 0; |
156 | } |
157 | |
158 | int w_Source_getPosition(lua_State *L) |
159 | { |
160 | Source *t = luax_checksource(L, 1); |
161 | float v[3]; |
162 | luax_catchexcept(L, [&](){ t->getPosition(v); }); |
163 | lua_pushnumber(L, v[0]); |
164 | lua_pushnumber(L, v[1]); |
165 | lua_pushnumber(L, v[2]); |
166 | return 3; |
167 | } |
168 | |
169 | int w_Source_setVelocity(lua_State *L) |
170 | { |
171 | Source *t = luax_checksource(L, 1); |
172 | float v[3]; |
173 | v[0] = (float)luaL_checknumber(L, 2); |
174 | v[1] = (float)luaL_checknumber(L, 3); |
175 | v[2] = (float)luaL_optnumber(L, 4, 0); |
176 | luax_catchexcept(L, [&](){ t->setVelocity(v); }); |
177 | return 0; |
178 | } |
179 | |
180 | int w_Source_getVelocity(lua_State *L) |
181 | { |
182 | Source *t = luax_checksource(L, 1); |
183 | float v[3]; |
184 | luax_catchexcept(L, [&](){ t->getVelocity(v); }); |
185 | lua_pushnumber(L, v[0]); |
186 | lua_pushnumber(L, v[1]); |
187 | lua_pushnumber(L, v[2]); |
188 | return 3; |
189 | } |
190 | |
191 | int w_Source_setDirection(lua_State *L) |
192 | { |
193 | Source *t = luax_checksource(L, 1); |
194 | float v[3]; |
195 | v[0] = (float)luaL_checknumber(L, 2); |
196 | v[1] = (float)luaL_checknumber(L, 3); |
197 | v[2] = (float)luaL_optnumber(L, 4, 0); |
198 | luax_catchexcept(L, [&](){ t->setDirection(v); }); |
199 | return 0; |
200 | } |
201 | |
202 | int w_Source_getDirection(lua_State *L) |
203 | { |
204 | Source *t = luax_checksource(L, 1); |
205 | float v[3]; |
206 | luax_catchexcept(L, [&](){ t->getDirection(v); }); |
207 | lua_pushnumber(L, v[0]); |
208 | lua_pushnumber(L, v[1]); |
209 | lua_pushnumber(L, v[2]); |
210 | return 3; |
211 | } |
212 | |
213 | int w_Source_setCone(lua_State *L) |
214 | { |
215 | Source *t = luax_checksource(L, 1); |
216 | float innerAngle = (float) luaL_checknumber(L, 2); |
217 | float outerAngle = (float) luaL_checknumber(L, 3); |
218 | float outerVolume = (float) luaL_optnumber(L, 4, 0.0); |
219 | float outerHighGain = (float) luaL_optnumber(L, 5, 1.0); |
220 | luax_catchexcept(L, [&](){ t->setCone(innerAngle, outerAngle, outerVolume, outerHighGain); }); |
221 | return 0; |
222 | } |
223 | |
224 | int w_Source_getCone(lua_State *L) |
225 | { |
226 | Source *t = luax_checksource(L, 1); |
227 | float innerAngle, outerAngle, outerVolume, outerHighGain; |
228 | luax_catchexcept(L, [&](){ t->getCone(innerAngle, outerAngle, outerVolume, outerHighGain); }); |
229 | lua_pushnumber(L, innerAngle); |
230 | lua_pushnumber(L, outerAngle); |
231 | lua_pushnumber(L, outerVolume); |
232 | lua_pushnumber(L, outerHighGain); |
233 | return 4; |
234 | } |
235 | |
236 | int w_Source_setRelative(lua_State *L) |
237 | { |
238 | Source *t = luax_checksource(L, 1); |
239 | luax_catchexcept(L, [&](){ t->setRelative(luax_checkboolean(L, 2)); }); |
240 | return 0; |
241 | } |
242 | |
243 | int w_Source_isRelative(lua_State *L) |
244 | { |
245 | Source *t = luax_checksource(L, 1); |
246 | luax_catchexcept(L, [&](){ luax_pushboolean(L, t->isRelative()); }); |
247 | return 1; |
248 | } |
249 | |
250 | int w_Source_setLooping(lua_State *L) |
251 | { |
252 | Source *t = luax_checksource(L, 1); |
253 | luax_catchexcept(L, [&](){ t->setLooping(luax_checkboolean(L, 2)); }); |
254 | return 0; |
255 | } |
256 | |
257 | int w_Source_isLooping(lua_State *L) |
258 | { |
259 | Source *t = luax_checksource(L, 1); |
260 | luax_pushboolean(L, t->isLooping()); |
261 | return 1; |
262 | } |
263 | |
264 | int w_Source_isPlaying(lua_State *L) |
265 | { |
266 | Source *t = luax_checksource(L, 1); |
267 | luax_pushboolean(L, t->isPlaying()); |
268 | return 1; |
269 | } |
270 | |
271 | int w_Source_setVolumeLimits(lua_State *L) |
272 | { |
273 | Source *t = luax_checksource(L, 1); |
274 | float vmin = (float)luaL_checknumber(L, 2); |
275 | float vmax = (float)luaL_checknumber(L, 3); |
276 | if (vmin < .0f || vmin > 1.f || vmax < .0f || vmax > 1.f) |
277 | return luaL_error(L, "Invalid volume limits: [%f:%f]. Must be in [0:1]" , vmin, vmax); |
278 | t->setMinVolume(vmin); |
279 | t->setMaxVolume(vmax); |
280 | return 0; |
281 | } |
282 | |
283 | int w_Source_getVolumeLimits(lua_State *L) |
284 | { |
285 | Source *t = luax_checksource(L, 1); |
286 | lua_pushnumber(L, t->getMinVolume()); |
287 | lua_pushnumber(L, t->getMaxVolume()); |
288 | return 2; |
289 | } |
290 | |
291 | int w_Source_setAttenuationDistances(lua_State *L) |
292 | { |
293 | Source *t = luax_checksource(L, 1); |
294 | float dref = (float)luaL_checknumber(L, 2); |
295 | float dmax = (float)luaL_checknumber(L, 3); |
296 | if (dref < .0f || dmax < .0f) |
297 | return luaL_error(L, "Invalid distances: %f, %f. Must be > 0" , dref, dmax); |
298 | luax_catchexcept(L, [&]() { |
299 | t->setReferenceDistance(dref); |
300 | t->setMaxDistance(dmax); |
301 | }); |
302 | return 0; |
303 | } |
304 | |
305 | int w_Source_getAttenuationDistances(lua_State *L) |
306 | { |
307 | Source *t = luax_checksource(L, 1); |
308 | luax_catchexcept(L, [&]() { |
309 | lua_pushnumber(L, t->getReferenceDistance()); |
310 | lua_pushnumber(L, t->getMaxDistance()); |
311 | }); |
312 | return 2; |
313 | } |
314 | |
315 | int w_Source_setRolloff(lua_State *L) |
316 | { |
317 | Source *t = luax_checksource(L, 1); |
318 | float rolloff = (float)luaL_checknumber(L, 2); |
319 | if (rolloff < .0f) |
320 | return luaL_error(L, "Invalid rolloff: %f. Must be > 0." , rolloff); |
321 | luax_catchexcept(L, [&](){ t->setRolloffFactor(rolloff); }); |
322 | return 0; |
323 | } |
324 | |
325 | int w_Source_getRolloff(lua_State *L) |
326 | { |
327 | Source *t = luax_checksource(L, 1); |
328 | luax_catchexcept(L, [&](){ lua_pushnumber(L, t->getRolloffFactor()); }); |
329 | return 1; |
330 | } |
331 | |
332 | int w_Source_setAirAbsorption(lua_State *L) |
333 | { |
334 | Source *t = luax_checksource(L, 1); |
335 | float factor = (float)luaL_checknumber(L, 2); |
336 | if (factor < 0.0f) |
337 | return luaL_error(L, "Invalid air absorption factor: %f. Must be > 0." , factor); |
338 | luax_catchexcept(L, [&](){ t->setAirAbsorptionFactor(factor); }); |
339 | return 0; |
340 | } |
341 | |
342 | int w_Source_getAirAbsorption(lua_State *L) |
343 | { |
344 | Source *t = luax_checksource(L, 1); |
345 | luax_catchexcept(L, [&](){ lua_pushnumber(L, t->getAirAbsorptionFactor()); }); |
346 | return 1; |
347 | } |
348 | |
349 | int w_Source_getChannelCount(lua_State *L) |
350 | { |
351 | Source *t = luax_checksource(L, 1); |
352 | lua_pushinteger(L, t->getChannelCount()); |
353 | return 1; |
354 | } |
355 | |
356 | int setFilterReadFilter(lua_State *L, int idx, std::map<Filter::Parameter, float> ¶ms) |
357 | { |
358 | if (lua_gettop(L) < idx || lua_isnoneornil(L, idx)) |
359 | return 0; |
360 | |
361 | luaL_checktype(L, idx, LUA_TTABLE); |
362 | |
363 | const char *paramstr = nullptr; |
364 | |
365 | Filter::getConstant(Filter::FILTER_TYPE, paramstr, Filter::TYPE_BASIC); |
366 | lua_pushstring(L, paramstr); |
367 | lua_rawget(L, idx); |
368 | if (lua_type(L, -1) == LUA_TNIL) |
369 | return luaL_error(L, "Filter type not specificed." ); |
370 | |
371 | Filter::Type type = Filter::TYPE_MAX_ENUM; |
372 | const char *typestr = luaL_checkstring(L, -1); |
373 | if (!Filter::getConstant(typestr, type)) |
374 | return luax_enumerror(L, "filter type" , Filter::getConstants(type), typestr); |
375 | |
376 | lua_pop(L, 1); |
377 | params[Filter::FILTER_TYPE] = static_cast<int>(type); |
378 | |
379 | lua_pushnil(L); |
380 | while (lua_next(L, idx)) |
381 | { |
382 | const char *keystr = luaL_checkstring(L, -2); |
383 | Filter::Parameter param; |
384 | |
385 | if(Filter::getConstant(keystr, param, type) || Filter::getConstant(keystr, param, Filter::TYPE_BASIC)) |
386 | { |
387 | #define luax_effecterror(l,t) luaL_error(l,"Bad parameter type for %s %s: " t " expected, got %s", typestr, keystr, lua_typename(L, -1)) |
388 | switch(Filter::getParameterType(param)) |
389 | { |
390 | case Filter::PARAM_FLOAT: |
391 | if (!lua_isnumber(L, -1)) |
392 | return luax_effecterror(L, "number" ); |
393 | params[param] = lua_tonumber(L, -1); |
394 | break; |
395 | case Filter::PARAM_TYPE: |
396 | case Filter::PARAM_MAX_ENUM: |
397 | break; |
398 | } |
399 | #undef luax_effecterror |
400 | } |
401 | else |
402 | luaL_error(L, "Invalid '%s' Effect parameter: %s" , typestr, keystr); |
403 | |
404 | //remove the value (-1) from stack, keep the key (-2) to feed into lua_next |
405 | lua_pop(L, 1); |
406 | } |
407 | |
408 | return 1; |
409 | } |
410 | |
411 | void getFilterWriteFilter(lua_State *L, int idx, std::map<Filter::Parameter, float> ¶ms) |
412 | { |
413 | const char *keystr, *valstr; |
414 | Filter::Type type = static_cast<Filter::Type>((int)params[Filter::FILTER_TYPE]); |
415 | |
416 | if (lua_istable(L, idx)) |
417 | lua_pushvalue(L, idx); |
418 | else |
419 | lua_createtable(L, 0, params.size()); |
420 | |
421 | for (auto p : params) |
422 | { |
423 | if (!Filter::getConstant(p.first, keystr, type)) |
424 | Filter::getConstant(p.first, keystr, Filter::TYPE_BASIC); |
425 | |
426 | lua_pushstring(L, keystr); |
427 | switch (Filter::getParameterType(p.first)) |
428 | { |
429 | case Filter::PARAM_FLOAT: |
430 | lua_pushnumber(L, p.second); |
431 | break; |
432 | case Filter::PARAM_TYPE: |
433 | Filter::getConstant(static_cast<Filter::Type>((int)p.second), valstr); |
434 | lua_pushstring(L, valstr); |
435 | break; |
436 | case Filter::PARAM_MAX_ENUM: |
437 | break; |
438 | } |
439 | lua_rawset(L, -3); |
440 | } |
441 | } |
442 | |
443 | int w_Source_setFilter(lua_State *L) |
444 | { |
445 | Source *t = luax_checksource(L, 1); |
446 | |
447 | std::map<Filter::Parameter, float> params; |
448 | |
449 | if (setFilterReadFilter(L, 2, params) == 1) |
450 | luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setFilter(params)); }); |
451 | else |
452 | luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setFilter()); }); |
453 | |
454 | return 1; |
455 | } |
456 | |
457 | int w_Source_getFilter(lua_State *L) |
458 | { |
459 | Source *t = luax_checksource(L, 1); |
460 | |
461 | std::map<Filter::Parameter, float> params; |
462 | |
463 | if (!t->getFilter(params)) |
464 | return 0; |
465 | |
466 | getFilterWriteFilter(L, 2, params); |
467 | return 1; |
468 | } |
469 | |
470 | int w_Source_setEffect(lua_State *L) |
471 | { |
472 | Source *t = luax_checksource(L, 1); |
473 | const char *namestr = luaL_checkstring(L, 2); |
474 | |
475 | const bool isBool = lua_gettop(L) >= 3 && lua_isboolean(L, 3); |
476 | |
477 | // :setEffect(effect, false) = clear effect |
478 | if (isBool && !lua_toboolean(L, 3)) |
479 | { |
480 | luax_catchexcept(L, [&]() { lua_pushboolean(L, t->unsetEffect(namestr)); }); |
481 | return 1; |
482 | } |
483 | |
484 | std::map<Filter::Parameter, float> params; |
485 | |
486 | // :setEffect(effect, [true]) = set effect without filter |
487 | if (isBool || setFilterReadFilter(L, 3, params) == 0) |
488 | luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setEffect(namestr)); }); |
489 | else |
490 | luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setEffect(namestr, params)); }); |
491 | return 1; |
492 | } |
493 | |
494 | int w_Source_getEffect(lua_State *L) |
495 | { |
496 | Source *t = luax_checksource(L, 1); |
497 | const char *namestr = luaL_checkstring(L, 2); |
498 | |
499 | std::map<Filter::Parameter, float> params; |
500 | if (!t->getEffect(namestr, params)) |
501 | { |
502 | luax_pushboolean(L, false); |
503 | return 1; |
504 | } |
505 | |
506 | luax_pushboolean(L, true); |
507 | |
508 | // No filter associated, return nil as second argument |
509 | if (params.size() == 0) |
510 | return 1; |
511 | |
512 | // Return filter settings as second argument |
513 | getFilterWriteFilter(L, 3, params); |
514 | return 2; |
515 | } |
516 | |
517 | int w_Source_getActiveEffects(lua_State *L) |
518 | { |
519 | Source *t = luax_checksource(L, 1); |
520 | |
521 | std::vector<std::string> list; |
522 | t->getActiveEffects(list); |
523 | |
524 | lua_createtable(L, 0, (int) list.size()); |
525 | for (int i = 0; i < (int) list.size(); i++) |
526 | { |
527 | lua_pushnumber(L, i + 1); |
528 | lua_pushstring(L, list[i].c_str()); |
529 | lua_rawset(L, -3); |
530 | } |
531 | return 1; |
532 | } |
533 | |
534 | int w_Source_getFreeBufferCount(lua_State *L) |
535 | { |
536 | Source *t = luax_checksource(L, 1); |
537 | lua_pushinteger(L, t->getFreeBufferCount()); |
538 | return 1; |
539 | } |
540 | |
541 | int w_Source_queue(lua_State *L) |
542 | { |
543 | Source *t = luax_checksource(L, 1); |
544 | bool success; |
545 | |
546 | if (luax_istype(L, 2, love::sound::SoundData::type)) |
547 | { |
548 | auto s = luax_totype<love::sound::SoundData>(L, 2); |
549 | |
550 | int offset = 0; |
551 | size_t length = s->getSize(); |
552 | |
553 | if (lua_gettop(L) == 4) |
554 | { |
555 | offset = luaL_checknumber(L, 3); |
556 | length = luaL_checknumber(L, 4); |
557 | } |
558 | else if (lua_gettop(L) == 3) |
559 | length = luaL_checknumber(L, 3); |
560 | |
561 | if (offset < 0 || length > s->getSize() - offset) |
562 | return luaL_error(L, "Data region out of bounds." ); |
563 | |
564 | luax_catchexcept(L, [&]() { |
565 | success = t->queue((unsigned char *)s->getData() + offset, length, |
566 | s->getSampleRate(), s->getBitDepth(), s->getChannelCount()); |
567 | }); |
568 | } |
569 | else if (lua_islightuserdata(L, 2)) |
570 | { |
571 | int offset = luaL_checknumber(L, 3); |
572 | int length = luaL_checknumber(L, 4); |
573 | int sampleRate = luaL_checknumber(L, 5); |
574 | int bitDepth = luaL_checknumber(L, 6); |
575 | int channels = luaL_checknumber(L, 7); |
576 | |
577 | if (length < 0 || offset < 0) |
578 | return luaL_error(L, "Data region out of bounds." ); |
579 | |
580 | luax_catchexcept(L, [&]() { |
581 | success = t->queue((void*)((uintptr_t)lua_touserdata(L, 2) + (uintptr_t)offset), length, sampleRate, bitDepth, channels); |
582 | }); |
583 | } |
584 | else |
585 | return luax_typerror(L, 2, "SoundData or lightuserdata" ); |
586 | |
587 | luax_pushboolean(L, success); |
588 | return 1; |
589 | } |
590 | |
591 | int w_Source_getType(lua_State *L) |
592 | { |
593 | Source *t = luax_checksource(L, 1); |
594 | Source::Type type = t->getType(); |
595 | const char *str = nullptr; |
596 | |
597 | if (!Source::getConstant(type, str)) |
598 | return luaL_error(L, "Unknown Source type." ); |
599 | |
600 | lua_pushstring(L, str); |
601 | return 1; |
602 | } |
603 | |
604 | // Deprecated |
605 | |
606 | int w_Source_getChannels(lua_State *L) |
607 | { |
608 | luax_markdeprecated(L, "Source:getChannels" , API_METHOD, DEPRECATED_RENAMED, "Source:getChannelCount" ); |
609 | return w_Source_getChannelCount(L); |
610 | } |
611 | |
612 | static const luaL_Reg w_Source_functions[] = |
613 | { |
614 | { "clone" , w_Source_clone }, |
615 | |
616 | { "play" , w_Source_play }, |
617 | { "stop" , w_Source_stop }, |
618 | { "pause" , w_Source_pause }, |
619 | |
620 | { "setPitch" , w_Source_setPitch }, |
621 | { "getPitch" , w_Source_getPitch }, |
622 | { "setVolume" , w_Source_setVolume }, |
623 | { "getVolume" , w_Source_getVolume }, |
624 | { "seek" , w_Source_seek }, |
625 | { "tell" , w_Source_tell }, |
626 | { "getDuration" , w_Source_getDuration }, |
627 | { "setPosition" , w_Source_setPosition }, |
628 | { "getPosition" , w_Source_getPosition }, |
629 | { "setVelocity" , w_Source_setVelocity }, |
630 | { "getVelocity" , w_Source_getVelocity }, |
631 | { "setDirection" , w_Source_setDirection }, |
632 | { "getDirection" , w_Source_getDirection }, |
633 | { "setCone" , w_Source_setCone }, |
634 | { "getCone" , w_Source_getCone }, |
635 | |
636 | { "setRelative" , w_Source_setRelative }, |
637 | { "isRelative" , w_Source_isRelative }, |
638 | |
639 | { "setLooping" , w_Source_setLooping }, |
640 | { "isLooping" , w_Source_isLooping }, |
641 | { "isPlaying" , w_Source_isPlaying }, |
642 | |
643 | { "setVolumeLimits" , w_Source_setVolumeLimits }, |
644 | { "getVolumeLimits" , w_Source_getVolumeLimits }, |
645 | { "setAttenuationDistances" , w_Source_setAttenuationDistances }, |
646 | { "getAttenuationDistances" , w_Source_getAttenuationDistances }, |
647 | { "setRolloff" , w_Source_setRolloff }, |
648 | { "getRolloff" , w_Source_getRolloff }, |
649 | { "setAirAbsorption" , w_Source_setAirAbsorption }, |
650 | { "getAirAbsorption" , w_Source_getAirAbsorption }, |
651 | |
652 | { "getChannelCount" , w_Source_getChannelCount }, |
653 | |
654 | { "setFilter" , w_Source_setFilter }, |
655 | { "getFilter" , w_Source_getFilter }, |
656 | { "setEffect" , w_Source_setEffect }, |
657 | { "getEffect" , w_Source_getEffect }, |
658 | { "getActiveEffects" , w_Source_getActiveEffects }, |
659 | |
660 | { "getFreeBufferCount" , w_Source_getFreeBufferCount }, |
661 | { "queue" , w_Source_queue }, |
662 | |
663 | { "getType" , w_Source_getType }, |
664 | |
665 | // Deprecated |
666 | { "getChannels" , w_Source_getChannels }, |
667 | |
668 | { 0, 0 } |
669 | }; |
670 | |
671 | extern "C" int luaopen_source(lua_State *L) |
672 | { |
673 | return luax_register_type(L, &love::audio::Source::type, w_Source_functions, nullptr); |
674 | } |
675 | |
676 | } // audio |
677 | } // love |
678 | |