mixer.cpp

Go to the documentation of this file.
00001 /* $Id: mixer.cpp 15299 2009-01-31 20:16:06Z smatz $ */
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;
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 }

Generated on Sun Mar 15 22:49:47 2009 for openttd by  doxygen 1.5.6