diff --git a/src/include/sound_server.h b/src/include/sound_server.h index 6407bfb7a..552b8f7b0 100644 --- a/src/include/sound_server.h +++ b/src/include/sound_server.h @@ -173,10 +173,6 @@ extern unsigned AllocatedSoundMemory; extern unsigned CompressedSoundMemory; #endif -#ifdef USE_SDLCD - /// SDL cdrom device -extern SDL_CD *CDRom; -#endif #if defined(USE_SDLCD) || defined(USE_LIBCDA) /// cd play mode, ":off" ":random" or ":all" extern char *CDMode; @@ -192,6 +188,11 @@ extern int NumCDTracks; -- Functions ----------------------------------------------------------------------------*/ +extern Sample* LoadFlac(const char* name); /// Load a flac file +extern Sample* LoadWav(const char* name); /// Load a wav file +extern Sample* LoadOgg(const char* name); /// Load a ogg file +extern Sample* LoadMp3(const char* name); /// Load a mp3 file + /// Register a sound (can be a simple sound or a group) extern SoundId RegisterSound(char* file[],unsigned number); diff --git a/src/sound/Makefile b/src/sound/Makefile index 105ad13c2..ba9439d04 100644 --- a/src/sound/Makefile +++ b/src/sound/Makefile @@ -33,7 +33,7 @@ MODULE = sound HDRS = libcda.h -SRCS = sound.c sound_server.c ccl_sound.c sound_id.c \ +SRCS = sound.c sound_server.c ccl_sound.c sound_id.c music.c \ mad.c ogg.c flac.c wav.c unitsound.c libcda.c oss_audio.c sdl_audio.c OBJS = $(addprefix $(OBJDIR), $(SRCS:.c=.$(OE))) diff --git a/src/sound/mad.cpp b/src/sound/mad.cpp index 50b22f6d2..04614fa3d 100644 --- a/src/sound/mad.cpp +++ b/src/sound/mad.cpp @@ -35,6 +35,7 @@ #if defined(WITH_SOUND) && defined(USE_MAD) // { #include <stdlib.h> +#include <memory.h> #include "mad.h" #include "iolib.h" @@ -50,7 +51,7 @@ typedef struct _my_user_ { CLFile* File; // File handle Sample* Sample; // Sample buffer - char Buffer[4096]; // Decoded buffer + unsigned char Buffer[4096]; // Decoded buffer } MyUser; /*---------------------------------------------------------------------------- @@ -68,6 +69,7 @@ typedef struct _my_user_ { local enum mad_flow MAD_read(void *user, struct mad_stream *stream) { int i; + int l; CLFile *f; MyUser *u; @@ -76,13 +78,21 @@ local enum mad_flow MAD_read(void *user, struct mad_stream *stream) u = (MyUser *) user; f = u->File; - if ((i = CLread(f, u->Buffer, sizeof(u->Buffer))) != sizeof(u->Buffer)) { - if (!i) { - return MAD_FLOW_STOP; - } + l = 0; + // Copy remaining bytes over + if (stream->next_frame) { + memmove(u->Buffer, stream->next_frame, + l = &u->Buffer[sizeof(u->Buffer)] - stream->next_frame); } - DebugLevel3Fn("%d bytes\n", i); - mad_stream_buffer(stream, u->Buffer, i); + + i = CLread(f, u->Buffer + l, sizeof(u->Buffer) - l); + //if (!(l + i)) { + if (!i) { + return MAD_FLOW_STOP; + } + DebugLevel3Fn("%d bytes\n", l + i); + mad_stream_buffer(stream, u->Buffer, l + i); + return MAD_FLOW_CONTINUE; } diff --git a/src/sound/music.cpp b/src/sound/music.cpp new file mode 100644 index 000000000..29da59afc --- /dev/null +++ b/src/sound/music.cpp @@ -0,0 +1,355 @@ +// ___________ _________ _____ __ +// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_ +// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\ +// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | | +// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__| +// \/ \/ \/ \/ \/ +// ______________________ ______________________ +// T H E W A R B E G I N S +// FreeCraft - A free fantasy real time strategy game engine +// +/**@name music.c - Background music support */ +// +// (c) Copyright 2002 by Lutz Sammer +// +// FreeCraft is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation; only version 2 of the License. +// +// FreeCraft is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// $Id$ + +//@{ + +/*---------------------------------------------------------------------------- +-- Includes +----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include "freecraft.h" + +#if defined(WITH_SOUND) // { + +#include <stdlib.h> +#include <string.h> + +#ifdef USE_LIBMODPLUG +#include "../libmodplug/modplug.h" +#endif + +#ifdef USE_LIBCDA +#include "libcda.h" +#endif + +#ifdef USE_SDLCD +#include <SDL.h> +#endif + +#include "iolib.h" +#include "sound.h" +#include "sound_server.h" + +/*---------------------------------------------------------------------------- +-- Declaration +----------------------------------------------------------------------------*/ + +#define SoundFrequency 44100 // sample rate of dsp + +/*---------------------------------------------------------------------------- +-- Variables +----------------------------------------------------------------------------*/ + +#ifdef USE_LIBMODPLUG +global ModPlugFile* ModFile; /// Mod file loaded into memory +#endif +#if defined(USE_OGG) || defined(USE_FLAC) || defined(USE_MAD) +global Sample* MusicSample; /// Music samples +global int MusicIndex; /// Music sample index +#endif +#if defined(USE_SDLCD) || defined(USE_LIBCDA) +global char *CDMode = ":off"; /// cd play mode, ":off" ":random" or ":all" +global int CDTrack; /// Current cd track +#endif +#ifdef USE_SDLCD +global SDL_CD *CDRom; /// SDL cdrom device +#endif +#ifdef USE_LIBCDA +global int NumCDTracks; /// Number of tracks on the cd +#endif + +/*---------------------------------------------------------------------------- +-- Functions +----------------------------------------------------------------------------*/ + +/** +** Stop the current playing music. +** +** @todo FIXME: Stop the CD-PLAYER. +*/ +global void StopMusic(void) +{ + if (PlayingMusic) { + PlayingMusic = 0; // Callback! +#ifdef USE_LIBMODPLUG + if (ModFile) { + ModPlug_Unload(ModFile); + ModFile = NULL; + return; + } +#endif +#if defined(USE_OGG) || defined(USE_FLAC) || defined(USE_MAD) + if (MusicSample) { + free(MusicSample); + MusicSample = NULL; + MusicIndex = 0; + return; + } +#endif + } +} + +#ifdef USE_LIBMODPLUG +/** +** Load a mod file. +*/ +local int LoadMod(const char* name) +{ + ModPlug_Settings settings; + CLFile* f; + char* buffer; + int size; + int i; + + ModPlug_GetSettings(&settings); + settings.mFrequency=SoundFrequency; +#ifdef USE_LIBMODPLUG32 + settings.mBits=32; +#else + settings.mBits=16; +#endif + settings.mLoopCount=0; // Disable looping + ModPlug_SetSettings(&settings); + + buffer=malloc(8192); + DebugLevel2Fn("Loading `%s'\n",name); + + if( !(f=CLopen(name)) ) { + printf("Can't open file `%s'\n",name); + return 0; + } + + size=0; + while( (i=CLread(f,buffer+size,8192))==8192 ) { + size+=8192; + buffer=realloc(buffer,size+8192); + } + size+=i; + buffer=realloc(buffer,size); + DebugLevel3Fn("%d\n",size); + + StopMusic(); // stop music before new music + + ModFile=ModPlug_Load(buffer,size); + + free(buffer); + + if( ModFile ) { + DebugLevel0Fn("Started\n"); + PlayingMusic=1; + return 1; + } + + return 0; +} +#endif + +#ifdef USE_SDLCD +/** +** Play music from cdrom. +** +** :all :random :off +** +** @param name Name starting with ":". +*/ +local int PlayCDRom(const char* name) +{ + // Old mode off, starting cdrom play. + if (!strcmp(CDMode, ":off")) { + if (!strncmp(name, ":", 1)) { + StopMusic(); // stop music before new music + SDL_Init(SDL_INIT_CDROM); + CDRom = SDL_CDOpen(0); + SDL_CDStatus(CDRom); + } + } + // CDPlayer command? + if (!strncmp(name, ":", 1)) { + if (!CDRom) { + fprintf(stderr, "Couldn't open cdrom drive: %s\n", SDL_GetError()); + return 1; + } + // if mode is play all tracks + if (!strcmp(name, ":all")) { + CDMode = ":all"; + SDL_CDPlayTracks(CDRom, 0, 0, 0, 0); + return 1; + } + // if mode is play random tracks + if (!strcmp(name, ":random")) { + CDMode = ":random"; + CDTrack = MyRand() % CDRom->numtracks; + SDL_CDPlayTracks(CDRom, CDTrack, 0, 0, 0); + } + CDMode = ":off"; + return 1; + } + + // FIXME: no cdrom, must stop it now! + + return 0; +} +#endif + +#ifdef USE_LIBCDA +/** +** Play music from cdrom. +** +** :all :random :off +** +** @param name Name starting with ":". +*/ +local int PlayCDRom(const char* name) +{ + if (!strcmp(CDMode, ":off")) { + if (!strncmp(name, ":", 1)) { + if (cd_init() < 0) { + fprintf(stderr, "Error initialising libcda \n"); + return 1; + } + cd_get_tracks(&CDTrack, &NumCDTracks); + if (NumCDTracks == 0) { + return 1; + } + --CDTrack; + } + } + + if (!strncmp(name, ":", 1)) { + + // if mode is play all tracks + if (!strcmp(name, ":all")) { + CDMode = ":all"; + do { + if (CDTrack > NumCDTracks) + CDTrack = 1; + } while (cd_is_audio(++CDTrack) < 1); + cd_play(CDTrack); + return 1; + } + // if mode is play random tracks + if (!strcmp(name, ":random")) { + CDMode = ":random"; + do { + CDTrack = MyRand() % NumCDTracks; + } while (cd_is_audio(CDTrack) < 1); + cd_play(CDTrack); + return 1; + } + CDMode = ":off"; + return 1; + } + + // FIXME: no cdrom, must stop it now! + + return 0; +} +#endif + +/** +** Play a music file. +** Currently supported are .mod, .it, .s3m, .wav, .xm. +** Optional .ogg, mp3 and cdrom. +** +** Some quick hacks for mods. +** +** @param name Name of sound file, format is automatic detected. +** Names starting with ':' control the cdrom. +*/ +global void PlayMusic(const char* name) +{ + char buffer[1024]; + Sample *sample; + +#ifdef USE_SDLCD + if (PlayCDRom(name)) { + return; + } +#endif +#ifdef USE_LIBCDA + if (PlayCDRom(name)) { + return; + } +#endif + name = LibraryFileName(name, buffer); +#ifdef USE_OGG + if ((sample = LoadOgg(name))) { + if( sample->Channels!=2 + || sample->SampleSize!=16 + || sample->Frequency!=SoundFrequency ) { + DebugLevel0Fn("Not supported music format\n"); + free(sample); + return; + } + StopMusic(); + MusicSample = sample; + MusicIndex = 0; + PlayingMusic = 1; + return; + } +#endif +#ifdef USE_MAD + if ((sample = LoadMp3(name))) { + if( sample->Channels!=2 + || sample->SampleSize!=16 + || sample->Frequency!=SoundFrequency ) { + DebugLevel0Fn("Not supported music format\n"); + free(sample); + return; + } + StopMusic(); + MusicSample = sample; + MusicIndex = 0; + PlayingMusic = 1; + return; + } +#endif +#ifdef USE_FLAC + if ((sample = LoadFlac(name))) { + if( sample->Channels!=2 + || sample->SampleSize!=16 + || sample->Frequency!=SoundFrequency ) { + DebugLevel0Fn("Not supported music format\n"); + free(sample); + return; + } + StopMusic(); + MusicSample = sample; + MusicIndex = 0; + PlayingMusic = 1; + return; + } +#endif +#ifdef USE_LIBMODPLUG + if (LoadMod(name)) { + return; + } +#endif +} + +#endif // } WITH_SOUND + +//@} diff --git a/src/sound/sound_server.cpp b/src/sound/sound_server.cpp index 570896d18..3d849545e 100644 --- a/src/sound/sound_server.cpp +++ b/src/sound/sound_server.cpp @@ -93,11 +93,6 @@ #include <SDL.h> #endif -extern Sample* LoadFlac(const char* name); /// Load a flac file -extern Sample* LoadWav(const char* name); /// Load a wav file -extern Sample* LoadOgg(const char* name); /// Load a ogg file -extern Sample* LoadMp3(const char* name); /// Load a mp3 file - /*---------------------------------------------------------------------------- -- Defines ----------------------------------------------------------------------------*/ @@ -141,165 +136,21 @@ global int WithSoundThread; /// FIXME: docu global int SoundThreadRunning; /// FIXME: docu #ifdef USE_SDLCD -global SDL_CD *CDRom; -#endif -#if defined(USE_SDLCD) || defined(USE_LIBCDA) -global char *CDMode = ":off"; -global int CDTrack; -#endif -#ifdef USE_LIBCDA -global int NumCDTracks; +global SDL_CD *CDRom; /// SDL cdrom device #endif /*---------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------*/ -#ifdef USE_LIBMODPLUG -local ModPlugFile* ModFile; /// Mod file loaded into memory - -/** -** Play a music file. Currently supported are .mod, .it, .s3m, .wav, .xm. -** -** Some quick hacks for mods. -** -** @param name Name of sound file, format is automatic detected. -*/ -global void PlayMusic(const char* name) -{ - ModPlug_Settings settings; - CLFile* f; - char* buffer; - int size; - int i; - - ModPlug_GetSettings(&settings); - settings.mFrequency=SoundFrequency; -#ifdef USE_LIBMODPLUG32 - settings.mBits=32; -#else - settings.mBits=16; +#if defined(USE_OGG) || defined(USE_FLAC) || defined(USE_MAD) +extern Sample* MusicSample; /// Music samples +extern int MusicIndex; /// Music sample index #endif - settings.mLoopCount=0; // Disable looping - ModPlug_SetSettings(&settings); - -#ifdef USE_SDLCD - if (!strcmp(CDMode,":off")) { - if (!strncmp(name,":",1)) { - SDL_Init(SDL_INIT_CDROM); - CDRom = SDL_CDOpen(0); - SDL_CDStatus(CDRom); - } - } - - if (!strncmp(name,":",1)) { - if (!CDRom) { - fprintf(stderr, "Couldn't open cdrom drive: %s\n", SDL_GetError()); - return; - } +#if defined(USE_OGG) || defined(USE_FLAC) || defined(USE_MAD) || defined(USE_LIBMODPLUG) - // if mode is play all tracks - if (!strcmp(name, ":all")) { - CDMode = ":all"; - SDL_CDPlayTracks(CDRom, 0, 0, 0, 0); - return; - } - - // if mode is play random tracks - if (!strcmp(name, ":random")) { - CDMode = ":random"; - CDTrack = MyRand() % CDRom->numtracks; - SDL_CDPlayTracks(CDRom, CDTrack, 0, 0, 0); - return; - } - return; - } -#endif - -#ifdef USE_LIBCDA - if (!strcmp(CDMode,":off")) { - if (!strncmp(name,":",1)) { - if (cd_init() < 0) { - fprintf(stderr,"Error initialising libcda \n"); - return; - } - cd_get_tracks(&CDTrack, &NumCDTracks); - if (NumCDTracks == 0) - return; - --CDTrack; - } - } - - if (!strncmp(name,":",1)) { - - // if mode is play all tracks - if (!strcmp(name, ":all")) { - CDMode = ":all"; - do { - if (CDTrack > NumCDTracks) - CDTrack = 1; - } while (cd_is_audio(++CDTrack) < 1); - cd_play(CDTrack); - return; - } - - // if mode is play random tracks - if (!strcmp(name, ":random")) { - CDMode = ":random"; - do { - CDTrack = MyRand() % NumCDTracks; - } while (cd_is_audio(CDTrack) < 1); - cd_play(CDTrack); - return; - } - } -#endif - - buffer=malloc(8192); - name=LibraryFileName(name,buffer); - - DebugLevel2Fn("Loading `%s'\n",name); - - if( !(f=CLopen(name)) ) { - printf("Can't open file `%s'\n",name); - return; - } - - size=0; - while( (i=CLread(f,buffer+size,8192))==8192 ) { - size+=8192; - buffer=realloc(buffer,size+8192); - } - size+=i; - buffer=realloc(buffer,size); - DebugLevel0Fn("%d\n",size); - - StopMusic(); // stop music before new music - - ModFile=ModPlug_Load(buffer,size); - - free(buffer); - - if( ModFile ) { - DebugLevel0Fn("Started\n"); - PlayingMusic=1; - } -} - -/** -** Stop the current playing music. -*/ -global void StopMusic(void) -{ - if( PlayingMusic ) { - PlayingMusic=0; // Callback! - if( ModFile ) { - ModPlug_Unload(ModFile); - ModFile=NULL; - } - } -} +extern ModPlugFile* ModFile; /// Mod file loaded into memory /** ** Mix music to stereo 32 bit. @@ -307,49 +158,72 @@ global void StopMusic(void) ** @param buffer Buffer for mixed samples. ** @param size Number of samples that fits into buffer. */ -local void MixMusicToStereo32(int* buffer,int size) +local void MixMusicToStereo32(int* buffer, int size) { -#ifdef USE_LIBMODPLUG32 - long* buf; -#else - short* buf; -#endif int i; int n; - - if( PlayingMusic ) { - DebugCheck( !ModFile ); - - buf=alloca(size*sizeof(*buf)); - - n=ModPlug_Read(ModFile,buf,size*sizeof(*buf)); - - for( i=0; i<n/sizeof(*buf); ++i ) { // Add to our samples + if (PlayingMusic) { + n = 0; +#ifdef USE_LIBMODPLUG + if (ModFile) { #ifdef USE_LIBMODPLUG32 - buffer[i]+=((buf[i]>>16)*MusicVolume)/256; + long *buf; #else - buffer[i]+=(buf[i]*MusicVolume)/256; + short *buf; #endif - } + buf = alloca(size * sizeof(*buf)); - if( n!=size*sizeof(*buf) ) { // End reached - SCM cb; + n = ModPlug_Read(ModFile, buf, size * sizeof(*buf)); - DebugLevel2Fn("End of music %d\n",i); - PlayingMusic=0; - if( ModFile ) { - ModPlug_Unload(ModFile); + for (i = 0; i < n / sizeof(*buf); ++i) { // Add to our samples +#ifdef USE_LIBMODPLUG32 + buffer[i] += ((buf[i] >> 16) * MusicVolume) / 256; +#else + buffer[i] += (buf[i] * MusicVolume) / 256; +#endif } - if( CallbackMusic ) { - cb=gh_symbol2scm("music-stopped"); - if( !gh_null_p(symbol_boundp(cb,NIL)) ) { + n = n != size * sizeof(*buf); // End reached? + } +#endif +#if defined(USE_OGG) || defined(USE_FLAC) || defined(USE_MAD) + if (MusicSample) { + short *buf; + + buf = (short *)(MusicSample->Data + MusicIndex); + if (size * 2 > MusicSample->Length - MusicIndex) { + n = MusicSample->Length - MusicIndex; + } else { + n = size * 2; + } + n >>= 1; + for (i = 0; i < n; ++i) { // Add to our samples + buffer[i] += (buf[i] * MusicVolume) / 256; + } + MusicIndex += i * 2; + + n = MusicIndex == MusicSample->Length; + } +#endif + + if (n) { // End reached + SCM cb; + + DebugLevel3Fn("End of music %d\n", i); + PlayingMusic = 0; + if (ModFile) { + ModPlug_Unload(ModFile); + } + // FIXME: we are inside the SDL callback! + if (CallbackMusic) { + cb = gh_symbol2scm("music-stopped"); + if (!gh_null_p(symbol_boundp(cb, NIL))) { SCM value; - value=symbol_value(cb,NIL); - if( !gh_null_p(value) ) { - gh_apply(value,NIL); + value = symbol_value(cb, NIL); + if (!gh_null_p(value)) { + gh_apply(value, NIL); } } } @@ -371,6 +245,11 @@ global void StopMusic(void) #endif +/** +** Check cdrom. +** +** Perodic called from the main loop. +*/ global void CDRomCheck(void) { #ifdef USE_SDLCD @@ -394,8 +273,9 @@ global void CDRomCheck(void) } else { DebugLevel0Fn("get track\n"); CDTrack = cd_current_track() + 1; - if (CDTrack > NumCDTracks) + if (CDTrack > NumCDTracks) { CDTrack = 1; + } } #endif }