# 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 }