diff --git a/Makefile b/Makefile index 1401c69d0b..c8a38190ae 100644 --- a/Makefile +++ b/Makefile @@ -600,6 +600,7 @@ C_SOURCES += minilzo.c C_SOURCES += misc.c C_SOURCES += misc_cmd.c C_SOURCES += misc_gui.c +C_SOURCES += mixer.c C_SOURCES += music_gui.c C_SOURCES += namegen.c C_SOURCES += network.c diff --git a/mixer.c b/mixer.c new file mode 100644 index 0000000000..1a113dbeda --- /dev/null +++ b/mixer.c @@ -0,0 +1,154 @@ +#include "stdafx.h" +#include "ttd.h" +#include "mixer.h" + +struct MixerChannel { + // Mixer + Mixer *mx; + 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; +}; + +struct Mixer { + uint32 play_rate; + MixerChannel channels[8]; +}; + + +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->memory = NULL; + mc->active = false; +} + +void MxMixSamples(Mixer *mx, void *buffer, uint samples) +{ + MixerChannel *mc; + + // Clear the buffer + memset(buffer, 0, sizeof(int16) * 2 * samples); + + // Mix each channel + for (mc = mx->channels; mc != endof(mx->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(Mixer *mx) +{ + MixerChannel *mc; + for (mc = mx->channels; mc != endof(mx->channels); mc++) + if (mc->memory == NULL) { + mc->active = false; + mc->mx = mx; + 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) / mc->mx->play_rate; + + // adjust the magnitude to prevent overflow + while (size & 0xFFFF0000) { + size >>= 1; + rate = (rate >> 1) + 1; + } + + mc->samples_left = size * mc->mx->play_rate / rate; +} + +void MxSetChannelVolume(MixerChannel *mc, uint left, uint right) +{ + mc->volume_left = left; + mc->volume_right = right; +} + + +void MxActivate(MixerChannel* mc) +{ + mc->active = true; +} + + +bool MxInitialize(uint rate) +{ + static Mixer mx; + _mixer = &mx; + mx.play_rate = rate; + return true; +} diff --git a/mixer.h b/mixer.h new file mode 100644 index 0000000000..86ace050d9 --- /dev/null +++ b/mixer.h @@ -0,0 +1,24 @@ +#ifndef MIXER_H +#define MIXER_H + +typedef struct Mixer Mixer; +typedef struct MixerChannel MixerChannel; + +enum { + MX_AUTOFREE = 1, +// MX_8BIT = 2, +// MX_STEREO = 4, +// MX_UNSIGNED = 8, +}; + +VARDEF Mixer *_mixer; + +bool MxInitialize(uint rate); +void MxMixSamples(Mixer *mx, void *buffer, uint samples); + +MixerChannel *MxAllocateChannel(Mixer *mx); +void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags); +void MxSetChannelVolume(MixerChannel *mc, uint left, uint right); +void MxActivate(MixerChannel*); + +#endif diff --git a/sdl.c b/sdl.c index 9433faa73c..c2f432c9d1 100644 --- a/sdl.c +++ b/sdl.c @@ -4,7 +4,7 @@ #include "ttd.h" #include "debug.h" #include "gfx.h" -#include "sound.h" +#include "mixer.h" #include "window.h" #include #include "player.h" diff --git a/sound.c b/sound.c index 28055dee40..d0600445ae 100644 --- a/sound.c +++ b/sound.c @@ -1,33 +1,13 @@ #include "stdafx.h" #include "ttd.h" #include "map.h" +#include "mixer.h" #include "sound.h" #include "vehicle.h" #include "window.h" #include "viewport.h" #include "fileio.h" -typedef struct MixerChannel { - // Mixer - Mixer *mx; - 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; -} MixerChannel; - typedef struct FileEntry { uint32 file_offset; uint32 file_size; @@ -36,150 +16,29 @@ typedef struct FileEntry { uint8 channels; } FileEntry; -struct Mixer { - uint32 play_rate; - FileEntry *files; - uint32 file_count; - MixerChannel channels[8]; -}; - -enum { - MX_AUTOFREE = 1, -// MX_8BIT = 2, -// MX_STEREO = 4, - MX_UNSIGNED = 8, -}; +static uint _file_count; +static FileEntry* _files; #define SOUND_SLOT 31 -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->memory = NULL; - mc->active = false; -} - -void MxMixSamples(Mixer *mx, void *buffer, uint samples) -{ - MixerChannel *mc; - - // Clear the buffer - memset(buffer, 0, sizeof(int16) * 2 * samples); - - // Mix each channel - for (mc = mx->channels; mc != endof(mx->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 -} - -static MixerChannel *MxAllocateChannel(Mixer *mx) -{ - MixerChannel *mc; - for (mc = mx->channels; mc != endof(mx->channels); mc++) - if (mc->memory == NULL) { - mc->active = false; - mc->mx = mx; - return mc; - } - return NULL; -} - -static 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) / mc->mx->play_rate; - - // adjust the magnitude to prevent overflow - while (size & 0xFFFF0000) { - size >>= 1; - rate = (rate >> 1) + 1; - } - - mc->samples_left = size * mc->mx->play_rate / rate; -} - -static void MxSetChannelVolume(MixerChannel *mc, uint left, uint right) -{ - mc->volume_left = left; - mc->volume_right = right; -} - -static void MxOpenBankFile(Mixer *mx, const char *filename) +static void OpenBankFile(const char *filename) { uint count, i; uint32 size, tag; FileEntry *fe; FioOpenFile(SOUND_SLOT, filename); - mx->file_count = count = FioReadDword() >> 3; - fe = mx->files = calloc(sizeof(FileEntry), count); + _file_count = count = FioReadDword() >> 3; + fe = _files = calloc(sizeof(FileEntry), count); FioSeekTo(0, SEEK_SET); - for (i = 0; i != count; i++, fe++) { - fe->file_offset = FioReadDword(); - fe->file_size = FioReadDword(); + for (i = 0; i != count; i++) { + fe[i].file_offset = FioReadDword(); + fe[i].file_size = FioReadDword(); } - fe = mx->files; for (i = 0; i != count; i++, fe++) { char name[255]; @@ -227,9 +86,9 @@ static void MxOpenBankFile(Mixer *mx, const char *filename) } } -static bool MxSetBankSource(MixerChannel *mc, uint bank) +static bool SetBankSource(MixerChannel *mc, uint bank) { - FileEntry *fe = &mc->mx->files[bank]; + FileEntry *fe = &_files[bank]; int8 *mem; uint i; @@ -245,17 +104,14 @@ static bool MxSetBankSource(MixerChannel *mc, uint bank) assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0); - MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE | MX_UNSIGNED); + MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE); return true; } -bool MxInitialize(uint rate, const char *filename) +bool SoundInitialize(const char *filename) { - static Mixer mx; - _mixer = &mx; - mx.play_rate = rate; - MxOpenBankFile(&mx, filename); + OpenBankFile(filename); return true; } @@ -266,9 +122,9 @@ static void StartSound(uint sound, uint panning, uint volume) MixerChannel *mc = MxAllocateChannel(_mixer); if (mc == NULL) return; - if (MxSetBankSource(mc, sound)) { + if (SetBankSource(mc, sound)) { MxSetChannelVolume(mc, volume << 8, volume << 8); - mc->active = true; + MxActivate(mc); } } } diff --git a/sound.h b/sound.h index 10859e63fb..8b3522d654 100644 --- a/sound.h +++ b/sound.h @@ -1,8 +1,6 @@ #ifndef SOUND_H #define SOUND_H -typedef struct Mixer Mixer; - typedef struct MusicFileSettings { byte playlist; byte music_vol; @@ -17,10 +15,8 @@ VARDEF byte _music_wnd_cursong; VARDEF bool _song_is_active; VARDEF byte _cur_playlist[33]; VARDEF MusicFileSettings msf; -VARDEF Mixer *_mixer; -bool MxInitialize(uint rate, const char *filename); -void MxMixSamples(Mixer *mx, void *buffer, uint samples); +bool SoundInitialize(const char *filename); typedef enum SoundFx { SND_02_SPLAT, // 0 == 0x00 ! diff --git a/ttd.c b/ttd.c index c1a4f8956f..a230a5ab21 100644 --- a/ttd.c +++ b/ttd.c @@ -8,6 +8,7 @@ #define VARDEF #include "ttd.h" +#include "mixer.h" #include "spritecache.h" #include "gfx.h" #include "gui.h" @@ -626,7 +627,8 @@ int ttd_main(int argc, char* argv[]) // Sample catalogue DEBUG(misc, 1) ("Loading sound effects..."); _os_version = GetOSVersion(); - MxInitialize(11025, "sample.cat"); + MxInitialize(11025); + SoundInitialize("sample.cat"); // This must be done early, since functions use the InvalidateWindow* calls InitWindowSystem(); diff --git a/win32.c b/win32.c index 9bd3a9cab3..8f1e124d3c 100644 --- a/win32.c +++ b/win32.c @@ -4,7 +4,7 @@ #include "string.h" #include "table/strings.h" #include "gfx.h" -#include "sound.h" +#include "mixer.h" #include "window.h" #include "gui.h" #include