123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453 |
- /*
- Copyright (C) 1994-1995 Apogee Software, Ltd.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of 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 of
- MERCHANTABILITY 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 License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- /**********************************************************************
- 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>
- #include <dos.h>
- #include <time.h>
- #include <conio.h>
- #include "dpmi.h"
- #include "usrhooks.h"
- #include "interrup.h"
- #include "dma.h"
- #include "linklist.h"
- #include "sndcards.h"
- #include "blaster.h"
- #include "sndscape.h"
- #include "sndsrc.h"
- #include "pas16.h"
- #include "guswave.h"
- #include "pitch.h"
- #include "multivoc.h"
- #include "_multivc.h"
- #include "debugio.h"
- #define RoundFixed( fixedval, bits ) \
- ( \
- ( \
- (fixedval) + ( 1 << ( (bits) - 1 ) )\
- ) >> (bits) \
- )
- #define IS_QUIET( ptr ) ( ( void * )( ptr ) == ( void * )&MV_VolumeTable[ 0 ] )
- static int MV_ReverbLevel;
- static int MV_ReverbDelay;
- static VOLUME16 *MV_ReverbTable = NULL;
- //static signed short MV_VolumeTable[ MV_MaxVolume + 1 ][ 256 ];
- static signed short MV_VolumeTable[ 63 + 1 ][ 256 ];
- //static Pan MV_PanTable[ MV_NumPanPositions ][ MV_MaxVolume + 1 ];
- static Pan MV_PanTable[ MV_NumPanPositions ][ 63 + 1 ];
- static int MV_Installed = FALSE;
- static int MV_SoundCard = SoundBlaster;
- static int MV_TotalVolume = MV_MaxTotalVolume;
- static int MV_MaxVoices = 1;
- static int MV_Recording;
- static int MV_BufferSize = MixBufferSize;
- static int MV_BufferLength;
- static int MV_NumberOfBuffers = NumberOfBuffers;
- static int MV_MixMode = MONO_8BIT;
- static int MV_Channels = 1;
- static int MV_Bits = 8;
- static int MV_Silence = SILENCE_8BIT;
- static int MV_SwapLeftRight = FALSE;
- static int MV_RequestedMixRate;
- static int MV_MixRate;
- static int MV_DMAChannel = -1;
- static int MV_BuffShift;
- static int MV_TotalMemory;
- static int MV_BufferDescriptor;
- static int MV_BufferEmpty[ NumberOfBuffers ];
- char *MV_MixBuffer[ NumberOfBuffers + 1 ];
- static VoiceNode *MV_Voices = NULL;
- static volatile VoiceNode VoiceList;
- static volatile VoiceNode VoicePool;
- static int MV_MixPage = 0;
- static int MV_VoiceHandle = MV_MinVoiceHandle;
- static void ( *MV_CallBackFunc )( unsigned long ) = NULL;
- static void ( *MV_RecordFunc )( char *ptr, int length ) = NULL;
- static void ( *MV_MixFunction )( VoiceNode *voice, int buffer );
- static int MV_MaxVolume = 63;
- char *MV_HarshClipTable;
- char *MV_MixDestination;
- short *MV_LeftVolume;
- short *MV_RightVolume;
- int MV_SampleSize = 1;
- int MV_RightChannelOffset;
- unsigned long MV_MixPosition;
- int MV_ErrorCode = MV_Ok;
- #define MV_SetErrorCode( status ) \
- MV_ErrorCode = ( status );
- /*---------------------------------------------------------------------
- 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
- (
- int 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 :
- ErrorString = BLASTER_ErrorString( BLASTER_Error );
- break;
- case MV_PasError :
- ErrorString = PAS_ErrorString( PAS_Error );
- break;
- case MV_SoundScapeError :
- ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error );
- break;
- #ifndef SOUNDSOURCE_OFF
- case MV_SoundSourceError :
- ErrorString = SS_ErrorString( SS_Error );
- break;
- #endif
- 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_InvalidMixMode :
- ErrorString = "Invalid mix mode request in Multivoc.";
- break;
- case MV_SoundSourceFailure :
- ErrorString = "Sound Source playback failed.";
- 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:
- **********************************************************************/
- #define MV_LockStart MV_Mix
- /*---------------------------------------------------------------------
- Function: MV_Mix
- Mixes the sound into the buffer.
- ---------------------------------------------------------------------*/
- static void MV_Mix
- (
- VoiceNode *voice,
- int buffer
- )
- {
- char *start;
- int length;
- long voclength;
- unsigned long position;
- unsigned long rate;
- unsigned long 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 );
- RestoreInterrupts( flags );
- }
- /*---------------------------------------------------------------------
- Function: MV_StopVoice
- Removes the voice from the play list and adds it to the free list.
- ---------------------------------------------------------------------*/
- void MV_StopVoice
- (
- VoiceNode *voice
- )
- {
- unsigned flags;
- flags = DisableInterrupts();
- // 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 int backcolor = 1;
- void MV_ServiceVoc
- (
- void
- )
- {
- VoiceNode *voice;
- VoiceNode *next;
- char *buffer;
- if ( MV_DMAChannel >= 0 )
- {
- // Get the currently playing buffer
- buffer = ( char * )DMA_GetCurrentPos( MV_DMAChannel );
- MV_MixPage = ( unsigned )( buffer - MV_MixBuffer[ 0 ] );
- MV_MixPage >>= MV_BuffShift;
- }
- // 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 );
- if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
- {
- ClearBuffer_DW( MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset,
- MV_Silence, MV_BufferSize >> 2 );
- }
- MV_BufferEmpty[ MV_MixPage ] = TRUE;
- }
- }
- else
- {
- char *end;
- char *source;
- char *dest;
- int count;
- int 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 );
- if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
- {
- MV_16BitReverb( source + MV_RightChannelOffset,
- dest + MV_RightChannelOffset, MV_ReverbTable, count / 2 );
- }
- }
- else
- {
- MV_16BitReverbFast( source, dest, count / 2, MV_ReverbLevel );
- if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
- {
- MV_16BitReverbFast( source + MV_RightChannelOffset,
- dest + MV_RightChannelOffset, count / 2, MV_ReverbLevel );
- }
- }
- }
- else
- {
- if ( MV_ReverbTable != NULL )
- {
- MV_8BitReverb( source, dest, MV_ReverbTable, count );
- if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
- {
- MV_8BitReverb( source + MV_RightChannelOffset,
- dest + MV_RightChannelOffset, MV_ReverbTable, count );
- }
- }
- else
- {
- MV_8BitReverbFast( source, dest, count, MV_ReverbLevel );
- if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
- {
- MV_8BitReverbFast( source + MV_RightChannelOffset,
- dest + MV_RightChannelOffset, 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 )
- {
- MV_CallBackFunc( voice->callbackval );
- }
- }
- }
- }
- int leftpage = -1;
- int rightpage = -1;
- void MV_ServiceGus( char **ptr, unsigned long *length )
- {
- if ( leftpage == MV_MixPage )
- {
- MV_ServiceVoc();
- }
- leftpage = MV_MixPage;
- *ptr = MV_MixBuffer[ MV_MixPage ];
- *length = MV_BufferSize;
- }
- void MV_ServiceRightGus( char **ptr, unsigned long *length )
- {
- if ( rightpage == MV_MixPage )
- {
- MV_ServiceVoc();
- }
- rightpage = MV_MixPage;
- *ptr = MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset;
- *length = MV_BufferSize;
- }
- /*---------------------------------------------------------------------
- Function: MV_GetNextVOCBlock
- Interperate the information of a VOC format sound file.
- ---------------------------------------------------------------------*/
- playbackstatus MV_GetNextVOCBlock
- (
- VoiceNode *voice
- )
- {
- unsigned char *ptr;
- int blocktype;
- int lastblocktype;
- unsigned long blocklength;
- unsigned long samplespeed;
- unsigned int tc;
- int packtype;
- int voicemode;
- int done;
- unsigned BitsPerSample;
- unsigned Channels;
- unsigned Format;
- if ( voice->BlockLength > 0 )
- {
- voice->position -= voice->length;
- voice->sound += voice->length >> 16;
- if ( voice->bits == 16 )
- {
- voice->sound += voice->length >> 16;
- }
- voice->length = min( voice->BlockLength, 0x8000 );
- voice->BlockLength -= voice->length;
- voice->length <<= 16;
- return( KeepPlaying );
- }
- if ( ( voice->length > 0 ) && ( voice->LoopEnd != NULL ) &&
- ( voice->LoopStart != NULL ) )
- {
- voice->BlockLength = voice->LoopSize;
- voice->sound = voice->LoopStart;
- voice->position = 0;
- voice->length = min( voice->BlockLength, 0x8000 );
- voice->BlockLength -= voice->length;
- voice->length <<= 16;
- return( KeepPlaying );
- }
- ptr = ( unsigned char * )voice->NextBlock;
- voice->Playing = TRUE;
- voicemode = 0;
- lastblocktype = 0;
- packtype = 0;
- done = FALSE;
- while( !done )
- {
- // Stop playing if we get a NULL pointer
- if ( ptr == NULL )
- {
- voice->Playing = FALSE;
- done = TRUE;
- break;
- }
- blocktype = ( int )*ptr;
- blocklength = ( *( unsigned long * )( ptr + 1 ) ) & 0x00ffffff;
- ptr += 4;
- switch( blocktype )
- {
- case 0 :
- // End of data
- if ( ( voice->LoopStart == NULL ) ||
- ( voice->LoopStart >= ( ptr - 4 ) ) )
- {
- voice->Playing = FALSE;
- done = TRUE;
- }
- else
- {
- voice->BlockLength = ( ptr - 4 ) - voice->LoopStart;
- voice->sound = voice->LoopStart;
- voice->position = 0;
- voice->length = min( voice->BlockLength, 0x8000 );
- voice->BlockLength -= voice->length;
- voice->length <<= 16;
- return( KeepPlaying );
- }
- break;
- case 1 :
- // Sound data block
- voice->bits = 8;
- if ( lastblocktype != 8 )
- {
- tc = ( unsigned int )*ptr << 8;
- packtype = *( ptr + 1 );
- }
- ptr += 2;
- blocklength -= 2;
- samplespeed = 256000000L / ( 65536 - tc );
- // Skip packed or stereo data
- if ( ( packtype != 0 ) || ( voicemode != 0 ) )
- {
- ptr += blocklength;
- }
- else
- {
- done = TRUE;
- }
- voicemode = 0;
- break;
- case 2 :
- // Sound continuation block
- samplespeed = voice->SamplingRate;
- done = TRUE;
- break;
- case 3 :
- // Silence
- // Not implimented.
- ptr += blocklength;
- break;
- case 4 :
- // Marker
- // Not implimented.
- ptr += blocklength;
- break;
- case 5 :
- // ASCII string
- // Not implimented.
- ptr += blocklength;
- break;
- case 6 :
- // Repeat begin
- if ( voice->LoopEnd == NULL )
- {
- voice->LoopCount = *( unsigned short * )ptr;
- voice->LoopStart = ptr + blocklength;
- }
- ptr += blocklength;
- break;
- case 7 :
- // Repeat end
- ptr += blocklength;
- if ( lastblocktype == 6 )
- {
- voice->LoopCount = 0;
- }
- else
- {
- if ( ( voice->LoopCount > 0 ) && ( voice->LoopStart != NULL ) )
- {
- ptr = voice->LoopStart;
- if ( voice->LoopCount < 0xffff )
- {
- voice->LoopCount--;
- if ( voice->LoopCount == 0 )
- {
- voice->LoopStart = NULL;
- }
- }
- }
- }
- break;
- case 8 :
- // Extended block
- voice->bits = 8;
- tc = *( unsigned short * )ptr;
- packtype = *( ptr + 2 );
- voicemode = *( ptr + 3 );
- ptr += blocklength;
- break;
- case 9 :
- // New sound data block
- samplespeed = *( unsigned long * )ptr;
- BitsPerSample = ( unsigned )*( ptr + 4 );
- Channels = ( unsigned )*( ptr + 5 );
- Format = ( unsigned )*( unsigned short * )( ptr + 6 );
- if ( ( BitsPerSample == 8 ) && ( Channels == 1 ) &&
- ( Format == VOC_8BIT ) )
- {
- ptr += 12;
- blocklength -= 12;
- voice->bits = 8;
- done = TRUE;
- }
- else if ( ( BitsPerSample == 16 ) && ( Channels == 1 ) &&
- ( Format == VOC_16BIT ) )
- {
- ptr += 12;
- blocklength -= 12;
- voice->bits = 16;
- done = TRUE;
- }
- else
- {
- ptr += blocklength;
- }
- break;
- default :
- // Unknown data. Probably not a VOC file.
- voice->Playing = FALSE;
- done = TRUE;
- break;
- }
- lastblocktype = blocktype;
- }
- if ( voice->Playing )
- {
- voice->NextBlock = ptr + blocklength;
- voice->sound = ptr;
- voice->SamplingRate = samplespeed;
- voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate;
- // Multiply by MixBufferSize - 1
- voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) -
- voice->RateScale;
- if ( voice->LoopEnd != NULL )
- {
- if ( blocklength > ( unsigned long )voice->LoopEnd )
- {
- blocklength = ( unsigned long )voice->LoopEnd;
- }
- else
- {
- voice->LoopEnd = ( char * )blocklength;
- }
- voice->LoopStart = voice->sound + ( unsigned long )voice->LoopStart;
- voice->LoopEnd = voice->sound + ( unsigned long )voice->LoopEnd;
- voice->LoopSize = voice->LoopEnd - voice->LoopStart;
- }
- if ( voice->bits == 16 )
- {
- blocklength /= 2;
- }
- voice->position = 0;
- voice->length = min( blocklength, 0x8000 );
- voice->BlockLength = blocklength - voice->length;
- voice->length <<= 16;
- MV_SetVoiceMixMode( voice );
- return( KeepPlaying );
- }
- return( NoMoreData );
- }
- /*---------------------------------------------------------------------
- Function: MV_GetNextDemandFeedBlock
- Controls playback of demand fed data.
- ---------------------------------------------------------------------*/
- playbackstatus MV_GetNextDemandFeedBlock
- (
- VoiceNode *voice
- )
- {
- if ( voice->BlockLength > 0 )
- {
- voice->position -= voice->length;
- voice->sound += voice->length >> 16;
- voice->length = min( voice->BlockLength, 0x8000 );
- voice->BlockLength -= voice->length;
- voice->length <<= 16;
- return( KeepPlaying );
- }
- if ( voice->DemandFeed == NULL )
- {
- return( NoMoreData );
- }
- voice->position = 0;
- ( voice->DemandFeed )( &voice->sound, &voice->BlockLength );
- voice->length = min( voice->BlockLength, 0x8000 );
- voice->BlockLength -= voice->length;
- voice->length <<= 16;
- if ( ( voice->length > 0 ) && ( voice->sound != NULL ) )
- {
- return( KeepPlaying );
- }
- return( NoMoreData );
- }
- /*---------------------------------------------------------------------
- Function: MV_GetNextRawBlock
- Controls playback of demand fed data.
- ---------------------------------------------------------------------*/
- playbackstatus MV_GetNextRawBlock
- (
- VoiceNode *voice
- )
- {
- if ( voice->BlockLength <= 0 )
- {
- if ( voice->LoopStart == NULL )
- {
- voice->Playing = FALSE;
- return( NoMoreData );
- }
- voice->BlockLength = voice->LoopSize;
- voice->NextBlock = voice->LoopStart;
- voice->length = 0;
- voice->position = 0;
- }
- voice->sound = voice->NextBlock;
- voice->position -= voice->length;
- voice->length = min( voice->BlockLength, 0x8000 );
- voice->NextBlock += voice->length;
- if ( voice->bits == 16 )
- {
- voice->NextBlock += voice->length;
- }
- voice->BlockLength -= voice->length;
- voice->length <<= 16;
- return( KeepPlaying );
- }
- /*---------------------------------------------------------------------
- Function: MV_GetNextWAVBlock
- Controls playback of demand fed data.
- ---------------------------------------------------------------------*/
- playbackstatus MV_GetNextWAVBlock
- (
- VoiceNode *voice
- )
- {
- if ( voice->BlockLength <= 0 )
- {
- if ( voice->LoopStart == NULL )
- {
- voice->Playing = FALSE;
- return( NoMoreData );
- }
- voice->BlockLength = voice->LoopSize;
- voice->NextBlock = voice->LoopStart;
- voice->length = 0;
- voice->position = 0;
- }
- voice->sound = voice->NextBlock;
- voice->position -= voice->length;
- voice->length = min( voice->BlockLength, 0x8000 );
- voice->NextBlock += voice->length;
- if ( voice->bits == 16 )
- {
- voice->NextBlock += voice->length;
- }
- voice->BlockLength -= voice->length;
- voice->length <<= 16;
- return( KeepPlaying );
- }
- /*---------------------------------------------------------------------
- Function: MV_ServiceRecord
- Starts recording of the waiting buffer.
- ---------------------------------------------------------------------*/
- static void MV_ServiceRecord
- (
- void
- )
- {
- if ( MV_RecordFunc )
- {
- MV_RecordFunc( MV_MixBuffer[ 0 ] + MV_MixPage * MixBufferSize,
- MixBufferSize );
- }
- // Toggle which buffer we'll mix next
- MV_MixPage++;
- if ( MV_MixPage >= NumberOfBuffers )
- {
- MV_MixPage = 0;
- }
- }
- /*---------------------------------------------------------------------
- Function: MV_GetVoice
- Locates the voice with the specified handle.
- ---------------------------------------------------------------------*/
- VoiceNode *MV_GetVoice
- (
- int handle
- )
- {
- VoiceNode *voice;
- unsigned flags;
- flags = DisableInterrupts();
- for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next )
- {
- if ( handle == voice->handle )
- {
- break;
- }
- }
- RestoreInterrupts( flags );
- if ( voice == &VoiceList )
- {
- MV_SetErrorCode( MV_VoiceNotFound );
- }
- return( voice );
- }
- /*---------------------------------------------------------------------
- Function: MV_VoicePlaying
- Checks if the voice associated with the specified handle is
- playing.
- ---------------------------------------------------------------------*/
- int MV_VoicePlaying
- (
- int handle
- )
- {
- VoiceNode *voice;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( FALSE );
- }
- voice = MV_GetVoice( handle );
- if ( voice == NULL )
- {
- return( FALSE );
- }
- return( TRUE );
- }
- /*---------------------------------------------------------------------
- Function: MV_KillAllVoices
- Stops output of all currently active voices.
- ---------------------------------------------------------------------*/
- int MV_KillAllVoices
- (
- void
- )
- {
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- // Remove all the voices from the list
- while( VoiceList.next != &VoiceList )
- {
- MV_Kill( VoiceList.next->handle );
- }
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_Kill
- Stops output of the voice associated with the specified handle.
- ---------------------------------------------------------------------*/
- int MV_Kill
- (
- int handle
- )
- {
- VoiceNode *voice;
- unsigned flags;
- unsigned long callbackval;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- flags = DisableInterrupts();
- voice = MV_GetVoice( handle );
- if ( voice == NULL )
- {
- RestoreInterrupts( flags );
- MV_SetErrorCode( MV_VoiceNotFound );
- return( MV_Error );
- }
- callbackval = voice->callbackval;
- MV_StopVoice( voice );
- RestoreInterrupts( flags );
- if ( MV_CallBackFunc )
- {
- MV_CallBackFunc( callbackval );
- }
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_VoicesPlaying
- Determines the number of currently active voices.
- ---------------------------------------------------------------------*/
- int MV_VoicesPlaying
- (
- void
- )
- {
- VoiceNode *voice;
- int NumVoices = 0;
- unsigned flags;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( 0 );
- }
- flags = DisableInterrupts();
- for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next )
- {
- NumVoices++;
- }
- RestoreInterrupts( flags );
- return( NumVoices );
- }
- /*---------------------------------------------------------------------
- Function: MV_AllocVoice
- Retrieve an inactive or lower priority voice for output.
- ---------------------------------------------------------------------*/
- VoiceNode *MV_AllocVoice
- (
- int priority
- )
- {
- VoiceNode *voice;
- VoiceNode *node;
- unsigned flags;
- //return( NULL );
- if ( MV_Recording )
- {
- return( NULL );
- }
- flags = DisableInterrupts();
- // Check if we have any free voices
- if ( LL_Empty( &VoicePool, next, prev ) )
- {
- // check if we have a higher priority than a voice that is playing.
- voice = VoiceList.next;
- for( node = voice->next; node != &VoiceList; node = node->next )
- {
- if ( node->priority < voice->priority )
- {
- voice = node;
- }
- }
- if ( priority >= voice->priority )
- {
- MV_Kill( voice->handle );
- }
- }
- // Check if any voices are in the voice pool
- if ( LL_Empty( &VoicePool, next, prev ) )
- {
- // No free voices
- RestoreInterrupts( flags );
- return( NULL );
- }
- voice = VoicePool.next;
- LL_Remove( voice, next, prev );
- RestoreInterrupts( flags );
- // Find a free voice handle
- do
- {
- MV_VoiceHandle++;
- if ( MV_VoiceHandle < MV_MinVoiceHandle )
- {
- MV_VoiceHandle = MV_MinVoiceHandle;
- }
- }
- while( MV_VoicePlaying( MV_VoiceHandle ) );
- voice->handle = MV_VoiceHandle;
- return( voice );
- }
- /*---------------------------------------------------------------------
- Function: MV_VoiceAvailable
- Checks if a voice can be play at the specified priority.
- ---------------------------------------------------------------------*/
- int MV_VoiceAvailable
- (
- int priority
- )
- {
- VoiceNode *voice;
- VoiceNode *node;
- unsigned flags;
- // Check if we have any free voices
- if ( !LL_Empty( &VoicePool, next, prev ) )
- {
- return( TRUE );
- }
- flags = DisableInterrupts();
- // check if we have a higher priority than a voice that is playing.
- voice = VoiceList.next;
- for( node = VoiceList.next; node != &VoiceList; node = node->next )
- {
- if ( node->priority < voice->priority )
- {
- voice = node;
- }
- }
- RestoreInterrupts( flags );
- if ( ( voice != &VoiceList ) && ( priority >= voice->priority ) )
- {
- return( TRUE );
- }
- return( FALSE );
- }
- /*---------------------------------------------------------------------
- Function: MV_SetVoicePitch
- Sets the pitch for the specified voice.
- ---------------------------------------------------------------------*/
- void MV_SetVoicePitch
- (
- VoiceNode *voice,
- unsigned long rate,
- int pitchoffset
- )
- {
- voice->SamplingRate = rate;
- voice->PitchScale = PITCH_GetScale( pitchoffset );
- voice->RateScale = ( rate * voice->PitchScale ) / MV_MixRate;
- // Multiply by MixBufferSize - 1
- voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) -
- voice->RateScale;
- }
- /*---------------------------------------------------------------------
- Function: MV_SetPitch
- Sets the pitch for the voice associated with the specified handle.
- ---------------------------------------------------------------------*/
- int MV_SetPitch
- (
- int handle,
- int pitchoffset
- )
- {
- VoiceNode *voice;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- voice = MV_GetVoice( handle );
- if ( voice == NULL )
- {
- MV_SetErrorCode( MV_VoiceNotFound );
- return( MV_Error );
- }
- MV_SetVoicePitch( voice, voice->SamplingRate, pitchoffset );
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_SetFrequency
- Sets the frequency for the voice associated with the specified handle.
- ---------------------------------------------------------------------*/
- int MV_SetFrequency
- (
- int handle,
- int frequency
- )
- {
- VoiceNode *voice;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- voice = MV_GetVoice( handle );
- if ( voice == NULL )
- {
- MV_SetErrorCode( MV_VoiceNotFound );
- return( MV_Error );
- }
- MV_SetVoicePitch( voice, frequency, 0 );
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_GetVolumeTable
- Returns a pointer to the volume table associated with the specified
- volume.
- ---------------------------------------------------------------------*/
- static short *MV_GetVolumeTable
- (
- int vol
- )
- {
- int volume;
- short *table;
- volume = MIX_VOLUME( vol );
- table = &MV_VolumeTable[ volume ];
- return( table );
- }
- /*---------------------------------------------------------------------
- Function: MV_SetVoiceMixMode
- Selects which method should be used to mix the voice.
- ---------------------------------------------------------------------*/
- static void MV_SetVoiceMixMode
- (
- VoiceNode *voice
- )
- {
- unsigned flags;
- int test;
- flags = DisableInterrupts();
- test = T_DEFAULT;
- if ( MV_Bits == 8 )
- {
- test |= T_8BITS;
- }
- if ( voice->bits == 16 )
- {
- test |= T_16BITSOURCE;
- }
- if ( MV_Channels == 1 )
- {
- test |= T_MONO;
- }
- else
- {
- if ( IS_QUIET( voice->RightVolume ) )
- {
- test |= T_RIGHTQUIET;
- }
- else if ( IS_QUIET( voice->LeftVolume ) )
- {
- test |= T_LEFTQUIET;
- }
- }
- // Default case
- voice->mix = MV_Mix8BitMono;
- switch( test )
- {
- case T_8BITS | T_MONO | T_16BITSOURCE :
- voice->mix = MV_Mix8BitMono16;
- break;
- case T_8BITS | T_MONO :
- voice->mix = MV_Mix8BitMono;
- break;
- case T_8BITS | T_16BITSOURCE | T_LEFTQUIET :
- MV_LeftVolume = MV_RightVolume;
- voice->mix = MV_Mix8BitMono16;
- break;
- case T_8BITS | T_LEFTQUIET :
- MV_LeftVolume = MV_RightVolume;
- voice->mix = MV_Mix8BitMono;
- break;
- case T_8BITS | T_16BITSOURCE | T_RIGHTQUIET :
- voice->mix = MV_Mix8BitMono16;
- break;
- case T_8BITS | T_RIGHTQUIET :
- voice->mix = MV_Mix8BitMono;
- break;
- case T_8BITS | T_16BITSOURCE :
- voice->mix = MV_Mix8BitStereo16;
- break;
- case T_8BITS :
- voice->mix = MV_Mix8BitStereo;
- break;
- case T_MONO | T_16BITSOURCE :
- voice->mix = MV_Mix16BitMono16;
- break;
- case T_MONO :
- voice->mix = MV_Mix16BitMono;
- break;
- case T_16BITSOURCE | T_LEFTQUIET :
- MV_LeftVolume = MV_RightVolume;
- voice->mix = MV_Mix16BitMono16;
- break;
- case T_LEFTQUIET :
- MV_LeftVolume = MV_RightVolume;
- voice->mix = MV_Mix16BitMono;
- break;
- case T_16BITSOURCE | T_RIGHTQUIET :
- voice->mix = MV_Mix16BitMono16;
- break;
- case T_RIGHTQUIET :
- voice->mix = MV_Mix16BitMono;
- break;
- case T_16BITSOURCE :
- voice->mix = MV_Mix16BitStereo16;
- break;
- case T_SIXTEENBIT_STEREO :
- voice->mix = MV_Mix16BitStereo;
- break;
- default :
- voice->mix = MV_Mix8BitMono;
- }
- RestoreInterrupts( flags );
- }
- /*---------------------------------------------------------------------
- Function: MV_SetVoiceVolume
- Sets the stereo and mono volume level of the voice associated
- with the specified handle.
- ---------------------------------------------------------------------*/
- void MV_SetVoiceVolume
- (
- VoiceNode *voice,
- int vol,
- int left,
- int right
- )
- {
- if ( MV_Channels == 1 )
- {
- left = vol;
- right = vol;
- }
- if ( MV_SwapLeftRight )
- {
- // SBPro uses reversed panning
- voice->LeftVolume = MV_GetVolumeTable( right );
- voice->RightVolume = MV_GetVolumeTable( left );
- }
- else
- {
- voice->LeftVolume = MV_GetVolumeTable( left );
- voice->RightVolume = MV_GetVolumeTable( right );
- }
- MV_SetVoiceMixMode( voice );
- }
- /*---------------------------------------------------------------------
- Function: MV_EndLooping
- Stops the voice associated with the specified handle from looping
- without stoping the sound.
- ---------------------------------------------------------------------*/
- int MV_EndLooping
- (
- int handle
- )
- {
- VoiceNode *voice;
- unsigned flags;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- flags = DisableInterrupts();
- voice = MV_GetVoice( handle );
- if ( voice == NULL )
- {
- RestoreInterrupts( flags );
- MV_SetErrorCode( MV_VoiceNotFound );
- return( MV_Warning );
- }
- voice->LoopCount = 0;
- voice->LoopStart = NULL;
- voice->LoopEnd = NULL;
- RestoreInterrupts( flags );
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_SetPan
- Sets the stereo and mono volume level of the voice associated
- with the specified handle.
- ---------------------------------------------------------------------*/
- int MV_SetPan
- (
- int handle,
- int vol,
- int left,
- int right
- )
- {
- VoiceNode *voice;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- voice = MV_GetVoice( handle );
- if ( voice == NULL )
- {
- MV_SetErrorCode( MV_VoiceNotFound );
- return( MV_Warning );
- }
- MV_SetVoiceVolume( voice, vol, left, right );
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_Pan3D
- Set the angle and distance from the listener of the voice associated
- with the specified handle.
- ---------------------------------------------------------------------*/
- int MV_Pan3D
- (
- int handle,
- int angle,
- int distance
- )
- {
- int left;
- int right;
- int mid;
- int volume;
- int status;
- if ( distance < 0 )
- {
- distance = -distance;
- angle += MV_NumPanPositions / 2;
- }
- volume = MIX_VOLUME( distance );
- // Ensure angle is within 0 - 31
- angle &= MV_MaxPanPosition;
- left = MV_PanTable[ angle ][ volume ].left;
- right = MV_PanTable[ angle ][ volume ].right;
- mid = max( 0, 255 - distance );
- status = MV_SetPan( handle, mid, left, right );
- return( status );
- }
- /*---------------------------------------------------------------------
- Function: MV_SetReverb
- Sets the level of reverb to add to mix.
- ---------------------------------------------------------------------*/
- void MV_SetReverb
- (
- int reverb
- )
- {
- MV_ReverbLevel = MIX_VOLUME( reverb );
- MV_ReverbTable = &MV_VolumeTable[ MV_ReverbLevel ];
- }
- /*---------------------------------------------------------------------
- Function: MV_SetFastReverb
- Sets the level of reverb to add to mix.
- ---------------------------------------------------------------------*/
- void MV_SetFastReverb
- (
- int reverb
- )
- {
- MV_ReverbLevel = max( 0, min( 16, reverb ) );
- MV_ReverbTable = NULL;
- }
- /*---------------------------------------------------------------------
- Function: MV_GetMaxReverbDelay
- Returns the maximum delay time for reverb.
- ---------------------------------------------------------------------*/
- int MV_GetMaxReverbDelay
- (
- void
- )
- {
- int maxdelay;
- maxdelay = MixBufferSize * MV_NumberOfBuffers;
- return maxdelay;
- }
- /*---------------------------------------------------------------------
- Function: MV_GetReverbDelay
- Returns the current delay time for reverb.
- ---------------------------------------------------------------------*/
- int MV_GetReverbDelay
- (
- void
- )
- {
- return MV_ReverbDelay / MV_SampleSize;
- }
- /*---------------------------------------------------------------------
- Function: MV_SetReverbDelay
- Sets the delay level of reverb to add to mix.
- ---------------------------------------------------------------------*/
- void MV_SetReverbDelay
- (
- int delay
- )
- {
- int maxdelay;
- maxdelay = MV_GetMaxReverbDelay();
- MV_ReverbDelay = max( MixBufferSize, min( delay, maxdelay ) );
- MV_ReverbDelay *= MV_SampleSize;
- }
- /*---------------------------------------------------------------------
- Function: MV_SetMixMode
- Prepares Multivoc to play stereo of mono digitized sounds.
- ---------------------------------------------------------------------*/
- int MV_SetMixMode
- (
- int numchannels,
- int samplebits
- )
- {
- int mode;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- mode = 0;
- if ( numchannels == 2 )
- {
- mode |= STEREO;
- }
- if ( samplebits == 16 )
- {
- mode |= SIXTEEN_BIT;
- }
- switch( MV_SoundCard )
- {
- case UltraSound :
- MV_MixMode = mode;
- break;
- case SoundBlaster :
- case Awe32 :
- MV_MixMode = BLASTER_SetMixMode( mode );
- break;
- case ProAudioSpectrum :
- case SoundMan16 :
- MV_MixMode = PAS_SetMixMode( mode );
- break;
- case SoundScape :
- MV_MixMode = SOUNDSCAPE_SetMixMode( mode );
- break;
- #ifndef SOUNDSOURCE_OFF
- case SoundSource :
- case TandySoundSource :
- MV_MixMode = SS_SetMixMode( mode );
- break;
- #endif
- }
- MV_Channels = 1;
- if ( MV_MixMode & STEREO )
- {
- MV_Channels = 2;
- }
- MV_Bits = 8;
- if ( MV_MixMode & SIXTEEN_BIT )
- {
- MV_Bits = 16;
- }
- MV_BuffShift = 7 + MV_Channels;
- MV_SampleSize = sizeof( MONO8 ) * MV_Channels;
- if ( MV_Bits == 8 )
- {
- MV_Silence = SILENCE_8BIT;
- }
- else
- {
- MV_Silence = SILENCE_16BIT;
- MV_BuffShift += 1;
- MV_SampleSize *= 2;
- }
- MV_BufferSize = MixBufferSize * MV_SampleSize;
- MV_NumberOfBuffers = TotalBufferSize / MV_BufferSize;
- MV_BufferLength = TotalBufferSize;
- MV_RightChannelOffset = MV_SampleSize / 2;
- if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) )
- {
- MV_SampleSize /= 2;
- MV_BufferSize /= 2;
- MV_RightChannelOffset = MV_BufferSize * MV_NumberOfBuffers;
- MV_BufferLength /= 2;
- }
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_StartPlayback
- Starts the sound playback engine.
- ---------------------------------------------------------------------*/
- int MV_StartPlayback
- (
- void
- )
- {
- int status;
- int buffer;
- // Initialize the buffers
- ClearBuffer_DW( MV_MixBuffer[ 0 ], MV_Silence, TotalBufferSize >> 2 );
- for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ )
- {
- MV_BufferEmpty[ buffer ] = TRUE;
- }
- // Set the mix buffer variables
- MV_MixPage = 1;
- MV_MixFunction = MV_Mix;
- //JIM
- // MV_MixRate = MV_RequestedMixRate;
- // return( MV_Ok );
- // Start playback
- switch( MV_SoundCard )
- {
- case SoundBlaster :
- case Awe32 :
- status = BLASTER_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
- TotalBufferSize, MV_NumberOfBuffers,
- MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc );
- if ( status != BLASTER_Ok )
- {
- MV_SetErrorCode( MV_BlasterError );
- return( MV_Error );
- }
- MV_MixRate = BLASTER_GetPlaybackRate();
- MV_DMAChannel = BLASTER_DMAChannel;
- break;
- case UltraSound :
- status = GUSWAVE_StartDemandFeedPlayback( MV_ServiceGus, 1,
- MV_Bits, MV_RequestedMixRate, 0, ( MV_Channels == 1 ) ?
- 0 : 24, 255, 0xffff, 0 );
- if ( status < GUSWAVE_Ok )
- {
- MV_SetErrorCode( MV_BlasterError );
- return( MV_Error );
- }
- if ( MV_Channels == 2 )
- {
- status = GUSWAVE_StartDemandFeedPlayback( MV_ServiceRightGus, 1,
- MV_Bits, MV_RequestedMixRate, 0, 8, 255, 0xffff, 0 );
- if ( status < GUSWAVE_Ok )
- {
- GUSWAVE_KillAllVoices();
- MV_SetErrorCode( MV_BlasterError );
- return( MV_Error );
- }
- }
- MV_MixRate = MV_RequestedMixRate;
- MV_DMAChannel = -1;
- break;
- case ProAudioSpectrum :
- case SoundMan16 :
- status = PAS_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
- TotalBufferSize, MV_NumberOfBuffers,
- MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc );
- if ( status != PAS_Ok )
- {
- MV_SetErrorCode( MV_PasError );
- return( MV_Error );
- }
- MV_MixRate = PAS_GetPlaybackRate();
- MV_DMAChannel = PAS_DMAChannel;
- break;
- case SoundScape :
- status = SOUNDSCAPE_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
- TotalBufferSize, MV_NumberOfBuffers, MV_RequestedMixRate,
- MV_MixMode, MV_ServiceVoc );
- if ( status != SOUNDSCAPE_Ok )
- {
- MV_SetErrorCode( MV_SoundScapeError );
- return( MV_Error );
- }
- MV_MixRate = SOUNDSCAPE_GetPlaybackRate();
- MV_DMAChannel = SOUNDSCAPE_DMAChannel;
- break;
- #ifndef SOUNDSOURCE_OFF
- case SoundSource :
- case TandySoundSource :
- SS_BeginBufferedPlayback( MV_MixBuffer[ 0 ],
- TotalBufferSize, MV_NumberOfBuffers,
- MV_ServiceVoc );
- MV_MixRate = SS_SampleRate;
- MV_DMAChannel = -1;
- break;
- #endif
- }
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_StopPlayback
- Stops the sound playback engine.
- ---------------------------------------------------------------------*/
- void MV_StopPlayback
- (
- void
- )
- {
- VoiceNode *voice;
- VoiceNode *next;
- unsigned flags;
- // Stop sound playback
- switch( MV_SoundCard )
- {
- case SoundBlaster :
- case Awe32 :
- BLASTER_StopPlayback();
- break;
- case UltraSound :
- GUSWAVE_KillAllVoices();
- break;
- case ProAudioSpectrum :
- case SoundMan16 :
- PAS_StopPlayback();
- break;
- case SoundScape :
- SOUNDSCAPE_StopPlayback();
- break;
- #ifndef SOUNDSOURCE_OFF
- case SoundSource :
- case TandySoundSource :
- SS_StopPlayback();
- break;
- #endif
- }
- // Make sure all callbacks are done.
- flags = DisableInterrupts();
- for( voice = VoiceList.next; voice != &VoiceList; voice = next )
- {
- next = voice->next;
- MV_StopVoice( voice );
- if ( MV_CallBackFunc )
- {
- MV_CallBackFunc( voice->callbackval );
- }
- }
- RestoreInterrupts( flags );
- }
- /*---------------------------------------------------------------------
- Function: MV_StartRecording
- Starts the sound recording engine.
- ---------------------------------------------------------------------*/
- int MV_StartRecording
- (
- int MixRate,
- void ( *function )( char *ptr, int length )
- )
- {
- int status;
- switch( MV_SoundCard )
- {
- case SoundBlaster :
- case Awe32 :
- case ProAudioSpectrum :
- case SoundMan16 :
- break;
- default :
- MV_SetErrorCode( MV_UnsupportedCard );
- return( MV_Error );
- break;
- }
- if ( function == NULL )
- {
- MV_SetErrorCode( MV_NullRecordFunction );
- return( MV_Error );
- }
- MV_StopPlayback();
- // Initialize the buffers
- ClearBuffer_DW( MV_MixBuffer[ 0 ], SILENCE_8BIT, TotalBufferSize >> 2 );
- // Set the mix buffer variables
- MV_MixPage = 0;
- MV_RecordFunc = function;
- // Start playback
- switch( MV_SoundCard )
- {
- case SoundBlaster :
- case Awe32 :
- status = BLASTER_BeginBufferedRecord( MV_MixBuffer[ 0 ],
- TotalBufferSize, NumberOfBuffers, MixRate, MONO_8BIT,
- MV_ServiceRecord );
- if ( status != BLASTER_Ok )
- {
- MV_SetErrorCode( MV_BlasterError );
- return( MV_Error );
- }
- break;
- case ProAudioSpectrum :
- case SoundMan16 :
- status = PAS_BeginBufferedRecord( MV_MixBuffer[ 0 ],
- TotalBufferSize, NumberOfBuffers, MixRate, MONO_8BIT,
- MV_ServiceRecord );
- if ( status != PAS_Ok )
- {
- MV_SetErrorCode( MV_PasError );
- return( MV_Error );
- }
- break;
- }
- MV_Recording = TRUE;
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_StopRecord
- Stops the sound record engine.
- ---------------------------------------------------------------------*/
- void MV_StopRecord
- (
- void
- )
- {
- // Stop sound playback
- switch( MV_SoundCard )
- {
- case SoundBlaster :
- case Awe32 :
- BLASTER_StopPlayback();
- break;
- case ProAudioSpectrum :
- case SoundMan16 :
- PAS_StopPlayback();
- break;
- }
- MV_Recording = FALSE;
- MV_StartPlayback();
- }
- /*---------------------------------------------------------------------
- Function: MV_StartDemandFeedPlayback
- Plays a digitized sound from a user controlled buffering system.
- ---------------------------------------------------------------------*/
- int MV_StartDemandFeedPlayback
- (
- void ( *function )( char **ptr, unsigned long *length ),
- int rate,
- int pitchoffset,
- int vol,
- int left,
- int right,
- int priority,
- unsigned long callbackval
- )
- {
- VoiceNode *voice;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- // Request a voice from the voice pool
- voice = MV_AllocVoice( priority );
- if ( voice == NULL )
- {
- MV_SetErrorCode( MV_NoVoices );
- return( MV_Error );
- }
- voice->wavetype = DemandFeed;
- voice->bits = 8;
- voice->GetSound = MV_GetNextDemandFeedBlock;
- voice->NextBlock = NULL;
- voice->DemandFeed = function;
- voice->LoopStart = NULL;
- voice->LoopCount = 0;
- voice->BlockLength = 0;
- voice->position = 0;
- voice->sound = NULL;
- voice->length = 0;
- voice->BlockLength = 0;
- voice->Playing = TRUE;
- voice->next = NULL;
- voice->prev = NULL;
- voice->priority = priority;
- voice->callbackval = callbackval;
- MV_SetVoicePitch( voice, rate, pitchoffset );
- MV_SetVoiceVolume( voice, vol, left, right );
- MV_PlayVoice( voice );
- return( voice->handle );
- }
- /*---------------------------------------------------------------------
- Function: MV_PlayRaw
- Begin playback of sound data with the given sound levels and
- priority.
- ---------------------------------------------------------------------*/
- int MV_PlayRaw
- (
- char *ptr,
- unsigned long length,
- unsigned rate,
- int pitchoffset,
- int vol,
- int left,
- int right,
- int priority,
- unsigned long callbackval
- )
- {
- int status;
- status = MV_PlayLoopedRaw( ptr, length, NULL, NULL, rate, pitchoffset,
- vol, left, right, priority, callbackval );
- return( status );
- }
- /*---------------------------------------------------------------------
- Function: MV_PlayLoopedRaw
- Begin playback of sound data with the given sound levels and
- priority.
- ---------------------------------------------------------------------*/
- int MV_PlayLoopedRaw
- (
- char *ptr,
- long length,
- char *loopstart,
- char *loopend,
- unsigned rate,
- int pitchoffset,
- int vol,
- int left,
- int right,
- int priority,
- unsigned long callbackval
- )
- {
- VoiceNode *voice;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- // Request a voice from the voice pool
- voice = MV_AllocVoice( priority );
- if ( voice == NULL )
- {
- MV_SetErrorCode( MV_NoVoices );
- return( MV_Error );
- }
- voice->wavetype = Raw;
- voice->bits = 8;
- voice->GetSound = MV_GetNextRawBlock;
- voice->Playing = TRUE;
- voice->NextBlock = ptr;
- voice->position = 0;
- voice->BlockLength = length;
- voice->length = 0;
- voice->next = NULL;
- voice->prev = NULL;
- voice->priority = priority;
- voice->callbackval = callbackval;
- voice->LoopStart = loopstart;
- voice->LoopEnd = loopend;
- voice->LoopSize = ( voice->LoopEnd - voice->LoopStart ) + 1;
- MV_SetVoicePitch( voice, rate, pitchoffset );
- MV_SetVoiceVolume( voice, vol, left, right );
- MV_PlayVoice( voice );
- return( voice->handle );
- }
- /*---------------------------------------------------------------------
- Function: MV_PlayWAV
- Begin playback of sound data with the given sound levels and
- priority.
- ---------------------------------------------------------------------*/
- int MV_PlayWAV
- (
- char *ptr,
- int pitchoffset,
- int vol,
- int left,
- int right,
- int priority,
- unsigned long callbackval
- )
- {
- int status;
- status = MV_PlayLoopedWAV( ptr, -1, -1, pitchoffset, vol, left, right,
- priority, callbackval );
- return( status );
- }
- /*---------------------------------------------------------------------
- Function: MV_PlayWAV3D
- Begin playback of sound data at specified angle and distance
- from listener.
- ---------------------------------------------------------------------*/
- int MV_PlayWAV3D
- (
- char *ptr,
- int pitchoffset,
- int angle,
- int distance,
- int priority,
- unsigned long callbackval
- )
- {
- int left;
- int right;
- int mid;
- int volume;
- int status;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- if ( distance < 0 )
- {
- distance = -distance;
- angle += MV_NumPanPositions / 2;
- }
- volume = MIX_VOLUME( distance );
- // Ensure angle is within 0 - 31
- angle &= MV_MaxPanPosition;
- left = MV_PanTable[ angle ][ volume ].left;
- right = MV_PanTable[ angle ][ volume ].right;
- mid = max( 0, 255 - distance );
- status = MV_PlayWAV( ptr, pitchoffset, mid, left, right, priority,
- callbackval );
- return( status );
- }
- /*---------------------------------------------------------------------
- Function: MV_PlayLoopedWAV
- Begin playback of sound data with the given sound levels and
- priority.
- ---------------------------------------------------------------------*/
- int MV_PlayLoopedWAV
- (
- char *ptr,
- long loopstart,
- long loopend,
- int pitchoffset,
- int vol,
- int left,
- int right,
- int priority,
- unsigned long callbackval
- )
- {
- riff_header *riff;
- format_header *format;
- data_header *data;
- VoiceNode *voice;
- int length;
- int absloopend;
- int absloopstart;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- riff = ( riff_header * )ptr;
- if ( ( strncmp( riff->RIFF, "RIFF", 4 ) != 0 ) ||
- ( strncmp( riff->WAVE, "WAVE", 4 ) != 0 ) ||
- ( strncmp( riff->fmt, "fmt ", 4) != 0 ) )
- {
- MV_SetErrorCode( MV_InvalidWAVFile );
- return( MV_Error );
- }
- format = ( format_header * )( riff + 1 );
- data = ( data_header * )( ( ( char * )format ) + riff->format_size );
- // Check if it's PCM data.
- if ( format->wFormatTag != 1 )
- {
- MV_SetErrorCode( MV_InvalidWAVFile );
- return( MV_Error );
- }
- if ( format->nChannels != 1 )
- {
- MV_SetErrorCode( MV_InvalidWAVFile );
- return( MV_Error );
- }
- if ( ( format->nBitsPerSample != 8 ) &&
- ( format->nBitsPerSample != 16 ) )
- {
- MV_SetErrorCode( MV_InvalidWAVFile );
- return( MV_Error );
- }
- if ( strncmp( data->DATA, "data", 4 ) != 0 )
- {
- MV_SetErrorCode( MV_InvalidWAVFile );
- return( MV_Error );
- }
- // Request a voice from the voice pool
- voice = MV_AllocVoice( priority );
- if ( voice == NULL )
- {
- MV_SetErrorCode( MV_NoVoices );
- return( MV_Error );
- }
- voice->wavetype = WAV;
- voice->bits = format->nBitsPerSample;
- voice->GetSound = MV_GetNextWAVBlock;
- length = data->size;
- absloopstart = loopstart;
- absloopend = loopend;
- if ( voice->bits == 16 )
- {
- loopstart *= 2;
- data->size &= ~1;
- loopend *= 2;
- length /= 2;
- }
- loopend = min( loopend, data->size );
- absloopend = min( absloopend, length );
- voice->Playing = TRUE;
- voice->DemandFeed = NULL;
- voice->LoopStart = NULL;
- voice->LoopCount = 0;
- voice->position = 0;
- voice->length = 0;
- voice->BlockLength = absloopend;
- voice->NextBlock = ( char * )( data + 1 );
- voice->next = NULL;
- voice->prev = NULL;
- voice->priority = priority;
- voice->callbackval = callbackval;
- voice->LoopStart = voice->NextBlock + loopstart;
- voice->LoopEnd = voice->NextBlock + loopend;
- voice->LoopSize = absloopend - absloopstart;
- if ( ( loopstart >= data->size ) || ( loopstart < 0 ) )
- {
- voice->LoopStart = NULL;
- voice->LoopEnd = NULL;
- voice->BlockLength = length;
- }
- MV_SetVoicePitch( voice, format->nSamplesPerSec, pitchoffset );
- MV_SetVoiceVolume( voice, vol, left, right );
- MV_PlayVoice( voice );
- return( voice->handle );
- }
- /*---------------------------------------------------------------------
- Function: MV_PlayVOC3D
- Begin playback of sound data at specified angle and distance
- from listener.
- ---------------------------------------------------------------------*/
- int MV_PlayVOC3D
- (
- char *ptr,
- int pitchoffset,
- int angle,
- int distance,
- int priority,
- unsigned long callbackval
- )
- {
- int left;
- int right;
- int mid;
- int volume;
- int status;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- if ( distance < 0 )
- {
- distance = -distance;
- angle += MV_NumPanPositions / 2;
- }
- volume = MIX_VOLUME( distance );
- // Ensure angle is within 0 - 31
- angle &= MV_MaxPanPosition;
- left = MV_PanTable[ angle ][ volume ].left;
- right = MV_PanTable[ angle ][ volume ].right;
- mid = max( 0, 255 - distance );
- status = MV_PlayVOC( ptr, pitchoffset, mid, left, right, priority,
- callbackval );
- return( status );
- }
- /*---------------------------------------------------------------------
- Function: MV_PlayVOC
- Begin playback of sound data with the given sound levels and
- priority.
- ---------------------------------------------------------------------*/
- int MV_PlayVOC
- (
- char *ptr,
- int pitchoffset,
- int vol,
- int left,
- int right,
- int priority,
- unsigned long callbackval
- )
- {
- int status;
- status = MV_PlayLoopedVOC( ptr, -1, -1, pitchoffset, vol, left, right,
- priority, callbackval );
- return( status );
- }
- /*---------------------------------------------------------------------
- Function: MV_PlayLoopedVOC
- Begin playback of sound data with the given sound levels and
- priority.
- ---------------------------------------------------------------------*/
- int MV_PlayLoopedVOC
- (
- char *ptr,
- long loopstart,
- long loopend,
- int pitchoffset,
- int vol,
- int left,
- int right,
- int priority,
- unsigned long callbackval
- )
- {
- VoiceNode *voice;
- int status;
- if ( !MV_Installed )
- {
- MV_SetErrorCode( MV_NotInstalled );
- return( MV_Error );
- }
- // Make sure it's a valid VOC file.
- status = strncmp( ptr, "Creative Voice File", 19 );
- if ( status != 0 )
- {
- MV_SetErrorCode( MV_InvalidVOCFile );
- return( MV_Error );
- }
- // Request a voice from the voice pool
- voice = MV_AllocVoice( priority );
- if ( voice == NULL )
- {
- MV_SetErrorCode( MV_NoVoices );
- return( MV_Error );
- }
- voice->wavetype = VOC;
- voice->bits = 8;
- voice->GetSound = MV_GetNextVOCBlock;
- voice->NextBlock = ptr + *( unsigned short int * )( ptr + 0x14 );
- voice->DemandFeed = NULL;
- voice->LoopStart = NULL;
- voice->LoopCount = 0;
- voice->BlockLength = 0;
- voice->PitchScale = PITCH_GetScale( pitchoffset );
- voice->length = 0;
- voice->next = NULL;
- voice->prev = NULL;
- voice->priority = priority;
- voice->callbackval = callbackval;
- voice->LoopStart = ( char * )loopstart;
- voice->LoopEnd = ( char * )loopend;
- voice->LoopSize = loopend - loopstart + 1;
- if ( loopstart < 0 )
- {
- voice->LoopStart = NULL;
- voice->LoopEnd = NULL;
- }
- MV_SetVoiceVolume( voice, vol, left, right );
- MV_PlayVoice( voice );
- return( voice->handle );
- }
- /*---------------------------------------------------------------------
- Function: MV_LockEnd
- Used for determining the length of the functions to lock in memory.
- ---------------------------------------------------------------------*/
- static void MV_LockEnd
- (
- void
- )
- {
- }
- /*---------------------------------------------------------------------
- Function: MV_CreateVolumeTable
- Create the table used to convert sound data to a specific volume
- level.
- ---------------------------------------------------------------------*/
- void MV_CreateVolumeTable
- (
- int index,
- int volume,
- int MaxVolume
- )
- {
- int val;
- int level;
- int i;
- level = ( volume * MaxVolume ) / MV_MaxTotalVolume;
- if ( MV_Bits == 16 )
- {
- for( i = 0; i < 65536; i += 256 )
- {
- val = i - 0x8000;
- val *= level;
- val /= MV_MaxVolume;
- MV_VolumeTable[ index ][ i / 256 ] = val;
- }
- }
- else
- {
- for( i = 0; i < 256; i++ )
- {
- val = i - 0x80;
- val *= level;
- val /= MV_MaxVolume;
- MV_VolumeTable[ volume ][ i ] = val;
- }
- }
- }
- /*---------------------------------------------------------------------
- Function: MV_CalcVolume
- Create the table used to convert sound data to a specific volume
- level.
- ---------------------------------------------------------------------*/
- void MV_CalcVolume
- (
- int MaxVolume
- )
- {
- int volume;
- for( volume = 0; volume < 128; volume++ )
- {
- MV_HarshClipTable[ volume ] = 0;
- MV_HarshClipTable[ volume + 384 ] = 255;
- }
- for( volume = 0; volume < 256; volume++ )
- {
- MV_HarshClipTable[ volume + 128 ] = volume;
- }
- // For each volume level, create a translation table with the
- // appropriate volume calculated.
- for( volume = 0; volume <= MV_MaxVolume; volume++ )
- {
- MV_CreateVolumeTable( volume, volume, MaxVolume );
- }
- }
- /*---------------------------------------------------------------------
- Function: MV_CalcPanTable
- Create the table used to determine the stereo volume level of
- a sound located at a specific angle and distance from the listener.
- ---------------------------------------------------------------------*/
- void MV_CalcPanTable
- (
- void
- )
- {
- int level;
- int angle;
- int distance;
- int HalfAngle;
- int ramp;
- HalfAngle = ( MV_NumPanPositions / 2 );
- for( distance = 0; distance <= MV_MaxVolume; distance++ )
- {
- level = ( 255 * ( MV_MaxVolume - distance ) ) / MV_MaxVolume;
- for( angle = 0; angle <= HalfAngle / 2; angle++ )
- {
- ramp = level - ( ( level * angle ) /
- ( MV_NumPanPositions / 4 ) );
- MV_PanTable[ angle ][ distance ].left = ramp;
- MV_PanTable[ HalfAngle - angle ][ distance ].left = ramp;
- MV_PanTable[ HalfAngle + angle ][ distance ].left = level;
- MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].left = level;
- MV_PanTable[ angle ][ distance ].right = level;
- MV_PanTable[ HalfAngle - angle ][ distance ].right = level;
- MV_PanTable[ HalfAngle + angle ][ distance ].right = ramp;
- MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].right = ramp;
- }
- }
- }
- /*---------------------------------------------------------------------
- Function: MV_SetVolume
- Sets the volume of digitized sound playback.
- ---------------------------------------------------------------------*/
- void MV_SetVolume
- (
- int volume
- )
- {
- volume = max( 0, volume );
- volume = min( volume, MV_MaxTotalVolume );
- MV_TotalVolume = volume;
- // Calculate volume table
- MV_CalcVolume( volume );
- }
- /*---------------------------------------------------------------------
- Function: MV_GetVolume
- Returns the volume of digitized sound playback.
- ---------------------------------------------------------------------*/
- int MV_GetVolume
- (
- void
- )
- {
- return( MV_TotalVolume );
- }
- /*---------------------------------------------------------------------
- Function: MV_SetCallBack
- Set the function to call when a voice stops.
- ---------------------------------------------------------------------*/
- void MV_SetCallBack
- (
- void ( *function )( unsigned long )
- )
- {
- MV_CallBackFunc = function;
- }
- /*---------------------------------------------------------------------
- Function: MV_SetReverseStereo
- Set the orientation of the left and right channels.
- ---------------------------------------------------------------------*/
- void MV_SetReverseStereo
- (
- int setting
- )
- {
- MV_SwapLeftRight = setting;
- }
- /*---------------------------------------------------------------------
- Function: MV_GetReverseStereo
- Returns the orientation of the left and right channels.
- ---------------------------------------------------------------------*/
- int MV_GetReverseStereo
- (
- void
- )
- {
- return( MV_SwapLeftRight );
- }
- /*---------------------------------------------------------------------
- Function: MV_TestPlayback
- Checks if playback has started.
- ---------------------------------------------------------------------*/
- int MV_TestPlayback
- (
- void
- )
- {
- unsigned flags;
- long time;
- int start;
- int status;
- int pos;
- if ( MV_SoundCard == UltraSound )
- {
- return( MV_Ok );
- }
- flags = DisableInterrupts();
- _enable();
- status = MV_Error;
- start = MV_MixPage;
- time = clock() + CLOCKS_PER_SEC * 2;
- while( clock() < time )
- {
- if ( MV_MixPage != start )
- {
- status = MV_Ok;
- }
- }
- RestoreInterrupts( flags );
- if ( status != MV_Ok )
- {
- // Just in case an error doesn't get reported
- MV_SetErrorCode( MV_DMAFailure );
- switch( MV_SoundCard )
- {
- case SoundBlaster :
- case Awe32 :
- pos = BLASTER_GetCurrentPos();
- break;
- case ProAudioSpectrum :
- case SoundMan16 :
- pos = PAS_GetCurrentPos();
- break;
- case SoundScape :
- pos = SOUNDSCAPE_GetCurrentPos();
- break;
- #ifndef SOUNDSOURCE_OFF
- case SoundSource :
- case TandySoundSource :
- MV_SetErrorCode( MV_SoundSourceFailure );
- pos = -1;
- break;
- #endif
- default :
- MV_SetErrorCode( MV_UnsupportedCard );
- pos = -2;
- break;
- }
- if ( pos > 0 )
- {
- MV_SetErrorCode( MV_IrqFailure );
- }
- else if ( pos == 0 )
- {
- if ( MV_Bits == 16 )
- {
- MV_SetErrorCode( MV_DMA16Failure );
- }
- else
- {
- MV_SetErrorCode( MV_DMAFailure );
- }
- }
- }
- return( status );
- }
- /*---------------------------------------------------------------------
- Function: MV_Init
- Perform the initialization of variables and memory used by
- Multivoc.
- ---------------------------------------------------------------------*/
- int MV_Init
- (
- int soundcard,
- int MixRate,
- int Voices,
- int numchannels,
- int samplebits
- )
- {
- char *ptr;
- int status;
- int buffer;
- int index;
- if ( MV_Installed )
- {
- MV_Shutdown();
- }
- MV_SetErrorCode( MV_Ok );
- status = MV_LockMemory();
- if ( status != MV_Ok )
- {
- return( status );
- }
- MV_TotalMemory = Voices * sizeof( VoiceNode ) + sizeof( HARSH_CLIP_TABLE_8 );
- status = USRHOOKS_GetMem( ( void ** )&ptr, MV_TotalMemory );
- if ( status != USRHOOKS_Ok )
- {
- MV_UnlockMemory();
- MV_SetErrorCode( MV_NoMem );
- return( MV_Error );
- }
- status = DPMI_LockMemory( ptr, MV_TotalMemory );
- if ( status != DPMI_Ok )
- {
- USRHOOKS_FreeMem( ptr );
- MV_UnlockMemory();
- MV_SetErrorCode( MV_DPMI_Error );
- return( MV_Error );
- }
- MV_Voices = ( VoiceNode * )ptr;
- MV_HarshClipTable = ptr + ( MV_TotalMemory - sizeof( HARSH_CLIP_TABLE_8 ) );
- // Set number of voices before calculating volume table
- MV_MaxVoices = Voices;
- LL_Reset( &VoiceList, next, prev );
- LL_Reset( &VoicePool, next, prev );
- for( index = 0; index < Voices; index++ )
- {
- LL_Add( &VoicePool, &MV_Voices[ index ], next, prev );
- }
- // Allocate mix buffer within 1st megabyte
- status = DPMI_GetDOSMemory( ( void ** )&ptr, &MV_BufferDescriptor,
- 2 * TotalBufferSize );
- if ( status )
- {
- DPMI_UnlockMemory( MV_Voices, MV_TotalMemory );
- USRHOOKS_FreeMem( MV_Voices );
- MV_Voices = NULL;
- MV_TotalMemory = 0;
- MV_UnlockMemory();
- MV_SetErrorCode( MV_NoMem );
- return( MV_Error );
- }
- MV_SetReverseStereo( FALSE );
- // Initialize the sound card
- switch( soundcard )
- {
- case UltraSound :
- status = GUSWAVE_Init( 2 );
- if ( status != GUSWAVE_Ok )
- {
- //JIM
- MV_SetErrorCode( MV_BlasterError );
- }
- break;
- case SoundBlaster :
- case Awe32 :
- status = BLASTER_Init();
- if ( status != BLASTER_Ok )
- {
- MV_SetErrorCode( MV_BlasterError );
- }
- if ( ( BLASTER_Config.Type == SBPro ) ||
- ( BLASTER_Config.Type == SBPro2 ) )
- {
- MV_SetReverseStereo( TRUE );
- }
- break;
- case ProAudioSpectrum :
- case SoundMan16 :
- status = PAS_Init();
- if ( status != PAS_Ok )
- {
- MV_SetErrorCode( MV_PasError );
- }
- break;
- case SoundScape :
- status = SOUNDSCAPE_Init();
- if ( status != SOUNDSCAPE_Ok )
- {
- MV_SetErrorCode( MV_SoundScapeError );
- }
- break;
- #ifndef SOUNDSOURCE_OFF
- case SoundSource :
- case TandySoundSource :
- status = SS_Init( soundcard );
- if ( status != SS_Ok )
- {
- MV_SetErrorCode( MV_SoundSourceError );
- }
- break;
- #endif
- default :
- MV_SetErrorCode( MV_UnsupportedCard );
- break;
- }
- if ( MV_ErrorCode != MV_Ok )
- {
- status = MV_ErrorCode;
- DPMI_UnlockMemory( MV_Voices, MV_TotalMemory );
- USRHOOKS_FreeMem( MV_Voices );
- MV_Voices = NULL;
- MV_TotalMemory = 0;
- DPMI_FreeDOSMemory( MV_BufferDescriptor );
- MV_UnlockMemory();
- MV_SetErrorCode( status );
- return( MV_Error );
- }
- MV_SoundCard = soundcard;
- MV_Installed = TRUE;
- MV_CallBackFunc = NULL;
- MV_RecordFunc = NULL;
- MV_Recording = FALSE;
- MV_ReverbLevel = 0;
- MV_ReverbTable = NULL;
- // Set the sampling rate
- MV_RequestedMixRate = MixRate;
- // Set Mixer to play stereo digitized sound
- MV_SetMixMode( numchannels, samplebits );
- MV_ReverbDelay = MV_BufferSize * 3;
- // Make sure we don't cross a physical page
- if ( ( ( unsigned long )ptr & 0xffff ) + TotalBufferSize > 0x10000 )
- {
- ptr = ( char * )( ( ( unsigned long )ptr & 0xff0000 ) + 0x10000 );
- }
- MV_MixBuffer[ MV_NumberOfBuffers ] = ptr;
- for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ )
- {
- MV_MixBuffer[ buffer ] = ptr;
- ptr += MV_BufferSize;
- }
- // Calculate pan table
- MV_CalcPanTable();
- MV_SetVolume( MV_MaxTotalVolume );
- // Start the playback engine
- status = MV_StartPlayback();
- if ( status != MV_Ok )
- {
- // Preserve error code while we shutdown.
- status = MV_ErrorCode;
- MV_Shutdown();
- MV_SetErrorCode( status );
- return( MV_Error );
- }
- if ( MV_TestPlayback() != MV_Ok )
- {
- status = MV_ErrorCode;
- MV_Shutdown();
- MV_SetErrorCode( status );
- return( MV_Error );
- }
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_Shutdown
- Restore any resources allocated by Multivoc back to the system.
- ---------------------------------------------------------------------*/
- int MV_Shutdown
- (
- void
- )
- {
- int buffer;
- unsigned flags;
- if ( !MV_Installed )
- {
- return( MV_Ok );
- }
- flags = DisableInterrupts();
- MV_KillAllVoices();
- MV_Installed = FALSE;
- // Stop the sound recording engine
- if ( MV_Recording )
- {
- MV_StopRecord();
- }
- // Stop the sound playback engine
- MV_StopPlayback();
- // Shutdown the sound card
- switch( MV_SoundCard )
- {
- case UltraSound :
- GUSWAVE_Shutdown();
- break;
- case SoundBlaster :
- case Awe32 :
- BLASTER_Shutdown();
- break;
- case ProAudioSpectrum :
- case SoundMan16 :
- PAS_Shutdown();
- break;
- case SoundScape :
- SOUNDSCAPE_Shutdown();
- break;
- #ifndef SOUNDSOURCE_OFF
- case SoundSource :
- case TandySoundSource :
- SS_Shutdown();
- break;
- #endif
- }
- RestoreInterrupts( flags );
- // Free any voices we allocated
- DPMI_UnlockMemory( MV_Voices, MV_TotalMemory );
- USRHOOKS_FreeMem( MV_Voices );
- MV_Voices = NULL;
- MV_TotalMemory = 0;
- LL_Reset( &VoiceList, next, prev );
- LL_Reset( &VoicePool, next, prev );
- MV_MaxVoices = 1;
- // Release the descriptor from our mix buffer
- DPMI_FreeDOSMemory( MV_BufferDescriptor );
- for( buffer = 0; buffer < NumberOfBuffers; buffer++ )
- {
- MV_MixBuffer[ buffer ] = NULL;
- }
- return( MV_Ok );
- }
- /*---------------------------------------------------------------------
- Function: MV_UnlockMemory
- Unlocks all neccessary data.
- ---------------------------------------------------------------------*/
- void MV_UnlockMemory
- (
- void
- )
- {
- PITCH_UnlockMemory();
- DPMI_UnlockMemoryRegion( MV_LockStart, MV_LockEnd );
- DPMI_Unlock( MV_VolumeTable );
- DPMI_Unlock( MV_PanTable );
- DPMI_Unlock( MV_Installed );
- DPMI_Unlock( MV_SoundCard );
- DPMI_Unlock( MV_TotalVolume );
- DPMI_Unlock( MV_MaxVoices );
- DPMI_Unlock( MV_BufferSize );
- DPMI_Unlock( MV_BufferLength );
- DPMI_Unlock( MV_SampleSize );
- DPMI_Unlock( MV_NumberOfBuffers );
- DPMI_Unlock( MV_MixMode );
- DPMI_Unlock( MV_Channels );
- DPMI_Unlock( MV_Bits );
- DPMI_Unlock( MV_Silence );
- DPMI_Unlock( MV_SwapLeftRight );
- DPMI_Unlock( MV_RequestedMixRate );
- DPMI_Unlock( MV_MixRate );
- DPMI_Unlock( MV_BufferDescriptor );
- DPMI_Unlock( MV_MixBuffer );
- DPMI_Unlock( MV_BufferEmpty );
- DPMI_Unlock( MV_Voices );
- DPMI_Unlock( VoiceList );
- DPMI_Unlock( VoicePool );
- DPMI_Unlock( MV_MixPage );
- DPMI_Unlock( MV_VoiceHandle );
- DPMI_Unlock( MV_CallBackFunc );
- DPMI_Unlock( MV_RecordFunc );
- DPMI_Unlock( MV_Recording );
- DPMI_Unlock( MV_MixFunction );
- DPMI_Unlock( MV_HarshClipTable );
- DPMI_Unlock( MV_MixDestination );
- DPMI_Unlock( MV_LeftVolume );
- DPMI_Unlock( MV_RightVolume );
- DPMI_Unlock( MV_MixPosition );
- DPMI_Unlock( MV_ErrorCode );
- DPMI_Unlock( MV_DMAChannel );
- DPMI_Unlock( MV_BuffShift );
- DPMI_Unlock( MV_ReverbLevel );
- DPMI_Unlock( MV_ReverbDelay );
- DPMI_Unlock( MV_ReverbTable );
- }
- /*---------------------------------------------------------------------
- Function: MV_LockMemory
- Locks all neccessary data.
- ---------------------------------------------------------------------*/
- int MV_LockMemory
- (
- void
- )
- {
- int status;
- int pitchstatus;
- status = DPMI_LockMemoryRegion( MV_LockStart, MV_LockEnd );
- status |= DPMI_Lock( MV_VolumeTable );
- status |= DPMI_Lock( MV_PanTable );
- status |= DPMI_Lock( MV_Installed );
- status |= DPMI_Lock( MV_SoundCard );
- status |= DPMI_Lock( MV_TotalVolume );
- status |= DPMI_Lock( MV_MaxVoices );
- status |= DPMI_Lock( MV_BufferSize );
- status |= DPMI_Lock( MV_BufferLength );
- status |= DPMI_Lock( MV_SampleSize );
- status |= DPMI_Lock( MV_NumberOfBuffers );
- status |= DPMI_Lock( MV_MixMode );
- status |= DPMI_Lock( MV_Channels );
- status |= DPMI_Lock( MV_Bits );
- status |= DPMI_Lock( MV_Silence );
- status |= DPMI_Lock( MV_SwapLeftRight );
- status |= DPMI_Lock( MV_RequestedMixRate );
- status |= DPMI_Lock( MV_MixRate );
- status |= DPMI_Lock( MV_BufferDescriptor );
- status |= DPMI_Lock( MV_MixBuffer );
- status |= DPMI_Lock( MV_BufferEmpty );
- status |= DPMI_Lock( MV_Voices );
- status |= DPMI_Lock( VoiceList );
- status |= DPMI_Lock( VoicePool );
- status |= DPMI_Lock( MV_MixPage );
- status |= DPMI_Lock( MV_VoiceHandle );
- status |= DPMI_Lock( MV_CallBackFunc );
- status |= DPMI_Lock( MV_RecordFunc );
- status |= DPMI_Lock( MV_Recording );
- status |= DPMI_Lock( MV_MixFunction );
- status |= DPMI_Lock( MV_HarshClipTable );
- status |= DPMI_Lock( MV_MixDestination );
- status |= DPMI_Lock( MV_LeftVolume );
- status |= DPMI_Lock( MV_RightVolume );
- status |= DPMI_Lock( MV_MixPosition );
- status |= DPMI_Lock( MV_ErrorCode );
- status |= DPMI_Lock( MV_DMAChannel );
- status |= DPMI_Lock( MV_BuffShift );
- status |= DPMI_Lock( MV_ReverbLevel );
- status |= DPMI_Lock( MV_ReverbDelay );
- status |= DPMI_Lock( MV_ReverbTable );
- pitchstatus = PITCH_LockMemory();
- if ( ( pitchstatus != PITCH_Ok ) || ( status != DPMI_Ok ) )
- {
- MV_UnlockMemory();
- MV_SetErrorCode( MV_DPMI_Error );
- return( MV_Error );
- }
- return( MV_Ok );
- }
|