📄 multivoc.c
字号:
/*Copyright (C) 1994-1995 Apogee Software, Ltd.This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.Modifications for JonoF's port by Jonathon Fowler (jonof@edgenetwk.com)*//********************************************************************** module: MULTIVOC.C author: James R. Dose date: December 20, 1993 Routines to provide multichannel digitized sound playback for Sound Blaster compatible sound cards. (c) Copyright 1993 James R. Dose. All Rights Reserved.**********************************************************************/#include <stdlib.h>#include <string.h>#ifndef _MSC_VER#include <unistd.h>#endif#include <duke3d.h>#ifdef _WIN32#include "dsoundout.h"#ifdef USE_OPENAL#include "openal.h"#endif#else#include "dsl.h"#endif#include "compat.h"#include "baselayer.h"#include "linklist.h"#include "pitch.h"#include "multivoc.h"#include "_multivc.h"#define STEREO 1#define SIXTEEN_BIT 2#define MONO_8BIT 0#define STEREO_8BIT (STEREO)#define MONO_16BIT (SIXTEEN_BIT)#define STEREO_16BIT (STEREO | SIXTEEN_BIT)#define IS_QUIET(ptr) ((void *)(ptr) == (void *)&MV_VolumeTable[ 0 ])static int32_t MV_ReverbLevel;static int32_t MV_ReverbDelay;static VOLUME16 *MV_ReverbTable = NULL;//static signed short MV_VolumeTable[ MV_MaxVolume + 1 ][ 256 ];static int16_t MV_VolumeTable[ 63 + 1 ][ 256 ];//static Pan MV_PanTable[ MV_NumPanPositions ][ MV_MaxVolume + 1 ];static Pan MV_PanTable[ MV_NumPanPositions ][ 63 + 1 ];static int32_t MV_Installed = FALSE;static int32_t MV_SoundCard = -1;static int32_t MV_TotalVolume = MV_MaxTotalVolume;static int32_t MV_MaxVoices = 1;static int32_t MV_Recording;static int32_t MV_BufferSize = 0;static int32_t MV_BufferLength;static int32_t MV_NumberOfBuffers = NumberOfBuffers;static int32_t MV_MixMode = MONO_8BIT;static int32_t MV_Channels = 1;static int32_t MV_Bits = 8;static int32_t MV_Silence = SILENCE_8BIT;static int32_t MV_SwapLeftRight = FALSE;static int32_t MV_RequestedMixRate;static int32_t MV_MixRate;static int32_t MV_BuffShift;static int32_t MV_TotalMemory;static int32_t MV_BufferEmpty[ NumberOfBuffers ];char *MV_MixBuffer[ NumberOfBuffers + 1 ];static char *MV_MixBufferPtr = NULL;static VoiceNode *MV_Voices = NULL;static VoiceNode VoiceList;static VoiceNode VoicePool;int32_t MV_MixPage = 0;static int32_t MV_VoiceHandle = MV_MinVoiceHandle;static void(*MV_CallBackFunc)(uint32_t) = NULL;static void(*MV_RecordFunc)(char *ptr, int32_t length) = NULL;static void(*MV_MixFunction)(VoiceNode *voice, int32_t buffer);static int32_t MV_MaxVolume = 63;char *MV_HarshClipTable;char *MV_MixDestination;int16_t *MV_LeftVolume;int16_t *MV_RightVolume;int32_t MV_SampleSize = 1;int32_t MV_RightChannelOffset;uint32_t MV_MixPosition;int32_t MV_ErrorCode = MV_Ok;#define MV_SetErrorCode(status) \ MV_ErrorCode = (status);/*--------------------------------------------------------------------- Function: ClearBuffer_DW Function code relocated from _multivc.h due to linking issues.---------------------------------------------------------------------*/void ClearBuffer_DW(void *ptr, int32_t data, int32_t length){ int32_t *pptr = ptr; for (; length>0; length--) *(pptr++) = data;}/*--------------------------------------------------------------------- Function: MV_ErrorString Returns a pointer to the error message associated with an error number. A -1 returns a pointer the current error.---------------------------------------------------------------------*/char *MV_ErrorString(int32_t ErrorNumber){ char *ErrorString; switch (ErrorNumber) { case MV_Warning : case MV_Error : ErrorString = MV_ErrorString(MV_ErrorCode); break; case MV_Ok : ErrorString = "Multivoc ok."; break; case MV_UnsupportedCard : ErrorString = "Selected sound card is not supported by Multivoc."; break; case MV_NotInstalled : ErrorString = "Multivoc not installed."; break; case MV_NoVoices : ErrorString = "No free voices available to Multivoc."; break; case MV_NoMem : ErrorString = "Out of memory in Multivoc."; break; case MV_VoiceNotFound : ErrorString = "No voice with matching handle found."; break; case MV_BlasterError :#if defined(_WIN32) ErrorString = DSOUND_ErrorString(DSOUND_ErrorCode);#else ErrorString = DSL_ErrorString(DSL_ErrorCode);#endif break; case MV_DPMI_Error : ErrorString = "DPMI Error in Multivoc."; break; case MV_InvalidVOCFile : ErrorString = "Invalid VOC file passed in to Multivoc."; break; case MV_InvalidWAVFile : ErrorString = "Invalid WAV file passed in to Multivoc."; break; case MV_InvalidOGGFile : ErrorString = "Invalid OGG file passed in to Multivoc."; break; case MV_InvalidMixMode : ErrorString = "Invalid mix mode request in Multivoc."; break; case MV_IrqFailure : ErrorString = "Playback failed, possibly due to an invalid or conflicting IRQ."; break; case MV_DMAFailure : ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel."; break; case MV_DMA16Failure : ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel. \n" "Make sure the 16-bit DMA channel is correct."; break; case MV_NullRecordFunction : ErrorString = "Null record function passed to MV_StartRecording."; break; default : ErrorString = "Unknown Multivoc error code."; break; } return(ErrorString);}/********************************************************************** Memory locked functions:**********************************************************************//*--------------------------------------------------------------------- Function: MV_GetBufferSize Returns the buffer size for the given samplerate.---------------------------------------------------------------------*/#if defined(_WIN32)#define BASEBUFSZ (512+128)static uint32_t MV_GetBufferSize(unsigned samplerate){ static unsigned lastsr = 0, lastbufsz = 0; if (samplerate == lastsr) return lastbufsz; lastsr = samplerate; lastbufsz = (samplerate*BASEBUFSZ/22050)&(~15);#ifdef RENDERTYPEWIN { extern int32_t is_vista; if (is_vista) lastbufsz = (samplerate*BASEBUFSZ/22050*2)&(~15); }#endif return lastbufsz;}#endif/*--------------------------------------------------------------------- Function: MV_Mix Mixes the sound into the buffer.---------------------------------------------------------------------*/static void MV_Mix(VoiceNode *voice, int32_t buffer){ char *start; int32_t length; int32_t voclength; uint32_t position; uint32_t rate; uint32_t FixedPointBufferSize; if ((voice->length == 0) && (voice->GetSound(voice) != KeepPlaying)) { return; } length = MixBufferSize; FixedPointBufferSize = voice->FixedPointBufferSize; MV_MixDestination = MV_MixBuffer[ buffer ]; MV_LeftVolume = voice->LeftVolume; MV_RightVolume = voice->RightVolume; if ((MV_Channels == 2) && (IS_QUIET(MV_LeftVolume))) { MV_LeftVolume = MV_RightVolume; MV_MixDestination += MV_RightChannelOffset; } // Add this voice to the mix while (length > 0) { start = voice->sound; rate = voice->RateScale; position = voice->position; // Check if the last sample in this buffer would be // beyond the length of the sample block if ((position + FixedPointBufferSize) >= voice->length) { if (position < voice->length) { voclength = (voice->length - position + rate - 1) / rate; } else { voice->GetSound(voice); return; } } else { voclength = length; } voice->mix(position, rate, start, voclength); if (voclength & 1) { MV_MixPosition += rate; voclength -= 1; } voice->position = MV_MixPosition; length -= voclength; if (voice->position >= voice->length) { // Get the next block of sound if (voice->GetSound(voice) != KeepPlaying) { return; } if (length > 0) { // Get the position of the last sample in the buffer FixedPointBufferSize = voice->RateScale * (length - 1); } } }}/*--------------------------------------------------------------------- Function: MV_PlayVoice Adds a voice to the play list.---------------------------------------------------------------------*/void MV_PlayVoice(VoiceNode *voice){ unsigned flags; flags = DisableInterrupts(); LL_SortedInsertion(&VoiceList, voice, prev, next, VoiceNode, priority);// if(!voice->bufsnd)voice->bufsnd=(char *)Bcalloc(0x8000*4,sizeof(uint8_t));// if(!voice->bufsnd)initprintf("Attention. It gonna crash! Thank you."); // FIXME: change the msg RestoreInterrupts(flags);}/*--------------------------------------------------------------------- Function: MV_StopVoice Removes the voice from the play list and adds it to the free list.---------------------------------------------------------------------*/void MV_StopVoice(VoiceNode *voice){ uint32_t flags; flags = DisableInterrupts();// if(!voice->bufsnd)Bfree(voice->bufsnd); // move the voice from the play list to the free list LL_Remove(voice, next, prev); LL_Add(&VoicePool, voice, next, prev); RestoreInterrupts(flags);}/*--------------------------------------------------------------------- Function: MV_ServiceVoc Starts playback of the waiting buffer and mixes the next one.---------------------------------------------------------------------*/// static int32_t backcolor = 1;int32_t MV_ServiceVoc(int32_t buffer){ VoiceNode *voice; VoiceNode *next; // Get the currently playing buffer#if defined(_WIN32) MV_MixPage = buffer;#else UNREFERENCED_PARAMETER(buffer);#endif // Toggle which buffer we'll mix next MV_MixPage++; if (MV_MixPage >= MV_NumberOfBuffers) { MV_MixPage -= MV_NumberOfBuffers; } if (MV_ReverbLevel == 0) { // Initialize buffer //Commented out so that the buffer is always cleared. //This is so the guys at Echo Speech can mix into the //buffer even when no sounds are playing. //if (!MV_BufferEmpty[ MV_MixPage ]) { ClearBuffer_DW(MV_MixBuffer[ MV_MixPage ], MV_Silence, MV_BufferSize >> 2); MV_BufferEmpty[ MV_MixPage ] = TRUE; } } else { char *end; char *source; char *dest; int32_t count; int32_t length; end = MV_MixBuffer[ 0 ] + MV_BufferLength; dest = MV_MixBuffer[ MV_MixPage ]; source = MV_MixBuffer[ MV_MixPage ] - MV_ReverbDelay; if (source < MV_MixBuffer[ 0 ]) { source += MV_BufferLength; } length = MV_BufferSize; while (length > 0) { count = length; if (source + count > end) { count = end - source; } if (MV_Bits == 16) { if (MV_ReverbTable != NULL) { MV_16BitReverb(source, dest, MV_ReverbTable, count / 2); } else { MV_16BitReverbFast(source, dest, count / 2, MV_ReverbLevel); } } else { if (MV_ReverbTable != NULL) { MV_8BitReverb((char *)source, (char *)dest, MV_ReverbTable, count); } else { MV_8BitReverbFast((char *)source, (char *)dest, count, MV_ReverbLevel); } } // if we go through the loop again, it means that we've wrapped around the buffer source = MV_MixBuffer[ 0 ]; dest += count; length -= count; } } // Play any waiting voices for (voice = VoiceList.next; voice != &VoiceList; voice = next) {// if ((voice < &MV_Voices[ 0 ]) || (voice > &MV_Voices[ 8 ]))// {// SetBorderColor(backcolor++);// break;// } MV_BufferEmpty[ MV_MixPage ] = FALSE; MV_MixFunction(voice, MV_MixPage); next = voice->next; // Is this voice done? if (!voice->Playing) { MV_StopVoice(voice); if (MV_CallBackFunc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -