1
/******************************************************************************
3
* Copyright (C) 2006-2009 by Tor Andersson. *
5
* This file is part of Gargoyle. *
7
* Gargoyle is free software; you can redistribute it and/or modify *
8
* it under the terms of the GNU General Public License as published by *
9
* the Free Software Foundation; either version 2 of the License, or *
10
* (at your option) any later version. *
12
* Gargoyle is distributed in the hope that it will be useful, *
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
* GNU General Public License for more details. *
17
* You should have received a copy of the GNU General Public License *
18
* along with Gargoyle; if not, write to the Free Software *
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
21
*****************************************************************************/
23
/* SDL support donated by Lorenzo Marcantonio */
31
#include <SDL_mixer.h>
32
#include <SDL_sound.h>
39
#define giblorb_ID_MOD (giblorb_make_id('M', 'O', 'D', ' '))
40
#define giblorb_ID_OGG (giblorb_make_id('O', 'G', 'G', 'V'))
41
#define giblorb_ID_FORM (giblorb_make_id('F', 'O', 'R', 'M'))
43
/* non-standard types */
44
#define giblorb_ID_MP3 (giblorb_make_id('M', 'P', '3', ' '))
45
#define giblorb_ID_WAVE (giblorb_make_id('W', 'A', 'V', 'E'))
47
#define SDL_CHANNELS 64
49
static channel_t *gli_channellist = NULL;
50
static channel_t *sound_channels[SDL_CHANNELS];
51
static channel_t *music_channel;
53
static Sound_AudioInfo *output = NULL;
54
static const int FREE = 1;
55
static const int BUSY = 2;
57
void gli_initialize_sound(void)
59
if (gli_conf_sound == 1) {
60
if (SDL_Init(SDL_INIT_AUDIO) == -1) {
61
gli_strict_warning("SDL init failed\n");
62
gli_strict_warning(SDL_GetError());
66
if (Sound_Init() == -1) {
67
gli_strict_warning("SDL Sound init failed\n");
68
gli_strict_warning(Sound_GetError());
72
Sound_AudioInfo *audio;
73
audio = malloc(sizeof(Sound_AudioInfo));
74
audio->format = MIX_DEFAULT_FORMAT;
78
if (Mix_OpenAudio(output->rate, output->format, output->channels, 4096) == -1) {
79
gli_strict_warning("SDL Mixer init failed\n");
80
gli_strict_warning(Mix_GetError());
84
int channels = Mix_AllocateChannels(SDL_CHANNELS);
85
Mix_GroupChannels(0, channels - 1 , FREE);
89
schanid_t glk_schannel_create(glui32 rock)
95
chan = malloc(sizeof(channel_t));
101
chan->status = CHANNEL_IDLE;
102
chan->volume = 0x10000;
106
chan->sdl_memory = 0;
111
chan->sdl_channel = -1;
114
chan->chain_prev = NULL;
115
chan->chain_next = gli_channellist;
116
gli_channellist = chan;
117
if (chan->chain_next) {
118
chan->chain_next->chain_prev = chan;
121
if (gli_register_obj) {
122
chan->disprock = (*gli_register_obj)(chan, gidisp_Class_Schannel);
124
chan->disprock.ptr = NULL;
130
static void cleanup_channel(schanid_t chan)
132
if (chan->sdl_rwops) {
134
SDL_FreeRW(chan->sdl_rwops);
136
Sound_FreeSample(chan->decode);
141
if (chan->sdl_memory) {
142
free(chan->sdl_memory);
143
chan->sdl_memory = 0;
145
switch (chan->status) {
148
Mix_FreeChunk(chan->sample);
150
if (chan->sdl_channel >= 0) {
151
Mix_GroupChannel(chan->sdl_channel, FREE);
152
sound_channels[chan->sdl_channel] = 0;
157
Mix_FreeMusic(chan->music);
162
chan->status = CHANNEL_IDLE;
163
chan->sdl_channel = -1;
167
void glk_schannel_destroy(schanid_t chan)
169
channel_t *prev, *next;
172
gli_strict_warning("schannel_destroy: invalid id.");
176
glk_schannel_stop(chan);
177
cleanup_channel(chan);
178
if (gli_unregister_obj) {
179
(*gli_unregister_obj)(chan, gidisp_Class_Schannel, chan->disprock);
182
prev = chan->chain_prev;
183
next = chan->chain_next;
184
chan->chain_prev = NULL;
185
chan->chain_next = NULL;
188
prev->chain_next = next;
190
gli_channellist = next;
193
next->chain_prev = prev;
199
schanid_t glk_schannel_iterate(schanid_t chan, glui32 *rock)
202
chan = gli_channellist;
204
chan = chan->chain_next;
218
glui32 glk_schannel_get_rock(schanid_t chan)
221
gli_strict_warning("schannel_get_rock: invalid id.");
227
glui32 glk_schannel_play(schanid_t chan, glui32 snd)
229
return glk_schannel_play_ext(chan, snd, 1, 0);
232
void glk_sound_load_hint(glui32 snd, glui32 flag)
237
void glk_schannel_set_volume(schanid_t chan, glui32 vol)
240
gli_strict_warning("schannel_set_volume: invalid id.");
244
switch (chan->status) {
248
Mix_Volume(chan->sdl_channel, vol / 512);
251
Mix_VolumeMusic(vol / 512);
256
/* Notify the music channel completion */
257
static void music_completion_callback()
259
if (!music_channel) {
260
gli_strict_warning("music callback failed");
263
if (music_channel->notify) {
264
gli_event_store(evtype_SoundNotify, 0,
265
music_channel->resid, music_channel->notify);
267
cleanup_channel(music_channel);
270
/* Notify the sound channel completion */
271
static void sound_completion_callback(int chan)
273
channel_t *sound_channel = sound_channels[chan];
274
if (!sound_channel || Mix_Playing(chan)) {
275
gli_strict_warning("sound callback failed");
278
if (!sound_channel->buffered || !sound_channel->decode) {
279
if (sound_channel->notify) {
280
gli_event_store(evtype_SoundNotify, 0,
281
sound_channel->resid, sound_channel->notify);
283
cleanup_channel(sound_channel);
284
sound_channels[chan] = 0;
287
Uint32 soundbytes = Sound_Decode(sound_channel->decode);
289
sound_channel->loop--;
290
if (!sound_channel->loop) {
291
if (sound_channel->notify) {
292
gli_event_store(evtype_SoundNotify, 0,
293
sound_channel->resid, sound_channel->notify);
295
cleanup_channel(sound_channel);
296
sound_channels[chan] = 0;
299
Sound_Rewind(sound_channel->decode);
300
soundbytes = Sound_Decode(sound_channel->decode);
303
Sound_Sample *sample = sound_channel->decode;
304
sound_channel->sample = Mix_QuickLoad_RAW(sample->buffer, soundbytes);
305
Mix_ChannelFinished(&sound_completion_callback);
306
if (Mix_PlayChannel(sound_channel->sdl_channel,
307
sound_channel->sample,
311
gli_strict_warning("buffer sound failed");
312
gli_strict_warning(Mix_GetError());
313
cleanup_channel(sound_channel);
317
static glui32 load_sound_resource(glui32 snd, long *len, char **buf)
319
if (!giblorb_is_resource_map()) {
323
sprintf(name, "%s/SND%ld", gli_workdir, (long) snd);
325
file = fopen(name, "rb");
329
fseek(file, 0, SEEK_END);
339
if (fread(*buf, 1, *len, file) != *len && !feof(file)) return 0;
343
if (*len > 4 && !memcmp(*buf, "FORM", 4)) {
344
return giblorb_ID_FORM;
348
if (*len > 4 && !memcmp(*buf, "WAVE", 4)) {
349
return giblorb_ID_WAVE;
353
if (*len > 0x30 && !memcmp(*buf + 0x2c, "SCRM", 4)) {
354
return giblorb_ID_MOD;
358
if (*len > 20 && !memcmp(*buf, "Extended Module: ", 17)) {
359
return giblorb_ID_MOD;
365
memcpy(resname, (*buf) + 1080, 4);
366
if (!strcmp(resname+1, "CHN") || /* 4CHN, 6CHN, 8CHN */
367
!strcmp(resname+2, "CN") || /* 16CN, 32CN */
368
!strcmp(resname, "M.K.") || !strcmp(resname, "M!K!") ||
369
!strcmp(resname, "FLT4") || !strcmp(resname, "CD81") ||
370
!strcmp(resname, "OKTA") || !strcmp(resname, " "))
371
return giblorb_ID_MOD;
374
if (!memcmp(*buf, "\377\372", 2)) { /* mp3 */
375
return giblorb_ID_MP3;
378
return giblorb_ID_MP3;
384
giblorb_get_resource(giblorb_ID_Snd, snd, &file, &pos, len, &type);
393
if (fread(*buf, 1, *len, file) != *len && !feof(file)) return 0;
398
/** Start a sound channel */
399
static glui32 play_sound(schanid_t chan)
402
chan->status = CHANNEL_SOUND;
404
chan->sdl_channel = Mix_GroupAvailable(FREE);
405
Mix_GroupChannel(chan->sdl_channel, BUSY);
407
chan->sample = Mix_LoadWAV_RW(chan->sdl_rwops, FALSE);
408
if (chan->sdl_channel < 0) {
409
gli_strict_warning("No available sound channels");
411
if (chan->sdl_channel >= 0 && chan->sample) {
413
sound_channels[chan->sdl_channel] = chan;
415
Mix_Volume(chan->sdl_channel, chan->volume / 512);
416
Mix_ChannelFinished(&sound_completion_callback);
417
if (Mix_PlayChannel(chan->sdl_channel, chan->sample,
418
chan->loop-1) >= 0) {
422
gli_strict_warning("play sound failed");
423
gli_strict_warning(Mix_GetError());
425
cleanup_channel(chan);
430
/** Start a compressed sound channel */
431
static glui32 play_compressed(schanid_t chan, char *ext)
434
chan->status = CHANNEL_SOUND;
436
chan->sdl_channel = Mix_GroupAvailable(FREE);
437
Mix_GroupChannel(chan->sdl_channel, BUSY);
439
chan->decode = Sound_NewSample(chan->sdl_rwops, ext, output, 65536);
440
Uint32 soundbytes = Sound_Decode(chan->decode);
441
Sound_Sample *sample = chan->decode;
442
chan->sample = Mix_QuickLoad_RAW(sample->buffer, soundbytes);
443
if (chan->sdl_channel < 0) {
444
gli_strict_warning("No available sound channels");
446
if (chan->sdl_channel >= 0 && chan->sample) {
448
sound_channels[chan->sdl_channel] = chan;
450
Mix_Volume(chan->sdl_channel, chan->volume / 512);
451
Mix_ChannelFinished(&sound_completion_callback);
452
if (Mix_PlayChannel(chan->sdl_channel, chan->sample, 0) >= 0) {
456
gli_strict_warning("play sound failed");
457
gli_strict_warning(Mix_GetError());
459
cleanup_channel(chan);
464
/** Start a mod music channel */
465
static glui32 play_mod(schanid_t chan, long len)
472
chan->status = CHANNEL_MUSIC;
473
/* The fscking mikmod lib want to read the mod only from disk! */
474
tempdir = getenv("TEMP");
475
if (tempdir == NULL) tempdir = ".";
476
tn = tempnam(tempdir, "gargtmp");
477
file = fopen(tn, "wb");
478
fwrite(chan->sdl_memory, 1, len, file);
480
chan->music = Mix_LoadMUS(tn);
483
music_busy = Mix_PlayingMusic();
485
gli_strict_warning("MOD player already in use");
487
if (!music_busy && chan->music) {
489
music_channel = chan;
491
Mix_VolumeMusic(chan->volume / 512);
492
Mix_HookMusicFinished(&music_completion_callback);
493
if (Mix_PlayMusic(chan->music, chan->loop-1) >= 0) {
497
gli_strict_warning("play mod failed");
498
gli_strict_warning(Mix_GetError());
500
cleanup_channel(chan);
505
glui32 glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, glui32 notify)
512
gli_strict_warning("schannel_play_ext: invalid id.");
516
/* stop previous noise */
517
glk_schannel_stop(chan);
522
/* load sound resource into memory */
523
type = load_sound_resource(snd, &len, &buf);
525
chan->sdl_memory = (unsigned char*)buf;
526
chan->sdl_rwops = SDL_RWFromConstMem(buf, len);
527
chan->notify = notify;
529
chan->loop = repeats;
532
case giblorb_ID_FORM:
533
case giblorb_ID_WAVE:
534
return play_sound(chan);
538
return play_compressed(chan, "OGG");
542
return play_compressed(chan, "MP3");
546
return play_mod(chan, len);
550
gli_strict_warning("schannel_play_ext: unknown resource type.");
556
void glk_schannel_stop(schanid_t chan)
559
gli_strict_warning("schannel_stop: invalid id.");
565
switch (chan->status) {
567
Mix_HaltChannel(chan->sdl_channel);
574
cleanup_channel(chan);