(svn r3674) -Feature: [OSX] Added support for tripple binaries (binaries optimised for G3, G5 and i686)
G4 have no problems using G3 code while G5 can, but really benefit from getting their own optimised code (Apple: G5 is not just a fast G4)
Also changed FAT_BINARY to UNIVERSAL_BINARY since Apple removed most (all?) references to fat binaries on their homepage two days after I added FAT_BINARY
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "mixer.h"
struct MixerChannel {
bool active;
// pointer to allocated buffer memory
int8 *memory;
// current position in memory
uint32 pos;
uint32 frac_pos;
uint32 frac_speed;
uint32 samples_left;
// Mixing volume
uint volume_left;
uint volume_right;
uint flags;
};
static MixerChannel _channels[8];
static uint32 _play_rate;
static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
{
int8 *b;
uint32 frac_pos;
uint32 frac_speed;
uint volume_left;
uint volume_right;
if (samples > sc->samples_left) samples = sc->samples_left;
sc->samples_left -= samples;
assert(samples > 0);
b = sc->memory + sc->pos;
frac_pos = sc->frac_pos;
frac_speed = sc->frac_speed;
volume_left = sc->volume_left;
volume_right = sc->volume_right;
if (frac_speed == 0x10000) {
// Special case when frac_speed is 0x10000
do {
buffer[0] += *b * volume_left >> 8;
buffer[1] += *b * volume_right >> 8;
b++;
buffer += 2;
} while (--samples > 0);
} else {
do {
buffer[0] += *b * volume_left >> 8;
buffer[1] += *b * volume_right >> 8;
buffer += 2;
frac_pos += frac_speed;
b += frac_pos >> 16;
frac_pos &= 0xffff;
} while (--samples > 0);
}
sc->frac_pos = frac_pos;
sc->pos = b - sc->memory;
}
static void MxCloseChannel(MixerChannel *mc)
{
if (mc->flags & MX_AUTOFREE) free(mc->memory);
mc->active = false;
mc->memory = NULL;
}
void MxMixSamples(void *buffer, uint samples)
{
MixerChannel *mc;
// Clear the buffer
memset(buffer, 0, sizeof(int16) * 2 * samples);
// Mix each channel
for (mc = _channels; mc != endof(_channels); mc++) {
if (mc->active) {
mix_int8_to_int16(mc, buffer, samples);
if (mc->samples_left == 0) MxCloseChannel(mc);
}
}
#if 0
{
static FILE *out = NULL;
if (out == NULL)
out = fopen("d:\\dump.raw", "wb");
fwrite(buffer, samples * 4, 1, out);
}
#endif
}
MixerChannel *MxAllocateChannel(void)
{
MixerChannel *mc;
for (mc = _channels; mc != endof(_channels); mc++)
if (mc->memory == NULL) {
mc->active = false;
return mc;
}
return NULL;
}
void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags)
{
mc->memory = mem;
mc->flags = flags;
mc->frac_pos = 0;
mc->pos = 0;
mc->frac_speed = (rate << 16) / _play_rate;
// adjust the magnitude to prevent overflow
while (size & 0xFFFF0000) {
size >>= 1;
rate = (rate >> 1) + 1;
}
mc->samples_left = size * _play_rate / rate;
}
void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
{
mc->volume_left = left;
mc->volume_right = right;
}
void MxActivateChannel(MixerChannel* mc)
{
mc->active = true;
}
bool MxInitialize(uint rate)
{
_play_rate = rate;
return true;
}