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
00043 static const int MAX_VOLUME = 128 * 128;
00044
00052 template <typename T>
00053 static int RateConversion(T *b, int frac_pos)
00054 {
00055 return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
00056 }
00057
00058 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
00059 {
00060 int16 *b;
00061 uint32 frac_pos;
00062 uint32 frac_speed;
00063 int volume_left;
00064 int volume_right;
00065
00066 if (samples > sc->samples_left) samples = sc->samples_left;
00067 sc->samples_left -= samples;
00068 assert(samples > 0);
00069
00070 b = (int16*)sc->memory + sc->pos;
00071 frac_pos = sc->frac_pos;
00072 frac_speed = sc->frac_speed;
00073 volume_left = sc->volume_left;
00074 volume_right = sc->volume_right;
00075
00076 if (frac_speed == 0x10000) {
00077
00078 do {
00079 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> 16), -MAX_VOLUME, MAX_VOLUME);
00080 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00081 b++;
00082 buffer += 2;
00083 } while (--samples > 0);
00084 } else {
00085 do {
00086 int data = RateConversion(b, frac_pos);
00087 buffer[0] = Clamp(buffer[0] + (data * volume_left >> 16), -MAX_VOLUME, MAX_VOLUME);
00088 buffer[1] = Clamp(buffer[1] + (data * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
00089 buffer += 2;
00090 frac_pos += frac_speed;
00091 b += frac_pos >> 16;
00092 frac_pos &= 0xffff;
00093 } while (--samples > 0);
00094 }
00095
00096 sc->frac_pos = frac_pos;
00097 sc->pos = b - (int16*)sc->memory;
00098 }
00099
00100 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
00101 {
00102 int8 *b;
00103 uint32 frac_pos;
00104 uint32 frac_speed;
00105 int volume_left;
00106 int volume_right;
00107
00108 if (samples > sc->samples_left) samples = sc->samples_left;
00109 sc->samples_left -= samples;
00110 assert(samples > 0);
00111
00112 b = sc->memory + sc->pos;
00113 frac_pos = sc->frac_pos;
00114 frac_speed = sc->frac_speed;
00115 volume_left = sc->volume_left;
00116 volume_right = sc->volume_right;
00117
00118 if (frac_speed == 0x10000) {
00119
00120 do {
00121 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> 8), -MAX_VOLUME, MAX_VOLUME);
00122 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00123 b++;
00124 buffer += 2;
00125 } while (--samples > 0);
00126 } else {
00127 do {
00128 int data = RateConversion(b, frac_pos);
00129 buffer[0] = Clamp(buffer[0] + (data * volume_left >> 8), -MAX_VOLUME, MAX_VOLUME);
00130 buffer[1] = Clamp(buffer[1] + (data * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
00131 buffer += 2;
00132 frac_pos += frac_speed;
00133 b += frac_pos >> 16;
00134 frac_pos &= 0xffff;
00135 } while (--samples > 0);
00136 }
00137
00138 sc->frac_pos = frac_pos;
00139 sc->pos = b - sc->memory;
00140 }
00141
00142 static void MxCloseChannel(MixerChannel *mc)
00143 {
00144 free(mc->memory);
00145 mc->active = false;
00146 mc->memory = NULL;
00147 }
00148
00149 void MxMixSamples(void *buffer, uint samples)
00150 {
00151 MixerChannel *mc;
00152
00153
00154 memset(buffer, 0, sizeof(int16) * 2 * samples);
00155
00156
00157 for (mc = _channels; mc != endof(_channels); mc++) {
00158 if (mc->active) {
00159 if (mc->is16bit) {
00160 mix_int16(mc, (int16*)buffer, samples);
00161 } else {
00162 mix_int8_to_int16(mc, (int16*)buffer, samples);
00163 }
00164 if (mc->samples_left == 0) MxCloseChannel(mc);
00165 }
00166 }
00167 }
00168
00169 MixerChannel *MxAllocateChannel()
00170 {
00171 MixerChannel *mc;
00172 for (mc = _channels; mc != endof(_channels); mc++)
00173 if (mc->memory == NULL) {
00174 mc->active = false;
00175 return mc;
00176 }
00177 return NULL;
00178 }
00179
00180 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
00181 {
00182 mc->memory = mem;
00183 mc->frac_pos = 0;
00184 mc->pos = 0;
00185
00186 mc->frac_speed = (rate << 16) / _play_rate;
00187
00188
00189 while (size & ~0xFFFF) {
00190 size >>= 1;
00191 rate = (rate >> 1) + 1;
00192 }
00193
00194 int div = is16bit ? 2 : 1;
00195
00196 mc->samples_left = (uint)size * _play_rate / rate / div;
00197 mc->is16bit = is16bit;
00198 }
00199
00200 void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
00201 {
00202 mc->volume_left = left;
00203 mc->volume_right = right;
00204 }
00205
00206
00207 void MxActivateChannel(MixerChannel *mc)
00208 {
00209 mc->active = true;
00210 }
00211
00212
00213 bool MxInitialize(uint rate)
00214 {
00215 _play_rate = rate;
00216 return true;
00217 }