mixer.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "core/math_func.hpp"
00014
00015 struct MixerChannel {
00016 bool active;
00017
00018
00019 int8 *memory;
00020
00021
00022 uint32 pos;
00023 uint32 frac_pos;
00024 uint32 frac_speed;
00025 uint32 samples_left;
00026
00027
00028 int volume_left;
00029 int volume_right;
00030
00031 bool is16bit;
00032 };
00033
00034 static MixerChannel _channels[8];
00035 static uint32 _play_rate = 11025;
00036 static uint32 _max_size = UINT_MAX;
00037
00044 static const int MAX_VOLUME = 128 * 128;
00045
00053 template <typename T>
00054 static int RateConversion(T *b, int frac_pos)
00055 {
00056 return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
00057 }
00058
00059 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
00060 {
00061 if (samples > sc->samples_left) samples = sc->samples_left;
00062 sc->samples_left -= samples;
00063 assert(samples > 0);
00064
00065 const int16 *b = (const int16 *)sc->memory + sc->pos;
00066 uint32 frac_pos = sc->frac_pos;
00067 uint32 frac_speed = sc->frac_speed;
00068 int volume_left = sc->volume_left;
00069 int volume_right = sc->volume_right;
00070
00071 if (frac_speed == 0x10000) {
00072
00073 do {
00074 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> 16), -MAX_VOLUME, MAX_VOLUME);
00075 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00076 b++;
00077 buffer += 2;
00078 } while (--samples > 0);
00079 } else {
00080 do {
00081 int data = RateConversion(b, frac_pos);
00082 buffer[0] = Clamp(buffer[0] + (data * volume_left >> 16), -MAX_VOLUME, MAX_VOLUME);
00083 buffer[1] = Clamp(buffer[1] + (data * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00084 buffer += 2;
00085 frac_pos += frac_speed;
00086 b += frac_pos >> 16;
00087 frac_pos &= 0xffff;
00088 } while (--samples > 0);
00089 }
00090
00091 sc->frac_pos = frac_pos;
00092 sc->pos = b - (const int16 *)sc->memory;
00093 }
00094
00095 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
00096 {
00097 if (samples > sc->samples_left) samples = sc->samples_left;
00098 sc->samples_left -= samples;
00099 assert(samples > 0);
00100
00101 const int8 *b = sc->memory + sc->pos;
00102 uint32 frac_pos = sc->frac_pos;
00103 uint32 frac_speed = sc->frac_speed;
00104 int volume_left = sc->volume_left;
00105 int volume_right = sc->volume_right;
00106
00107 if (frac_speed == 0x10000) {
00108
00109 do {
00110 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> 8), -MAX_VOLUME, MAX_VOLUME);
00111 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00112 b++;
00113 buffer += 2;
00114 } while (--samples > 0);
00115 } else {
00116 do {
00117 int data = RateConversion(b, frac_pos);
00118 buffer[0] = Clamp(buffer[0] + (data * volume_left >> 8), -MAX_VOLUME, MAX_VOLUME);
00119 buffer[1] = Clamp(buffer[1] + (data * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00120 buffer += 2;
00121 frac_pos += frac_speed;
00122 b += frac_pos >> 16;
00123 frac_pos &= 0xffff;
00124 } while (--samples > 0);
00125 }
00126
00127 sc->frac_pos = frac_pos;
00128 sc->pos = b - sc->memory;
00129 }
00130
00131 static void MxCloseChannel(MixerChannel *mc)
00132 {
00133 mc->active = false;
00134 }
00135
00136 void MxMixSamples(void *buffer, uint samples)
00137 {
00138 MixerChannel *mc;
00139
00140
00141 memset(buffer, 0, sizeof(int16) * 2 * samples);
00142
00143
00144 for (mc = _channels; mc != endof(_channels); mc++) {
00145 if (mc->active) {
00146 if (mc->is16bit) {
00147 mix_int16(mc, (int16*)buffer, samples);
00148 } else {
00149 mix_int8_to_int16(mc, (int16*)buffer, samples);
00150 }
00151 if (mc->samples_left == 0) MxCloseChannel(mc);
00152 }
00153 }
00154 }
00155
00156 MixerChannel *MxAllocateChannel()
00157 {
00158 MixerChannel *mc;
00159 for (mc = _channels; mc != endof(_channels); mc++)
00160 if (!mc->active) {
00161 free(mc->memory);
00162 mc->memory = NULL;
00163 return mc;
00164 }
00165 return NULL;
00166 }
00167
00168 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
00169 {
00170 mc->memory = mem;
00171 mc->frac_pos = 0;
00172 mc->pos = 0;
00173
00174 mc->frac_speed = (rate << 16) / _play_rate;
00175
00176 if (is16bit) size /= 2;
00177
00178
00179 while (size >= _max_size) {
00180 size >>= 1;
00181 rate = (rate >> 1) + 1;
00182 }
00183
00184 mc->samples_left = (uint)size * _play_rate / rate;
00185 mc->is16bit = is16bit;
00186 }
00187
00188 void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
00189 {
00190 mc->volume_left = left;
00191 mc->volume_right = right;
00192 }
00193
00194
00195 void MxActivateChannel(MixerChannel *mc)
00196 {
00197 mc->active = true;
00198 }
00199
00200
00201 bool MxInitialize(uint rate)
00202 {
00203 _play_rate = rate;
00204 _max_size = UINT_MAX / _play_rate;
00205 return true;
00206 }