mixer.cpp

Go to the documentation of this file.
00001 /* $Id: mixer.cpp 18835 2010-01-16 22:15:02Z peter1138 $ */
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 static uint32 _max_size = UINT_MAX;
00037 
00044 static const int MAX_VOLUME = 128 * 128;
00045 
00053 template <typename T>
00054 static int RateConversion(T *b, int frac_pos)
00055 {
00056   return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
00057 }
00058 
00059 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
00060 {
00061   if (samples > sc->samples_left) samples = sc->samples_left;
00062   sc->samples_left -= samples;
00063   assert(samples > 0);
00064 
00065   const int16 *b = (const int16 *)sc->memory + sc->pos;
00066   uint32 frac_pos = sc->frac_pos;
00067   uint32 frac_speed = sc->frac_speed;
00068   int volume_left = sc->volume_left;
00069   int volume_right = sc->volume_right;
00070 
00071   if (frac_speed == 0x10000) {
00072     /* Special case when frac_speed is 0x10000 */
00073     do {
00074       buffer[0] = Clamp(buffer[0] + (*b * volume_left  >> 16), -MAX_VOLUME, MAX_VOLUME);
00075       buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00076       b++;
00077       buffer += 2;
00078     } while (--samples > 0);
00079   } else {
00080     do {
00081       int data = RateConversion(b, frac_pos);
00082       buffer[0] = Clamp(buffer[0] + (data * volume_left  >> 16), -MAX_VOLUME, MAX_VOLUME);
00083       buffer[1] = Clamp(buffer[1] + (data * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00084       buffer += 2;
00085       frac_pos += frac_speed;
00086       b += frac_pos >> 16;
00087       frac_pos &= 0xffff;
00088     } while (--samples > 0);
00089   }
00090 
00091   sc->frac_pos = frac_pos;
00092   sc->pos = b - (const int16 *)sc->memory;
00093 }
00094 
00095 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
00096 {
00097   if (samples > sc->samples_left) samples = sc->samples_left;
00098   sc->samples_left -= samples;
00099   assert(samples > 0);
00100 
00101   const int8 *b = sc->memory + sc->pos;
00102   uint32 frac_pos = sc->frac_pos;
00103   uint32 frac_speed = sc->frac_speed;
00104   int volume_left = sc->volume_left;
00105   int volume_right = sc->volume_right;
00106 
00107   if (frac_speed == 0x10000) {
00108     /* Special case when frac_speed is 0x10000 */
00109     do {
00110       buffer[0] = Clamp(buffer[0] + (*b * volume_left  >> 8), -MAX_VOLUME, MAX_VOLUME);
00111       buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00112       b++;
00113       buffer += 2;
00114     } while (--samples > 0);
00115   } else {
00116     do {
00117       int data = RateConversion(b, frac_pos);
00118       buffer[0] = Clamp(buffer[0] + (data * volume_left  >> 8), -MAX_VOLUME, MAX_VOLUME);
00119       buffer[1] = Clamp(buffer[1] + (data * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00120       buffer += 2;
00121       frac_pos += frac_speed;
00122       b += frac_pos >> 16;
00123       frac_pos &= 0xffff;
00124     } while (--samples > 0);
00125   }
00126 
00127   sc->frac_pos = frac_pos;
00128   sc->pos = b - sc->memory;
00129 }
00130 
00131 static void MxCloseChannel(MixerChannel *mc)
00132 {
00133   mc->active = false;
00134 }
00135 
00136 void MxMixSamples(void *buffer, uint samples)
00137 {
00138   MixerChannel *mc;
00139 
00140   /* Clear the buffer */
00141   memset(buffer, 0, sizeof(int16) * 2 * samples);
00142 
00143   /* Mix each channel */
00144   for (mc = _channels; mc != endof(_channels); mc++) {
00145     if (mc->active) {
00146       if (mc->is16bit) {
00147         mix_int16(mc, (int16*)buffer, samples);
00148       } else {
00149         mix_int8_to_int16(mc, (int16*)buffer, samples);
00150       }
00151       if (mc->samples_left == 0) MxCloseChannel(mc);
00152     }
00153   }
00154 }
00155 
00156 MixerChannel *MxAllocateChannel()
00157 {
00158   MixerChannel *mc;
00159   for (mc = _channels; mc != endof(_channels); mc++)
00160     if (!mc->active) {
00161       free(mc->memory);
00162       mc->memory = NULL;
00163       return mc;
00164     }
00165   return NULL;
00166 }
00167 
00168 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
00169 {
00170   mc->memory = mem;
00171   mc->frac_pos = 0;
00172   mc->pos = 0;
00173 
00174   mc->frac_speed = (rate << 16) / _play_rate;
00175 
00176   if (is16bit) size /= 2;
00177 
00178   /* adjust the magnitude to prevent overflow */
00179   while (size >= _max_size) {
00180     size >>= 1;
00181     rate = (rate >> 1) + 1;
00182   }
00183 
00184   mc->samples_left = (uint)size * _play_rate / rate;
00185   mc->is16bit = is16bit;
00186 }
00187 
00188 void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
00189 {
00190   mc->volume_left = left;
00191   mc->volume_right = right;
00192 }
00193 
00194 
00195 void MxActivateChannel(MixerChannel *mc)
00196 {
00197   mc->active = true;
00198 }
00199 
00200 
00201 bool MxInitialize(uint rate)
00202 {
00203   _play_rate = rate;
00204   _max_size  = UINT_MAX / _play_rate;
00205   return true;
00206 }

Generated on Sat Jun 19 17:14:49 2010 for OpenTTD by  doxygen 1.6.1