]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - snd_main.c
sprite tracking distance fix; update inverse view matrix before rendering a scene...
[xonotic/darkplaces.git] / snd_main.c
index e29b55eb060039efac85467658fed0c046705831..4f7ca310813450a96a2e18d9bee6093c5ad75836 100644 (file)
@@ -23,10 +23,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "snd_main.h"
 #include "snd_ogg.h"
+#include "snd_modplug.h"
 
 
 #define SND_MIN_SPEED 8000
-#define SND_MAX_SPEED 48000
+#define SND_MAX_SPEED 96000
 #define SND_MIN_WIDTH 1
 #define SND_MAX_WIDTH 2
 #define SND_MIN_CHANNELS 1
@@ -173,7 +174,9 @@ cvar_t snd_soundradius = {0, "snd_soundradius", "2000", "radius of weapon sounds
 cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.1", "how much sound to mix ahead of time"};
 cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1", "enables keeping compressed ogg sound files compressed, decompressing them only as needed, otherwise they will be decompressed completely at load (may use a lot of memory)"};
 cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0", "swaps left/right speakers for old ISA soundblaster cards"};
+extern cvar_t v_flipped;
 cvar_t snd_channellayout = {0, "snd_channellayout", "0", "channel layout. Can be 0 (auto - snd_restart needed), 1 (standard layout), or 2 (ALSA layout)"};
+cvar_t snd_mutewhenidle = {CVAR_SAVE, "snd_mutewhenidle", "1", "whether to disable sound output when game window is inactive"};
 
 // Local cvars
 static cvar_t nosound = {0, "nosound", "0", "disables sound"};
@@ -317,6 +320,7 @@ static qboolean S_ChooseCheaperFormat (snd_format_t* format, qboolean fixed_spee
                { 22050,                        2,                              2 },
                { 44100,                        2,                              2 },
                { 48000,                        2,                              6 },
+               { 96000,                        2,                              6 },
                { SND_MAX_SPEED,        SND_MAX_WIDTH,  SND_MAX_CHANNELS },
        };
        const unsigned int nb_thresholds = sizeof(thresholds) / sizeof(thresholds[0]);
@@ -400,7 +404,7 @@ static void S_SetChannelLayout (void)
        listeners = snd_speakerlayout.listeners;
 
        // Swap the left and right channels if snd_swapstereo is set
-       if (snd_swapstereo.integer)
+       if (boolxor(snd_swapstereo.integer, v_flipped.integer))
        {
                switch (snd_speakerlayout.channels)
                {
@@ -454,7 +458,7 @@ static void S_SetChannelLayout (void)
                                   (layout == SND_CHANNELLAYOUT_ALSA) ? "ALSA" : "standard");
        }
 
-       current_swapstereo = snd_swapstereo.integer;
+       current_swapstereo = boolxor(snd_swapstereo.integer, v_flipped.integer);
        current_channellayout = snd_channellayout.integer;
        current_channellayout_used = layout;
 }
@@ -686,6 +690,14 @@ void S_Shutdown(void)
 
 void S_Restart_f(void)
 {
+       // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches)
+       // So, refuse to do this if we are connected.
+       if(cls.state == ca_connected)
+       {
+               Con_Printf("snd_restart would wreak havoc if you do that while connected!\n");
+               return;
+       }
+
        S_Shutdown();
        S_Startup();
 }
@@ -706,6 +718,7 @@ void S_Init(void)
        Cvar_RegisterVariable(&snd_speed);
        Cvar_RegisterVariable(&snd_width);
        Cvar_RegisterVariable(&snd_channels);
+       Cvar_RegisterVariable(&snd_mutewhenidle);
 
 // COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio)
        if (COM_CheckParm("-nosound"))
@@ -747,6 +760,7 @@ void S_Init(void)
        memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
 
        OGG_OpenLibrary ();
+       ModPlug_OpenLibrary ();
 }
 
 
@@ -760,6 +774,7 @@ Shutdown and free all resources
 void S_Terminate (void)
 {
        S_Shutdown ();
+       ModPlug_CloseLibrary ();
        OGG_CloseLibrary ();
 
        // Free all SFXs
@@ -780,6 +795,14 @@ void S_UnloadAllSounds_f (void)
 {
        int i;
 
+       // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches)
+       // So, refuse to do this if we are connected.
+       if(cls.state == ca_connected)
+       {
+               Con_Printf("snd_unloadallsounds would wreak havoc if you do that while connected!\n");
+               return;
+       }
+
        // stop any active sounds
        S_StopAllSounds();
 
@@ -871,7 +894,7 @@ void S_FreeSfx (sfx_t *sfx, qboolean force)
 
        // Free it
        if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
-               sfx->fetcher->free (sfx);
+               sfx->fetcher->free (sfx->fetcher_data);
        Mem_Free (sfx);
 }
 
@@ -1099,6 +1122,7 @@ SND_Spatialize
 Spatializes a channel
 =================
 */
+extern cvar_t cl_gameplayfix_soundsmovewithentities;
 void SND_Spatialize(channel_t *ch, qboolean isstatic)
 {
        int i;
@@ -1106,12 +1130,19 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic)
        vec3_t source_vec;
 
        // update sound origin if we know about the entity
-       if (ch->entnum > 0 && cls.state == ca_connected && cl.entities[ch->entnum].state_current.active)
+       if (ch->entnum > 0 && cls.state == ca_connected && cl_gameplayfix_soundsmovewithentities.integer)
        {
-               //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl.entities[ch->entnum].state_current.origin[0], cl.entities[ch->entnum].state_current.origin[1], cl.entities[ch->entnum].state_current.origin[2]);
-               VectorCopy(cl.entities[ch->entnum].state_current.origin, ch->origin);
-               if (cl.entities[ch->entnum].state_current.modelindex && cl.model_precache[cl.entities[ch->entnum].state_current.modelindex] && cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->soundfromcenter)
-                       VectorMAMAM(1.0f, ch->origin, 0.5f, cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->normalmins, 0.5f, cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->normalmaxs, ch->origin);
+               if (ch->entnum >= 32768)
+               {
+                       // TODO: sounds that follow CSQC entities?
+               }
+               else if (cl.entities[ch->entnum].state_current.active)
+               {
+                       //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl.entities[ch->entnum].state_current.origin[0], cl.entities[ch->entnum].state_current.origin[1], cl.entities[ch->entnum].state_current.origin[2]);
+                       VectorCopy(cl.entities[ch->entnum].state_current.origin, ch->origin);
+                       if (cl.entities[ch->entnum].state_current.modelindex && cl.model_precache[cl.entities[ch->entnum].state_current.modelindex] && cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->soundfromcenter)
+                               VectorMAMAM(1.0f, ch->origin, 0.5f, cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->normalmins, 0.5f, cl.model_precache[cl.entities[ch->entnum].state_current.modelindex]->normalmaxs, ch->origin);
+               }
        }
 
        mastervol = ch->master_vol;
@@ -1161,7 +1192,6 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags,
        // Initialize the channel
        memset (target_chan, 0, sizeof (*target_chan));
        VectorCopy (origin, target_chan->origin);
-       target_chan->master_vol = (int)(fvol * 255);
        target_chan->sfx = sfx;
        target_chan->flags = flags;
        target_chan->pos = 0; // start of the sound
@@ -1178,6 +1208,9 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags,
 
        // Lock the SFX during play
        S_LockSfx (sfx);
+
+       // and finally, apply the volume
+       S_SetChannelVolume(target_chan - channels, fvol);
 }
 
 
@@ -1192,9 +1225,6 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
        if (sfx->fetcher == NULL)
                return -1;
 
-       if (entnum && entnum >= cl.max_entities)
-               CL_ExpandEntities(entnum);
-
        // Pick a channel to play on
        target_chan = SND_PickChannel(entnum, entchannel);
        if (!target_chan)
@@ -1240,12 +1270,13 @@ void S_StopChannel (unsigned int channel_ind)
                {
                        snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
                        if (fetcher_endsb != NULL)
-                               fetcher_endsb (ch);
+                               fetcher_endsb (ch->fetcher_data);
                }
 
                // Remove the lock it holds
                S_UnlockSfx (sfx);
 
+               ch->fetcher_data = NULL;
                ch->sfx = NULL;
        }
 }
@@ -1330,6 +1361,16 @@ void S_PauseGameSounds (qboolean toggle)
 
 void S_SetChannelVolume (unsigned int ch_ind, float fvol)
 {
+       sfx_t *sfx = channels[ch_ind].sfx;
+       if(sfx->volume_peak > 0)
+       {
+               // Replaygain support
+               // Con_DPrintf("Setting volume on ReplayGain-enabled track... %f -> ", fvol);
+               fvol *= sfx->volume_mult;
+               if(fvol * sfx->volume_peak > 1)
+                       fvol = 1 / sfx->volume_peak;
+               // Con_DPrintf("%f\n", fvol);
+       }
        channels[ch_ind].master_vol = (int)(fvol * 255.0f);
 }
 
@@ -1524,7 +1565,7 @@ void S_Update(const matrix4x4_t *listenermatrix)
                return;
 
        // If snd_swapstereo or snd_channellayout has changed, recompute the channel layout
-       if (current_swapstereo != snd_swapstereo.integer ||
+       if (current_swapstereo != boolxor(snd_swapstereo.integer, v_flipped.integer) ||
                current_channellayout != snd_channellayout.integer)
                S_SetChannelLayout();