1 /*
2 * Copyright 2009-2018 Peter Kosyh <p.kosyh at gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25 #include "externals.h"
26 #include "internals.h"
27
28 static int cur_vol = 0;
29
game_change_vol(int d,int val)30 int game_change_vol(int d, int val)
31 {
32 int v = snd_volume_mus(-1);
33 int pc = snd_vol_to_pcn(v);
34 int opc = pc;
35 if (d) {
36 pc += d;
37 if (pc < 0)
38 pc = 0;
39 if (pc > 100)
40 pc = 100;
41 while (snd_vol_to_pcn(v) != pc)
42 v += (d<0)?-1:1;
43 } else {
44 v = val;
45 pc = snd_vol_to_pcn(v);
46 }
47 if (!pc)
48 v = 0;
49 snd_volume_mus(v);
50 if (opc && !pc) {
51 game_stop_mus(0);
52 }
53 if (!opc && pc) {
54 game_music_player();
55 }
56 cur_vol = snd_volume_mus(-1);
57 if (!nosound_sw)
58 opt_vol = cur_vol;
59 return 0;
60 }
61
62 #define MAX_WAVS SND_CHANNELS * 2
63
64 static LIST_HEAD(sounds);
65 static int sounds_nr = 0;
66
67 typedef struct {
68 struct list_node list;
69 char *fname;
70 wav_t wav;
71 int loaded;
72 int system;
73 int fmt;
74 short *buf;
75 size_t len;
76 } _snd_t;
77 typedef struct {
78 _snd_t *snd;
79 int loop;
80 int channel;
81 } _snd_req_t;
82 static _snd_t *channels[SND_CHANNELS];
83 static _snd_req_t sound_reqs[SND_CHANNELS];
84 static void sound_play(_snd_t *sn, int chan, int loop);
85
sound_play_click(void)86 void sound_play_click(void)
87 {
88 sound_play(game_theme.click, -1, 1);
89 }
90
sound_callback(void * aux)91 static void sound_callback(void *aux)
92 {
93 _snd_req_t *r;
94 int channel = *((int *)aux);
95 int c = channel % SND_CHANNELS;
96 free(aux);
97 /* fprintf(stderr, "finished: %d\n", channel); */
98 channels[c] = NULL;
99 r = &sound_reqs[c];
100 if (r->snd) {
101 _snd_t *s = r->snd;
102 r->snd = NULL;
103 sound_play(s, channel, r->loop);
104 } else {
105 snd_halt_chan(channel, 0); /* to avoid races */
106 }
107 }
108
game_channel_finished(int channel)109 void game_channel_finished(int channel) /* SDL callback */
110 {
111 int *i = malloc(sizeof(channel));
112 if (!i) {
113 fprintf(stderr, "game_channel_finished: No memory\n");
114 return;
115 }
116 *i = channel;
117 push_user_event(sound_callback, i);
118 }
119
sound_playing(_snd_t * snd)120 static int sound_playing(_snd_t *snd)
121 {
122 int i;
123 for (i = 0; i < SND_CHANNELS; i++) {
124 if (channels[i] == snd)
125 return i;
126 if (sound_reqs[i].snd == snd)
127 return i;
128 }
129 return -1;
130 }
131
sound_channel(int i)132 static const char *sound_channel(int i)
133 {
134 _snd_t *sn;
135 if (i >= SND_CHANNELS)
136 i = i % SND_CHANNELS;
137 if (i == -1) {
138 for (i = 0; i < SND_CHANNELS; i++) {
139 sn = channels[i];
140 if (sn && !sn->system)
141 return sn->fname;
142 }
143 return NULL;
144 }
145 sn = channels[i];
146 if (!sn)
147 return NULL;
148 if (sn->system)
149 return NULL; /* hidden system sound */
150 return sn->fname;
151 }
152
sound_free(_snd_t * sn)153 static void sound_free(_snd_t *sn)
154 {
155 if (!sn)
156 return;
157 list_del(&sn->list);
158 sounds_nr --;
159 free(sn->fname);
160 snd_free_wav(sn->wav);
161 if (sn->buf)
162 free(sn->buf);
163 free(sn);
164 }
165
sounds_shrink(void)166 static void sounds_shrink(void)
167 {
168 _snd_t *pos, *pos2;
169 _snd_t *sn;
170 pos = list_top(&sounds, _snd_t, list);
171 /* fprintf(stderr,"shrink try\n"); */
172 while (pos && sounds_nr > MAX_WAVS) {
173 sn = (_snd_t*)pos;
174 if (sound_playing(sn) != -1 || sn->loaded) {
175 pos = list_next(&sounds, pos, list);
176 continue;
177 }
178 pos2 = list_next(&sounds, pos, list);
179 sound_free(sn);
180 pos = pos2;
181 /* fprintf(stderr,"shrink by 1\n"); */
182 }
183 }
184
sounds_free(void)185 static void sounds_free(void)
186 {
187 int i = 0;
188 _snd_t *pos, *pos2;
189 _snd_t *sn;
190 pos = list_top(&sounds, _snd_t, list);
191
192 snd_halt_chan(-1, 0); /* halt sounds */
193 while (pos) {
194 sn = (_snd_t*)pos;
195 pos2 = list_next(&sounds, pos, list);
196 if (sn->system)
197 sn->loaded = 1; /* ref by system only */
198 else
199 sound_free(sn);
200 pos = pos2;
201 }
202 for (i = 0; i < SND_CHANNELS; i++) {
203 channels[i] = NULL;
204 sound_reqs[i].snd = NULL;
205 }
206 /* sounds_nr = 0;
207 fprintf(stderr, "%d\n", sounds_nr); */
208 input_uevents(); /* all callbacks */
209 }
210
sound_find(const char * fname)211 static _snd_t *sound_find(const char *fname)
212 {
213 _snd_t *pos = NULL;
214 _snd_t *sn;
215 if (!fname)
216 return NULL;
217 list_for_each(&sounds, pos, list) {
218 sn = (_snd_t*)pos;
219 if (!strcmp(fname, sn->fname)) {
220 list_del(&sn->list);
221 list_add(&sounds, &sn->list); /* move it on head */
222 return sn;
223 }
224 }
225 return NULL;
226 }
227
sound_find_channel(void)228 static int sound_find_channel(void)
229 {
230 int i;
231 for (i = 0; i < SND_CHANNELS; i ++) {
232 if (!channels[i] && !sound_reqs[i].snd)
233 return i;
234 }
235 return -1;
236 }
237
sound_play(_snd_t * sn,int chan,int loop)238 static void sound_play(_snd_t *sn, int chan, int loop)
239 {
240 int c;
241 if (!sn)
242 return;
243 if (chan == -1) {
244 c = sound_find_channel();
245 if (c == -1)
246 return; /* all channels are busy */
247 } else
248 c = chan;
249 if (channels[c]) {
250 sound_reqs[c].snd = sn;
251 sound_reqs[c].loop = loop;
252 sound_reqs[c].channel = chan;
253 snd_halt_chan(chan, 0); /* work in callback */
254 input_uevents(); /* all callbacks */
255 return;
256 }
257 c = snd_play(sn->wav, c, loop - 1);
258 /* fprintf(stderr, "added: %d\n", c); */
259 if (c == -1)
260 return;
261 channels[c] = sn;
262 }
263
sound_add(const char * fname,int fmt,short * buf,int len)264 static _snd_t *sound_add(const char *fname, int fmt, short *buf, int len)
265 {
266 wav_t w;
267 _snd_t *sn;
268 if (!fname || !*fname)
269 return NULL;
270 sn = malloc(sizeof(_snd_t));
271 if (!sn)
272 return NULL;
273 memset(sn, 0, sizeof(*sn));
274 /* LIST_HEAD_INIT(&sn->list); */
275 sn->fname = strdup(fname);
276 sn->loaded = 0;
277 sn->system = 0;
278 sn->buf = buf;
279 sn->len = len;
280 sn->fmt = fmt;
281 if (!sn->fname) {
282 free(sn);
283 return NULL;
284 }
285 if (buf)
286 w = snd_load_mem(fmt, buf, len);
287 else
288 w = snd_load_wav(fname);
289 if (!w) {
290 if (snd_enabled())
291 game_res_err_msg(fname, debug_sw);
292 goto err;
293 }
294 sn->wav = w;
295
296 sounds_shrink();
297
298 list_add(&sounds, &sn->list);
299 sounds_nr ++;
300 return sn;
301 err:
302 free(sn->fname);
303 free(sn);
304 return NULL;
305 }
306
sounds_reload(void)307 static void sounds_reload(void)
308 {
309 _snd_t *pos = NULL;
310 _snd_t *sn;
311 int i;
312 snd_halt_chan(-1, 0); /* stop all sound */
313 list_for_each(&sounds, pos, list) {
314 sn = (_snd_t*)pos;
315 snd_free_wav(sn->wav);
316 if (sn->buf)
317 sn->wav = snd_load_mem(sn->fmt, sn->buf, sn->len);
318 else
319 sn->wav = snd_load_wav(sn->fname);
320 }
321 for (i = 0; i < SND_CHANNELS; i++) {
322 channels[i] = NULL;
323 sound_reqs[i].snd = NULL;
324 }
325 input_uevents(); /* all callbacks */
326 }
327
_sound_get(const char * fname,int fmt,short * buff,size_t len)328 static void *_sound_get(const char *fname, int fmt, short *buff, size_t len)
329 {
330 _snd_t *sn = NULL;
331 if (fname) {
332 sn = sound_find(fname);
333 if (sn) {
334 sn->loaded ++; /* to pin */
335 return sn;
336 }
337 sn = sound_add(fname, fmt, buff, len);
338 } else if (buff) {
339 char *name = malloc(64);
340 if (!name)
341 return NULL;
342 snprintf(name, 64, "snd:%p", buff); name[64 - 1] = 0;
343 sn = sound_add(name, fmt, buff, len);
344 if (!sn)
345 free(name);
346 else {
347 snprintf(name, 64, "snd:%p", sn); name[64 - 1] = 0;
348 free(sn->fname);
349 sn->fname = name;
350 }
351 }
352 if (!sn)
353 return NULL;
354 sn->loaded = 1;
355 return sn;
356 }
357
_sound_put(void * s)358 static void _sound_put(void *s)
359 {
360 _snd_t *sn = (_snd_t *)s;
361 if (!sn || !sn->loaded)
362 return;
363 if (!sn->system || sn->loaded > 1)
364 sn->loaded --;
365 if (!sn->loaded && sound_playing(sn) == -1)
366 sound_free(sn);
367 return;
368 }
369
sound_get(const char * fname)370 void *sound_get(const char *fname)
371 {
372 _snd_t *sn = _sound_get(fname, 0, NULL, 0);
373 if (!sn)
374 return NULL;
375 sn->system = 1;
376 return sn;
377 }
378
sound_put(void * s)379 void sound_put(void *s)
380 {
381 _snd_t *sn = (_snd_t *)s;
382 if (!sn)
383 return;
384 sn->system = 0;
385 _sound_put(sn);
386 }
387
sound_load(const char * fname)388 static int sound_load(const char *fname)
389 {
390 _snd_t *sn = _sound_get(fname, 0, NULL, 0);
391 if (!sn)
392 return -1;
393 return 0;
394 }
395
sound_load_mem(int fmt,short * buff,size_t len)396 static char *sound_load_mem(int fmt, short *buff, size_t len)
397 {
398 _snd_t *sn = _sound_get(NULL, fmt, buff, len);
399 if (!sn)
400 return NULL;
401 return sn->fname;
402 }
403
sound_unload(const char * fname)404 static void sound_unload(const char *fname)
405 {
406 _snd_t *sn;
407 sn = sound_find(fname);
408 _sound_put(sn);
409 return;
410 }
411
_play_combined_snd(char * filename,int chan,int loop)412 static int _play_combined_snd(char *filename, int chan, int loop)
413 {
414 char *str;
415 char *p, *ep;
416 _snd_t *sn;
417 p = str = strdup(filename);
418 if (!str)
419 return -1;
420
421 p = strip(p);
422 while (*p) {
423 int c = chan, l = loop;
424 int at = 0;
425 ep = p + strcspn(p, ";@");
426
427 if (*ep == '@') {
428 at = 1;
429 *ep = 0; ep ++;
430 if (sscanf(ep, "%d,%d", &c, &l) > 1)
431 at ++;
432 ep += strcspn(ep, ";");
433 if (*ep)
434 ep ++;
435 } else if (*ep == ';') {
436 *ep = 0; ep ++;
437 } else if (*ep) {
438 goto err;
439 }
440 p = strip(p);
441 sn = sound_find(p);
442 if (!sn)
443 sn = sound_add(p, 0, NULL, 0);
444 if (sn)
445 sound_play(sn, c, l);
446 else if (at || c != -1) { /* if @ or specific channel */
447 snd_halt_chan(c, (at == 2)?l:500);
448 }
449 p = ep;
450 }
451 free(str);
452 return 0;
453 err:
454 free(str);
455 return -1;
456 }
457
game_sound_player(void)458 static void game_sound_player(void)
459 {
460 char *snd;
461 int chan = -1;
462 int loop = 1;
463
464 struct instead_args args[] = {
465 { .val = "nil", .type = INSTEAD_NIL },
466 { .val = "-1", .type = INSTEAD_NUM },
467 { .val = NULL }
468 };
469
470 if (!snd_volume_mus(-1))
471 return;
472
473 instead_lock();
474 instead_function("instead.get_sound", NULL);
475
476 loop = instead_iretval(2);
477 chan = instead_iretval(1);
478 snd = instead_retval(0);
479 instead_clear();
480 if (!snd) {
481 if (chan != -1) {
482 /* halt channel */
483 snd_halt_chan(chan, 500);
484 instead_function("instead.set_sound", args); instead_clear();
485 }
486 instead_unlock();
487 return;
488 }
489 instead_function("instead.set_sound", args); instead_clear();
490 instead_unlock();
491 unix_path(snd);
492 _play_combined_snd(snd, chan, loop);
493 free(snd);
494 }
495
496 static char *last_music = NULL;
497
free_last_music(void)498 static void free_last_music(void)
499 {
500 if (last_music)
501 free(last_music);
502 last_music = NULL;
503 }
504
game_change_hz(int hz)505 int game_change_hz(int hz)
506 {
507 if (!hz)
508 return -1;
509 #ifndef __EMSCRIPTEN__
510 snd_close();
511 free_last_music();
512 snd_open(hz);
513 snd_volume_mus(cur_vol);
514 sounds_reload();
515 game_music_player();
516 #endif
517 opt_hz = snd_hz();
518 return 0;
519 }
520
game_stop_mus(int ms)521 void game_stop_mus(int ms)
522 {
523 snd_stop_mus(ms);
524 free_last_music();
525 }
526
finish_music(void * data)527 static void finish_music(void *data)
528 {
529 int rc;
530 if (!curgame_dir)
531 return;
532 instead_lock();
533 instead_function("instead.finish_music", NULL);
534 rc = instead_bretval(0);
535 instead_clear();
536 instead_unlock();
537 if (rc)
538 free_last_music();
539 snd_volume_mus(cur_vol); /* reset volume */
540 }
541
game_music_finished(void)542 void game_music_finished(void) /* SDL callback */
543 {
544 push_user_event(&finish_music, NULL);
545 }
546
game_music_player(void)547 void game_music_player(void)
548 {
549 int loop;
550 char *mus;
551
552 int cf_out = 0;
553 int cf_in = 0;
554
555 if (!snd_volume_mus(-1))
556 return;
557 if (!opt_music || !curgame_dir)
558 return;
559 instead_lock();
560 instead_function("instead.get_music", NULL);
561 mus = instead_retval(0);
562 loop = instead_iretval(1);
563 unix_path(mus);
564 instead_clear();
565
566 instead_function("instead.get_music_fading", NULL);
567 cf_out = instead_iretval(0);
568 cf_in = instead_iretval(1);
569 instead_clear();
570 instead_unlock();
571 if (mus && loop == -1) { /* disabled, 0 - forever, 1-n - loops */
572 free(mus);
573 mus = NULL;
574 }
575
576 if (loop == 0)
577 loop = -1;
578
579 if (cf_out == 0)
580 cf_out = 500;
581 else if (cf_out < 0)
582 cf_out = 0;
583
584 if (cf_in < 0)
585 cf_in = 0;
586
587 if (!mus) {
588 if (last_music) {
589 game_stop_mus(cf_out);
590 }
591 } else if (!last_music || strcmp(last_music, mus)) {
592 game_stop_mus(cf_out);
593 last_music = mus;
594 if (snd_play_mus(mus, cf_in, loop) < 0)
595 game_res_err_msg(mus, debug_sw);
596 } else
597 free(mus);
598 }
599
luaB_is_sound(lua_State * L)600 static int luaB_is_sound(lua_State *L) {
601 const char *chan = luaL_optstring(L, 1, NULL);
602 int c, r;
603 if (!chan)
604 c = -1;
605 else
606 c = atoi(chan);
607 r = (sound_channel(c) != NULL);
608 lua_pushboolean(L, r); /* else not a number */
609 return 1;
610 }
611
luaB_load_sound(lua_State * L)612 static int luaB_load_sound(lua_State *L) {
613 int rc;
614 const char *fname = luaL_optstring(L, 1, NULL);
615 if (!fname)
616 return 0;
617 rc = sound_load(fname);
618 if (rc)
619 return 0;
620 lua_pushstring(L, fname);
621 return 1;
622 }
623 #define SND_F2S(v) ((short)((float)(v) * 16383.0) * 2)
624
luaB_load_sound_mem(lua_State * L)625 static int luaB_load_sound_mem(lua_State *L) {
626 int hz = luaL_optinteger(L, 1, -1);
627 int channels = luaL_optinteger(L, 2, -1);
628 int len; int i;
629 short *buf = NULL;
630 const char *name;
631 int fmt = 0;
632 luaL_checktype(L, 3, LUA_TTABLE);
633
634 if (hz < 0 || channels < 0)
635 return 0;
636 #if LUA_VERSION_NUM >= 502
637 len = lua_rawlen(L, 3);
638 #else
639 len = lua_objlen(L, 3);
640 #endif
641 if (len <= 0)
642 return 0;
643 buf = malloc(sizeof(short) * len);
644 if (!buf)
645 return 0;
646
647 lua_pushvalue(L, 3);
648
649 for (i = 0; i < len; i++) {
650 float v;
651 lua_pushinteger(L, i + 1);
652 lua_gettable(L, -2);
653
654 if (!lua_isnumber(L, -1)) {
655 v = 0;
656 } else {
657 v = (float)lua_tonumber(L, -1);
658 }
659 buf[i] = SND_F2S(v);
660 lua_pop(L, 1);
661 }
662 lua_pop(L, 1);
663 /* here we got the sample */
664 if (channels == 2)
665 fmt |= SND_FMT_STEREO;
666
667 if (hz == 11025)
668 fmt |= SND_FMT_11;
669 else if (hz == 22050)
670 fmt |= SND_FMT_22;
671 else
672 fmt |= SND_FMT_44;
673 name = sound_load_mem(fmt, buf, len);
674 /* free(buf); */
675 if (!name)
676 return 0;
677 lua_pushstring(L, name);
678 return 1;
679 }
680
luaB_free_sound(lua_State * L)681 static int luaB_free_sound(lua_State *L) {
682 const char *fname = luaL_optstring(L, 1, NULL);
683 if (!fname)
684 return 0;
685 sound_unload(fname);
686 return 0;
687 }
688
luaB_free_sounds(lua_State * L)689 static int luaB_free_sounds(lua_State *L) {
690 sounds_free();
691 return 0;
692 }
693
luaB_panning_sound(lua_State * L)694 static int luaB_panning_sound(lua_State *L) {
695 int chan = luaL_optinteger(L, 1, -1);
696 int left = luaL_optnumber(L, 2, 255);
697 int right = luaL_optnumber(L, 3, 255);
698 snd_panning(chan, left, right);
699 return 0;
700 }
701
luaB_volume_sound(lua_State * L)702 static int luaB_volume_sound(lua_State *L) {
703 int vol = luaL_optnumber(L, 1, -1);
704 vol = snd_volume_mus(vol);
705 lua_pushinteger(L, vol);
706 return 1;
707 }
708
luaB_channel_sound(lua_State * L)709 static int luaB_channel_sound(lua_State *L) {
710 const char *s;
711 int ch = luaL_optinteger(L, 1, 0);
712 ch = ch % SND_CHANNELS;
713 s = sound_channel(ch);
714 if (s) {
715 lua_pushstring(L, s);
716 return 1;
717 }
718 return 0;
719 }
720 static int callback_ref = 0;
721 static int sound_inited = 0;
722
723 #define SOUND_MAGIC 0x2004
724 struct lua_sound {
725 int type;
726 short *buf;
727 int len;
728 };
mus_callback(void * udata,unsigned char * stream,int len)729 static void mus_callback(void *udata, unsigned char *stream, int len)
730 {
731 lua_State *L = (lua_State *) udata;
732 struct lua_sound *hdr;
733 if (!callback_ref)
734 return;
735 instead_lock();
736 lua_rawgeti(L, LUA_REGISTRYINDEX, callback_ref);
737 lua_pushinteger(L, snd_hz());
738 lua_pushinteger(L, len >> 1);
739 hdr = lua_newuserdata(L, sizeof(*hdr));
740 if (!hdr)
741 goto err;
742 hdr->type = SOUND_MAGIC;
743 hdr->len = len >> 1; /* 16bits */
744 hdr->buf = (short *)stream;
745 luaL_getmetatable(L, "soundbuffer metatable");
746 lua_setmetatable(L, -2);
747 if (instead_pcall(L, 3)) { /* on any error */
748 err:
749 snd_mus_callback(NULL, NULL);
750 luaL_unref(L, LUA_REGISTRYINDEX, callback_ref);
751 callback_ref = 0;
752 }
753 instead_clear();
754 instead_unlock();
755 return;
756 }
757
luaB_music_callback(lua_State * L)758 static int luaB_music_callback(lua_State *L) {
759 if (!sound_inited)
760 return 0;
761
762 snd_mus_callback(NULL, NULL);
763 if (callback_ref)
764 luaL_unref(L, LUA_REGISTRYINDEX, callback_ref);
765 callback_ref = 0;
766
767 if (lua_isfunction(L, 1)) {
768 game_stop_mus(0);
769 callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
770 snd_mus_callback(mus_callback, L);
771 }
772
773 return 0;
774 }
775
776 static const luaL_Reg sound_funcs[] = {
777 {"instead_sound", luaB_is_sound},
778 {"instead_sound_load", luaB_load_sound},
779 {"instead_sound_load_mem", luaB_load_sound_mem},
780 {"instead_sound_free", luaB_free_sound},
781 {"instead_sound_channel", luaB_channel_sound},
782 {"instead_sound_panning", luaB_panning_sound},
783 {"instead_sound_volume", luaB_volume_sound},
784 {"instead_sounds_free", luaB_free_sounds},
785 {"instead_music_callback", luaB_music_callback},
786 {NULL, NULL}
787 };
788
789
sound_done(void)790 static int sound_done(void)
791 {
792 if (!sound_inited)
793 return 0;
794 if (callback_ref) {
795 snd_mus_callback(NULL, NULL);
796 luaL_unref(instead_lua(), LUA_REGISTRYINDEX, callback_ref);
797 callback_ref = 0;
798 }
799 game_stop_mus(0);
800 sounds_free();
801 snd_close();
802 sound_inited = 0;
803 return 0;
804 }
805 /*
806 static int sound_size(lua_State *L) {
807 struct lua_sound *hdr = (struct lua_sound*)lua_touserdata(L, 1);
808 if (!hdr || hdr->type != SOUND_MAGIC)
809 return 0;
810 lua_pushnumber(L, hdr->len);
811 return 1;
812 }
813 */
sound_value(lua_State * L)814 static int sound_value(lua_State *L) {
815 struct lua_sound *hdr = (struct lua_sound*)lua_touserdata(L, 1);
816 int pos = luaL_optinteger(L, 2, -1);
817 float v = luaL_optnumber(L, 3, 0.0f);
818 if (pos <= 0)
819 return 0;
820 if (pos > hdr->len)
821 return 0;
822 pos --;
823 if (lua_isnoneornil(L, 3)) {
824 lua_pushinteger(L, hdr->buf[pos]);
825 return 1;
826 }
827 hdr->buf[pos] = SND_F2S(v);
828 return 0;
829 }
830
831 /*
832 ** Creates chunk metatable.
833 */
chunk_create_meta(lua_State * L)834 static int chunk_create_meta (lua_State *L) {
835 luaL_newmetatable (L, "soundbuffer metatable");
836 lua_pushstring (L, "__index");
837 lua_pushcfunction(L, sound_value);
838 lua_settable(L, -3);
839
840 lua_pushstring (L, "__newindex");
841 lua_pushcfunction(L, sound_value);
842 lua_settable(L, -3);
843 /*
844 lua_pushstring (L, "size");
845 lua_pushcfunction (L, sound_size);
846 lua_settable(L, -3);
847 */
848 return 0;
849 }
850
sound_init(void)851 static int sound_init(void)
852 {
853 int rc;
854 char path[PATH_MAX];
855
856 instead_api_register(sound_funcs);
857 chunk_create_meta(instead_lua());
858
859 snprintf(path, sizeof(path), "%s/%s", instead_stead_path(), "/ext/sound.lua");
860
861 rc = instead_loadfile(dirpath(path));
862 if (rc)
863 return rc;
864 snd_open(opt_hz);
865 if (!nosound_sw)
866 game_change_vol(0, opt_vol);
867 sound_inited = 1;
868 return 0;
869 }
870
sound_cmd(void)871 static int sound_cmd(void)
872 {
873 game_music_player();
874 game_sound_player();
875 return 0;
876 }
877
878 static struct instead_ext ext = {
879 .init = sound_init,
880 .done = sound_done,
881 .cmd = sound_cmd,
882 };
883
instead_sound_init(void)884 int instead_sound_init(void)
885 {
886 return instead_extension(&ext);
887 }
888