/* * Copyright (c) 2002, 2003, 2004, 2005, 2007 by Christian Nowak * Last update: 20th October, 2007 */ #include "mixer.h" #define DO_LOOPING \ if (forward) \ { \ playpos += incval; \ if (playpos >= loop_end) \ { \ if (looped) \ { \ if (pingpong) \ { \ forward = !forward; \ playpos -= incval; \ } else \ playpos -= loop_end - loop_start; \ } else \ { \ playpos = loop_end; \ vinfo->playing = FALSE; \ break; \ } \ } \ } else \ { \ playpos -= incval; \ if (/*playpos <= loop_start*/playpos - loop_start <= incval) \ { \ if (looped) \ { \ if (pingpong) \ { \ forward = !forward; \ playpos += incval; \ } else \ playpos += loop_end - loop_start; \ } else \ { \ playpos = loop_start; \ vinfo->playing = FALSE; \ break; \ } \ } \ } #define DO_LOOPING_OLD \ playpos += incval; \ if (playpos >= loop_end) \ { \ if (looped) \ { \ playpos -= loop_end-loop_start; \ } else \ { \ playpos = loop_end; \ vinfo->playing = FALSE; \ break; \ } \ } #define DO_LOOPING_PINGPONG \ playpos += incval; \ if (forward && playpos >= loop_end) \ { \ if (looped) \ { \ incval = -incval; \ forward = FALSE; \ } else \ { \ playpos = loop_end; \ vinfo->playing = FALSE; \ break; \ } \ } else \ if (!forward && playpos <= loop_start) \ { \ if (looped) \ { \ incval = -incval; \ forward = TRUE; \ } else \ { \ playpos = loop_start; \ vinfo->playing = FALSE; \ break; \ } \ } int mix_destbufsize(int flags) { int size = 1; if (flags & MIXER_DEST_STEREO) size *= 2; if (flags & MIXER_DEST_16BIT) size *= 2; return size; } int clearbuf_final(int flags, void *dest, int nSamples) { if (flags & MIXER_USE_S32) { if (flags & MIXER_DEST_STEREO) { clearbuf_s32((s32*)dest, 2, nSamples); } else { clearbuf_s32((s32*)dest, 1, nSamples); } } return nSamples; } int mix_final_1616bit(int flags, void *dest, int nSamples, MOD_VOICEINFO16 *vinfo, u8 mainvol) { if (flags & MIXER_USE_S32) { if (flags & MIXER_DEST_STEREO) { if (vinfo->sampleInfo->bit_16) { mix_s16m_to_s32s_1616bit((s32*)dest, nSamples, vinfo, mainvol); } else { mix_s8m_to_s32s_1616bit((s32*)dest, nSamples, vinfo, mainvol); } } else { if (vinfo->sampleInfo->bit_16) { mix_s16m_to_s32m_1616bit((s32*)dest, nSamples, vinfo, mainvol); } else { mix_s8m_to_s32m_1616bit((s32*)dest, nSamples, vinfo, mainvol); } } } return nSamples; } int copybuf_final(int flags, void *dest, void *src, int nSamples) { if (flags & MIXER_USE_S32) { if (flags & MIXER_DEST_SIGNED) { if (flags & MIXER_DEST_16BIT) { if (flags & MIXER_DEST_STEREO) { copybuf_s32_to_s16((s16*)dest, (s32*)src, 2, nSamples); } else { copybuf_s32_to_s16((s16*)dest, (s32*)src, 1, nSamples); } } else { if (flags & MIXER_DEST_STEREO) { copybuf_s32_to_s8((s8*)dest, (s32*)src, 2, nSamples); } else { copybuf_s32_to_s8((s8*)dest, (s32*)src, 1, nSamples); } } } else { if (flags & MIXER_DEST_16BIT) { if (flags & MIXER_DEST_STEREO) { copybuf_s32_to_u16((u16*)dest, (s32*)src, 2, nSamples); } else { copybuf_s32_to_u16((u16*)dest, (s32*)src, 1, nSamples); } } else { if (flags & MIXER_DEST_STEREO) { copybuf_s32_to_u8((u8*)dest, (s32*)src, 2, nSamples); } else { copybuf_s32_to_u8((u8*)dest, (s32*)src, 1, nSamples); } } } } return nSamples; } /* Mix s8 mono -> s32 mono, 16.16bit fixed point */ int mix_s8m_to_s32m_1616bit(s32 *dest, int nSamples, MOD_VOICEINFO16 *vinfo, u8 mainvol) { int k; s32 volume; MIXER_TYPE playpos = vinfo->playpos; MIXER_TYPE incval = vinfo->incval; MIXER_TYPE loop_end = ((MIXER_TYPE)vinfo->sampleInfo->loop_end) << MIXER_SHIFT; MIXER_TYPE loop_start = ((MIXER_TYPE)vinfo->sampleInfo->loop_start) << MIXER_SHIFT; BOOL looped = vinfo->sampleInfo->looped; BOOL forward = vinfo->forward; BOOL pingpong = vinfo->sampleInfo->pingpong; s8 *sampledata = vinfo->sampleInfo->sampledata; if (!vinfo->playing) return nSamples; volume = ((s32)vinfo->volume * (s32)mainvol * (s32)vinfo->envVolume) >> 12; for (k = 0; k < nSamples; k++) { s32 value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; dest[k] += value * volume; DO_LOOPING; } vinfo->playpos = playpos; vinfo->forward = forward; return nSamples; } /* Mix s16 mono -> s32 mono, 16.16bit fixed point */ int mix_s16m_to_s32m_1616bit(s32 *dest, int nSamples, MOD_VOICEINFO16 *vinfo, u8 mainvol) { int k; s32 volume; MIXER_TYPE playpos = vinfo->playpos; MIXER_TYPE incval = vinfo->incval; MIXER_TYPE loop_end = ((MIXER_TYPE)vinfo->sampleInfo->loop_end) << MIXER_SHIFT; MIXER_TYPE loop_start = ((MIXER_TYPE)vinfo->sampleInfo->loop_start) << MIXER_SHIFT; BOOL looped = vinfo->sampleInfo->looped; BOOL forward = vinfo->forward; BOOL pingpong = vinfo->sampleInfo->pingpong; s16 *sampledata = vinfo->sampleInfo->sampledata; if (!vinfo->playing) return nSamples; volume = ((s32)vinfo->volume * (s32)mainvol * (s32)vinfo->envVolume) >> 12; for (k = 0; k > MIXER_SHIFT]; dest[k] += value * volume; DO_LOOPING; } vinfo->playpos = playpos; vinfo->forward = forward; return nSamples; } /* Mix s8 mono -> s32 stereo, 16.16bit fixed point */ int mix_s8m_to_s32s_1616bit(s32 *dest, int nSamples, MOD_VOICEINFO16 *vinfo, u8 mainvol) { int k; s32 volume; u8 lvolume, rvolume; MIXER_TYPE playpos = vinfo->playpos; MIXER_TYPE incval = vinfo->incval; MIXER_TYPE loop_end = ((MIXER_TYPE)vinfo->sampleInfo->loop_end) << MIXER_SHIFT; MIXER_TYPE loop_start = ((MIXER_TYPE)vinfo->sampleInfo->loop_start) << MIXER_SHIFT; BOOL looped = vinfo->sampleInfo->looped; BOOL forward = vinfo->forward; BOOL pingpong = vinfo->sampleInfo->pingpong; s8 * sampledata = vinfo->sampleInfo->sampledata; s32 panning; int mxamount = nSamples >> 3; int mxrest = nSamples & ((1 << 3) - 1); if (!vinfo->playing) return nSamples; volume = ((s32)vinfo->volume * (s32)mainvol * (s32)vinfo->envVolume) >> 12; panning = ((s32)(vinfo->panning >> 2) - 32) + ((s32)vinfo->envPanning - 32); if (panning > 32) panning = 32; if (panning < -32) panning = -32; panning += 32; lvolume = (((u32)64 - panning) * volume) >> 6; rvolume = (((u32)panning) * volume) >> 6; for (k = 0; k < mxamount; k++) { s32 value; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; } for (k = 0; k < mxrest; k++) { s32 value; value = ((s32)(s16)((s8*)sampledata)[playpos >> MIXER_SHIFT]) << 8; (*(dest++)) += value * lvolume; (*(dest++)) += value * rvolume; DO_LOOPING; } vinfo->playpos = playpos; vinfo->forward = forward; return nSamples; } /* Mix s16 mono -> s32 stereo, 16.16bit fixed point */ int mix_s16m_to_s32s_1616bit(s32 *dest, int nSamples, MOD_VOICEINFO16 *vinfo, u8 mainvol) { int k; s32 volume; u8 lvolume, rvolume; MIXER_TYPE playpos = vinfo->playpos; MIXER_TYPE incval = vinfo->incval; MIXER_TYPE loop_end = ((MIXER_TYPE)vinfo->sampleInfo->loop_end) << MIXER_SHIFT; MIXER_TYPE loop_start = ((MIXER_TYPE)vinfo->sampleInfo->loop_start) << MIXER_SHIFT; BOOL looped = vinfo->sampleInfo->looped; BOOL forward = vinfo->forward; BOOL pingpong = vinfo->sampleInfo->pingpong; s16 * sampledata = vinfo->sampleInfo->sampledata; if (!vinfo->playing) return nSamples; volume = ((s32)vinfo->volume * (s32)mainvol * (s32)vinfo->envVolume) >> 12; lvolume = (((u32)64-(vinfo->panning >> 2))*volume) >> 6; rvolume = (((u32)(vinfo->panning >> 2))*volume) >> 6; for (k = 0; k < nSamples * 2; k += 2) { s32 value = (s32)((s16*)sampledata)[playpos >> MIXER_SHIFT]; dest[k] += value * lvolume; dest[k + 1] += value * rvolume; DO_LOOPING; } vinfo->playpos = playpos; vinfo->forward = forward; return nSamples; } void clearbuf_s32(s32 *dest, int channels, int nSamples) { int k; int mxamount; int mxrest; mxamount = (nSamples * channels) >> 3; mxrest = (nSamples * channels) & ((1 << 3) - 1); for (k = 0; k < mxamount; k++) { (*(dest++)) = 0; (*(dest++)) = 0; (*(dest++)) = 0; (*(dest++)) = 0; (*(dest++)) = 0; (*(dest++)) = 0; (*(dest++)) = 0; (*(dest++)) = 0; } for (k = 0; k < mxrest; k++) { (*(dest++)) = 0; } /* for (k = 0; k < nSamples * channels; k++) dest[k] = 0;*/ } void copybuf_s32_to_s16(s16 *dest, s32 *src, int channels, int nSamples) { int k; for (k = 0; k < nSamples*channels; k++) { s32 value = src[k] >> 8; if (value < -32768) value = -32768; else if (value > 32767) value = 32767; dest[k] = (s16)value; } } #define CLIP_S32(a) \ if (a < -32768) a = 32768; else if (a > 32767) a = 32767; void copybuf_s32_to_u16(u16 *dest, s32 *src, int channels, int nSamples) { int k; int mxamount; int mxrest; mxamount = (nSamples * channels) >> 3; mxrest = (nSamples * channels) & ((1 << 3) - 1); for (k = 0; k < mxamount; k++) { s32 value; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; } for (k = 0; k < mxrest; k++) { s32 value; value = (*(src++)) >> 7; CLIP_S32(value); (*(dest++)) = ((u16)(s16)value) ^ 0x8000; } /* for (k=0; k>7; if (value<-32768) value = -32768; else if (value>32767) value = 32767; dest[k] = ((u16)(s16)value)^0x8000; }*/ } void copybuf_s32_to_s8(s8 *dest, s32 *src, int channels, int nSamples) { int k; for (k = 0; k < nSamples * channels; k++) { s32 value = src[k] >> 16; if (value < -128) value = -128; else if (value > 127) value = 127; dest[k] = (s8)value; } } void copybuf_s32_to_u8(u8 *dest, s32 *src, int channels, int nSamples) { int k; for (k = 0; k < nSamples * channels; k++) { s32 value = src[k] >> 16; if (value < -128) value = -128; else if (value > 127) value = 127; dest[k] = ((u8)(s8)value) ^ 0x80; } }