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 }

Generated on Mon Sep 22 20:34:16 2008 for openttd by  doxygen 1.5.6