s_mix.c

Go to the documentation of this file.
00001 
00006 /*
00007 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "s_local.h"
00027 #include "s_mix.h"
00028 #include "s_main.h"
00029 
00034 static int S_AllocChannel (void)
00035 {
00036     int i;
00037 
00038     for (i = 0; i < MAX_CHANNELS; i++) {
00039         if (!s_env.channels[i].sample)
00040             return i;
00041     }
00042 
00043     return -1;
00044 }
00045 
00050 void S_FreeChannel (int c)
00051 {
00052     memset(&s_env.channels[c], 0, sizeof(s_env.channels[0]));
00053 }
00054 
00059 void S_SpatializeChannel (const s_channel_t *ch)
00060 {
00061     vec3_t delta;
00062     float dist, angle;
00063     const int c = (int)((ptrdiff_t)(ch - s_env.channels));
00064 
00065     VectorSubtract(ch->org, cl.cam.camorg, delta);
00066 
00067     dist = VectorNormalize(delta) * snd_distance_scale->value * ch->atten;
00068 
00069     if (dist > 255.0)  /* clamp to max */
00070         dist = 255.0;
00071 
00072     if (dist > 50.0) {  /* resolve stereo panning */
00073         const float dot = DotProduct(s_env.right, delta);
00074         angle = (int)(450.0 - acos(dot) * todeg) % 360;
00075     } else
00076         angle = 0;
00077 
00078     Mix_SetPosition(c, (int)angle, (int)dist);
00079 }
00080 
00091 void S_PlaySample (const vec3_t origin, s_sample_t* sample, float atten, float relVolume)
00092 {
00093     s_channel_t *ch;
00094     int i;
00095     float volume;
00096 
00097     if (!s_env.initialized)
00098         return;
00099 
00100     if (!sample)
00101         return;
00102 
00103     /* if the last mix of this particular sample is less than half a second ago, skip it */
00104     if (sample->lastPlayed > CL_Milliseconds() - s_env.sampleRepeatRate)
00105         return;
00106 
00107     if ((i = S_AllocChannel()) == -1)
00108         return;
00109 
00110     sample->lastPlayed = CL_Milliseconds();
00111     ch = &s_env.channels[i];
00112 
00113     ch->atten = atten;
00114     ch->sample = sample;
00115 
00116     if (origin != NULL) {
00117         VectorCopy(origin, ch->org);
00118         S_SpatializeChannel(ch);
00119     }
00120 
00121     volume = snd_volume->value * relVolume * MIX_MAX_VOLUME;
00122     Com_DPrintf(DEBUG_SOUND, "%i: Playing sample '%s' at volume %f at channel %i\n",
00123             CL_Milliseconds(), sample->name, volume, i);
00124     Mix_VolumeChunk(ch->sample->chunk, volume);
00125     Mix_PlayChannel(i, ch->sample->chunk, 0);
00126 }
00127 
00131 void S_LoopSample (const vec3_t org, s_sample_t *sample, float volume, float attenuation)
00132 {
00133     s_channel_t *ch;
00134     int i;
00135 
00136     if (!sample || !sample->chunk)
00137         return;
00138 
00139     ch = NULL;
00140 
00141     for (i = 0; i < MAX_CHANNELS; i++){  /* find existing loop sound */
00142         if (s_env.channels[i].sample == sample) {
00143             vec3_t delta;
00144             VectorSubtract(s_env.channels[i].org, org, delta);
00145             if (VectorLength(delta) < 255.0) {
00146                 ch = &s_env.channels[i];
00147                 break;
00148             }
00149         }
00150     }
00151 
00152     if (ch) {  /* update existing loop sample */
00153         ch->count++;
00154 
00155         VectorMix(ch->org, org, 1.0 / ch->count, ch->org);
00156     } else {  /* or allocate a new one */
00157         if ((i = S_AllocChannel()) == -1)
00158             return;
00159 
00160         ch = &s_env.channels[i];
00161 
00162         sample->lastPlayed = CL_Milliseconds();
00163         VectorCopy(org, ch->org);
00164         ch->count = 1;
00165         ch->atten = attenuation;
00166         ch->sample = sample;
00167 
00168         Mix_PlayChannel(i, ch->sample->chunk, 0);
00169     }
00170 
00171     S_SpatializeChannel(ch);
00172 }
00173 
00181 void S_StartLocalSample (const char *name, float relVolume)
00182 {
00183     s_sample_t *sample;
00184 
00185     if (!s_env.initialized)
00186         return;
00187 
00188     sample = S_LoadSample(name);
00189     if (!sample) {
00190         Com_Printf("S_StartLocalSample: Failed to load %s\n", name);
00191         return;
00192     }
00193     S_PlaySample(NULL, sample, SOUND_ATTN_NORM, relVolume);
00194 }

Generated by  doxygen 1.6.2