// sound.cpp: uses fmod on windows and sdl_mixer on unix (both had problems on the other platform) #include "cube.h" #include "bot/bot.h" //#ifndef WIN32 // NOTE: fmod not being supported for the moment as it does not allow stereo pan/vol updating during playback #define USE_MIXER //#endif VARP(soundvol, 0, 150, 255); bool nosound = true; #define MAXCHAN 32 #define SOUNDFREQ 22050 struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN]; #ifdef USE_MIXER #include "SDL_mixer.h" #define MAXVOL MIX_MAX_VOLUME Mix_Music *mod = NULL; void *stream = NULL; #else #include "fmod.h" #define MAXVOL 255 FMUSIC_MODULE *mod = NULL; FSOUND_STREAM *stream = NULL; #endif int musicvol = 125; void setmusicvol(int vol) { if(musicvol > 255 || musicvol < 0) return; musicvol = vol; if(nosound) return; #ifdef USE_MIXER if(mod) Mix_VolumeMusic((musicvol*MAXVOL)/255); #else if(mod) FMUSIC_SetMasterVolume(mod, musicvol); else if(stream && musicchan>=0) FSOUND_SetVolume(musicchan, (musicvol*MAXVOL)/255); #endif } COMMANDN(musicvol, setmusicvol, ARG_1INT); void stopsound() { if(nosound) return; if(mod) { #ifdef USE_MIXER Mix_HaltMusic(); Mix_FreeMusic(mod); #else FMUSIC_FreeSong(mod); #endif mod = NULL; } if(stream) { #ifndef USE_MIXER FSOUND_Stream_Close(stream); #endif stream = NULL; } } VAR(soundbufferlen, 128, 1024, 4096); void initsound() { memset(soundlocs, 0, sizeof(soundloc)*MAXCHAN); #ifdef USE_MIXER if(Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0) { conoutf("sound init failed (SDL_mixer): %s", (size_t)Mix_GetError()); return; } Mix_AllocateChannels(MAXCHAN); #else if(FSOUND_GetVersion()=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); } } #endif else { conoutf("could not play music: %s", sn); } } } COMMAND(music, ARG_1STR); #ifdef USE_MIXER vector samples; #else vector samples; #endif cvector snames; int registersound(char *name) { loopv(snames) if(strcmp(snames[i], name)==0) return i; snames.add(newstring(name)); samples.add(NULL); return samples.length()-1; } COMMAND(registersound, ARG_1EST); void cleansound() { if(nosound) return; stopsound(); #ifdef USE_MIXER Mix_CloseAudio(); #else FSOUND_Close(); #endif } VAR(stereo, 0, 1, 1); void updatechanvol(int chan, vec *loc) { int vol = soundvol, pan = 255/2; if(loc) { vec v; float dist = camera1->o.dist(*loc, v); vol -= (int)(dist*3*soundvol/255); // simple mono distance attenuation if(vol<0) vol = 0; if(stereo && (v.x != 0 || v.y != 0)) { float yaw = -atan2f(v.x, v.y) - camera1->yaw*RAD; // relative angle of sound along X-Y axis pan = int(255.9f*(0.5f*sinf(yaw)+0.5f)); // range is from 0 (left) to 255 (right) } } vol = (vol*MAXVOL)/255; #ifdef USE_MIXER Mix_Volume(chan, vol); Mix_SetPanning(chan, 255-pan, pan); #else FSOUND_SetVolume(chan, vol); FSOUND_SetPan(chan, pan); #endif } void newsoundloc(int chan, vec *loc) { ASSERT(chan>=0 && chan5) return; // avoid bursts of sounds with heavy packetloss and in sp if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; } if(!samples[n]) { s_sprintfd(buf)("packages/audio/sounds/%s.wav", snames[n]); #ifdef USE_MIXER samples[n] = Mix_LoadWAV(path(buf)); #else samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0); #endif if(!samples[n]) { conoutf("failed to load sample: %s", buf); return; } } #ifdef USE_MIXER int chan = Mix_PlayChannel(-1, samples[n], 0); #else int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true); #endif if(chan<0) return; if(loc) newsoundloc(chan, loc); updatechanvol(chan, loc); #ifndef USE_MIXER FSOUND_SetPaused(chan, false); #endif } void sound(int n) { playsound(n, NULL); } COMMAND(sound, ARG_1INT);