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