mixer.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD 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, version 2.
00006  * OpenTTD 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.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include <math.h>
00014 #include "core/math_func.hpp"
00015 
00016 struct MixerChannel {
00017   bool active;
00018 
00019   /* pointer to allocated buffer memory */
00020   int8 *memory;
00021 
00022   /* current position in memory */
00023   uint32 pos;
00024   uint32 frac_pos;
00025   uint32 frac_speed;
00026   uint32 samples_left;
00027 
00028   /* Mixing volume */
00029   int volume_left;
00030   int volume_right;
00031 
00032   bool is16bit;
00033 };
00034 
00035 static MixerChannel _channels[8];
00036 static uint32 _play_rate = 11025;
00037 static uint32 _max_size = UINT_MAX;
00038 
00045 static const int MAX_VOLUME = 128 * 128;
00046 
00054 template <typename T>
00055 static int RateConversion(T *b, int frac_pos)
00056 {
00057   return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
00058 }
00059 
00060 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
00061 {
00062   if (samples > sc->samples_left) samples = sc->samples_left;
00063   sc->samples_left -= samples;
00064   assert(samples > 0);
00065 
00066   const int16 *b = (const int16 *)sc->memory + sc->pos;
00067   uint32 frac_pos = sc->frac_pos;
00068   uint32 frac_speed = sc->frac_speed;
00069   int volume_left = sc->volume_left;
00070   int volume_right = sc->volume_right;
00071 
00072   if (frac_speed == 0x10000) {
00073     /* Special case when frac_speed is 0x10000 */
00074     do {
00075       buffer[0] = Clamp(buffer[0] + (*b * volume_left  >> 16), -MAX_VOLUME, MAX_VOLUME);
00076       buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00077       b++;
00078       buffer += 2;
00079     } while (--samples > 0);
00080   } else {
00081     do {
00082       int data = RateConversion(b, frac_pos);
00083       buffer[0] = Clamp(buffer[0] + (data * volume_left  >> 16), -MAX_VOLUME, MAX_VOLUME);
00084       buffer[1] = Clamp(buffer[1] + (data * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00085       buffer += 2;
00086       frac_pos += frac_speed;
00087       b += frac_pos >> 16;
00088       frac_pos &= 0xffff;
00089     } while (--samples > 0);
00090   }
00091 
00092   sc->frac_pos = frac_pos;
00093   sc->pos = b - (const int16 *)sc->memory;
00094 }
00095 
00096 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
00097 {
00098   if (samples > sc->samples_left) samples = sc->samples_left;
00099   sc->samples_left -= samples;
00100   assert(samples > 0);
00101 
00102   const int8 *b = sc->memory + sc->pos;
00103   uint32 frac_pos = sc->frac_pos;
00104   uint32 frac_speed = sc->frac_speed;
00105   int volume_left = sc->volume_left;
00106   int volume_right = sc->volume_right;
00107 
00108   if (frac_speed == 0x10000) {
00109     /* Special case when frac_speed is 0x10000 */
00110     do {
00111       buffer[0] = Clamp(buffer[0] + (*b * volume_left  >> 8), -MAX_VOLUME, MAX_VOLUME);
00112       buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00113       b++;
00114       buffer += 2;
00115     } while (--samples > 0);
00116   } else {
00117     do {
00118       int data = RateConversion(b, frac_pos);
00119       buffer[0] = Clamp(buffer[0] + (data * volume_left  >> 8), -MAX_VOLUME, MAX_VOLUME);
00120       buffer[1] = Clamp(buffer[1] + (data * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00121       buffer += 2;
00122       frac_pos += frac_speed;
00123       b += frac_pos >> 16;
00124       frac_pos &= 0xffff;
00125     } while (--samples > 0);
00126   }
00127 
00128   sc->frac_pos = frac_pos;
00129   sc->pos = b - sc->memory;
00130 }
00131 
00132 static void MxCloseChannel(MixerChannel *mc)
00133 {
00134   mc->active = false;
00135 }
00136 
00137 void MxMixSamples(void *buffer, uint samples)
00138 {
00139   MixerChannel *mc;
00140 
00141   /* Clear the buffer */
00142   memset(buffer, 0, sizeof(int16) * 2 * samples);
00143 
00144   /* Mix each channel */
00145   for (mc = _channels; mc != endof(_channels); mc++) {
00146     if (mc->active) {
00147       if (mc->is16bit) {
00148         mix_int16(mc, (int16*)buffer, samples);
00149       } else {
00150         mix_int8_to_int16(mc, (int16*)buffer, samples);
00151       }
00152       if (mc->samples_left == 0) MxCloseChannel(mc);
00153     }
00154   }
00155 }
00156 
00157 MixerChannel *MxAllocateChannel()
00158 {
00159   MixerChannel *mc;
00160   for (mc = _channels; mc != endof(_channels); mc++) {
00161     if (!mc->active) {
00162       free(mc->memory);
00163       mc->memory = NULL;
00164       return mc;
00165     }
00166   }
00167   return NULL;
00168 }
00169 
00170 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
00171 {
00172   mc->memory = mem;
00173   mc->frac_pos = 0;
00174   mc->pos = 0;
00175 
00176   mc->frac_speed = (rate << 16) / _play_rate;
00177 
00178   if (is16bit) size /= 2;
00179 
00180   /* adjust the magnitude to prevent overflow */
00181   while (size >= _max_size) {
00182     size >>= 1;
00183     rate = (rate >> 1) + 1;
00184   }
00185 
00186   mc->samples_left = (uint)size * _play_rate / rate;
00187   mc->is16bit = is16bit;
00188 }
00189 
00196 void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
00197 {
00198   /* Use sinusoidal pan to maintain overall sound power level regardless
00199    * of position. */
00200   mc->volume_left = (uint)(sin((1.0 - pan) * M_PI / 2.0) * volume);
00201   mc->volume_right = (uint)(sin(pan * M_PI / 2.0) * volume);
00202 }
00203 
00204 
00205 void MxActivateChannel(MixerChannel *mc)
00206 {
00207   mc->active = true;
00208 }
00209 
00210 
00211 bool MxInitialize(uint rate)
00212 {
00213   _play_rate = rate;
00214   _max_size  = UINT_MAX / _play_rate;
00215   return true;
00216 }

Generated on Sun Jun 5 04:19:57 2011 for OpenTTD by  doxygen 1.6.1