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