diff --git a/CHANGELOG.txt b/CHANGELOG.txt index cdfed1f59..9af961535 100755 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,11 @@ D2X-Rebirth Changelog +20070918 +-------- +SConstruct, main/inferno.c, main/digi.h, arch/sdl/include/digi_audio.h, arch/sdl/include/digi_mixer_music.h, arch/sdl/include/digi_mixer.h, arch/sdl/digi.c, arch/sdl/digi_mixer.c, arch/sdl/digi_mixer_music.c, arch/sdl/digi_audio.c : huge refactoring of sound system using function pointers, to allow sound backend selection at runtime and provide a common interface (digi.c) +include/args.h, main/args.c : handle SDL_mixer-specific args +arch/sdl/jukebox.c, arch/sdl/jukebox.c, include/dl_list.h, misc/dl_list.c : added jukebox functionality + 20070913 -------- main/game.c, main/gamecntl.c, main/multi.c, main/network.c: Code Re-formatting; Preventing Redundancy in Restricted-game joining; Dumping refused player back to Join-menu; Expanded Game-help screen diff --git a/SConstruct b/SConstruct index e038c682c..c3c859f23 100644 --- a/SConstruct +++ b/SConstruct @@ -79,6 +79,8 @@ common_sources = [ 'arch/sdl/mouse.c', 'arch/sdl/rbaudio.c', 'arch/sdl/timer.c', +'arch/sdl/digi.c', +'arch/sdl/digi_audio.c', 'iff/iff.c', 'libmve/decoder8.c', 'libmve/decoder16.c', @@ -159,6 +161,7 @@ common_sources = [ 'main/weapon.c', 'mem/mem.c', 'misc/args.c', +'misc/dl_list.c', 'misc/error.c', 'misc/hash.c', 'misc/ignorecase.c', @@ -247,18 +250,16 @@ arch_linux_sources = [ 'arch/linux/ukali.c', ] -# choosing a sound implementation for *nix -common_sound_hmp2mid = [ 'misc/hmp2mid.c' ] -arch_unix_sound_sdlmixer = [ 'arch/sdl/mixdigi.c', 'arch/sdl/mixmusic.c' ] -arch_unix_sound_old = [ 'arch/sdl/digi.c' ] -#arch_linux_sound_old = ['arch/linux/hmiplay.c' ] +# SDL_mixer sound implementation +arch_sdlmixer = [ +'misc/hmp2mid.c', +'arch/sdl/digi_mixer.c', +'arch/sdl/digi_mixer_music.c', +'arch/sdl/jukebox.c' +] if (sdlmixer == 1): - common_sources += common_sound_hmp2mid - arch_unix_sources += arch_unix_sound_sdlmixer -else: - arch_unix_sources += arch_unix_sound_old -# arch_linux_sources += arch_linux_sound_old + arch_linux_sources += arch_sdlmixer # for windows arch_win32_sources = [ @@ -318,12 +319,19 @@ env.ParseConfig('sdl-config --libs') env.Append(CPPFLAGS = ['-Wall', '-funsigned-char']) env.Append(CPPDEFINES = [('D2XMAJOR', '\\"' + str(D2XMAJOR) + '\\"'), ('D2XMINOR', '\\"' + str(D2XMINOR) + '\\"')]) #env.Append(CPPDEFINES = [('VERSION', '\\"' + str(VERSION) + '\\"')]) -env.Append(CPPDEFINES = [('USE_SDLMIXER', sdlmixer)]) +#env.Append(CPPDEFINES = [('USE_SDLMIXER', sdlmixer)]) env.Append(CPPDEFINES = ['NMONO', 'PIGGY_USE_PAGING', 'NETWORK', 'HAVE_NETIPX_IPX_H', 'NEWDEMO', '_REENTRANT']) env.Append(CPPPATH = ['include', 'main', 'arch/include']) generic_libs = ['SDL', 'physfs'] sdlmixerlib = ['SDL_mixer'] +if sdlmixer: + env.Append(CPPDEFINES = ['USE_SDLMIXER']) + +if (D2XMICRO): + env.Append(CPPDEFINES = [('D2XMICRO', '\\"' + str(D2XMICRO) + '\\"')]) + + # Get traditional compiler environment variables if os.environ.has_key('CC'): env['CC'] = os.environ['CC'] diff --git a/arch/include/digi_audio.h b/arch/include/digi_audio.h new file mode 100644 index 000000000..75db08a1a --- /dev/null +++ b/arch/include/digi_audio.h @@ -0,0 +1,28 @@ +#ifndef __DIGI_AUDIO__ +#define __DIGI_AUDIO__ + +#include "fix.h" + +int digi_audio_init(); +void digi_audio_reset(); +void digi_audio_close(); +void digi_audio_stop_all_channels(); +int digi_audio_start_sound(short, fix, int, int, int, int, int ); +int digi_audio_find_channel(int ); +int digi_audio_is_sound_playing(int ); +void digi_audio_set_max_channels(int ); +int digi_audio_get_max_channels(); +int digi_audio_is_channel_playing(int ); +void digi_audio_set_channel_volume(int, int ); +void digi_audio_set_channel_pan(int, int ); +void digi_audio_stop_sound(int ); +void digi_audio_end_sound(int ); +void digi_audio_play_midi_song( char *, char *, char *, int ); +void digi_audio_set_digi_volume(int); +void digi_audio_set_midi_volume(int); +void digi_audio_stop_current_song(); +void digi_audio_pause_midi(); +void digi_audio_resume_midi(); +void digi_audio_debug(); + +#endif diff --git a/arch/include/digi_mixer.h b/arch/include/digi_mixer.h new file mode 100644 index 000000000..26f1acc40 --- /dev/null +++ b/arch/include/digi_mixer.h @@ -0,0 +1,28 @@ +#ifndef __DIGI_MIXER__ +#define __DIGI_MIXER__ + +#include "fix.h" + +int digi_mixer_init(); +void digi_mixer_close(); +int digi_mixer_start_sound(short, fix, int, int, int, int, int); +void digi_mixer_set_channel_volume(int, int); +void digi_mixer_set_channel_pan(int, int); +void digi_mixer_stop_sound(int); +void digi_mixer_end_sound(int); +int digi_mixer_find_channel(int); +int digi_mixer_is_sound_playing(int); +int digi_mixer_is_channel_playing(int); +void digi_mixer_reset(); +void digi_set_max_channels(int); +int digi_get_max_channels(); +void digi_mixer_stop_all_channels(); +void digi_mixer_play_midi_song(char *, char *, char *, int); +void digi_mixer_set_midi_volume(int); +void digi_mixer_set_digi_volume(int); +void digi_mixer_stop_current_song(); +void digi_mixer_pause_midi(); +void digi_mixer_resume_midi(); +void digi_mixer_debug(); + +#endif diff --git a/arch/include/mixmusic.h b/arch/include/digi_mixer_music.h similarity index 61% rename from arch/include/mixmusic.h rename to arch/include/digi_mixer_music.h index e1df302a6..a87be3772 100644 --- a/arch/include/mixmusic.h +++ b/arch/include/digi_mixer_music.h @@ -7,8 +7,9 @@ #ifndef _SDLMIXER_MUSIC_H #define _SDLMIXER_MUSIC_H -void mix_play_music(char *filename, int loop); -void mix_set_music_volume(int vol); +void mix_play_music(char *, int); +void mix_play_file(char *, char *, int); +void mix_set_music_volume(int); void mix_stop_music(); #endif diff --git a/arch/include/jukebox.h b/arch/include/jukebox.h new file mode 100644 index 000000000..e4367bb9d --- /dev/null +++ b/arch/include/jukebox.h @@ -0,0 +1,15 @@ +#ifndef __JUKEBOX_H__ +#define __JUKEBOX_H__ + +void jukebox_load(); +void jukebox_play(); +void jukebox_stop(); +void jukebox_stop_hook(); +void jukebox_next(); +void jukebox_prev(); +char *jukebox_current(); +int jukebox_is_loaded(); +int jukebox_is_playing(); +void jukebox_list(); + +#endif diff --git a/arch/sdl/digi.c b/arch/sdl/digi.c index a04e99038..421e80e9c 100755 --- a/arch/sdl/digi.c +++ b/arch/sdl/digi.c @@ -1,9 +1,6 @@ -/* $Id: digi.c,v 1.1.1.1 2006/03/17 19:53:41 zicodxx Exp $ */ /* - * - * SDL digital audio support - * - * + * Digital audio support + * Library-independent stub for dynamic selection of sound system */ #ifdef HAVE_CONFIG_H @@ -14,470 +11,127 @@ #include #include -#include +#include +#include -#include "pstypes.h" -#include "error.h" -#include "mono.h" -#include "fix.h" -#include "vecmat.h" -#include "gr.h" // needed for piggy.h -#include "piggy.h" -#include "digi.h" -#include "sounds.h" -#include "wall.h" -#include "newdemo.h" -#include "kconfig.h" - -//edited 05/17/99 Matt Mueller - added ifndef NO_ASM -//added on 980905 by adb to add inline fixmul for mixer on i386 -#ifndef NO_ASM -#ifdef __i386__ -#define do_fixmul(x,y) \ -({ \ - int _ax, _dx; \ - asm("imull %2\n\tshrdl %3,%1,%0" \ - : "=a"(_ax), "=d"(_dx) \ - : "rm"(y), "i"(16), "0"(x)); \ - _ax; \ -}) -extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); } -#endif -#endif -//end edit by adb -//end edit -MM - -//changed on 980905 by adb to increase number of concurrent sounds -#define MAX_SOUND_SLOTS 32 -//end changes by adb -#ifdef GP2X -#define SOUND_BUFFER_SIZE 64 -#else -#define SOUND_BUFFER_SIZE 512 +#ifdef USE_SDLMIXER +#include #endif -#define MIN_VOLUME 10 +/* Sound system function pointers */ -/* This table is used to add two sound values together and pin - * the value to avoid overflow. (used with permission from ARDI) - * DPH: Taken from SDL/src/SDL_mixer.c. - */ -static const Uint8 mix8[] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, - 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, - 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, - 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, - 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, - 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, - 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, - 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, - 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, - 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, - 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, - 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, - 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; +int (*fptr_init)() = NULL; +void (*fptr_close)() = NULL; +void (*fptr_reset)() = NULL; +void (*fptr_set_channel_volume)(int, int) = NULL; +void (*fptr_set_channel_pan)(int, int) = NULL; -//added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2 -#define SOUND_MAX_VOLUME (F1_0 / 2) +int (*fptr_start_sound)(short, fix, int, int, int, int, int) = NULL; +void (*fptr_stop_sound)(int) = NULL; +void (*fptr_end_sound)(int) = NULL; +int (*fptr_find_channel)(int) = NULL; +int (*fptr_is_sound_playing)(int) = NULL; +int (*fptr_is_channel_playing)(int) = NULL; +void (*fptr_stop_all_channels)() = NULL; +void (*fptr_set_digi_volume)(int) = NULL; + +void (*fptr_play_midi_song)(char *, char *, char *, int) = NULL; +void (*fptr_set_midi_volume)(int) = NULL; +void (*fptr_stop_current_song)() = NULL; +void (*fptr_pause_midi)() = NULL; +void (*fptr_resume_midi)() = NULL; + +void digi_select_system(int n) { + switch (n) { +#ifdef USE_SDLMIXER + case SDLMIXER_SYSTEM: + printf("Using SDL_mixer library\n"); + fptr_init = digi_mixer_init; + fptr_close = digi_mixer_close; + fptr_reset = digi_mixer_reset; + fptr_set_channel_volume = digi_mixer_set_channel_volume; + fptr_set_channel_pan = digi_mixer_set_channel_pan; + fptr_start_sound = digi_mixer_start_sound; + fptr_stop_sound = digi_mixer_stop_sound; + fptr_end_sound = digi_mixer_end_sound; + fptr_find_channel = digi_mixer_find_channel; + fptr_is_sound_playing = digi_mixer_is_sound_playing; + fptr_is_channel_playing = digi_mixer_is_channel_playing; + fptr_stop_all_channels = digi_mixer_stop_all_channels; + fptr_play_midi_song = digi_mixer_play_midi_song; + fptr_stop_current_song = digi_mixer_stop_current_song; + fptr_pause_midi = digi_mixer_pause_midi; + fptr_resume_midi = digi_mixer_resume_midi; + fptr_set_midi_volume = digi_mixer_set_midi_volume; + fptr_set_digi_volume = digi_mixer_set_digi_volume; + break; +#endif + case SDLAUDIO_SYSTEM: + default: + printf("Using plain old SDL audio\n"); + fptr_init = digi_audio_init; + fptr_close = digi_audio_close; + fptr_reset = digi_audio_reset; + fptr_set_channel_volume = digi_audio_set_channel_volume; + fptr_set_channel_pan = digi_audio_set_channel_pan; + fptr_start_sound = digi_audio_start_sound; + fptr_stop_sound = digi_audio_stop_sound; + fptr_end_sound = digi_audio_end_sound; + fptr_find_channel = digi_audio_find_channel; + fptr_is_sound_playing = digi_audio_is_sound_playing; + fptr_is_channel_playing = digi_audio_is_channel_playing; + fptr_stop_all_channels = digi_audio_stop_all_channels; + fptr_play_midi_song = digi_audio_play_midi_song; + fptr_stop_current_song = digi_audio_stop_current_song; + fptr_pause_midi = digi_audio_pause_midi; + fptr_resume_midi = digi_audio_resume_midi; + fptr_set_midi_volume = digi_audio_set_midi_volume; + fptr_set_digi_volume = digi_audio_set_digi_volume; + break; + } +} + +/* Common digi functions */ + +int digi_sample_rate = SAMPLE_RATE_22K; int digi_volume = SOUND_MAX_VOLUME; -//end edit by adb +int midi_volume = SOUND_MAX_VOLUME; -static int digi_initialised = 0; - -struct sound_slot { - int soundno; - int playing; // Is there a sample playing on this channel? - int looped; // Play this sample looped? - fix pan; // 0 = far left, 1 = far right - fix volume; // 0 = nothing, 1 = fully on - //changed on 980905 by adb from char * to unsigned char * - unsigned char *samples; - //end changes by adb - unsigned int length; // Length of the sample - unsigned int position; // Position we are at at the moment. - int soundobj; // Which soundobject is on this channel - int persistent; // This can't be pre-empted -} SoundSlots[MAX_SOUND_SLOTS]; - -static SDL_AudioSpec WaveSpec; - -static int digi_max_channels = 16; - -static int next_channel = 0; - -/* Audio mixing callback */ -//changed on 980905 by adb to cleanup, add pan support and optimize mixer -static void audio_mixcallback(void *userdata, Uint8 *stream, int len) -{ - Uint8 *streamend = stream + len; - struct sound_slot *sl; - - if (!digi_initialised) - return; - - memset(stream, 0x80, len); // fix "static" sound bug on Mac OS X - - for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) { - if (sl->playing) { - Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length; - Uint8 *sp = stream, s; - signed char v; - fix vl, vr; - int x; - - if ((x = sl->pan) & 0x8000) { - vl = 0x20000 - x * 2; - vr = 0x10000; - } else { - vl = 0x10000; - vr = x * 2; - } - vl = fixmul(vl, (x = sl->volume)); - vr = fixmul(vr, x); - while (sp < streamend) { - if (sldata == slend) { - if (!sl->looped) { - sl->playing = 0; - break; - } - sldata = sl->samples; - } - v = *(sldata++) - 0x80; - s = *sp; - *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ]; - s = *sp; - *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ]; - } - sl->position = sldata - sl->samples; - } - } -} -//end changes by adb - -/* Initialise audio devices. */ -int digi_init() -{ - if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) { - Error("SDL audio initialisation failed: %s.",SDL_GetError()); - } - - WaveSpec.freq = GameArg.SndDigiSampleRate; - //added/changed by Sam Lantinga on 12/01/98 for new SDL version - WaveSpec.format = AUDIO_U8; - WaveSpec.channels = 2; - //end this section addition/change - SL - WaveSpec.samples = SOUND_BUFFER_SIZE; - WaveSpec.callback = audio_mixcallback; - - if ( SDL_OpenAudio(&WaveSpec, NULL) < 0 ) { - //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound. - Warning("\nError: Couldn't open audio: %s\n", SDL_GetError()); - //killed exit(2); - return 1; - //end edit -MM - } - SDL_PauseAudio(0); - - atexit(digi_close); - digi_initialised = 1; - return 0; +void digi_set_volume(int dvolume, int mvolume) { + digi_volume = dvolume; + midi_volume = mvolume; + if (fptr_set_digi_volume) digi_set_digi_volume(dvolume); + if (fptr_set_midi_volume) digi_set_midi_volume(mvolume); } -/* Toggle audio */ -void digi_reset() { } +void digi_set_sample_rate(int r) { digi_sample_rate = r; } -/* Shut down audio */ -void digi_close() -{ - if (!digi_initialised) return; - digi_initialised = 0; -#ifdef __MINGW32__ - SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening? -#endif - SDL_CloseAudio(); -} +/* Stub functions */ -void digi_stop_all_channels() -{ - int i; +int digi_init() { return fptr_init(); } +void digi_close() { fptr_close(); } +void digi_reset() { fptr_reset(); } - for (i = 0; i < MAX_SOUND_SLOTS; i++) - digi_stop_sound(i); -} +void digi_set_channel_volume(int channel, int volume) { fptr_set_channel_volume(channel, volume); } +void digi_set_channel_pan(int channel, int pan) { fptr_set_channel_pan(channel, pan); } +int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj) { return fptr_start_sound(soundnum, volume, pan, looping, loop_start, loop_end, soundobj); } +void digi_stop_sound(int channel) { fptr_stop_sound(channel); } +void digi_end_sound(int channel) { fptr_end_sound(channel); } -extern void digi_end_soundobj(int channel); -extern int SoundQ_channel; -extern void SoundQ_end(); -int verify_sound_channel_free(int channel); +int digi_find_channel(int soundno) { return fptr_find_channel(soundno); } +int digi_is_sound_playing(int soundno) { return fptr_is_sound_playing(soundno); } +int digi_is_channel_playing(int channel) { return fptr_is_channel_playing(channel); } +void digi_stop_all_channels() { fptr_stop_all_channels(); } +void digi_set_max_channels(int n) { } +int digi_get_max_channels() { return 0; } +void digi_set_digi_volume(int dvolume) { fptr_set_digi_volume(dvolume); } -// Volume 0-F1_0 -int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj) -{ - int i, starting_channel; +void digi_play_midi_song(char * filename, char * melodic_bank, char * drum_bank, int loop ) { fptr_play_midi_song(filename, melodic_bank, drum_bank, loop); } +void digi_set_midi_volume(int mvolume) { fptr_set_midi_volume(mvolume); } +void digi_stop_current_song() { fptr_stop_current_song(); } +void digi_pause_midi() { fptr_pause_midi(); } +void digi_resume_midi() { fptr_resume_midi(); } - if (!digi_initialised) return -1; - - if (soundnum < 0) return -1; - - Assert(GameSounds[soundnum].data != (void *)-1); - - starting_channel = next_channel; - - while(1) - { - if (!SoundSlots[next_channel].playing) - break; - - if (!SoundSlots[next_channel].persistent) - break; // use this channel! - - next_channel++; - if (next_channel >= digi_max_channels) - next_channel = 0; - if (next_channel == starting_channel) - { - mprintf((1, "OUT OF SOUND CHANNELS!!!\n")); - return -1; - } - } - if (SoundSlots[next_channel].playing) - { - SoundSlots[next_channel].playing = 0; - if (SoundSlots[next_channel].soundobj > -1) - { - digi_end_soundobj(SoundSlots[next_channel].soundobj); - } - if (SoundQ_channel == next_channel) - SoundQ_end(); - } - -#ifndef NDEBUG - verify_sound_channel_free(next_channel); -#endif - - SoundSlots[next_channel].soundno = soundnum; - SoundSlots[next_channel].samples = GameSounds[soundnum].data; - SoundSlots[next_channel].length = GameSounds[soundnum].length; - SoundSlots[next_channel].volume = fixmul(digi_volume, volume); - SoundSlots[next_channel].pan = pan; - SoundSlots[next_channel].position = 0; - SoundSlots[next_channel].looped = looping; - SoundSlots[next_channel].playing = 1; - SoundSlots[next_channel].soundobj = soundobj; - SoundSlots[next_channel].persistent = 0; - if ((soundobj > -1) || (looping) || (volume > F1_0)) - SoundSlots[next_channel].persistent = 1; - - i = next_channel; - next_channel++; - if (next_channel >= digi_max_channels) - next_channel = 0; - - return i; -} - -// Returns the channel a sound number is playing on, or -// -1 if none. -int digi_find_channel(int soundno) -{ - if (!digi_initialised) - return -1; - - if (soundno < 0 ) - return -1; - - if (GameSounds[soundno].data == NULL) - { - Int3(); - return -1; - } - - //FIXME: not implemented - return -1; -} - - -//added on 980905 by adb from original source to make sfx volume work -void digi_set_digi_volume( int dvolume ) -{ - dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff); - if ( dvolume > SOUND_MAX_VOLUME ) - digi_volume = SOUND_MAX_VOLUME; - else if ( dvolume < 0 ) - digi_volume = 0; - else - digi_volume = dvolume; - - if ( !digi_initialised ) return; - - digi_sync_sounds(); -} -//end edit by adb - -void digi_set_volume( int dvolume, int mvolume ) -{ - digi_set_digi_volume(dvolume); - digi_set_midi_volume(mvolume); -// mprintf(( 1, "Volume: 0x%x and 0x%x\n", digi_volume, midi_volume )); -} - -int digi_is_sound_playing(int soundno) -{ - int i; - - soundno = digi_xlat_sound(soundno); - - for (i = 0; i < MAX_SOUND_SLOTS; i++) - //changed on 980905 by adb: added SoundSlots[i].playing && - if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno) - //end changes by adb - return 1; - return 0; -} - - - //added on 980905 by adb to make sound channel setting work -void digi_set_max_channels(int n) { - digi_max_channels = n; - - if ( digi_max_channels < 1 ) - digi_max_channels = 1; - if (digi_max_channels > MAX_SOUND_SLOTS) - digi_max_channels = MAX_SOUND_SLOTS; - - if ( !digi_initialised ) return; - - digi_stop_all_channels(); -} - -int digi_get_max_channels() { - return digi_max_channels; -} -// end edit by adb - -int digi_is_channel_playing(int channel) -{ - if (!digi_initialised) - return 0; - - return SoundSlots[channel].playing; -} - -void digi_set_channel_volume(int channel, int volume) -{ - if (!digi_initialised) - return; - - if (!SoundSlots[channel].playing) - return; - - SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0); -} - -void digi_set_channel_pan(int channel, int pan) -{ - if (!digi_initialised) - return; - - if (!SoundSlots[channel].playing) - return; - - SoundSlots[channel].pan = pan; -} - -void digi_stop_sound(int channel) -{ - SoundSlots[channel].playing=0; - SoundSlots[channel].soundobj = -1; - SoundSlots[channel].persistent = 0; -} - -void digi_end_sound(int channel) -{ - if (!digi_initialised) - return; - - if (!SoundSlots[channel].playing) - return; - - SoundSlots[channel].soundobj = -1; - SoundSlots[channel].persistent = 0; -} - - -#ifndef _WIN32 -// MIDI stuff follows. -void digi_set_midi_volume( int mvolume ) { } -void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {} - -void digi_stop_current_song() -{ -#ifdef HMIPLAY - char buf[10]; - - sprintf(buf,"s"); - send_ipc(buf); -#endif -} -void digi_pause_midi() {} -void digi_resume_midi() {} -#endif - -#ifndef NDEBUG -void digi_debug() -{ - int i; - int n_voices = 0; - - if (!digi_initialised) - return; - - for (i = 0; i < digi_max_channels; i++) - { - if (digi_is_channel_playing(i)) - n_voices++; - } - - mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32) ", n_voices, digi_max_channels, -1)); - //mprintf_at((0, 3, 0, "DIGI: Number locked sounds: %d ", digi_total_locks )); -} -#endif diff --git a/arch/sdl/digi_audio.c b/arch/sdl/digi_audio.c new file mode 100644 index 000000000..da77f5218 --- /dev/null +++ b/arch/sdl/digi_audio.c @@ -0,0 +1,473 @@ +/* $Id: digi.c,v 1.1.1.1 2006/03/17 19:53:41 zicodxx Exp $ */ +/* + * + * SDL digital audio support + * + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include "pstypes.h" +#include "error.h" +#include "mono.h" +#include "fix.h" +#include "vecmat.h" +#include "gr.h" +#include "piggy.h" +#include "digi.h" +#include "sounds.h" +#include "wall.h" +#include "newdemo.h" +#include "kconfig.h" + +//edited 05/17/99 Matt Mueller - added ifndef NO_ASM +//added on 980905 by adb to add inline fixmul for mixer on i386 +#ifndef NO_ASM +#ifdef __i386__ +#define do_fixmul(x,y) \ +({ \ + int _ax, _dx; \ + asm("imull %2\n\tshrdl %3,%1,%0" \ + : "=a"(_ax), "=d"(_dx) \ + : "rm"(y), "i"(16), "0"(x)); \ + _ax; \ +}) +extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); } +#endif +#endif +//end edit by adb +//end edit -MM + +//changed on 980905 by adb to increase number of concurrent sounds +#define MAX_SOUND_SLOTS 32 +//end changes by adb +#ifdef GP2X +#define SOUND_BUFFER_SIZE 64 +#else +#define SOUND_BUFFER_SIZE 512 +#endif + +#define MIN_VOLUME 10 + +/* This table is used to add two sound values together and pin + * the value to avoid overflow. (used with permission from ARDI) + * DPH: Taken from SDL/src/SDL_mixer.c. + */ +static const Uint8 mix8[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, + 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, + 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, + 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, + 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, + 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, + 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, + 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, + 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, + 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, + 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static int digi_initialised = 0; + +struct sound_slot { + int soundno; + int playing; // Is there a sample playing on this channel? + int looped; // Play this sample looped? + fix pan; // 0 = far left, 1 = far right + fix volume; // 0 = nothing, 1 = fully on + //changed on 980905 by adb from char * to unsigned char * + unsigned char *samples; + //end changes by adb + unsigned int length; // Length of the sample + unsigned int position; // Position we are at at the moment. + int soundobj; // Which soundobject is on this channel + int persistent; // This can't be pre-empted +} SoundSlots[MAX_SOUND_SLOTS]; + +static SDL_AudioSpec WaveSpec; + +static int digi_max_channels = 16; + +static int next_channel = 0; + +void digi_stop_sound(int channel); +int digi_xlat_sound(int soundno); + +/* Audio mixing callback */ +//changed on 980905 by adb to cleanup, add pan support and optimize mixer +static void audio_mixcallback(void *userdata, Uint8 *stream, int len) +{ + Uint8 *streamend = stream + len; + struct sound_slot *sl; + + if (!digi_initialised) + return; + + memset(stream, 0x80, len); // fix "static" sound bug on Mac OS X + + for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) { + if (sl->playing) { + Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length; + Uint8 *sp = stream, s; + signed char v; + fix vl, vr; + int x; + + if ((x = sl->pan) & 0x8000) { + vl = 0x20000 - x * 2; + vr = 0x10000; + } else { + vl = 0x10000; + vr = x * 2; + } + vl = fixmul(vl, (x = sl->volume)); + vr = fixmul(vr, x); + while (sp < streamend) { + if (sldata == slend) { + if (!sl->looped) { + sl->playing = 0; + break; + } + sldata = sl->samples; + } + v = *(sldata++) - 0x80; + s = *sp; + *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ]; + s = *sp; + *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ]; + } + sl->position = sldata - sl->samples; + } + } +} +//end changes by adb + +/* Initialise audio devices. */ +int digi_audio_init() +{ + if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) { + Error("SDL audio initialisation failed: %s.",SDL_GetError()); + } + + WaveSpec.freq = digi_sample_rate; + //added/changed by Sam Lantinga on 12/01/98 for new SDL version + WaveSpec.format = AUDIO_U8; + WaveSpec.channels = 2; + //end this section addition/change - SL + WaveSpec.samples = SOUND_BUFFER_SIZE; + WaveSpec.callback = audio_mixcallback; + + if ( SDL_OpenAudio(&WaveSpec, NULL) < 0 ) { + //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound. + Warning("\nError: Couldn't open audio: %s\n", SDL_GetError()); + //killed exit(2); + return 1; + //end edit -MM + } + SDL_PauseAudio(0); + + atexit(digi_close); + digi_initialised = 1; + return 0; +} + +/* Toggle audio */ +void digi_audio_reset() { } + +/* Shut down audio */ +void digi_audio_close() +{ + if (!digi_initialised) return; + digi_initialised = 0; +#ifdef __MINGW32__ + SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening? +#endif + SDL_CloseAudio(); +} + +void digi_audio_stop_all_channels() +{ + int i; + + for (i = 0; i < MAX_SOUND_SLOTS; i++) + digi_audio_stop_sound(i); +} + + +extern void digi_end_soundobj(int channel); +extern int SoundQ_channel; +extern void SoundQ_end(); +int verify_sound_channel_free(int channel); + +// Volume 0-F1_0 +int digi_audio_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj) +{ + int i, starting_channel; + + if (!digi_initialised) return -1; + + if (soundnum < 0) return -1; + + Assert(GameSounds[soundnum].data != (void *)-1); + + starting_channel = next_channel; + + while(1) + { + if (!SoundSlots[next_channel].playing) + break; + + if (!SoundSlots[next_channel].persistent) + break; // use this channel! + + next_channel++; + if (next_channel >= digi_max_channels) + next_channel = 0; + if (next_channel == starting_channel) + { + mprintf((1, "OUT OF SOUND CHANNELS!!!\n")); + return -1; + } + } + if (SoundSlots[next_channel].playing) + { + SoundSlots[next_channel].playing = 0; + if (SoundSlots[next_channel].soundobj > -1) + { + digi_end_soundobj(SoundSlots[next_channel].soundobj); + } + if (SoundQ_channel == next_channel) + SoundQ_end(); + } + +#ifndef NDEBUG + verify_sound_channel_free(next_channel); +#endif + + SoundSlots[next_channel].soundno = soundnum; + SoundSlots[next_channel].samples = GameSounds[soundnum].data; + SoundSlots[next_channel].length = GameSounds[soundnum].length; + SoundSlots[next_channel].volume = fixmul(digi_volume, volume); + SoundSlots[next_channel].pan = pan; + SoundSlots[next_channel].position = 0; + SoundSlots[next_channel].looped = looping; + SoundSlots[next_channel].playing = 1; + SoundSlots[next_channel].soundobj = soundobj; + SoundSlots[next_channel].persistent = 0; + if ((soundobj > -1) || (looping) || (volume > F1_0)) + SoundSlots[next_channel].persistent = 1; + + i = next_channel; + next_channel++; + if (next_channel >= digi_max_channels) + next_channel = 0; + + return i; +} + +// Returns the channel a sound number is playing on, or +// -1 if none. +int digi_audio_find_channel(int soundno) +{ + if (!digi_initialised) + return -1; + + if (soundno < 0 ) + return -1; + + if (GameSounds[soundno].data == NULL) + { + Int3(); + return -1; + } + + //FIXME: not implemented + return -1; +} + + +//added on 980905 by adb from original source to make sfx volume work +void digi_audio_set_digi_volume( int dvolume ) +{ + dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff); + if ( dvolume > SOUND_MAX_VOLUME ) + digi_volume = SOUND_MAX_VOLUME; + else if ( dvolume < 0 ) + digi_volume = 0; + else + digi_volume = dvolume; + + if ( !digi_initialised ) return; + + digi_sync_sounds(); +} +//end edit by adb + +int digi_audio_is_sound_playing(int soundno) +{ + int i; + + soundno = digi_xlat_sound(soundno); + + for (i = 0; i < MAX_SOUND_SLOTS; i++) + //changed on 980905 by adb: added SoundSlots[i].playing && + if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno) + //end changes by adb + return 1; + return 0; +} + + + //added on 980905 by adb to make sound channel setting work +void digi_audio_set_max_channels(int n) { + digi_max_channels = n; + + if ( digi_max_channels < 1 ) + digi_max_channels = 1; + if (digi_max_channels > MAX_SOUND_SLOTS) + digi_max_channels = MAX_SOUND_SLOTS; + + if ( !digi_initialised ) return; + + digi_stop_all_channels(); +} + +int digi_audio_get_max_channels() { + return digi_max_channels; +} +// end edit by adb + +int digi_audio_is_channel_playing(int channel) +{ + if (!digi_initialised) + return 0; + + return SoundSlots[channel].playing; +} + +void digi_audio_set_channel_volume(int channel, int volume) +{ + if (!digi_initialised) + return; + + if (!SoundSlots[channel].playing) + return; + + SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0); +} + +void digi_audio_set_channel_pan(int channel, int pan) +{ + if (!digi_initialised) + return; + + if (!SoundSlots[channel].playing) + return; + + SoundSlots[channel].pan = pan; +} + +void digi_audio_stop_sound(int channel) +{ + SoundSlots[channel].playing=0; + SoundSlots[channel].soundobj = -1; + SoundSlots[channel].persistent = 0; +} + +void digi_audio_end_sound(int channel) +{ + if (!digi_initialised) + return; + + if (!SoundSlots[channel].playing) + return; + + SoundSlots[channel].soundobj = -1; + SoundSlots[channel].persistent = 0; +} + + +#ifndef _WIN32 +// MIDI stuff follows. +void digi_audio_set_midi_volume( int mvolume ) { } +void digi_audio_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) {} + +void digi_audio_stop_current_song() +{ +#ifdef HMIPLAY + char buf[10]; + + sprintf(buf,"s"); + send_ipc(buf); +#endif +} +void digi_audio_pause_midi() {} +void digi_audio_resume_midi() {} +#endif + +#ifndef NDEBUG +void digi_audio_debug() +{ + int i; + int n_voices = 0; + + if (!digi_initialised) + return; + + for (i = 0; i < digi_max_channels; i++) + { + if (digi_is_channel_playing(i)) + n_voices++; + } + + mprintf_at((0, 2, 0, "DIGI: Active Sound Channels: %d/%d (HMI says %d/32) ", n_voices, digi_max_channels, -1)); + //mprintf_at((0, 3, 0, "DIGI: Number locked sounds: %d ", digi_total_locks )); +} +#endif diff --git a/arch/sdl/mixdigi.c b/arch/sdl/digi_mixer.c similarity index 60% rename from arch/sdl/mixdigi.c rename to arch/sdl/digi_mixer.c index ca7b81361..a98e5be25 100644 --- a/arch/sdl/mixdigi.c +++ b/arch/sdl/digi_mixer.c @@ -20,27 +20,23 @@ #include #include -#include "mixmusic.h" +#include "pstypes.h" #include "error.h" #include "mono.h" +#include "sounds.h" +#include "digi.h" +#include "digi_mixer.h" +#include "digi_mixer_music.h" +#include "jukebox.h" + #include "fix.h" #include "gr.h" // needed for piggy.h #include "piggy.h" -#include "digi.h" -#include "sounds.h" -#include "wall.h" -#include "newdemo.h" -#include "kconfig.h" #define MIX_DIGI_DEBUG 0 - -#define MIX_OUTPUT_FREQUENCY 44100 // in 2006, we can afford it! #define MIX_OUTPUT_FORMAT AUDIO_S16 #define MIX_OUTPUT_CHANNELS 2 -//MD2211 - added 2006/12/12 to correctly remember music volume -static int midi_volume = F1_0; - //edited 05/17/99 Matt Mueller - added ifndef NO_ASM //added on 980905 by adb to add inline fixmul for mixer on i386 #ifndef NO_ASM @@ -60,26 +56,22 @@ extern inline fix fixmul(fix x, fix y) { return do_fixmul(x,y); } //end edit -MM #define MAX_SOUND_SLOTS 64 -#define SOUND_BUFFER_SIZE 2048 -#define MIN_VOLUME 0 - -//added/changed on 980905 by adb to make sfx volume work, on 990221 by adb changed F1_0 to F1_0 / 2 -#define SOUND_MAX_VOLUME (F1_0 / 2) -int digi_volume = SOUND_MAX_VOLUME; -//end edit by adb +#define SOUND_BUFFER_SIZE 4096 +#define MIN_VOLUME 10 static int digi_initialised = 0; static int digi_max_channels = MAX_SOUND_SLOTS; inline int fix2byte(fix f) { return (f / 256) % 256; } Mix_Chunk SoundChunks[MAX_SOUNDS]; - /* Initialise audio */ -int digi_init() { +int digi_mixer_init() { + digi_sample_rate = SAMPLE_RATE_44K; + if (MIX_DIGI_DEBUG) printf("digi_init %d (SDL_Mixer)\n", MAX_SOUNDS); if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) Error("SDL audio initialisation failed: %s.", SDL_GetError()); - if (Mix_OpenAudio(MIX_OUTPUT_FREQUENCY, MIX_OUTPUT_FORMAT, MIX_OUTPUT_CHANNELS, SOUND_BUFFER_SIZE)) { + if (Mix_OpenAudio(digi_sample_rate, MIX_OUTPUT_FORMAT, MIX_OUTPUT_CHANNELS, SOUND_BUFFER_SIZE)) { //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound. printf("\nError: Couldn't open audio: %s\n", SDL_GetError()); return 1; @@ -88,13 +80,18 @@ int digi_init() { Mix_AllocateChannels(digi_max_channels); Mix_Pause(0); + // Attempt to load jukebox + jukebox_load(); + //jukebox_list(); + atexit(digi_close); digi_initialised = 1; + return 0; } /* Shut down audio */ -void digi_close() { +void digi_mixer_close() { if (!digi_initialised) return; digi_initialised = 0; Mix_CloseAudio(); @@ -109,14 +106,14 @@ void mixdigi_convert_sound(int i) { SDL_AudioCVT cvt; Uint8 *data = GameSounds[i].data; Uint32 dlen = GameSounds[i].length; - int freq = GameArg.SndDigiSampleRate; //FIXME: assuming 22 KHz for now, but Descent 2 supports multiple sampling rates + int freq = GameArg.SndDigiSampleRate; //int bits = GameSounds[i].bits; if (SoundChunks[i].abuf) return; //proceed only if not converted yet if (data) { if (MIX_DIGI_DEBUG) printf("converting %d (%d)\n", i, dlen); - SDL_BuildAudioCVT(&cvt, AUDIO_U8, 1, freq, MIX_OUTPUT_FORMAT, MIX_OUTPUT_CHANNELS, MIX_OUTPUT_FREQUENCY); + SDL_BuildAudioCVT(&cvt, AUDIO_U8, 1, freq, MIX_OUTPUT_FORMAT, MIX_OUTPUT_CHANNELS, digi_sample_rate); cvt.buf = malloc(dlen * cvt.len_mult); cvt.len = dlen; @@ -126,12 +123,12 @@ void mixdigi_convert_sound(int i) { SoundChunks[i].abuf = cvt.buf; SoundChunks[i].alen = dlen * cvt.len_mult; SoundChunks[i].allocated = 1; - SoundChunks[i].volume = 128; // Max volume (SDL) = 128 + SoundChunks[i].volume = 128; // Max volume = 128 } } // Volume 0-F1_0 -int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj) +int digi_mixer_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj) { if (!digi_initialised) return -1; Assert(GameSounds[soundnum].data != (void *)-1); @@ -151,94 +148,87 @@ int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_ return channel; } -void digi_set_channel_volume(int channel, int volume) { - if (MIX_DIGI_DEBUG) printf("digi_set_channel_volume %d %d\n", channel, volume); +void digi_mixer_set_channel_volume(int channel, int volume) { + if (!digi_initialised) return; int mix_vol = fix2byte(volume); Mix_SetDistance(channel, 255-mix_vol); } -void digi_set_channel_pan(int channel, int pan) { +void digi_mixer_set_channel_pan(int channel, int pan) { int mix_pan = fix2byte(pan); Mix_SetPanning(channel, 255-mix_pan, mix_pan); } -void digi_stop_sound(int channel) { +void digi_mixer_stop_sound(int channel) { + if (!digi_initialised) return; if (MIX_DIGI_DEBUG) printf("digi_stop_sound %d\n", channel); Mix_HaltChannel(channel); } -void digi_end_sound(int channel) { - digi_stop_sound(channel); +void digi_mixer_end_sound(int channel) { + digi_mixer_stop_sound(channel); } -void digi_set_digi_volume( int dvolume ) +void digi_mixer_set_digi_volume( int dvolume ) { + digi_volume = dvolume; if (!digi_initialised) return; - if (MIX_DIGI_DEBUG) printf("digi_set_digi_volume %d\n", dvolume); - int mix_vol = fix2byte(dvolume); - Mix_Volume(-1, mix_vol); + Mix_Volume(-1, fix2byte(dvolume)); } -//added on 980905 by adb from original source to make sfx volume work -/* -void digi_set_digi_volume( int dvolume ) -{ - dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff); - if ( dvolume > SOUND_MAX_VOLUME ) - digi_volume = SOUND_MAX_VOLUME; - else if ( dvolume < 0 ) - digi_volume = 0; - else - digi_volume = dvolume; - - if ( !digi_initialised ) return; - - digi_sync_sounds(); -} -*/ -//end edit by adb - -void digi_set_volume( int dvolume, int mvolume ) { - if (MIX_DIGI_DEBUG) printf("digi_set_volume %d %d\n", dvolume, mvolume); - digi_set_digi_volume(dvolume); - digi_set_midi_volume(mvolume); +void digi_mixer_set_midi_volume( int mvolume ) { + midi_volume = mvolume; + if (!digi_initialised) return; + mix_set_music_volume(mvolume); } -int digi_find_channel(int soundno) { return 0; } -int digi_is_sound_playing(int soundno) { return 0; } -int digi_is_channel_playing(int channel) { return 0; } -void digi_reset() {} -void digi_stop_all_channels() {} +void digi_mixer_set_volume( int dvolume, int mvolume ) { + digi_mixer_set_digi_volume(dvolume); + digi_mixer_set_midi_volume(mvolume); +} + + +int digi_mixer_find_channel(int soundno) { return 0; } +int digi_mixer_is_sound_playing(int soundno) { return 0; } +int digi_mixer_is_channel_playing(int channel) { return 0; } + +void digi_mixer_reset() {} +void digi_mixer_stop_all_channels() {} extern void digi_end_soundobj(int channel); int verify_sound_channel_free(int channel); //added on 980905 by adb to make sound channel setting work -void digi_set_max_channels(int n) { digi_max_channels = n; } -int digi_get_max_channels() { return digi_max_channels; } +void digi_mixer_set_max_channels(int n) { } +int digi_mixer_get_max_channels() { return digi_max_channels; } // end edit by adb // MIDI stuff follows. #ifndef _WIN32 -void digi_set_midi_volume( int mvolume ) { - midi_volume = mvolume; - mix_set_music_volume(mvolume); -} -void digi_play_midi_song( char * filename, char * melodic_bank, char * drum_bank, int loop ) { + +void digi_mixer_play_midi_song(char * filename, char * melodic_bank, char * drum_bank, int loop ) { mix_set_music_volume(midi_volume); - mix_play_music(filename, loop); + + // quick hack to check if filename begins with "game" -- MD2211 + if (jukebox_is_loaded() && strstr(filename, "game") == filename) { + // use jukebox + jukebox_play(); + } + else { + // standard song playback + mix_play_music(filename, loop); + } } -void digi_stop_current_song() { - mix_stop_music(); +void digi_mixer_stop_current_song() { + jukebox_stop(); //stops jukebox as well as standard music } #endif -void digi_pause_midi() {} -void digi_resume_midi() {} +void digi_mixer_pause_midi() {} +void digi_mixer_resume_midi() {} #ifndef NDEBUG -void digi_debug() {} +void digi_mixer_debug() {} #endif - diff --git a/arch/sdl/mixmusic.c b/arch/sdl/digi_mixer_music.c similarity index 83% rename from arch/sdl/mixmusic.c rename to arch/sdl/digi_mixer_music.c index 46294ca1f..afb65b9a2 100644 --- a/arch/sdl/mixmusic.c +++ b/arch/sdl/digi_mixer_music.c @@ -66,6 +66,10 @@ void convert_hmp(char *filename, char *mid_filename) { } } +/* + * Plays a music given its name (regular game songs) + */ + void mix_play_music(char *filename, int loop) { loop *= -1; @@ -152,6 +156,33 @@ void mix_play_music(char *filename, int loop) { } } + +/* + * Plays a music file from an absolute path (used by jukebox) + */ + +void mix_play_file(char *basedir, char *filename, int loop) { + + int fn_buf_len = strlen(basedir) + strlen(filename) + 1; + char real_filename[fn_buf_len]; + sprintf(real_filename, "%s%s", basedir, filename); // build absolute path + + if ((current_music = Mix_LoadMUS(real_filename))) { + if (Mix_PlayingMusic()) { + // Fade-in effect sounds cleaner if we're already playing something + Mix_FadeInMusic(current_music, loop, MUSIC_FADE_TIME); + } + else { + Mix_PlayMusic(current_music, loop); + } + Mix_HookMusicFinished(music_done); + } + else { + fprintf(stderr, "Music %s could not be loaded%s\n", filename, basedir); + Mix_HaltMusic(); + } +} + void mix_set_music_volume(int vol) { printf("mix_set_music_volume %d\n", vol); Mix_VolumeMusic(vol); diff --git a/arch/sdl/jukebox.c b/arch/sdl/jukebox.c new file mode 100644 index 000000000..98888928b --- /dev/null +++ b/arch/sdl/jukebox.c @@ -0,0 +1,158 @@ +/* + * DXX Rebirth "jukebox" code + * MD 2211 , 2007 + */ + +#include +#include +#include +#include +#include +#include "args.h" +#include "dl_list.h" +#include "hudmsg.h" +#include "digi_mixer_music.h" +#include "jukebox.h" + +#define JUKEBOX_ARG "-jukebox" +#define MUSIC_HUDMSG_MAXLEN 40 +#define JUKEBOX_HUDMSG_PLAYING "Now playing:" +#define JUKEBOX_HUDMSG_STOPPED "Jukebox stopped" + +static int jukebox_loaded = 0; +static int jukebox_playing = 0; +static char *jukebox_path; +static dl_list *JukeboxSongs; +char hud_msg_buf[MUSIC_HUDMSG_MAXLEN+4]; + + +char *select_prev_song(dl_list *list) { + char *ret; + if (dl_is_empty(list)) { + ret = NULL; + } + else { + if (list->first == list->current) { + list->current = list->last; + } + else { + dl_backward(list); + } + ret = (char *) list->current->data; + } + return ret; +} + +char *select_next_song(dl_list *list) { + char *ret; + if (dl_is_empty(list)) { + ret = NULL; + } + else { + if (list->last == list->current) { + list->current = list->first; + } + else { + dl_forward(list); + } + ret = (char *) list->current->data; + } + return ret; +} + +/* Filter for scandir(); selects MP3 and OGG, files, rejects the rest */ +int file_select_all(const struct dirent *entry) { + char *fn = (char *) entry->d_name; + char *ext = strrchr(fn, '.'); + int ext_ok = (ext != NULL && (!strcmp(ext, ".mp3") || !strcmp(ext, ".ogg"))); + + return strcmp(fn, ".") && strcmp(entry->d_name, "..") && ext_ok; + +} + +/* Loads music file names from a given directory */ +void jukebox_load() { + int count, i, t; + struct dirent **files; + int (*file_select)(const struct dirent *) = file_select_all; + + if (!jukebox_loaded) { + t = FindArg(JUKEBOX_ARG); + if (t > 0) { + jukebox_path = Args[t+1]; + + JukeboxSongs = dl_init(); + count = scandir(jukebox_path, &files, file_select, alphasort); + + printf("Jukebox: %d music file(s) found in %s\n", count, jukebox_path); + + for (i=0; id_name); + + jukebox_loaded = 1; + } + } + else { printf("Jukebox already loaded\n"); } +} + +void jukebox_play() { + if (!jukebox_loaded) return; + char *music_filename = (char *) JukeboxSongs->current->data; + + mix_play_file(jukebox_path, music_filename, 0); + + // Formatting a pretty message + if (strlen(music_filename) >= MUSIC_HUDMSG_MAXLEN) { + strncpy(hud_msg_buf, music_filename, MUSIC_HUDMSG_MAXLEN); + strcpy(hud_msg_buf+MUSIC_HUDMSG_MAXLEN, "..."); + hud_msg_buf[MUSIC_HUDMSG_MAXLEN+3] = '\0'; + } else { + strcpy(hud_msg_buf, music_filename); + } + + hud_message(MSGC_GAME_FEEDBACK, "%s %s", JUKEBOX_HUDMSG_PLAYING, hud_msg_buf); + jukebox_playing = 1; +} + +void jukebox_stop() { + if (!jukebox_loaded) return; + mix_stop_music(); + hud_message(MSGC_GAME_FEEDBACK, JUKEBOX_HUDMSG_STOPPED); + jukebox_playing = 0; +} + +void jukebox_stop_hook() { + if (!jukebox_loaded) return; + if (jukebox_playing) jukebox_next(); +} + +void jukebox_next() { + if (!jukebox_loaded) return; + select_next_song(JukeboxSongs); + if (jukebox_playing) jukebox_play(); +} + +void jukebox_prev() { + if (!jukebox_loaded) return; + select_prev_song(JukeboxSongs); + if (jukebox_playing) jukebox_play(); +} + +char *jukebox_current() { + return JukeboxSongs->current->data; +} + +int jukebox_is_loaded() { return jukebox_loaded; } +int jukebox_is_playing() { return jukebox_playing; } + +void jukebox_list() { + dl_item *curr; + if (!jukebox_loaded) return; + if (dl_is_empty(JukeboxSongs)) { + printf("* No songs have been found\n"); + } + else { + for (curr = JukeboxSongs->first; curr != NULL; curr = curr->next) { + printf("* %s\n", (char *) curr->data); + } + } +} diff --git a/include/args.h b/include/args.h index 453660372..aabbb6750 100755 --- a/include/args.h +++ b/include/args.h @@ -62,6 +62,9 @@ typedef struct Arg int SndNoMusic; int SndDigiSampleRate; int SndEnableRedbook; + int SndSdlMixer; + char *SndExternalMusic; + char *SndJukebox; float GfxAspectX; float GfxAspectY; int GfxGaugeHudMode; diff --git a/include/dl_list.h b/include/dl_list.h new file mode 100644 index 000000000..b8372516f --- /dev/null +++ b/include/dl_list.h @@ -0,0 +1,30 @@ +/* + * Doubly-linked list implementation + * MD 2211 , 2007 + */ + +#ifndef __DL_LIST__ +#define __DL_LIST__ + +struct dl_list_elem { + void *data; + struct dl_list_elem *prev; + struct dl_list_elem *next; +}; + +typedef struct dl_list_elem dl_item; + +typedef struct { + struct dl_list_elem *first; + struct dl_list_elem *last; + struct dl_list_elem *current; +} dl_list; + +dl_list *dl_init(); +void dl_add(dl_list *, void *); +void dl_remove(dl_list *, dl_item *); +int dl_is_empty(dl_list *); +int dl_forward(dl_list *); +int dl_backward(dl_list *); + +#endif diff --git a/main/digi.h b/main/digi.h index 0f923c4ef..001ba6761 100755 --- a/main/digi.h +++ b/main/digi.h @@ -42,9 +42,6 @@ typedef struct digi_sound { } digi_sound; #endif -#define SAMPLE_RATE_11K 11025 -#define SAMPLE_RATE_22K 22050 - #ifdef __DJGPP__ @@ -125,4 +122,20 @@ extern void digi_stop_looping_sound(); // Plays a queued voice sound. extern void digi_start_sound_queued( short soundnum, fix volume ); +// Following declarations are for the runtime switching system + +#define SAMPLE_RATE_11K 11025 +#define SAMPLE_RATE_22K 22050 +#define SAMPLE_RATE_44K 44100 + +#define SDLMIXER_SYSTEM 1 +#define SDLAUDIO_SYSTEM 2 + +#define SOUND_MAX_VOLUME F1_0 // was (F1_0 / 2) + +extern int digi_volume; +extern int midi_volume; +extern int digi_sample_rate; +void digi_select_system(int); + #endif diff --git a/main/gamecntl.c b/main/gamecntl.c index 97874fb87..b41bf1d26 100755 --- a/main/gamecntl.c +++ b/main/gamecntl.c @@ -99,6 +99,8 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #include "rbaudio.h" #include "switch.h" #include "escort.h" +//MD2211 +#include "jukebox.h" //#define TEST_TIMER 1 //if this is set, do checking on timer @@ -1259,6 +1261,27 @@ int HandleSystemKey(int key) break; #endif + +#ifdef USE_SDLMIXER + /* + * Jukebox hotkeys -- MD2211, 2007 + * ============================================== + */ + case KEY_ALTED + KEY_SHIFTED + KEY_F9: + jukebox_play(); + break; + case KEY_ALTED + KEY_SHIFTED + KEY_F10: + jukebox_stop(); + break; + case KEY_ALTED + KEY_SHIFTED + KEY_F11: + jukebox_prev(); + break; + case KEY_ALTED + KEY_SHIFTED + KEY_F12: + jukebox_next(); + break; +#endif + + //added 8/23/99 by Matt Mueller for hot key res/fullscreen changing, and menu access #if 0 case KEY_CTRLED+KEY_SHIFTED+KEY_PADMULTIPLY: diff --git a/main/inferno.c b/main/inferno.c index af9036df3..005cfac92 100755 --- a/main/inferno.c +++ b/main/inferno.c @@ -354,8 +354,15 @@ int main(int argc, char *argv[]) key_init(); - if (!GameArg.SndNoSound) + if (!GameArg.SndNoSound) { + digi_select_system( + GameArg.SndSdlMixer || GameArg.SndExternalMusic || GameArg.SndJukebox ? + SDLMIXER_SYSTEM : SDLAUDIO_SYSTEM + ); digi_init(); + } + + printf("trace 2\n"); if (!GameArg.CtlNoMouse) d_mouse_init(); @@ -395,13 +402,19 @@ int main(int argc, char *argv[]) con_printf(CON_DEBUG, "Initializing font system...\n" ); gamefont_init(); // must load after palette data loaded. + printf("trace 3\n"); + con_printf( CON_DEBUG, "Initializing movie libraries...\n" ); init_movies(); //init movie libraries + printf("trace 4\n"); + show_titles(); set_screen_mode(SCREEN_MENU); + printf("trace 5\n"); + con_printf( CON_DEBUG , "\nDoing bm_init..." ); #ifdef EDITOR if (!bm_init_use_tbl()) diff --git a/misc/args.c b/misc/args.c index cae29f9ca..39c444999 100755 --- a/misc/args.c +++ b/misc/args.c @@ -235,6 +235,12 @@ void ReadCmdArgs(void) else GameArg.SndEnableRedbook = 0; +#ifdef USE_SDLMIXER + GameArg.SndSdlMixer = FindArg("-sdlmixer"); + GameArg.SndJukebox = (t = FindArg("-jukebox") ? Args[t+1] : NULL); + GameArg.SndExternalMusic = (t = FindArg("-music_ext") ? Args[t+1] : NULL); +#endif + // Graphics Options if ((t=FindResArg("aspect", &y, &x))) diff --git a/misc/dl_list.c b/misc/dl_list.c new file mode 100644 index 000000000..b24ef1c4f --- /dev/null +++ b/misc/dl_list.c @@ -0,0 +1,64 @@ +/* + * Doubly-linked list implementation with position marker + * MD 2211 , 2007 + */ + +#include +#include "dl_list.h" + +dl_list *dl_init() { + dl_list *list = malloc(sizeof(dl_list)); + list->first = NULL; + list->last = NULL; + list->current = NULL; + return list; +} + +void dl_add(dl_list *list, void *data) { + dl_item *item; + item = malloc(sizeof(dl_item)); + item->data = data; + item->prev = list->last; + item->next = NULL; + + if (list->last != NULL) { + list->last->next = item; + } + if (list->first == NULL) { + list->first = item; + list->current = item; + } + list->last = item; +} + +void dl_remove(dl_list *list, dl_item *item) { + if (list->current == item) list->current = item->prev; + + if (list->first == item) list->first = item->next; + else item->prev->next = item->next; + + if (list->last == item) list->last = item->prev; + else item->next->prev = item->prev; + + free(item); +} + +int dl_is_empty(dl_list *list) { + return (list->first == NULL); +} + +int dl_forward(dl_list *list) { + if (!dl_is_empty(list) && list->current->next != NULL) { + list->current = list->current->next; + return 1; + } + else return 0; +} + +int dl_backward(dl_list *list) { + if (!dl_is_empty(list) && list->current->prev != NULL) { + list->current = list->current->prev; + return 1; + } + else return 0; +}