123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204 |
- /* FAudio - XAudio Reimplementation for FNA
- *
- * Copyright (c) 2011-2021 Ethan Lee, Luigi Auriemma, and the MonoGame Team
- *
- * This software is provided 'as-is', without any express or implied warranty.
- * In no event will the authors be held liable for any damages arising from
- * the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software in a
- * product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- *
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- *
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * Ethan "flibitijibibo" Lee <flibitijibibo@flibitijibibo.com>
- *
- */
- #include "FAudio_internal.h"
- #define MAKE_SUBFORMAT_GUID(guid, fmt) \
- FAudioGUID DATAFORMAT_SUBTYPE_##guid = \
- { \
- (uint16_t) (fmt), \
- 0x0000, \
- 0x0010, \
- { \
- 0x80, \
- 0x00, \
- 0x00, \
- 0xAA, \
- 0x00, \
- 0x38, \
- 0x9B, \
- 0x71 \
- } \
- }
- MAKE_SUBFORMAT_GUID(PCM, 1);
- MAKE_SUBFORMAT_GUID(ADPCM, 2);
- MAKE_SUBFORMAT_GUID(IEEE_FLOAT, 3);
- MAKE_SUBFORMAT_GUID(XMAUDIO2, FAUDIO_FORMAT_XMAUDIO2);
- MAKE_SUBFORMAT_GUID(WMAUDIO2, FAUDIO_FORMAT_WMAUDIO2);
- MAKE_SUBFORMAT_GUID(WMAUDIO3, FAUDIO_FORMAT_WMAUDIO3);
- MAKE_SUBFORMAT_GUID(WMAUDIO_LOSSLESS, FAUDIO_FORMAT_WMAUDIO_LOSSLESS);
- #undef MAKE_SUBFORMAT_GUID
- #ifdef FAUDIO_DUMP_VOICES
- static void FAudio_DUMPVOICE_Init(const FAudioSourceVoice *voice);
- static void FAudio_DUMPVOICE_Finalize(const FAudioSourceVoice *voice);
- static void FAudio_DUMPVOICE_WriteBuffer(
- const FAudioSourceVoice *voice,
- const FAudioBuffer *pBuffer,
- const FAudioBufferWMA *pBufferWMA,
- const uint32_t playBegin,
- const uint32_t playLength
- );
- #endif /* FAUDIO_DUMP_VOICES */
- /* FAudio Version */
- uint32_t FAudioLinkedVersion(void)
- {
- return FAUDIO_COMPILED_VERSION;
- }
- /* FAudio Interface */
- uint32_t FAudioCreate(
- FAudio **ppFAudio,
- uint32_t Flags,
- FAudioProcessor XAudio2Processor
- ) {
- FAudioCOMConstructEXT(ppFAudio, FAUDIO_TARGET_VERSION);
- FAudio_Initialize(*ppFAudio, Flags, XAudio2Processor);
- return 0;
- }
- uint32_t FAudioCOMConstructEXT(FAudio **ppFAudio, uint8_t version)
- {
- return FAudioCOMConstructWithCustomAllocatorEXT(
- ppFAudio,
- version,
- FAudio_malloc,
- FAudio_free,
- FAudio_realloc
- );
- }
- uint32_t FAudioCreateWithCustomAllocatorEXT(
- FAudio **ppFAudio,
- uint32_t Flags,
- FAudioProcessor XAudio2Processor,
- FAudioMallocFunc customMalloc,
- FAudioFreeFunc customFree,
- FAudioReallocFunc customRealloc
- ) {
- FAudioCOMConstructWithCustomAllocatorEXT(
- ppFAudio,
- FAUDIO_TARGET_VERSION,
- customMalloc,
- customFree,
- customRealloc
- );
- FAudio_Initialize(*ppFAudio, Flags, XAudio2Processor);
- return 0;
- }
- uint32_t FAudioCOMConstructWithCustomAllocatorEXT(
- FAudio **ppFAudio,
- uint8_t version,
- FAudioMallocFunc customMalloc,
- FAudioFreeFunc customFree,
- FAudioReallocFunc customRealloc
- ) {
- #ifndef FAUDIO_DISABLE_DEBUGCONFIGURATION
- FAudioDebugConfiguration debugInit = {0};
- #endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */
- FAudio_PlatformAddRef();
- *ppFAudio = (FAudio*) customMalloc(sizeof(FAudio));
- FAudio_zero(*ppFAudio, sizeof(FAudio));
- (*ppFAudio)->version = version;
- #ifndef FAUDIO_DISABLE_DEBUGCONFIGURATION
- FAudio_SetDebugConfiguration(*ppFAudio, &debugInit, NULL);
- #endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */
- (*ppFAudio)->sourceLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE((*ppFAudio), (*ppFAudio)->sourceLock)
- (*ppFAudio)->submixLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE((*ppFAudio), (*ppFAudio)->submixLock)
- (*ppFAudio)->callbackLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE((*ppFAudio), (*ppFAudio)->callbackLock)
- (*ppFAudio)->operationLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE((*ppFAudio), (*ppFAudio)->operationLock)
- (*ppFAudio)->pMalloc = customMalloc;
- (*ppFAudio)->pFree = customFree;
- (*ppFAudio)->pRealloc = customRealloc;
- (*ppFAudio)->refcount = 1;
- return 0;
- }
- uint32_t FAudio_AddRef(FAudio *audio)
- {
- LOG_API_ENTER(audio)
- audio->refcount += 1;
- LOG_API_EXIT(audio)
- return audio->refcount;
- }
- uint32_t FAudio_Release(FAudio *audio)
- {
- uint32_t refcount;
- LOG_API_ENTER(audio)
- audio->refcount -= 1;
- refcount = audio->refcount;
- if (audio->refcount == 0)
- {
- FAudio_OPERATIONSET_ClearAll(audio);
- FAudio_StopEngine(audio);
- audio->pFree(audio->decodeCache);
- audio->pFree(audio->resampleCache);
- audio->pFree(audio->effectChainCache);
- LOG_MUTEX_DESTROY(audio, audio->sourceLock)
- FAudio_PlatformDestroyMutex(audio->sourceLock);
- LOG_MUTEX_DESTROY(audio, audio->submixLock)
- FAudio_PlatformDestroyMutex(audio->submixLock);
- LOG_MUTEX_DESTROY(audio, audio->callbackLock)
- FAudio_PlatformDestroyMutex(audio->callbackLock);
- LOG_MUTEX_DESTROY(audio, audio->operationLock)
- FAudio_PlatformDestroyMutex(audio->operationLock);
- audio->pFree(audio);
- FAudio_PlatformRelease();
- }
- else
- {
- LOG_API_EXIT(audio)
- }
- return refcount;
- }
- uint32_t FAudio_GetDeviceCount(FAudio *audio, uint32_t *pCount)
- {
- LOG_API_ENTER(audio)
- *pCount = FAudio_PlatformGetDeviceCount();
- LOG_API_EXIT(audio)
- return 0;
- }
- uint32_t FAudio_GetDeviceDetails(
- FAudio *audio,
- uint32_t Index,
- FAudioDeviceDetails *pDeviceDetails
- ) {
- uint32_t result;
- LOG_API_ENTER(audio)
- result = FAudio_PlatformGetDeviceDetails(Index, pDeviceDetails);
- LOG_API_EXIT(audio)
- return result;
- }
- uint32_t FAudio_Initialize(
- FAudio *audio,
- uint32_t Flags,
- FAudioProcessor XAudio2Processor
- ) {
- LOG_API_ENTER(audio)
- FAudio_assert(Flags == 0 || Flags == FAUDIO_DEBUG_ENGINE);
- FAudio_assert(XAudio2Processor == FAUDIO_DEFAULT_PROCESSOR);
- audio->initFlags = Flags;
- /* FIXME: This is lazy... */
- audio->decodeCache = (float*) audio->pMalloc(sizeof(float));
- audio->resampleCache = (float*) audio->pMalloc(sizeof(float));
- audio->decodeSamples = 1;
- audio->resampleSamples = 1;
- FAudio_StartEngine(audio);
- LOG_API_EXIT(audio)
- return 0;
- }
- uint32_t FAudio_RegisterForCallbacks(
- FAudio *audio,
- FAudioEngineCallback *pCallback
- ) {
- LOG_API_ENTER(audio)
- LinkedList_AddEntry(
- &audio->callbacks,
- pCallback,
- audio->callbackLock,
- audio->pMalloc
- );
- LOG_API_EXIT(audio)
- return 0;
- }
- void FAudio_UnregisterForCallbacks(
- FAudio *audio,
- FAudioEngineCallback *pCallback
- ) {
- LOG_API_ENTER(audio)
- LinkedList_RemoveEntry(
- &audio->callbacks,
- pCallback,
- audio->callbackLock,
- audio->pFree
- );
- LOG_API_EXIT(audio)
- }
- uint32_t FAudio_CreateSourceVoice(
- FAudio *audio,
- FAudioSourceVoice **ppSourceVoice,
- const FAudioWaveFormatEx *pSourceFormat,
- uint32_t Flags,
- float MaxFrequencyRatio,
- FAudioVoiceCallback *pCallback,
- const FAudioVoiceSends *pSendList,
- const FAudioEffectChain *pEffectChain
- ) {
- uint32_t i;
- LOG_API_ENTER(audio)
- LOG_FORMAT(audio, pSourceFormat)
- *ppSourceVoice = (FAudioSourceVoice*) audio->pMalloc(sizeof(FAudioVoice));
- FAudio_zero(*ppSourceVoice, sizeof(FAudioSourceVoice));
- (*ppSourceVoice)->audio = audio;
- (*ppSourceVoice)->type = FAUDIO_VOICE_SOURCE;
- (*ppSourceVoice)->flags = Flags;
- (*ppSourceVoice)->filter.Type = FAUDIO_DEFAULT_FILTER_TYPE;
- (*ppSourceVoice)->filter.Frequency = FAUDIO_DEFAULT_FILTER_FREQUENCY;
- (*ppSourceVoice)->filter.OneOverQ = FAUDIO_DEFAULT_FILTER_ONEOVERQ;
- (*ppSourceVoice)->sendLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSourceVoice)->sendLock)
- (*ppSourceVoice)->effectLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSourceVoice)->effectLock)
- (*ppSourceVoice)->filterLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSourceVoice)->filterLock)
- (*ppSourceVoice)->volumeLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSourceVoice)->volumeLock)
- /* Source Properties */
- FAudio_assert(MaxFrequencyRatio <= FAUDIO_MAX_FREQ_RATIO);
- (*ppSourceVoice)->src.maxFreqRatio = MaxFrequencyRatio;
- if ( pSourceFormat->wFormatTag == FAUDIO_FORMAT_PCM ||
- pSourceFormat->wFormatTag == FAUDIO_FORMAT_IEEE_FLOAT ||
- pSourceFormat->wFormatTag == FAUDIO_FORMAT_WMAUDIO2 )
- {
- FAudioWaveFormatExtensible *fmtex = (FAudioWaveFormatExtensible*) audio->pMalloc(
- sizeof(FAudioWaveFormatExtensible)
- );
- /* convert PCM to EXTENSIBLE */
- fmtex->Format.wFormatTag = FAUDIO_FORMAT_EXTENSIBLE;
- fmtex->Format.nChannels = pSourceFormat->nChannels;
- fmtex->Format.nSamplesPerSec = pSourceFormat->nSamplesPerSec;
- fmtex->Format.nAvgBytesPerSec = pSourceFormat->nAvgBytesPerSec;
- fmtex->Format.nBlockAlign = pSourceFormat->nBlockAlign;
- fmtex->Format.wBitsPerSample = pSourceFormat->wBitsPerSample;
- fmtex->Format.cbSize = sizeof(FAudioWaveFormatExtensible) - sizeof(FAudioWaveFormatEx);
- fmtex->Samples.wValidBitsPerSample = pSourceFormat->wBitsPerSample;
- fmtex->dwChannelMask = 0;
- if (pSourceFormat->wFormatTag == FAUDIO_FORMAT_PCM)
- {
- FAudio_memcpy(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_PCM, sizeof(FAudioGUID));
- }
- else if (pSourceFormat->wFormatTag == FAUDIO_FORMAT_IEEE_FLOAT)
- {
- FAudio_memcpy(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(FAudioGUID));
- }
- else if (pSourceFormat->wFormatTag == FAUDIO_FORMAT_WMAUDIO2)
- {
- FAudio_memcpy(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_WMAUDIO2, sizeof(FAudioGUID));
- }
- (*ppSourceVoice)->src.format = &fmtex->Format;
- }
- else if (pSourceFormat->wFormatTag == FAUDIO_FORMAT_MSADPCM)
- {
- FAudioADPCMWaveFormat *fmtex = (FAudioADPCMWaveFormat*) audio->pMalloc(
- sizeof(FAudioADPCMWaveFormat)
- );
- /* Copy what we can, ideally the sizes match! */
- size_t cbSize = sizeof(FAudioWaveFormatEx) + pSourceFormat->cbSize;
- FAudio_memcpy(
- fmtex,
- pSourceFormat,
- FAudio_min(cbSize, sizeof(FAudioADPCMWaveFormat))
- );
- if (cbSize < sizeof(FAudioADPCMWaveFormat))
- {
- FAudio_zero(
- ((uint8_t*) fmtex) + cbSize,
- sizeof(FAudioADPCMWaveFormat) - cbSize
- );
- }
- /* XAudio2 does not validate this input! */
- fmtex->wfx.cbSize = sizeof(FAudioADPCMWaveFormat) - sizeof(FAudioWaveFormatEx);
- fmtex->wSamplesPerBlock = ((
- fmtex->wfx.nBlockAlign / fmtex->wfx.nChannels
- ) - 6) * 2;
- (*ppSourceVoice)->src.format = &fmtex->wfx;
- }
- else if (pSourceFormat->wFormatTag == FAUDIO_FORMAT_XMAUDIO2)
- {
- FAudioXMA2WaveFormat *fmtex = (FAudioXMA2WaveFormat*) audio->pMalloc(
- sizeof(FAudioXMA2WaveFormat)
- );
- /* Copy what we can, ideally the sizes match! */
- size_t cbSize = sizeof(FAudioWaveFormatEx) + pSourceFormat->cbSize;
- FAudio_memcpy(
- fmtex,
- pSourceFormat,
- FAudio_min(cbSize, sizeof(FAudioXMA2WaveFormat))
- );
- if (cbSize < sizeof(FAudioXMA2WaveFormat))
- {
- FAudio_zero(
- ((uint8_t*) fmtex) + cbSize,
- sizeof(FAudioADPCMWaveFormat) - cbSize
- );
- }
- /* Does XAudio2 validate this input?! */
- fmtex->wfx.cbSize = sizeof(FAudioXMA2WaveFormat) - sizeof(FAudioWaveFormatEx);
- (*ppSourceVoice)->src.format = &fmtex->wfx;
- }
- else
- {
- /* direct copy anything else */
- (*ppSourceVoice)->src.format = (FAudioWaveFormatEx*) audio->pMalloc(
- sizeof(FAudioWaveFormatEx) + pSourceFormat->cbSize
- );
- FAudio_memcpy(
- (*ppSourceVoice)->src.format,
- pSourceFormat,
- sizeof(FAudioWaveFormatEx) + pSourceFormat->cbSize
- );
- }
- (*ppSourceVoice)->src.callback = pCallback;
- (*ppSourceVoice)->src.active = 0;
- (*ppSourceVoice)->src.freqRatio = 1.0f;
- (*ppSourceVoice)->src.totalSamples = 0;
- (*ppSourceVoice)->src.bufferList = NULL;
- (*ppSourceVoice)->src.flushList = NULL;
- (*ppSourceVoice)->src.bufferLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSourceVoice)->src.bufferLock)
- if ((*ppSourceVoice)->src.format->wFormatTag == FAUDIO_FORMAT_EXTENSIBLE)
- {
- FAudioWaveFormatExtensible *fmtex = (FAudioWaveFormatExtensible*) (*ppSourceVoice)->src.format;
- #define COMPARE_GUID(type) \
- (FAudio_memcmp( \
- &fmtex->SubFormat, \
- &DATAFORMAT_SUBTYPE_##type, \
- sizeof(FAudioGUID) \
- ) == 0)
- if (COMPARE_GUID(PCM))
- {
- #define DECODER(bit) \
- if (fmtex->Format.wBitsPerSample == bit) \
- { \
- (*ppSourceVoice)->src.decode = FAudio_INTERNAL_DecodePCM##bit; \
- }
- DECODER(16)
- else DECODER(8)
- else DECODER(24)
- else DECODER(32)
- else
- {
- LOG_ERROR(
- audio,
- "Unrecognized wBitsPerSample: %d",
- fmtex->Format.wBitsPerSample
- )
- FAudio_assert(0 && "Unrecognized wBitsPerSample!");
- }
- #undef DECODER
- }
- else if (COMPARE_GUID(IEEE_FLOAT))
- {
- /* FIXME: Weird behavior!
- * Prototype creates a source with the IEEE_FLOAT tag,
- * but it's actually PCM16. It seems to prioritize
- * wBitsPerSample over the format tag. Not sure if we
- * should fold this section into the section above...?
- * -flibit
- */
- if (fmtex->Format.wBitsPerSample == 16)
- {
- (*ppSourceVoice)->src.decode = FAudio_INTERNAL_DecodePCM16;
- }
- else
- {
- (*ppSourceVoice)->src.decode = FAudio_INTERNAL_DecodePCM32F;
- }
- }
- else if ( COMPARE_GUID(WMAUDIO2) ||
- COMPARE_GUID(WMAUDIO3) ||
- COMPARE_GUID(WMAUDIO_LOSSLESS) )
- {
- #ifdef HAVE_WMADEC
- if (FAudio_WMADEC_init(*ppSourceVoice, fmtex->SubFormat.Data1) != 0)
- {
- (*ppSourceVoice)->src.decode = FAudio_INTERNAL_DecodeWMAERROR;
- }
- #else
- FAudio_assert(0 && "xWMA is not supported!");
- (*ppSourceVoice)->src.decode = FAudio_INTERNAL_DecodeWMAERROR;
- #endif /* HAVE_WMADEC */
- }
- else
- {
- FAudio_assert(0 && "Unsupported WAVEFORMATEXTENSIBLE subtype!");
- }
- #undef COMPARE_GUID
- }
- else if ((*ppSourceVoice)->src.format->wFormatTag == FAUDIO_FORMAT_XMAUDIO2)
- {
- #ifdef HAVE_WMADEC
- if (FAudio_WMADEC_init(*ppSourceVoice, FAUDIO_FORMAT_XMAUDIO2) != 0)
- {
- (*ppSourceVoice)->src.decode = FAudio_INTERNAL_DecodeWMAERROR;
- }
- #else
- FAudio_assert(0 && "XMA2 is not supported!");
- (*ppSourceVoice)->src.decode = FAudio_INTERNAL_DecodeWMAERROR;
- #endif /* HAVE_WMADEC */
- }
- else if ((*ppSourceVoice)->src.format->wFormatTag == FAUDIO_FORMAT_MSADPCM)
- {
- (*ppSourceVoice)->src.decode = ((*ppSourceVoice)->src.format->nChannels == 2) ?
- FAudio_INTERNAL_DecodeStereoMSADPCM :
- FAudio_INTERNAL_DecodeMonoMSADPCM;
- }
- else
- {
- FAudio_assert(0 && "Unsupported format tag!");
- }
- if ((*ppSourceVoice)->src.format->nChannels == 1)
- {
- (*ppSourceVoice)->src.resample = FAudio_INTERNAL_ResampleMono;
- }
- else if ((*ppSourceVoice)->src.format->nChannels == 2)
- {
- (*ppSourceVoice)->src.resample = FAudio_INTERNAL_ResampleStereo;
- }
- else
- {
- (*ppSourceVoice)->src.resample = FAudio_INTERNAL_ResampleGeneric;
- }
- (*ppSourceVoice)->src.curBufferOffset = 0;
- /* Sends/Effects */
- FAudio_INTERNAL_VoiceOutputFrequency(*ppSourceVoice, pSendList);
- FAudioVoice_SetEffectChain(*ppSourceVoice, pEffectChain);
- /* Default Levels */
- (*ppSourceVoice)->volume = 1.0f;
- (*ppSourceVoice)->channelVolume = (float*) audio->pMalloc(
- sizeof(float) * (*ppSourceVoice)->outputChannels
- );
- for (i = 0; i < (*ppSourceVoice)->outputChannels; i += 1)
- {
- (*ppSourceVoice)->channelVolume[i] = 1.0f;
- }
- FAudioVoice_SetOutputVoices(*ppSourceVoice, pSendList);
- /* Filters */
- if (Flags & FAUDIO_VOICE_USEFILTER)
- {
- (*ppSourceVoice)->filterState = (FAudioFilterState*) audio->pMalloc(
- sizeof(FAudioFilterState) * (*ppSourceVoice)->src.format->nChannels
- );
- FAudio_zero(
- (*ppSourceVoice)->filterState,
- sizeof(FAudioFilterState) * (*ppSourceVoice)->src.format->nChannels
- );
- }
- /* Sample Storage */
- (*ppSourceVoice)->src.decodeSamples = (uint32_t) (FAudio_ceil(
- (double) audio->updateSize *
- (double) MaxFrequencyRatio *
- (double) (*ppSourceVoice)->src.format->nSamplesPerSec /
- (double) audio->master->master.inputSampleRate
- )) + EXTRA_DECODE_PADDING * (*ppSourceVoice)->src.format->nChannels;
- FAudio_INTERNAL_ResizeDecodeCache(
- audio,
- ((*ppSourceVoice)->src.decodeSamples + EXTRA_DECODE_PADDING) * (*ppSourceVoice)->src.format->nChannels
- );
- LOG_INFO(audio, "-> %p", (void*) (*ppSourceVoice))
- /* Add to list, finally. */
- LinkedList_PrependEntry(
- &audio->sources,
- *ppSourceVoice,
- audio->sourceLock,
- audio->pMalloc
- );
- FAudio_AddRef(audio);
- #ifdef FAUDIO_DUMP_VOICES
- FAudio_DUMPVOICE_Init(*ppSourceVoice);
- #endif /* FAUDIO_DUMP_VOICES */
- LOG_API_EXIT(audio)
- return 0;
- }
- uint32_t FAudio_CreateSubmixVoice(
- FAudio *audio,
- FAudioSubmixVoice **ppSubmixVoice,
- uint32_t InputChannels,
- uint32_t InputSampleRate,
- uint32_t Flags,
- uint32_t ProcessingStage,
- const FAudioVoiceSends *pSendList,
- const FAudioEffectChain *pEffectChain
- ) {
- uint32_t i;
- LOG_API_ENTER(audio)
- *ppSubmixVoice = (FAudioSubmixVoice*) audio->pMalloc(sizeof(FAudioVoice));
- FAudio_zero(*ppSubmixVoice, sizeof(FAudioSubmixVoice));
- (*ppSubmixVoice)->audio = audio;
- (*ppSubmixVoice)->type = FAUDIO_VOICE_SUBMIX;
- (*ppSubmixVoice)->flags = Flags;
- (*ppSubmixVoice)->filter.Type = FAUDIO_DEFAULT_FILTER_TYPE;
- (*ppSubmixVoice)->filter.Frequency = FAUDIO_DEFAULT_FILTER_FREQUENCY;
- (*ppSubmixVoice)->filter.OneOverQ = FAUDIO_DEFAULT_FILTER_ONEOVERQ;
- (*ppSubmixVoice)->sendLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSubmixVoice)->sendLock)
- (*ppSubmixVoice)->effectLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSubmixVoice)->effectLock)
- (*ppSubmixVoice)->filterLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSubmixVoice)->filterLock)
- (*ppSubmixVoice)->volumeLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppSubmixVoice)->volumeLock)
- /* Submix Properties */
- (*ppSubmixVoice)->mix.inputChannels = InputChannels;
- (*ppSubmixVoice)->mix.inputSampleRate = InputSampleRate;
- (*ppSubmixVoice)->mix.processingStage = ProcessingStage;
- /* Resampler */
- if (InputChannels == 1)
- {
- (*ppSubmixVoice)->mix.resample = FAudio_INTERNAL_ResampleMono;
- }
- else if (InputChannels == 2)
- {
- (*ppSubmixVoice)->mix.resample = FAudio_INTERNAL_ResampleStereo;
- }
- else
- {
- (*ppSubmixVoice)->mix.resample = FAudio_INTERNAL_ResampleGeneric;
- }
- /* Sample Storage */
- (*ppSubmixVoice)->mix.inputSamples = ((uint32_t) FAudio_ceil(
- audio->updateSize *
- (double) InputSampleRate /
- (double) audio->master->master.inputSampleRate
- ) + EXTRA_DECODE_PADDING) * InputChannels;
- (*ppSubmixVoice)->mix.inputCache = (float*) audio->pMalloc(
- sizeof(float) * (*ppSubmixVoice)->mix.inputSamples
- );
- FAudio_zero( /* Zero this now, for the first update */
- (*ppSubmixVoice)->mix.inputCache,
- sizeof(float) * (*ppSubmixVoice)->mix.inputSamples
- );
- /* Sends/Effects */
- FAudio_INTERNAL_VoiceOutputFrequency(*ppSubmixVoice, pSendList);
- FAudioVoice_SetEffectChain(*ppSubmixVoice, pEffectChain);
- /* Default Levels */
- (*ppSubmixVoice)->volume = 1.0f;
- (*ppSubmixVoice)->channelVolume = (float*) audio->pMalloc(
- sizeof(float) * (*ppSubmixVoice)->outputChannels
- );
- for (i = 0; i < (*ppSubmixVoice)->outputChannels; i += 1)
- {
- (*ppSubmixVoice)->channelVolume[i] = 1.0f;
- }
- FAudioVoice_SetOutputVoices(*ppSubmixVoice, pSendList);
- /* Filters */
- if (Flags & FAUDIO_VOICE_USEFILTER)
- {
- (*ppSubmixVoice)->filterState = (FAudioFilterState*) audio->pMalloc(
- sizeof(FAudioFilterState) * InputChannels
- );
- FAudio_zero(
- (*ppSubmixVoice)->filterState,
- sizeof(FAudioFilterState) * InputChannels
- );
- }
- /* Add to list, finally. */
- FAudio_INTERNAL_InsertSubmixSorted(
- &audio->submixes,
- *ppSubmixVoice,
- audio->submixLock,
- audio->pMalloc
- );
- FAudio_AddRef(audio);
- LOG_API_EXIT(audio)
- return 0;
- }
- uint32_t FAudio_CreateMasteringVoice(
- FAudio *audio,
- FAudioMasteringVoice **ppMasteringVoice,
- uint32_t InputChannels,
- uint32_t InputSampleRate,
- uint32_t Flags,
- uint32_t DeviceIndex,
- const FAudioEffectChain *pEffectChain
- ) {
- FAudioDeviceDetails details;
- LOG_API_ENTER(audio)
- /* For now we only support one allocated master voice at a time */
- FAudio_assert(audio->master == NULL);
- if (FAudio_GetDeviceDetails(audio, DeviceIndex, &details) != 0)
- {
- return FAUDIO_E_INVALID_CALL;
- }
- *ppMasteringVoice = (FAudioMasteringVoice*) audio->pMalloc(sizeof(FAudioVoice));
- FAudio_zero(*ppMasteringVoice, sizeof(FAudioMasteringVoice));
- (*ppMasteringVoice)->audio = audio;
- (*ppMasteringVoice)->type = FAUDIO_VOICE_MASTER;
- (*ppMasteringVoice)->flags = Flags;
- (*ppMasteringVoice)->effectLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppMasteringVoice)->effectLock)
- (*ppMasteringVoice)->volumeLock = FAudio_PlatformCreateMutex();
- LOG_MUTEX_CREATE(audio, (*ppMasteringVoice)->volumeLock)
- /* Default Levels */
- (*ppMasteringVoice)->volume = 1.0f;
- /* Master Properties */
- (*ppMasteringVoice)->master.inputChannels = (InputChannels == FAUDIO_DEFAULT_CHANNELS) ?
- details.OutputFormat.Format.nChannels :
- InputChannels;
- (*ppMasteringVoice)->master.inputSampleRate = (InputSampleRate == FAUDIO_DEFAULT_SAMPLERATE) ?
- details.OutputFormat.Format.nSamplesPerSec :
- InputSampleRate;
- /* Sends/Effects */
- FAudio_zero(&(*ppMasteringVoice)->sends, sizeof(FAudioVoiceSends));
- FAudioVoice_SetEffectChain(*ppMasteringVoice, pEffectChain);
- /* This is now safe enough to assign */
- audio->master = *ppMasteringVoice;
- /* Build the device format.
- * The most unintuitive part of this is the use of outputChannels
- * instead of master.inputChannels. Bizarrely, the effect chain can
- * dictate the _actual_ output channel count, and when the channel count
- * mismatches, we have to add a staging buffer for effects to process on
- * before ultimately copying the final result to the device. ARGH.
- */
- WriteWaveFormatExtensible(
- &audio->mixFormat,
- audio->master->outputChannels,
- audio->master->master.inputSampleRate,
- &DATAFORMAT_SUBTYPE_IEEE_FLOAT
- );
- /* Platform Device */
- FAudio_AddRef(audio);
- FAudio_PlatformInit(
- audio,
- audio->initFlags,
- DeviceIndex,
- &audio->mixFormat,
- &audio->updateSize,
- &audio->platform
- );
- if (audio->platform == NULL)
- {
- FAudioVoice_DestroyVoice(*ppMasteringVoice);
- *ppMasteringVoice = NULL;
- /* Not the best code, but it's probably true? */
- return FAUDIO_E_DEVICE_INVALIDATED;
- }
- audio->master->outputChannels = audio->mixFormat.Format.nChannels;
- audio->master->master.inputSampleRate = audio->mixFormat.Format.nSamplesPerSec;
- /* Effect Chain Cache */
- if ((*ppMasteringVoice)->master.inputChannels != (*ppMasteringVoice)->outputChannels)
- {
- (*ppMasteringVoice)->master.effectCache = (float*) audio->pMalloc(
- sizeof(float) *
- audio->updateSize *
- (*ppMasteringVoice)->master.inputChannels
- );
- }
- LOG_API_EXIT(audio)
- return 0;
- }
- uint32_t FAudio_CreateMasteringVoice8(
- FAudio *audio,
- FAudioMasteringVoice **ppMasteringVoice,
- uint32_t InputChannels,
- uint32_t InputSampleRate,
- uint32_t Flags,
- uint16_t *szDeviceId,
- const FAudioEffectChain *pEffectChain,
- FAudioStreamCategory StreamCategory
- ) {
- uint32_t DeviceIndex, retval;
- LOG_API_ENTER(audio)
- /* Eventually, we'll want the old CreateMastering to call the new one.
- * That will depend on us being able to use DeviceID though.
- * For now, use our little ID hack to turn szDeviceId into DeviceIndex.
- * -flibit
- */
- if (szDeviceId == NULL || szDeviceId[0] == 0)
- {
- DeviceIndex = 0;
- }
- else
- {
- DeviceIndex = szDeviceId[0] - L'0';
- if (DeviceIndex > FAudio_PlatformGetDeviceCount())
- {
- DeviceIndex = 0;
- }
- }
- /* Note that StreamCategory is ignored! */
- retval = FAudio_CreateMasteringVoice(
- audio,
- ppMasteringVoice,
- InputChannels,
- InputSampleRate,
- Flags,
- DeviceIndex,
- pEffectChain
- );
- LOG_API_EXIT(audio)
- return retval;
- }
- void FAudio_SetEngineProcedureEXT(
- FAudio *audio,
- FAudioEngineProcedureEXT clientEngineProc,
- void *user
- ) {
- LOG_API_ENTER(audio)
- audio->pClientEngineProc = clientEngineProc;
- audio->clientEngineUser = user;
- LOG_API_EXIT(audio)
- }
- uint32_t FAudio_StartEngine(FAudio *audio)
- {
- LOG_API_ENTER(audio)
- audio->active = 1;
- LOG_API_EXIT(audio)
- return 0;
- }
- void FAudio_StopEngine(FAudio *audio)
- {
- LOG_API_ENTER(audio)
- audio->active = 0;
- FAudio_OPERATIONSET_CommitAll(audio);
- FAudio_OPERATIONSET_Execute(audio);
- LOG_API_EXIT(audio)
- }
- uint32_t FAudio_CommitOperationSet(FAudio *audio, uint32_t OperationSet)
- {
- LOG_API_ENTER(audio)
- if (OperationSet == FAUDIO_COMMIT_ALL)
- {
- FAudio_OPERATIONSET_CommitAll(audio);
- }
- else
- {
- FAudio_OPERATIONSET_Commit(audio, OperationSet);
- }
- LOG_API_EXIT(audio)
- return 0;
- }
- uint32_t FAudio_CommitChanges(FAudio *audio)
- {
- FAudio_Log(
- "IF YOU CAN READ THIS, YOUR PROGRAM IS ABOUT TO BREAK!"
- "\n\nEither you or somebody else is using FAudio_CommitChanges,"
- "\nwhen they should be using FAudio_CommitOperationSet instead."
- "\n\nIf your program calls this, move to CommitOperationSet."
- "\n\nIf somebody else is calling this, find out who it is and"
- "\nfile a bug report with them ASAP."
- );
- /* Seriously, this is like the worst possible thing short of no-oping.
- * For the love-a Pete, just migrate, do it, what is wrong with you
- */
- return FAudio_CommitOperationSet(audio, FAUDIO_COMMIT_ALL);
- }
- void FAudio_GetPerformanceData(
- FAudio *audio,
- FAudioPerformanceData *pPerfData
- ) {
- LinkedList *list;
- FAudioSourceVoice *source;
- LOG_API_ENTER(audio)
- FAudio_zero(pPerfData, sizeof(FAudioPerformanceData));
- FAudio_PlatformLockMutex(audio->sourceLock);
- LOG_MUTEX_LOCK(audio, audio->sourceLock)
- list = audio->sources;
- while (list != NULL)
- {
- source = (FAudioSourceVoice*) list->entry;
- pPerfData->TotalSourceVoiceCount += 1;
- if (source->src.active)
- {
- pPerfData->ActiveSourceVoiceCount += 1;
- }
- list = list->next;
- }
- FAudio_PlatformUnlockMutex(audio->sourceLock);
- LOG_MUTEX_UNLOCK(audio, audio->sourceLock)
- FAudio_PlatformLockMutex(audio->submixLock);
- LOG_MUTEX_LOCK(audio, audio->submixLock)
- list = audio->submixes;
- while (list != NULL)
- {
- pPerfData->ActiveSubmixVoiceCount += 1;
- list = list->next;
- }
- FAudio_PlatformUnlockMutex(audio->submixLock);
- LOG_MUTEX_UNLOCK(audio, audio->submixLock)
- if (audio->master != NULL)
- {
- /* estimate, should use real latency from platform */
- pPerfData->CurrentLatencyInSamples = 2 * audio->updateSize;
- }
- LOG_API_EXIT(audio)
- }
- void FAudio_SetDebugConfiguration(
- FAudio *audio,
- FAudioDebugConfiguration *pDebugConfiguration,
- void* pReserved
- ) {
- #ifndef FAUDIO_DISABLE_DEBUGCONFIGURATION
- char *env;
- LOG_API_ENTER(audio)
- FAudio_memcpy(
- &audio->debug,
- pDebugConfiguration,
- sizeof(FAudioDebugConfiguration)
- );
- env = FAudio_getenv("FAUDIO_LOG_EVERYTHING");
- if (env != NULL && *env == '1')
- {
- audio->debug.TraceMask = (
- FAUDIO_LOG_ERRORS |
- FAUDIO_LOG_WARNINGS |
- FAUDIO_LOG_INFO |
- FAUDIO_LOG_DETAIL |
- FAUDIO_LOG_API_CALLS |
- FAUDIO_LOG_FUNC_CALLS |
- FAUDIO_LOG_TIMING |
- FAUDIO_LOG_LOCKS |
- FAUDIO_LOG_MEMORY |
- FAUDIO_LOG_STREAMING
- );
- audio->debug.LogThreadID = 1;
- audio->debug.LogFunctionName = 1;
- audio->debug.LogTiming = 1;
- }
- #define CHECK_ENV(type) \
- env = FAudio_getenv("FAUDIO_LOG_" #type); \
- if (env != NULL) \
- { \
- if (*env == '1') \
- { \
- audio->debug.TraceMask |= FAUDIO_LOG_##type; \
- } \
- else \
- { \
- audio->debug.TraceMask &= ~FAUDIO_LOG_##type; \
- } \
- }
- CHECK_ENV(ERRORS)
- CHECK_ENV(WARNINGS)
- CHECK_ENV(INFO)
- CHECK_ENV(DETAIL)
- CHECK_ENV(API_CALLS)
- CHECK_ENV(FUNC_CALLS)
- CHECK_ENV(TIMING)
- CHECK_ENV(LOCKS)
- CHECK_ENV(MEMORY)
- CHECK_ENV(STREAMING)
- #undef CHECK_ENV
- #define CHECK_ENV(envvar, boolvar) \
- env = FAudio_getenv("FAUDIO_LOG_LOG" #envvar); \
- if (env != NULL) \
- { \
- audio->debug.Log##boolvar = (*env == '1'); \
- }
- CHECK_ENV(THREADID, ThreadID)
- CHECK_ENV(FILELINE, Fileline)
- CHECK_ENV(FUNCTIONNAME, FunctionName)
- CHECK_ENV(TIMING, Timing)
- #undef CHECK_ENV
- LOG_API_EXIT(audio)
- #endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */
- }
- void FAudio_GetProcessingQuantum(
- FAudio *audio,
- uint32_t *quantumNumerator,
- uint32_t *quantumDenominator
- ) {
- FAudio_assert(audio->master != NULL);
- if (quantumNumerator != NULL)
- {
- *quantumNumerator = audio->updateSize;
- }
- if (quantumDenominator != NULL)
- {
- *quantumDenominator = audio->master->master.inputSampleRate;
- }
- }
- /* FAudioVoice Interface */
- static void FAudio_RecalcMixMatrix(FAudioVoice *voice, uint32_t sendIndex)
- {
- uint32_t oChan, s, d;
- FAudioVoice *out = voice->sends.pSends[sendIndex].pOutputVoice;
- float volume, *matrix = voice->mixCoefficients[sendIndex];
- if (voice->type == FAUDIO_VOICE_SUBMIX)
- {
- volume = 1.f;
- }
- else
- {
- volume = voice->volume;
- }
- if (out->type == FAUDIO_VOICE_MASTER)
- {
- oChan = out->master.inputChannels;
- }
- else
- {
- oChan = out->mix.inputChannels;
- }
- for (d = 0; d < oChan; d += 1)
- {
- for (s = 0; s < voice->outputChannels; s += 1)
- {
- matrix[d * voice->outputChannels + s] = volume *
- voice->channelVolume[s] *
- voice->sendCoefficients[sendIndex][d * voice->outputChannels + s];
- }
- }
- }
- void FAudioVoice_GetVoiceDetails(
- FAudioVoice *voice,
- FAudioVoiceDetails *pVoiceDetails
- ) {
- LOG_API_ENTER(voice->audio)
- pVoiceDetails->CreationFlags = voice->flags;
- pVoiceDetails->ActiveFlags = voice->flags;
- if (voice->type == FAUDIO_VOICE_SOURCE)
- {
- pVoiceDetails->InputChannels = voice->src.format->nChannels;
- pVoiceDetails->InputSampleRate = voice->src.format->nSamplesPerSec;
- }
- else if (voice->type == FAUDIO_VOICE_SUBMIX)
- {
- pVoiceDetails->InputChannels = voice->mix.inputChannels;
- pVoiceDetails->InputSampleRate = voice->mix.inputSampleRate;
- }
- else if (voice->type == FAUDIO_VOICE_MASTER)
- {
- pVoiceDetails->InputChannels = voice->master.inputChannels;
- pVoiceDetails->InputSampleRate = voice->master.inputSampleRate;
- }
- else
- {
- FAudio_assert(0 && "Unknown voice type!");
- }
- LOG_API_EXIT(voice->audio)
- }
- uint32_t FAudioVoice_SetOutputVoices(
- FAudioVoice *voice,
- const FAudioVoiceSends *pSendList
- ) {
- uint32_t i;
- uint32_t outChannels;
- FAudioVoiceSends defaultSends;
- FAudioSendDescriptor defaultSend;
- LOG_API_ENTER(voice->audio)
- if (voice->type == FAUDIO_VOICE_MASTER)
- {
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- if (FAudio_INTERNAL_VoiceOutputFrequency(voice, pSendList) != 0)
- {
- LOG_ERROR(
- voice->audio,
- "%s",
- "Changing the sample rate while an effect chain is attached is invalid!"
- )
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- FAudio_PlatformLockMutex(voice->volumeLock);
- LOG_MUTEX_LOCK(voice->audio, voice->volumeLock)
- /* FIXME: This is lazy... */
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- voice->audio->pFree(voice->sendCoefficients[i]);
- }
- if (voice->sendCoefficients != NULL)
- {
- voice->audio->pFree(voice->sendCoefficients);
- }
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- voice->audio->pFree(voice->mixCoefficients[i]);
- }
- if (voice->mixCoefficients != NULL)
- {
- voice->audio->pFree(voice->mixCoefficients);
- }
- if (voice->sendMix != NULL)
- {
- voice->audio->pFree(voice->sendMix);
- }
- if (voice->sendFilter != NULL)
- {
- voice->audio->pFree(voice->sendFilter);
- voice->sendFilter = NULL;
- }
- if (voice->sendFilterState != NULL)
- {
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- if (voice->sendFilterState[i] != NULL)
- {
- voice->audio->pFree(voice->sendFilterState[i]);
- }
- }
- voice->audio->pFree(voice->sendFilterState);
- voice->sendFilterState = NULL;
- }
- if (voice->sends.pSends != NULL)
- {
- voice->audio->pFree(voice->sends.pSends);
- }
- if (pSendList == NULL)
- {
- /* Default to the mastering voice as output */
- defaultSend.Flags = 0;
- defaultSend.pOutputVoice = voice->audio->master;
- defaultSends.SendCount = 1;
- defaultSends.pSends = &defaultSend;
- pSendList = &defaultSends;
- }
- else if (pSendList->SendCount == 0)
- {
- /* No sends? Nothing to do... */
- voice->sendCoefficients = NULL;
- voice->mixCoefficients = NULL;
- voice->sendMix = NULL;
- FAudio_zero(&voice->sends, sizeof(FAudioVoiceSends));
- FAudio_PlatformUnlockMutex(voice->volumeLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- /* Copy send list */
- voice->sends.SendCount = pSendList->SendCount;
- voice->sends.pSends = (FAudioSendDescriptor*) voice->audio->pMalloc(
- pSendList->SendCount * sizeof(FAudioSendDescriptor)
- );
- FAudio_memcpy(
- voice->sends.pSends,
- pSendList->pSends,
- pSendList->SendCount * sizeof(FAudioSendDescriptor)
- );
- /* Allocate/Reset default output matrix, mixer function, filters */
- voice->sendCoefficients = (float**) voice->audio->pMalloc(
- sizeof(float*) * pSendList->SendCount
- );
- voice->mixCoefficients = (float**) voice->audio->pMalloc(
- sizeof(float*) * pSendList->SendCount
- );
- voice->sendMix = (FAudioMixCallback*) voice->audio->pMalloc(
- sizeof(FAudioMixCallback) * pSendList->SendCount
- );
- for (i = 0; i < pSendList->SendCount; i += 1)
- {
- if (pSendList->pSends[i].pOutputVoice->type == FAUDIO_VOICE_MASTER)
- {
- outChannels = pSendList->pSends[i].pOutputVoice->master.inputChannels;
- }
- else
- {
- outChannels = pSendList->pSends[i].pOutputVoice->mix.inputChannels;
- }
- voice->sendCoefficients[i] = (float*) voice->audio->pMalloc(
- sizeof(float) * voice->outputChannels * outChannels
- );
- voice->mixCoefficients[i] = (float*) voice->audio->pMalloc(
- sizeof(float) * voice->outputChannels * outChannels
- );
- FAudio_assert(voice->outputChannels > 0 && voice->outputChannels < 9);
- FAudio_assert(outChannels > 0 && outChannels < 9);
- FAudio_memcpy(
- voice->sendCoefficients[i],
- FAUDIO_INTERNAL_MATRIX_DEFAULTS[voice->outputChannels - 1][outChannels - 1],
- voice->outputChannels * outChannels * sizeof(float)
- );
- FAudio_RecalcMixMatrix(voice, i);
- if (voice->outputChannels == 1)
- {
- if (outChannels == 1)
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_1in_1out_Scalar;
- }
- else if (outChannels == 2)
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_1in_2out_Scalar;
- }
- else if (outChannels == 6)
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_1in_6out_Scalar;
- }
- else if (outChannels == 8)
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_1in_8out_Scalar;
- }
- else
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_Generic;
- }
- }
- else if (voice->outputChannels == 2)
- {
- if (outChannels == 1)
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_2in_1out_Scalar;
- }
- else if (outChannels == 2)
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_2in_2out_Scalar;
- }
- else if (outChannels == 6)
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_2in_6out_Scalar;
- }
- else if (outChannels == 8)
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_2in_8out_Scalar;
- }
- else
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_Generic;
- }
- }
- else
- {
- voice->sendMix[i] = FAudio_INTERNAL_Mix_Generic;
- }
- if (pSendList->pSends[i].Flags & FAUDIO_SEND_USEFILTER)
- {
- /* Allocate the whole send filter array if needed... */
- if (voice->sendFilter == NULL)
- {
- voice->sendFilter = (FAudioFilterParameters*) voice->audio->pMalloc(
- sizeof(FAudioFilterParameters) * pSendList->SendCount
- );
- }
- if (voice->sendFilterState == NULL)
- {
- voice->sendFilterState = (FAudioFilterState**) voice->audio->pMalloc(
- sizeof(FAudioFilterState*) * pSendList->SendCount
- );
- FAudio_zero(
- voice->sendFilterState,
- sizeof(FAudioFilterState*) * pSendList->SendCount
- );
- }
- /* ... then fill in this send's filter data */
- voice->sendFilter[i].Type = FAUDIO_DEFAULT_FILTER_TYPE;
- voice->sendFilter[i].Frequency = FAUDIO_DEFAULT_FILTER_FREQUENCY;
- voice->sendFilter[i].OneOverQ = FAUDIO_DEFAULT_FILTER_ONEOVERQ;
- voice->sendFilterState[i] = (FAudioFilterState*) voice->audio->pMalloc(
- sizeof(FAudioFilterState) * outChannels
- );
- FAudio_zero(
- voice->sendFilterState[i],
- sizeof(FAudioFilterState) * outChannels
- );
- }
- }
- FAudio_PlatformUnlockMutex(voice->volumeLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioVoice_SetEffectChain(
- FAudioVoice *voice,
- const FAudioEffectChain *pEffectChain
- ) {
- uint32_t i;
- FAPO *fapo;
- uint32_t channelCount;
- FAudioVoiceDetails voiceDetails;
- FAPORegistrationProperties *pProps;
- FAudioWaveFormatExtensible srcFmt, dstFmt;
- FAPOLockForProcessBufferParameters srcLockParams, dstLockParams;
- LOG_API_ENTER(voice->audio)
- FAudioVoice_GetVoiceDetails(voice, &voiceDetails);
- /* SetEffectChain must not change the number of output channels once the voice has been created */
- if (pEffectChain == NULL && voice->outputChannels != 0)
- {
- /* cannot remove an effect chain that changes the number of channels */
- if (voice->outputChannels != voiceDetails.InputChannels)
- {
- LOG_ERROR(
- voice->audio,
- "%s",
- "Cannot remove effect chain that changes the number of channels"
- )
- FAudio_assert(0 && "Cannot remove effect chain that changes the number of channels");
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- }
- if (pEffectChain != NULL && voice->outputChannels != 0)
- {
- uint32_t lst = pEffectChain->EffectCount - 1;
- /* new effect chain must have same number of output channels */
- if (voice->outputChannels != pEffectChain->pEffectDescriptors[lst].OutputChannels)
- {
- LOG_ERROR(
- voice->audio,
- "%s",
- "New effect chain must have same number of output channels as the old chain"
- )
- FAudio_assert(0 && "New effect chain must have same number of output channels as the old chain");
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- }
- FAudio_PlatformLockMutex(voice->effectLock);
- LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
- if (pEffectChain == NULL)
- {
- FAudio_INTERNAL_FreeEffectChain(voice);
- FAudio_zero(&voice->effects, sizeof(voice->effects));
- voice->outputChannels = voiceDetails.InputChannels;
- }
- else
- {
- /* Validate incoming chain before changing the current chain */
- /* These are always the same, so just write them now. */
- srcLockParams.pFormat = &srcFmt.Format;
- dstLockParams.pFormat = &dstFmt.Format;
- if (voice->type == FAUDIO_VOICE_SOURCE)
- {
- srcLockParams.MaxFrameCount = voice->src.resampleSamples;
- dstLockParams.MaxFrameCount = voice->src.resampleSamples;
- }
- else if (voice->type == FAUDIO_VOICE_SUBMIX)
- {
- srcLockParams.MaxFrameCount = voice->mix.outputSamples;
- dstLockParams.MaxFrameCount = voice->mix.outputSamples;
- }
- else if (voice->type == FAUDIO_VOICE_MASTER)
- {
- srcLockParams.MaxFrameCount = voice->audio->updateSize;
- dstLockParams.MaxFrameCount = voice->audio->updateSize;
- }
- /* The first source is the voice input data... */
- srcFmt.Format.wBitsPerSample = 32;
- srcFmt.Format.wFormatTag = FAUDIO_FORMAT_EXTENSIBLE;
- srcFmt.Format.nChannels = voiceDetails.InputChannels;
- srcFmt.Format.nSamplesPerSec = voiceDetails.InputSampleRate;
- srcFmt.Format.nBlockAlign = srcFmt.Format.nChannels * (srcFmt.Format.wBitsPerSample / 8);
- srcFmt.Format.nAvgBytesPerSec = srcFmt.Format.nSamplesPerSec * srcFmt.Format.nBlockAlign;
- srcFmt.Format.cbSize = sizeof(FAudioWaveFormatExtensible) - sizeof(FAudioWaveFormatEx);
- srcFmt.Samples.wValidBitsPerSample = srcFmt.Format.wBitsPerSample;
- srcFmt.dwChannelMask = 0;
- FAudio_memcpy(&srcFmt.SubFormat, &DATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(FAudioGUID));
- FAudio_memcpy(&dstFmt, &srcFmt, sizeof(srcFmt));
- for (i = 0; i < pEffectChain->EffectCount; i += 1)
- {
- fapo = pEffectChain->pEffectDescriptors[i].pEffect;
- /* ... then we get this effect's format... */
- dstFmt.Format.nChannels = pEffectChain->pEffectDescriptors[i].OutputChannels;
- dstFmt.Format.nBlockAlign = dstFmt.Format.nChannels * (dstFmt.Format.wBitsPerSample / 8);
- dstFmt.Format.nAvgBytesPerSec = dstFmt.Format.nSamplesPerSec * dstFmt.Format.nBlockAlign;
- /* FIXME: This error needs to be found _before_ we start
- * shredding the voice's state. This function is highly
- * destructive so any errors need to be found at the
- * beginning, not in the middle! We can't undo this!
- * -flibit
- */
- if (fapo->LockForProcess(fapo, 1, &srcLockParams, 1, &dstLockParams))
- {
- LOG_ERROR(
- voice->audio,
- "%s",
- "Effect output format not supported"
- )
- FAudio_assert(0 && "Effect output format not supported");
- FAudio_PlatformUnlockMutex(voice->effectLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_UNSUPPORTED_FORMAT;
- }
- /* Okay, now this effect is the source and the next
- * effect will be the destination. Repeat until no
- * effects left.
- */
- FAudio_memcpy(&srcFmt, &dstFmt, sizeof(srcFmt));
- }
- FAudio_INTERNAL_FreeEffectChain(voice);
- FAudio_INTERNAL_AllocEffectChain(
- voice,
- pEffectChain
- );
- /* check if in-place processing is supported */
- channelCount = voiceDetails.InputChannels;
- for (i = 0; i < voice->effects.count; i += 1)
- {
- fapo = voice->effects.desc[i].pEffect;
- if (fapo->GetRegistrationProperties(fapo, &pProps) == 0)
- {
- voice->effects.inPlaceProcessing[i] = (pProps->Flags & FAPO_FLAG_INPLACE_SUPPORTED) == FAPO_FLAG_INPLACE_SUPPORTED;
- voice->effects.inPlaceProcessing[i] &= (channelCount == voice->effects.desc[i].OutputChannels);
- channelCount = voice->effects.desc[i].OutputChannels;
- /* Fails if in-place processing is mandatory and
- * the chain forces us to do otherwise...
- */
- FAudio_assert(
- !(pProps->Flags & FAPO_FLAG_INPLACE_REQUIRED) ||
- voice->effects.inPlaceProcessing[i]
- );
- voice->audio->pFree(pProps);
- }
- }
- voice->outputChannels = channelCount;
- }
- FAudio_PlatformUnlockMutex(voice->effectLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioVoice_EnableEffect(
- FAudioVoice *voice,
- uint32_t EffectIndex,
- uint32_t OperationSet
- ) {
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueEnableEffect(
- voice,
- EffectIndex,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_PlatformLockMutex(voice->effectLock);
- LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
- voice->effects.desc[EffectIndex].InitialState = 1;
- FAudio_PlatformUnlockMutex(voice->effectLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioVoice_DisableEffect(
- FAudioVoice *voice,
- uint32_t EffectIndex,
- uint32_t OperationSet
- ) {
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueDisableEffect(
- voice,
- EffectIndex,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_PlatformLockMutex(voice->effectLock);
- LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
- voice->effects.desc[EffectIndex].InitialState = 0;
- FAudio_PlatformUnlockMutex(voice->effectLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- void FAudioVoice_GetEffectState(
- FAudioVoice *voice,
- uint32_t EffectIndex,
- int32_t *pEnabled
- ) {
- LOG_API_ENTER(voice->audio)
- FAudio_PlatformLockMutex(voice->effectLock);
- LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
- *pEnabled = voice->effects.desc[EffectIndex].InitialState;
- FAudio_PlatformUnlockMutex(voice->effectLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
- LOG_API_EXIT(voice->audio)
- }
- uint32_t FAudioVoice_SetEffectParameters(
- FAudioVoice *voice,
- uint32_t EffectIndex,
- const void *pParameters,
- uint32_t ParametersByteSize,
- uint32_t OperationSet
- ) {
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueSetEffectParameters(
- voice,
- EffectIndex,
- pParameters,
- ParametersByteSize,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- if (voice->effects.parameters[EffectIndex] == NULL)
- {
- voice->effects.parameters[EffectIndex] = voice->audio->pMalloc(
- ParametersByteSize
- );
- voice->effects.parameterSizes[EffectIndex] = ParametersByteSize;
- }
- FAudio_PlatformLockMutex(voice->effectLock);
- LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
- if (voice->effects.parameterSizes[EffectIndex] < ParametersByteSize)
- {
- voice->effects.parameters[EffectIndex] = voice->audio->pRealloc(
- voice->effects.parameters[EffectIndex],
- ParametersByteSize
- );
- voice->effects.parameterSizes[EffectIndex] = ParametersByteSize;
- }
- FAudio_memcpy(
- voice->effects.parameters[EffectIndex],
- pParameters,
- ParametersByteSize
- );
- voice->effects.parameterUpdates[EffectIndex] = 1;
- FAudio_PlatformUnlockMutex(voice->effectLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioVoice_GetEffectParameters(
- FAudioVoice *voice,
- uint32_t EffectIndex,
- void *pParameters,
- uint32_t ParametersByteSize
- ) {
- FAPO *fapo;
- LOG_API_ENTER(voice->audio)
- FAudio_PlatformLockMutex(voice->effectLock);
- LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
- fapo = voice->effects.desc[EffectIndex].pEffect;
- fapo->GetParameters(fapo, pParameters, ParametersByteSize);
- FAudio_PlatformUnlockMutex(voice->effectLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioVoice_SetFilterParameters(
- FAudioVoice *voice,
- const FAudioFilterParameters *pParameters,
- uint32_t OperationSet
- ) {
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueSetFilterParameters(
- voice,
- pParameters,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- /* MSDN: "This method is usable only on source and submix voices and
- * has no effect on mastering voices."
- */
- if (voice->type == FAUDIO_VOICE_MASTER)
- {
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- if (!(voice->flags & FAUDIO_VOICE_USEFILTER))
- {
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_PlatformLockMutex(voice->filterLock);
- LOG_MUTEX_LOCK(voice->audio, voice->filterLock)
- FAudio_memcpy(
- &voice->filter,
- pParameters,
- sizeof(FAudioFilterParameters)
- );
- FAudio_PlatformUnlockMutex(voice->filterLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->filterLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- void FAudioVoice_GetFilterParameters(
- FAudioVoice *voice,
- FAudioFilterParameters *pParameters
- ) {
- LOG_API_ENTER(voice->audio)
- /* MSDN: "This method is usable only on source and submix voices and
- * has no effect on mastering voices."
- */
- if (voice->type == FAUDIO_VOICE_MASTER)
- {
- LOG_API_EXIT(voice->audio)
- return;
- }
- if (!(voice->flags & FAUDIO_VOICE_USEFILTER))
- {
- LOG_API_EXIT(voice->audio)
- return;
- }
- FAudio_PlatformLockMutex(voice->filterLock);
- LOG_MUTEX_LOCK(voice->audio, voice->filterLock)
- FAudio_memcpy(
- pParameters,
- &voice->filter,
- sizeof(FAudioFilterParameters)
- );
- FAudio_PlatformUnlockMutex(voice->filterLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->filterLock)
- LOG_API_EXIT(voice->audio)
- }
- uint32_t FAudioVoice_SetOutputFilterParameters(
- FAudioVoice *voice,
- FAudioVoice *pDestinationVoice,
- const FAudioFilterParameters *pParameters,
- uint32_t OperationSet
- ) {
- uint32_t i;
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueSetOutputFilterParameters(
- voice,
- pDestinationVoice,
- pParameters,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- /* MSDN: "This method is usable only on source and submix voices and
- * has no effect on mastering voices."
- */
- if (voice->type == FAUDIO_VOICE_MASTER)
- {
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- /* Find the send index */
- if (pDestinationVoice == NULL && voice->sends.SendCount == 1)
- {
- pDestinationVoice = voice->sends.pSends[0].pOutputVoice;
- }
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- if (pDestinationVoice == voice->sends.pSends[i].pOutputVoice)
- {
- break;
- }
- }
- if (i >= voice->sends.SendCount)
- {
- LOG_ERROR(
- voice->audio,
- "Destination not attached to source: %p %p",
- (void*) voice,
- (void*) pDestinationVoice
- )
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- if (!(voice->sends.pSends[i].Flags & FAUDIO_SEND_USEFILTER))
- {
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- /* Set the filter parameters, finally. */
- FAudio_memcpy(
- &voice->sendFilter[i],
- pParameters,
- sizeof(FAudioFilterParameters)
- );
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- void FAudioVoice_GetOutputFilterParameters(
- FAudioVoice *voice,
- FAudioVoice *pDestinationVoice,
- FAudioFilterParameters *pParameters
- ) {
- uint32_t i;
- LOG_API_ENTER(voice->audio)
- /* MSDN: "This method is usable only on source and submix voices and
- * has no effect on mastering voices."
- */
- if (voice->type == FAUDIO_VOICE_MASTER)
- {
- LOG_API_EXIT(voice->audio)
- return;
- }
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- /* Find the send index */
- if (pDestinationVoice == NULL && voice->sends.SendCount == 1)
- {
- pDestinationVoice = voice->sends.pSends[0].pOutputVoice;
- }
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- if (pDestinationVoice == voice->sends.pSends[i].pOutputVoice)
- {
- break;
- }
- }
- if (i >= voice->sends.SendCount)
- {
- LOG_ERROR(
- voice->audio,
- "Destination not attached to source: %p %p",
- (void*) voice,
- (void*) pDestinationVoice
- )
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return;
- }
- if (!(voice->sends.pSends[i].Flags & FAUDIO_SEND_USEFILTER))
- {
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return;
- }
- /* Set the filter parameters, finally. */
- FAudio_memcpy(
- pParameters,
- &voice->sendFilter[i],
- sizeof(FAudioFilterParameters)
- );
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- }
- uint32_t FAudioVoice_SetVolume(
- FAudioVoice *voice,
- float Volume,
- uint32_t OperationSet
- ) {
- uint32_t i;
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueSetVolume(
- voice,
- Volume,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- FAudio_PlatformLockMutex(voice->volumeLock);
- LOG_MUTEX_LOCK(voice->audio, voice->volumeLock)
- voice->volume = FAudio_clamp(
- Volume,
- -FAUDIO_MAX_VOLUME_LEVEL,
- FAUDIO_MAX_VOLUME_LEVEL
- );
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- FAudio_RecalcMixMatrix(voice, i);
- }
- FAudio_PlatformUnlockMutex(voice->volumeLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- void FAudioVoice_GetVolume(
- FAudioVoice *voice,
- float *pVolume
- ) {
- LOG_API_ENTER(voice->audio)
- *pVolume = voice->volume;
- LOG_API_EXIT(voice->audio)
- }
- uint32_t FAudioVoice_SetChannelVolumes(
- FAudioVoice *voice,
- uint32_t Channels,
- const float *pVolumes,
- uint32_t OperationSet
- ) {
- uint32_t i;
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueSetChannelVolumes(
- voice,
- Channels,
- pVolumes,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- if (pVolumes == NULL)
- {
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- if (voice->type == FAUDIO_VOICE_MASTER)
- {
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- if (voice->audio->version > 7 && Channels != voice->outputChannels)
- {
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- FAudio_PlatformLockMutex(voice->volumeLock);
- LOG_MUTEX_LOCK(voice->audio, voice->volumeLock)
- FAudio_memcpy(
- voice->channelVolume,
- pVolumes,
- sizeof(float) * Channels
- );
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- FAudio_RecalcMixMatrix(voice, i);
- }
- FAudio_PlatformUnlockMutex(voice->volumeLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- void FAudioVoice_GetChannelVolumes(
- FAudioVoice *voice,
- uint32_t Channels,
- float *pVolumes
- ) {
- LOG_API_ENTER(voice->audio)
- FAudio_PlatformLockMutex(voice->volumeLock);
- LOG_MUTEX_LOCK(voice->audio, voice->volumeLock)
- FAudio_memcpy(
- pVolumes,
- voice->channelVolume,
- sizeof(float) * Channels
- );
- FAudio_PlatformUnlockMutex(voice->volumeLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
- LOG_API_EXIT(voice->audio)
- }
- uint32_t FAudioVoice_SetOutputMatrix(
- FAudioVoice *voice,
- FAudioVoice *pDestinationVoice,
- uint32_t SourceChannels,
- uint32_t DestinationChannels,
- const float *pLevelMatrix,
- uint32_t OperationSet
- ) {
- uint32_t i, result = 0;
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueSetOutputMatrix(
- voice,
- pDestinationVoice,
- SourceChannels,
- DestinationChannels,
- pLevelMatrix,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- /* Find the send index */
- if (pDestinationVoice == NULL && voice->sends.SendCount == 1)
- {
- pDestinationVoice = voice->sends.pSends[0].pOutputVoice;
- }
- FAudio_assert(pDestinationVoice != NULL);
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- if (pDestinationVoice == voice->sends.pSends[i].pOutputVoice)
- {
- break;
- }
- }
- if (i >= voice->sends.SendCount)
- {
- LOG_ERROR(
- voice->audio,
- "Destination not attached to source: %p %p",
- (void*) voice,
- (void*) pDestinationVoice
- )
- result = FAUDIO_E_INVALID_CALL;
- goto end;
- }
- /* Verify the Source/Destination channel count */
- if (SourceChannels != voice->outputChannels)
- {
- LOG_ERROR(
- voice->audio,
- "SourceChannels not equal to voice channel count: %p %d %d",
- (void*) voice,
- SourceChannels,
- voice->outputChannels
- )
- result = FAUDIO_E_INVALID_CALL;
- goto end;
- }
- if (pDestinationVoice->type == FAUDIO_VOICE_MASTER)
- {
- if (DestinationChannels != pDestinationVoice->master.inputChannels)
- {
- LOG_ERROR(
- voice->audio,
- "DestinationChannels not equal to master channel count: %p %d %d",
- (void*) pDestinationVoice,
- DestinationChannels,
- pDestinationVoice->master.inputChannels
- )
- result = FAUDIO_E_INVALID_CALL;
- goto end;
- }
- }
- else
- {
- if (DestinationChannels != pDestinationVoice->mix.inputChannels)
- {
- LOG_ERROR(
- voice->audio,
- "DestinationChannels not equal to submix channel count: %p %d %d",
- (void*) pDestinationVoice,
- DestinationChannels,
- pDestinationVoice->mix.inputChannels
- )
- result = FAUDIO_E_INVALID_CALL;
- goto end;
- }
- }
- /* Set the matrix values, finally */
- FAudio_PlatformLockMutex(voice->volumeLock);
- LOG_MUTEX_LOCK(voice->audio, voice->volumeLock)
- FAudio_memcpy(
- voice->sendCoefficients[i],
- pLevelMatrix,
- sizeof(float) * SourceChannels * DestinationChannels
- );
- FAudio_RecalcMixMatrix(voice, i);
- FAudio_PlatformUnlockMutex(voice->volumeLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
- end:
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return result;
- }
- void FAudioVoice_GetOutputMatrix(
- FAudioVoice *voice,
- FAudioVoice *pDestinationVoice,
- uint32_t SourceChannels,
- uint32_t DestinationChannels,
- float *pLevelMatrix
- ) {
- uint32_t i;
- LOG_API_ENTER(voice->audio)
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- /* Find the send index */
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- if (pDestinationVoice == voice->sends.pSends[i].pOutputVoice)
- {
- break;
- }
- }
- if (i >= voice->sends.SendCount)
- {
- LOG_ERROR(
- voice->audio,
- "Destination not attached to source: %p %p",
- (void*) voice,
- (void*) pDestinationVoice
- )
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return;
- }
- /* Verify the Source/Destination channel count */
- if (voice->type == FAUDIO_VOICE_SOURCE)
- {
- FAudio_assert(SourceChannels == voice->src.format->nChannels);
- }
- else
- {
- FAudio_assert(SourceChannels == voice->mix.inputChannels);
- }
- if (pDestinationVoice->type == FAUDIO_VOICE_MASTER)
- {
- FAudio_assert(DestinationChannels == pDestinationVoice->master.inputChannels);
- }
- else
- {
- FAudio_assert(DestinationChannels == pDestinationVoice->mix.inputChannels);
- }
- /* Get the matrix values, finally */
- FAudio_memcpy(
- pLevelMatrix,
- voice->sendCoefficients[i],
- sizeof(float) * SourceChannels * DestinationChannels
- );
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- }
- void FAudioVoice_DestroyVoice(FAudioVoice *voice)
- {
- uint32_t i;
- LOG_API_ENTER(voice->audio)
- /* TODO: Check for dependencies and remove from audio graph first! */
- FAudio_OPERATIONSET_ClearAllForVoice(voice);
- if (voice->type == FAUDIO_VOICE_SOURCE)
- {
- FAudioBufferEntry *entry, *next;
- #ifdef FAUDIO_DUMP_VOICES
- FAudio_DUMPVOICE_Finalize((FAudioSourceVoice*) voice);
- #endif /* FAUDIO_DUMP_VOICES */
- FAudio_PlatformLockMutex(voice->audio->sourceLock);
- LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
- while (voice == voice->audio->processingSource)
- {
- FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
- FAudio_PlatformLockMutex(voice->audio->sourceLock);
- LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
- }
- LinkedList_RemoveEntry(
- &voice->audio->sources,
- voice,
- voice->audio->sourceLock,
- voice->audio->pFree
- );
- FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
- entry = voice->src.bufferList;
- while (entry != NULL)
- {
- next = entry->next;
- voice->audio->pFree(entry);
- entry = next;
- }
- entry = voice->src.flushList;
- while (entry != NULL)
- {
- next = entry->next;
- voice->audio->pFree(entry);
- entry = next;
- }
- voice->audio->pFree(voice->src.format);
- LOG_MUTEX_DESTROY(voice->audio, voice->src.bufferLock)
- FAudio_PlatformDestroyMutex(voice->src.bufferLock);
- #ifdef HAVE_WMADEC
- if (voice->src.wmadec)
- {
- FAudio_WMADEC_free(voice);
- }
- #endif /* HAVE_WMADEC */
- }
- else if (voice->type == FAUDIO_VOICE_SUBMIX)
- {
- /* Remove submix from list */
- LinkedList_RemoveEntry(
- &voice->audio->submixes,
- voice,
- voice->audio->submixLock,
- voice->audio->pFree
- );
- /* Delete submix data */
- voice->audio->pFree(voice->mix.inputCache);
- }
- else if (voice->type == FAUDIO_VOICE_MASTER)
- {
- if (voice->audio->platform != NULL)
- {
- FAudio_PlatformQuit(voice->audio->platform);
- voice->audio->platform = NULL;
- }
- if (voice->master.effectCache != NULL)
- {
- voice->audio->pFree(voice->master.effectCache);
- }
- voice->audio->master = NULL;
- }
- if (voice->sendLock != NULL)
- {
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- voice->audio->pFree(voice->sendCoefficients[i]);
- }
- if (voice->sendCoefficients != NULL)
- {
- voice->audio->pFree(voice->sendCoefficients);
- }
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- voice->audio->pFree(voice->mixCoefficients[i]);
- }
- if (voice->mixCoefficients != NULL)
- {
- voice->audio->pFree(voice->mixCoefficients);
- }
- if (voice->sendMix != NULL)
- {
- voice->audio->pFree(voice->sendMix);
- }
- if (voice->sendFilter != NULL)
- {
- voice->audio->pFree(voice->sendFilter);
- }
- if (voice->sendFilterState != NULL)
- {
- for (i = 0; i < voice->sends.SendCount; i += 1)
- {
- if (voice->sendFilterState[i] != NULL)
- {
- voice->audio->pFree(voice->sendFilterState[i]);
- }
- }
- voice->audio->pFree(voice->sendFilterState);
- }
- if (voice->sends.pSends != NULL)
- {
- voice->audio->pFree(voice->sends.pSends);
- }
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_MUTEX_DESTROY(voice->audio, voice->sendLock)
- FAudio_PlatformDestroyMutex(voice->sendLock);
- }
- if (voice->effectLock != NULL)
- {
- FAudio_PlatformLockMutex(voice->effectLock);
- LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
- FAudio_INTERNAL_FreeEffectChain(voice);
- FAudio_PlatformUnlockMutex(voice->effectLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
- LOG_MUTEX_DESTROY(voice->audio, voice->effectLock)
- FAudio_PlatformDestroyMutex(voice->effectLock);
- }
- if (voice->filterLock != NULL)
- {
- FAudio_PlatformLockMutex(voice->filterLock);
- LOG_MUTEX_LOCK(voice->audio, voice->filterLock)
- if (voice->filterState != NULL)
- {
- voice->audio->pFree(voice->filterState);
- }
- FAudio_PlatformUnlockMutex(voice->filterLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->filterLock)
- LOG_MUTEX_DESTROY(voice->audio, voice->filterLock)
- FAudio_PlatformDestroyMutex(voice->filterLock);
- }
- if (voice->volumeLock != NULL)
- {
- FAudio_PlatformLockMutex(voice->volumeLock);
- LOG_MUTEX_LOCK(voice->audio, voice->volumeLock)
- if (voice->channelVolume != NULL)
- {
- voice->audio->pFree(voice->channelVolume);
- }
- FAudio_PlatformUnlockMutex(voice->volumeLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
- LOG_MUTEX_DESTROY(voice->audio, voice->volumeLock)
- FAudio_PlatformDestroyMutex(voice->volumeLock);
- }
- LOG_API_EXIT(voice->audio)
- FAudio_Release(voice->audio);
- voice->audio->pFree(voice);
- }
- /* FAudioSourceVoice Interface */
- uint32_t FAudioSourceVoice_Start(
- FAudioSourceVoice *voice,
- uint32_t Flags,
- uint32_t OperationSet
- ) {
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueStart(
- voice,
- Flags,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- FAudio_assert(Flags == 0);
- voice->src.active = 1;
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioSourceVoice_Stop(
- FAudioSourceVoice *voice,
- uint32_t Flags,
- uint32_t OperationSet
- ) {
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueStop(
- voice,
- Flags,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- if (Flags & FAUDIO_PLAY_TAILS)
- {
- voice->src.active = 2;
- }
- else
- {
- voice->src.active = 0;
- }
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioSourceVoice_SubmitSourceBuffer(
- FAudioSourceVoice *voice,
- const FAudioBuffer *pBuffer,
- const FAudioBufferWMA *pBufferWMA
- ) {
- uint32_t adpcmMask, *adpcmByteCount;
- uint32_t playBegin, playLength, loopBegin, loopLength;
- FAudioBufferEntry *entry, *list;
- LOG_API_ENTER(voice->audio)
- LOG_INFO(
- voice->audio,
- "%p: {Flags: 0x%x, AudioBytes: %u, pAudioData: %p, Play: %u + %u, Loop: %u + %u x %u}",
- (void*) voice,
- pBuffer->Flags,
- pBuffer->AudioBytes,
- (const void*) pBuffer->pAudioData,
- pBuffer->PlayBegin,
- pBuffer->PlayLength,
- pBuffer->LoopBegin,
- pBuffer->LoopLength,
- pBuffer->LoopCount
- )
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- #ifdef HAVE_WMADEC
- FAudio_assert( (voice->src.wmadec != NULL && (pBufferWMA != NULL ||
- (voice->src.format->wFormatTag == FAUDIO_FORMAT_XMAUDIO2 ||
- voice->src.format->wFormatTag == FAUDIO_FORMAT_EXTENSIBLE))) ||
- (voice->src.wmadec == NULL && (pBufferWMA == NULL && voice->src.format->wFormatTag != FAUDIO_FORMAT_XMAUDIO2)) );
- #endif /* HAVE_WMADEC */
- /* Start off with whatever they just sent us... */
- playBegin = pBuffer->PlayBegin;
- playLength = pBuffer->PlayLength;
- loopBegin = pBuffer->LoopBegin;
- loopLength = pBuffer->LoopLength;
- /* "LoopBegin/LoopLength must be zero if LoopCount is 0" */
- if (pBuffer->LoopCount == 0 && (loopBegin > 0 || loopLength > 0))
- {
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- /* PlayLength Default */
- if (playLength == 0)
- {
- if (voice->src.format->wFormatTag == FAUDIO_FORMAT_MSADPCM)
- {
- FAudioADPCMWaveFormat *fmtex = (FAudioADPCMWaveFormat*) voice->src.format;
- playLength = (
- pBuffer->AudioBytes /
- fmtex->wfx.nBlockAlign *
- fmtex->wSamplesPerBlock
- ) - playBegin;
- }
- else if (voice->src.format->wFormatTag == FAUDIO_FORMAT_XMAUDIO2)
- {
- FAudioXMA2WaveFormat *fmtex = (FAudioXMA2WaveFormat*) voice->src.format;
- playLength = fmtex->dwSamplesEncoded - playBegin;
- }
- else if (pBufferWMA != NULL)
- {
- playLength = (
- pBufferWMA->pDecodedPacketCumulativeBytes[pBufferWMA->PacketCount - 1] /
- (voice->src.format->nChannels * voice->src.format->wBitsPerSample / 8)
- ) - playBegin;
- }
- else
- {
- playLength = (
- pBuffer->AudioBytes /
- voice->src.format->nBlockAlign
- ) - playBegin;
- }
- }
- if (pBuffer->LoopCount > 0 && pBufferWMA == NULL && voice->src.format->wFormatTag != FAUDIO_FORMAT_XMAUDIO2)
- {
- /* "The value of LoopBegin must be less than PlayBegin + PlayLength" */
- if (loopBegin >= (playBegin + playLength))
- {
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- /* LoopLength Default */
- if (loopLength == 0)
- {
- loopLength = playBegin + playLength - loopBegin;
- }
- /* "The value of LoopBegin + LoopLength must be greater than PlayBegin
- * and less than PlayBegin + PlayLength"
- */
- if ( voice->audio->version > 7 && (
- (loopBegin + loopLength) <= playBegin ||
- (loopBegin + loopLength) > (playBegin + playLength)) )
- {
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- }
- /* For ADPCM, round down to the nearest sample block size */
- if (voice->src.format->wFormatTag == FAUDIO_FORMAT_MSADPCM)
- {
- adpcmMask = ((FAudioADPCMWaveFormat*) voice->src.format)->wSamplesPerBlock;
- playBegin -= playBegin % adpcmMask;
- playLength -= playLength % adpcmMask;
- loopBegin -= loopBegin % adpcmMask;
- loopLength -= loopLength % adpcmMask;
- /* This is basically a const_cast... */
- adpcmByteCount = (uint32_t*) &pBuffer->AudioBytes;
- *adpcmByteCount = (
- pBuffer->AudioBytes / voice->src.format->nBlockAlign
- ) * voice->src.format->nBlockAlign;
- }
- else if (pBufferWMA != NULL || voice->src.format->wFormatTag == FAUDIO_FORMAT_XMAUDIO2)
- {
- /* WMA only supports looping the whole buffer */
- loopBegin = 0;
- loopLength = playBegin + playLength;
- }
- /* Allocate, now that we have valid input */
- entry = (FAudioBufferEntry*) voice->audio->pMalloc(sizeof(FAudioBufferEntry));
- FAudio_memcpy(&entry->buffer, pBuffer, sizeof(FAudioBuffer));
- entry->buffer.PlayBegin = playBegin;
- entry->buffer.PlayLength = playLength;
- entry->buffer.LoopBegin = loopBegin;
- entry->buffer.LoopLength = loopLength;
- if (pBufferWMA != NULL)
- {
- FAudio_memcpy(&entry->bufferWMA, pBufferWMA, sizeof(FAudioBufferWMA));
- }
- entry->next = NULL;
- if ( voice->audio->version <= 7 && (
- entry->buffer.LoopCount > 0 &&
- entry->buffer.LoopBegin + entry->buffer.LoopLength <= entry->buffer.PlayBegin))
- {
- entry->buffer.LoopCount = 0;
- }
- #ifdef FAUDIO_DUMP_VOICES
- /* dumping current buffer, append into "data" section */
- if (pBuffer->pAudioData != NULL && playLength > 0)
- {
- FAudio_DUMPVOICE_WriteBuffer(voice, pBuffer, pBufferWMA, playBegin, playLength);
- }
- #endif /* FAUDIO_DUMP_VOICES */
- /* Submit! */
- FAudio_PlatformLockMutex(voice->src.bufferLock);
- LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
- if (voice->src.bufferList == NULL)
- {
- voice->src.bufferList = entry;
- voice->src.curBufferOffset = entry->buffer.PlayBegin;
- voice->src.newBuffer = 1;
- }
- else
- {
- list = voice->src.bufferList;
- while (list->next != NULL)
- {
- list = list->next;
- }
- list->next = entry;
- /* For some bizarre reason we get scenarios where a buffer is freed, only to
- * have the allocator give us the exact same address and somehow get a single
- * buffer referencing itself. I don't even know.
- */
- FAudio_assert(list != entry);
- }
- LOG_INFO(
- voice->audio,
- "%p: appended buffer %p",
- (void*) voice,
- (void*) &entry->buffer
- )
- FAudio_PlatformUnlockMutex(voice->src.bufferLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioSourceVoice_FlushSourceBuffers(
- FAudioSourceVoice *voice
- ) {
- FAudioBufferEntry *entry, *latest;
- LOG_API_ENTER(voice->audio)
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- FAudio_PlatformLockMutex(voice->src.bufferLock);
- LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
- /* If the source is playing, don't flush the active buffer */
- entry = voice->src.bufferList;
- if ((voice->src.active == 1) && entry != NULL && !voice->src.newBuffer)
- {
- entry = entry->next;
- voice->src.bufferList->next = NULL;
- }
- else
- {
- voice->src.curBufferOffset = 0;
- voice->src.bufferList = NULL;
- voice->src.newBuffer = 0;
- }
- /* Move them to the pending flush list */
- if (entry != NULL)
- {
- if (voice->src.flushList == NULL)
- {
- voice->src.flushList = entry;
- }
- else
- {
- latest = voice->src.flushList;
- while (latest->next != NULL)
- {
- latest = latest->next;
- }
- latest->next = entry;
- }
- }
- FAudio_PlatformUnlockMutex(voice->src.bufferLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioSourceVoice_Discontinuity(
- FAudioSourceVoice *voice
- ) {
- FAudioBufferEntry *buf;
- LOG_API_ENTER(voice->audio)
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- FAudio_PlatformLockMutex(voice->src.bufferLock);
- LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
- if (voice->src.bufferList != NULL)
- {
- for (buf = voice->src.bufferList; buf->next != NULL; buf = buf->next);
- buf->buffer.Flags |= FAUDIO_END_OF_STREAM;
- }
- FAudio_PlatformUnlockMutex(voice->src.bufferLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- uint32_t FAudioSourceVoice_ExitLoop(
- FAudioSourceVoice *voice,
- uint32_t OperationSet
- ) {
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueExitLoop(
- voice,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- FAudio_PlatformLockMutex(voice->src.bufferLock);
- LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
- if (voice->src.bufferList != NULL)
- {
- voice->src.bufferList->buffer.LoopCount = 0;
- }
- FAudio_PlatformUnlockMutex(voice->src.bufferLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- void FAudioSourceVoice_GetState(
- FAudioSourceVoice *voice,
- FAudioVoiceState *pVoiceState,
- uint32_t Flags
- ) {
- FAudioBufferEntry *entry;
- LOG_API_ENTER(voice->audio)
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- FAudio_PlatformLockMutex(voice->src.bufferLock);
- LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
- if (!(Flags & FAUDIO_VOICE_NOSAMPLESPLAYED))
- {
- pVoiceState->SamplesPlayed = voice->src.totalSamples;
- }
- pVoiceState->BuffersQueued = 0;
- pVoiceState->pCurrentBufferContext = NULL;
- if (voice->src.bufferList != NULL)
- {
- entry = voice->src.bufferList;
- if (!voice->src.newBuffer)
- {
- pVoiceState->pCurrentBufferContext = entry->buffer.pContext;
- }
- do
- {
- pVoiceState->BuffersQueued += 1;
- entry = entry->next;
- } while (entry != NULL);
- }
- /* Pending flushed buffers also count */
- entry = voice->src.flushList;
- while (entry != NULL)
- {
- pVoiceState->BuffersQueued += 1;
- entry = entry->next;
- }
- LOG_INFO(
- voice->audio,
- "-> {pCurrentBufferContext: %p, BuffersQueued: %u, SamplesPlayed: %"FAudio_PRIu64"}",
- pVoiceState->pCurrentBufferContext, pVoiceState->BuffersQueued,
- pVoiceState->SamplesPlayed
- )
- FAudio_PlatformUnlockMutex(voice->src.bufferLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
- LOG_API_EXIT(voice->audio)
- }
- uint32_t FAudioSourceVoice_SetFrequencyRatio(
- FAudioSourceVoice *voice,
- float Ratio,
- uint32_t OperationSet
- ) {
- LOG_API_ENTER(voice->audio)
- if (OperationSet != FAUDIO_COMMIT_NOW && voice->audio->active)
- {
- FAudio_OPERATIONSET_QueueSetFrequencyRatio(
- voice,
- Ratio,
- OperationSet
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- if (voice->flags & FAUDIO_VOICE_NOPITCH)
- {
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- voice->src.freqRatio = FAudio_clamp(
- Ratio,
- FAUDIO_MIN_FREQ_RATIO,
- voice->src.maxFreqRatio
- );
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- void FAudioSourceVoice_GetFrequencyRatio(
- FAudioSourceVoice *voice,
- float *pRatio
- ) {
- LOG_API_ENTER(voice->audio)
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- *pRatio = voice->src.freqRatio;
- LOG_API_EXIT(voice->audio)
- }
- uint32_t FAudioSourceVoice_SetSourceSampleRate(
- FAudioSourceVoice *voice,
- uint32_t NewSourceSampleRate
- ) {
- uint32_t outSampleRate;
- uint32_t newDecodeSamples, newResampleSamples;
- LOG_API_ENTER(voice->audio)
- FAudio_assert(voice->type == FAUDIO_VOICE_SOURCE);
- FAudio_assert( NewSourceSampleRate >= FAUDIO_MIN_SAMPLE_RATE &&
- NewSourceSampleRate <= FAUDIO_MAX_SAMPLE_RATE );
- FAudio_PlatformLockMutex(voice->src.bufferLock);
- LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
- if ( voice->audio->version > 7 &&
- voice->src.bufferList != NULL )
- {
- FAudio_PlatformUnlockMutex(voice->src.bufferLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
- LOG_API_EXIT(voice->audio)
- return FAUDIO_E_INVALID_CALL;
- }
- FAudio_PlatformUnlockMutex(voice->src.bufferLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
- voice->src.format->nSamplesPerSec = NewSourceSampleRate;
- /* Resize decode cache */
- newDecodeSamples = (uint32_t) FAudio_ceil(
- voice->audio->updateSize *
- (double) voice->src.maxFreqRatio *
- (double) NewSourceSampleRate /
- (double) voice->audio->master->master.inputSampleRate
- ) + EXTRA_DECODE_PADDING * voice->src.format->nChannels;
- FAudio_INTERNAL_ResizeDecodeCache(
- voice->audio,
- (newDecodeSamples + EXTRA_DECODE_PADDING) * voice->src.format->nChannels
- );
- voice->src.decodeSamples = newDecodeSamples;
- FAudio_PlatformLockMutex(voice->sendLock);
- LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
- if (voice->sends.SendCount == 0)
- {
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- outSampleRate = voice->sends.pSends[0].pOutputVoice->type == FAUDIO_VOICE_MASTER ?
- voice->sends.pSends[0].pOutputVoice->master.inputSampleRate :
- voice->sends.pSends[0].pOutputVoice->mix.inputSampleRate;
- newResampleSamples = (uint32_t) (FAudio_ceil(
- (double) voice->audio->updateSize *
- (double) outSampleRate /
- (double) voice->audio->master->master.inputSampleRate
- ));
- voice->src.resampleSamples = newResampleSamples;
- FAudio_PlatformUnlockMutex(voice->sendLock);
- LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- /* FAudioMasteringVoice Interface */
- FAUDIOAPI uint32_t FAudioMasteringVoice_GetChannelMask(
- FAudioMasteringVoice *voice,
- uint32_t *pChannelMask
- ) {
- LOG_API_ENTER(voice->audio)
- FAudio_assert(voice->type == FAUDIO_VOICE_MASTER);
- FAudio_assert(pChannelMask != NULL);
- *pChannelMask = voice->audio->mixFormat.dwChannelMask;
- LOG_API_EXIT(voice->audio)
- return 0;
- }
- #ifdef FAUDIO_DUMP_VOICES
- static inline FAudioIOStreamOut *DumpVoices_fopen(
- const FAudioSourceVoice *voice,
- const FAudioWaveFormatEx *format,
- const char *mode,
- const char *ext
- ) {
- char loc[64];
- uint16_t format_tag = format->wFormatTag;
- uint16_t format_ex_tag = 0;
- if (format->wFormatTag == FAUDIO_FORMAT_EXTENSIBLE)
- {
- /* get the GUID of the extended subformat */
- const FAudioWaveFormatExtensible *format_ex =
- (const FAudioWaveFormatExtensible*) format;
- format_ex_tag = (uint16_t) (format_ex->SubFormat.Data1);
- }
- FAudio_snprintf(
- loc,
- sizeof(loc),
- "FA_fmt_0x%04X_0x%04X_0x%016lX%s.wav",
- format_tag,
- format_ex_tag,
- (uint64_t) voice,
- ext
- );
- FAudioIOStreamOut *fileOut = FAudio_fopen_out(loc, mode);
- return fileOut;
- }
- static inline void DumpVoices_finalize_section(
- const FAudioSourceVoice *voice,
- const FAudioWaveFormatEx *format,
- const char *section /* one of "data" or "dpds" */
- ) {
- /* data file only contains the real data bytes */
- FAudioIOStreamOut *io_data = DumpVoices_fopen(voice, format, "rb", section);
- if (!io_data)
- {
- return;
- }
- FAudio_PlatformLockMutex((FAudioMutex) io_data->lock);
- size_t file_size_data = io_data->size(io_data->data);
- if (file_size_data == 0)
- {
- /* nothing to do */
- /* close data file */
- FAudio_PlatformUnlockMutex((FAudioMutex) io_data->lock);
- FAudio_close_out(io_data);
- return;
- }
- /* we got some data: append data section to main file */
- FAudioIOStreamOut *io = DumpVoices_fopen(voice, format, "ab", "");
- if (!io)
- {
- /* close data file */
- FAudio_PlatformUnlockMutex((FAudioMutex) io_data->lock);
- FAudio_close_out(io_data);
- return;
- }
- /* data sub-chunk - 8 bytes + data */
- /* SubChunk2ID - 4 --> "data" or "dpds" */
- io->write(io->data, section, 4, 1);
- /* Subchunk2Size - 4 */
- uint32_t chunk_size = (uint32_t)file_size_data;
- io->write(io->data, &chunk_size, 4, 1);
- /* data */
- /* fill in data bytes */
- uint8_t buffer[1024*1024];
- size_t count;
- while((count = io_data->read(io_data->data, (void*) buffer, 1, 1024*1024)) > 0)
- {
- io->write(io->data, (void*) buffer, 1, count);
- }
- /* close data file */
- FAudio_PlatformUnlockMutex((FAudioMutex) io_data->lock);
- FAudio_close_out(io_data);
- /* close main file */
- FAudio_PlatformUnlockMutex((FAudioMutex) io->lock);
- FAudio_close_out(io);
- }
- static void FAudio_DUMPVOICE_Init(const FAudioSourceVoice *voice)
- {
- const FAudioWaveFormatEx *format = voice->src.format;
- FAudioIOStreamOut *io = DumpVoices_fopen(voice, format, "wb", "");
- if (!io)
- {
- return;
- }
- FAudio_PlatformLockMutex((FAudioMutex) io->lock);
- /* another GREAT ressource
- * https://wiki.multimedia.cx/index.php/Microsoft_xWMA
- */
- /* wave file format taken from
- * http://soundfile.sapp.org/doc/WaveFormat
- * https://sites.google.com/site/musicgapi/technical-documents/wav-file-format
- * |52 49|46 46|52 4A|02 00|
- * |c1 sz|af|nc|sp rt|bt rt|
- * |ba|bs|da ta|c2 sz|
- * | R I F F |chunk size |W A V E |f m t |
- * 19026
- * | 52 49 46 46 52 4A 02 00 57 41 56 45 66 6D 74 20 | RIFFRJ..WAVEfmt
- * | subchnk size|fmt |nChan |samplerate |byte rate |
- * | 50 | 2 |2 |11025 |11289 |
- * | 32 00 00 00 02 00 02 00 11 2B 00 00 19 2C 00 00 | 2........+...,..
- * |blkaln|bps |efmt |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|
- * | 512 |4 |32 |500 |7 |256 |0 |512 |
- * | 512 |4 |32 |459252 |256 |
- * | 00 02|04 00 20 00 F4 01 07 00 00 01 00 00 00 02 | .... .ô.........
- * | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
- * |
- * | 00 FF 00 00 00 00 C0 00 40 00 F0 00 00 00 CC 01 | .ÿ....À.@.ð...Ì.
- * | XXXXXXXXXXXXXXXXXX|d a t a |chunk size |XXXXX |
- * | | |18944 | |
- * | 30 FF 88 01 18 FF 64 61 74 61 00 4A 02 00 00 00 | 0ÿ...ÿdata.J....
- */
- uint16_t cbSize = format->cbSize;
- const char *formatFourcc = "WAVE";
- uint16_t wFormatTag = format->wFormatTag;
- /* special handling for WMAUDIO2 */
- if (wFormatTag == FAUDIO_FORMAT_EXTENSIBLE && cbSize >= 22)
- {
- const FAudioWaveFormatExtensible *format_ex =
- (const FAudioWaveFormatExtensible*) format;
- uint16_t format_ex_tag = (uint16_t) (format_ex->SubFormat.Data1);
- if (format_ex_tag == FAUDIO_FORMAT_WMAUDIO2)
- {
- cbSize = 0;
- formatFourcc = "XWMA";
- wFormatTag = FAUDIO_FORMAT_WMAUDIO2;
- }
- }
- { /* RIFF chunk descriptor - 12 byte */
- /* ChunkID - 4 */
- io->write(io->data, "RIFF", 4, 1);
- /* ChunkSize - 4 */
- uint32_t filesize = 0; /* the real file size is written in finalize step */
- io->write(io->data, &filesize, 4, 1);
- /* Format - 4 */
- io->write(io->data, formatFourcc, 4, 1);
- }
- { /* fmt sub-chunk 24 */
- /* Subchunk1ID - 4 */
- io->write(io->data, "fmt ", 4, 1);
- /* Subchunk1Size - 4 */
- /* 18 byte for WAVEFORMATEX and cbSize for WAVEFORMATEXTENDED */
- uint32_t chunk_data_size = 18 + (uint32_t) cbSize;
- io->write(io->data, &chunk_data_size, 4, 1);
- /* AudioFormat - 2 */
- io->write(io->data, &wFormatTag, 2, 1);
- /* NumChannels - 2 */
- io->write(io->data, &format->nChannels, 2, 1);
- /* SampleRate - 4 */
- io->write(io->data, &format->nSamplesPerSec, 4, 1);
- /* ByteRate - 4 */
- /* SampleRate * NumChannels * BitsPerSample/8 */
- io->write(io->data, &format->nAvgBytesPerSec, 4, 1);
- /* BlockAlign - 2 */
- /* NumChannels * BitsPerSample/8 */
- io->write(io->data, &format->nBlockAlign, 2, 1);
- /* BitsPerSample - 2 */
- io->write(io->data, &format->wBitsPerSample, 2, 1);
- }
- /* in case of extensible audio format write the additional data to the file */
- {
- /* always write the cbSize */
- io->write(io->data, &cbSize, 2, 1);
- if (cbSize >= 22)
- {
- /* we have a WAVEFORMATEXTENSIBLE struct to write */
- const FAudioWaveFormatExtensible *format_ex =
- (const FAudioWaveFormatExtensible*) format;
- io->write(io->data, &format_ex->Samples.wValidBitsPerSample, 2, 1);
- io->write(io->data, &format_ex->dwChannelMask, 4, 1);
- /* write FAudioGUID */
- io->write(io->data, &format_ex->SubFormat.Data1, 4, 1);
- io->write(io->data, &format_ex->SubFormat.Data2, 2, 1);
- io->write(io->data, &format_ex->SubFormat.Data3, 2, 1);
- io->write(io->data, &format_ex->SubFormat.Data4, 1, 8);
- }
- if (format->cbSize > 22)
- {
- /* fill up the remaining cbSize bytes with zeros */
- uint8_t zero = 0;
- for (uint16_t i=23; i<=format->cbSize; i++)
- {
- io->write(io->data, &zero, 1, 1);
- }
- }
- }
- { /* dpds sub-chunk - optional - 8 bytes + bufferWMA uint32_t samples */
- /* create file to hold the bufferWMA samples */
- FAudioIOStreamOut *io_dpds = DumpVoices_fopen(voice, format, "wb", "dpds");
- FAudio_close_out(io_dpds);
- /* io_dpds file will be filled by SubmitBuffer */
- }
- { /* data sub-chunk - 8 bytes + data */
- /* create file to hold the data samples */
- FAudioIOStreamOut *io_data = DumpVoices_fopen(voice, format, "wb", "data");
- FAudio_close_out(io_data);
- /* io_data file will be filled by SubmitBuffer */
- }
- FAudio_PlatformUnlockMutex((FAudioMutex) io->lock);
- FAudio_close_out(io);
- }
- static void FAudio_DUMPVOICE_Finalize(const FAudioSourceVoice *voice)
- {
- const FAudioWaveFormatEx *format = voice->src.format;
- /* add dpds subchunk - optional */
- DumpVoices_finalize_section(voice, format, "dpds");
- /* add data subchunk */
- DumpVoices_finalize_section(voice, format, "data");
- /* open main file to update filesize */
- FAudioIOStreamOut *io = DumpVoices_fopen(voice, format, "r+b", "");
- if (!io)
- {
- return;
- }
- FAudio_PlatformLockMutex((FAudioMutex) io->lock);
- size_t file_size = io->size(io->data);
- if (file_size >= 44)
- {
- /* update filesize */
- uint32_t chunk_size = (uint32_t)(file_size - 8);
- io->seek(io->data, 4, FAUDIO_SEEK_SET);
- io->write(io->data, &chunk_size, 4, 1);
- }
- FAudio_PlatformUnlockMutex((FAudioMutex) io->lock);
- FAudio_close_out(io);
- }
- static void FAudio_DUMPVOICE_WriteBuffer(
- const FAudioSourceVoice *voice,
- const FAudioBuffer *pBuffer,
- const FAudioBufferWMA *pBufferWMA,
- const uint32_t playBegin,
- const uint32_t playLength
- ) {
- FAudioIOStreamOut *io_data = DumpVoices_fopen(voice, voice->src.format, "ab", "data");
- if (io_data == NULL)
- {
- return;
- }
- FAudio_PlatformLockMutex((FAudioMutex) io_data->lock);
- if (pBufferWMA != NULL)
- {
- /* dump encoded buffer contents */
- if (pBufferWMA->PacketCount > 0)
- {
- FAudioIOStreamOut *io_dpds = DumpVoices_fopen(voice, voice->src.format, "ab", "dpds");
- if (io_dpds)
- {
- FAudio_PlatformLockMutex((FAudioMutex) io_dpds->lock);
- /* write to dpds file */
- io_dpds->write(io_dpds->data, pBufferWMA->pDecodedPacketCumulativeBytes, sizeof(uint32_t), pBufferWMA->PacketCount);
- FAudio_PlatformUnlockMutex((FAudioMutex) io_dpds->lock);
- FAudio_close_out(io_dpds);
- }
- /* write buffer contents to data file */
- io_data->write(io_data->data, pBuffer->pAudioData, sizeof(uint8_t), pBuffer->AudioBytes);
- }
- }
- else
- {
- /* dump unencoded buffer contents */
- uint16_t bytesPerFrame = (voice->src.format->nChannels * voice->src.format->wBitsPerSample / 8);
- FAudio_assert(bytesPerFrame > 0);
- const void *pAudioDataBegin = pBuffer->pAudioData + playBegin*bytesPerFrame;
- io_data->write(io_data->data, pAudioDataBegin, bytesPerFrame, playLength);
- }
- FAudio_PlatformUnlockMutex((FAudioMutex) io_data->lock);
- FAudio_close_out(io_data);
- }
- #endif /* FAUDIO_DUMP_VOICES */
- /* vim: set noexpandtab shiftwidth=8 tabstop=8: */
|