# mixer.cpp

Go to the documentation of this file.

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