# mixer.cpp

Go to the documentation of this file.

    00001 /* $Id: mixer.cpp 13708 2008-07-16 10:07:38Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "mixer.h"
    00008 #include "core/math_func.hpp"
    00009
    00010 struct MixerChannel {
    00011   bool active;
    00012
    00013   /* pointer to allocated buffer memory */
    00014   int8 *memory;
    00015
    00016   /* current position in memory */
    00017   uint32 pos;
    00018   uint32 frac_pos;
    00019   uint32 frac_speed;
    00020   uint32 samples_left;
    00021
    00022   /* Mixing volume */
    00023   int volume_left;
    00024   int volume_right;
    00025
    00026   uint flags;
    00027 };
    00028
    00029 static MixerChannel _channels[8];
    00030 static uint32 _play_rate;
    00031
    00038 static const int MAX_VOLUME = 128 * 128;
    00039
    00040
    00041 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
    00042 {
    00043   int8 *b;
    00044   uint32 frac_pos;
    00045   uint32 frac_speed;
    00046   int volume_left;
    00047   int volume_right;
    00048
    00049   if (samples > sc->samples_left) samples = sc->samples_left;
    00050   sc->samples_left -= samples;
    00051   assert(samples > 0);
    00052
    00053   b = sc->memory + sc->pos;
    00054   frac_pos = sc->frac_pos;
    00055   frac_speed = sc->frac_speed;
    00056   volume_left = sc->volume_left;
    00057   volume_right = sc->volume_right;
    00058
    00059   if (frac_speed == 0x10000) {
    00060     /* Special case when frac_speed is 0x10000 */
    00061     do {
    00062       buffer[0] = Clamp(buffer[0] + (*b * volume_left  >> 8), -MAX_VOLUME, MAX_VOLUME);
    00063       buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
    00064       b++;
    00065       buffer += 2;
    00066     } while (--samples > 0);
    00067   } else {
    00068     do {
    00069       buffer[0] = Clamp(buffer[0] + (*b * volume_left  >> 8), -MAX_VOLUME, MAX_VOLUME);
    00070       buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
    00071       buffer += 2;
    00072       frac_pos += frac_speed;
    00073       b += frac_pos >> 16;
    00074       frac_pos &= 0xffff;
    00075     } while (--samples > 0);
    00076   }
    00077
    00078   sc->frac_pos = frac_pos;
    00079   sc->pos = b - sc->memory;
    00080 }
    00081
    00082 static void MxCloseChannel(MixerChannel *mc)
    00083 {
    00084   if (mc->flags & MX_AUTOFREE) free(mc->memory);
    00085   mc->active = false;
    00086   mc->memory = NULL;
    00087 }
    00088
    00089 void MxMixSamples(void *buffer, uint samples)
    00090 {
    00091   MixerChannel *mc;
    00092
    00093   /* Clear the buffer */
    00094   memset(buffer, 0, sizeof(int16) * 2 * samples);
    00095
    00096   /* Mix each channel */
    00097   for (mc = _channels; mc != endof(_channels); mc++) {
    00098     if (mc->active) {
    00099       mix_int8_to_int16(mc, (int16*)buffer, samples);
    00100       if (mc->samples_left == 0) MxCloseChannel(mc);
    00101     }
    00102   }
    00103 }
    00104
    00105 MixerChannel *MxAllocateChannel()
    00106 {
    00107   MixerChannel *mc;
    00108   for (mc = _channels; mc != endof(_channels); mc++)
    00109     if (mc->memory == NULL) {
    00110       mc->active = false;
    00111       return mc;
    00112     }
    00113   return NULL;
    00114 }
    00115
    00116 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags)
    00117 {
    00118   mc->memory = mem;
    00119   mc->flags = flags;
    00120   mc->frac_pos = 0;
    00121   mc->pos = 0;
    00122
    00123   mc->frac_speed = (rate << 16) / _play_rate;
    00124
    00125   /* adjust the magnitude to prevent overflow */
    00126   while (size & 0xFFFF0000) {
    00127     size >>= 1;
    00128     rate = (rate >> 1) + 1;
    00129   }
    00130
    00131   mc->samples_left = size * _play_rate / rate;
    00132 }
    00133
    00134 void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
    00135 {
    00136   mc->volume_left = left;
    00137   mc->volume_right = right;
    00138 }
    00139
    00140
    00141 void MxActivateChannel(MixerChannel* mc)
    00142 {
    00143   mc->active = true;
    00144 }
    00145
    00146
    00147 bool MxInitialize(uint rate)
    00148 {
    00149   _play_rate = rate;
    00150   return true;
    00151 }