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 "core/math_func.hpp"
00014 
00015 struct MixerChannel {
00016   bool active;
00017 
00018   /* pointer to allocated buffer memory */
00019   int8 *memory;
00020 
00021   /* current position in memory */
00022   uint32 pos;
00023   uint32 frac_pos;
00024   uint32 frac_speed;
00025   uint32 samples_left;
00026 
00027   /* Mixing volume */
00028   int volume_left;
00029   int volume_right;
00030 
00031   bool is16bit;
00032 };
00033 
00034 static MixerChannel _channels[8];
00035 static uint32 _play_rate = 11025;
00036 
00043 static const int MAX_VOLUME = 128 * 128;
00044 
00052 template <typename T>
00053 static int RateConversion(T *b, int frac_pos)
00054 {
00055   return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
00056 }
00057 
00058 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
00059 {
00060   int16 *b;
00061   uint32 frac_pos;
00062   uint32 frac_speed;
00063   int volume_left;
00064   int volume_right;
00065 
00066   if (samples > sc->samples_left) samples = sc->samples_left;
00067   sc->samples_left -= samples;
00068   assert(samples > 0);
00069 
00070   b = (int16*)sc->memory + sc->pos;
00071   frac_pos = sc->frac_pos;
00072   frac_speed = sc->frac_speed;
00073   volume_left = sc->volume_left;
00074   volume_right = sc->volume_right;
00075 
00076   if (frac_speed == 0x10000) {
00077     /* Special case when frac_speed is 0x10000 */
00078     do {
00079       buffer[0] = Clamp(buffer[0] + (*b * volume_left  >> 16), -MAX_VOLUME, MAX_VOLUME);
00080       buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00081       b++;
00082       buffer += 2;
00083     } while (--samples > 0);
00084   } else {
00085     do {
00086       int data = RateConversion(b, frac_pos);
00087       buffer[0] = Clamp(buffer[0] + (data * volume_left  >> 16), -MAX_VOLUME, MAX_VOLUME);
00088       buffer[1] = Clamp(buffer[1] + (data * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00089       buffer += 2;
00090       frac_pos += frac_speed;
00091       b += frac_pos >> 16;
00092       frac_pos &= 0xffff;
00093     } while (--samples > 0);
00094   }
00095 
00096   sc->frac_pos = frac_pos;
00097   sc->pos = b - (int16*)sc->memory;
00098 }
00099 
00100 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
00101 {
00102   int8 *b;
00103   uint32 frac_pos;
00104   uint32 frac_speed;
00105   int volume_left;
00106   int volume_right;
00107 
00108   if (samples > sc->samples_left) samples = sc->samples_left;
00109   sc->samples_left -= samples;
00110   assert(samples > 0);
00111 
00112   b = sc->memory + sc->pos;
00113   frac_pos = sc->frac_pos;
00114   frac_speed = sc->frac_speed;
00115   volume_left = sc->volume_left;
00116   volume_right = sc->volume_right;
00117 
00118   if (frac_speed == 0x10000) {
00119     /* Special case when frac_speed is 0x10000 */
00120     do {
00121       buffer[0] = Clamp(buffer[0] + (*b * volume_left  >> 8), -MAX_VOLUME, MAX_VOLUME);
00122       buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00123       b++;
00124       buffer += 2;
00125     } while (--samples > 0);
00126   } else {
00127     do {
00128       int data = RateConversion(b, frac_pos);
00129       buffer[0] = Clamp(buffer[0] + (data * volume_left  >> 8), -MAX_VOLUME, MAX_VOLUME);
00130       buffer[1] = Clamp(buffer[1] + (data * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00131       buffer += 2;
00132       frac_pos += frac_speed;
00133       b += frac_pos >> 16;
00134       frac_pos &= 0xffff;
00135     } while (--samples > 0);
00136   }
00137 
00138   sc->frac_pos = frac_pos;
00139   sc->pos = b - sc->memory;
00140 }
00141 
00142 static void MxCloseChannel(MixerChannel *mc)
00143 {
00144   free(mc->memory);
00145   mc->active = false;
00146   mc->memory = NULL;
00147 }
00148 
00149 void MxMixSamples(void *buffer, uint samples)
00150 {
00151   MixerChannel *mc;
00152 
00153   /* Clear the buffer */
00154   memset(buffer, 0, sizeof(int16) * 2 * samples);
00155 
00156   /* Mix each channel */
00157   for (mc = _channels; mc != endof(_channels); mc++) {
00158     if (mc->active) {
00159       if (mc->is16bit) {
00160         mix_int16(mc, (int16*)buffer, samples);
00161       } else {
00162         mix_int8_to_int16(mc, (int16*)buffer, samples);
00163       }
00164       if (mc->samples_left == 0) MxCloseChannel(mc);
00165     }
00166   }
00167 }
00168 
00169 MixerChannel *MxAllocateChannel()
00170 {
00171   MixerChannel *mc;
00172   for (mc = _channels; mc != endof(_channels); mc++)
00173     if (mc->memory == NULL) {
00174       mc->active = false;
00175       return mc;
00176     }
00177   return NULL;
00178 }
00179 
00180 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
00181 {
00182   mc->memory = mem;
00183   mc->frac_pos = 0;
00184   mc->pos = 0;
00185 
00186   mc->frac_speed = (rate << 16) / _play_rate;
00187 
00188   /* adjust the magnitude to prevent overflow */
00189   while (size & ~0xFFFF) {
00190     size >>= 1;
00191     rate = (rate >> 1) + 1;
00192   }
00193 
00194   int div = is16bit ? 2 : 1;
00195 
00196   mc->samples_left = (uint)size * _play_rate / rate / div;
00197   mc->is16bit = is16bit;
00198 }
00199 
00200 void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
00201 {
00202   mc->volume_left = left;
00203   mc->volume_right = right;
00204 }
00205 
00206 
00207 void MxActivateChannel(MixerChannel *mc)
00208 {
00209   mc->active = true;
00210 }
00211 
00212 
00213 bool MxInitialize(uint rate)
00214 {
00215   _play_rate = rate;
00216   return true;
00217 }

Generated on Sat Dec 26 20:06:01 2009 for OpenTTD by  doxygen 1.5.6