# mixer.cpp

Go to the documentation of this file.

    00001 /* $Id: mixer.cpp 17693 2009-10-04 17:16:41Z rubidium $ */
    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 }